bashcov 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +3 -1
- data/README.md +5 -1
- data/bashcov.gemspec +3 -0
- data/bin/bashcov +1 -1
- data/lib/bashcov.rb +27 -8
- data/lib/bashcov/lexer.rb +14 -6
- data/lib/bashcov/line.rb +6 -2
- data/lib/bashcov/runner.rb +32 -17
- data/lib/bashcov/version.rb +2 -1
- data/lib/bashcov/xtrace.rb +13 -1
- data/spec/bashcov/lexer_spec.rb +8 -0
- data/spec/bashcov_spec.rb +2 -2
- data/spec/support/test_app.rb +3 -1
- data/spec/test_app/scripts/executable +4 -0
- data/spec/test_app/scripts/multiline.sh +8 -0
- data/spec/test_app/scripts/sourced.txt +0 -0
- data/spec/test_app/test_suite.sh +1 -1
- metadata +41 -4
- data/TODO +0 -3
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[bashcov] is [simplecov] for Bash.
|
4
4
|
|
5
|
-
**[
|
5
|
+
Check out the **[demo](http://infertux.github.com/bashcov/test_app/)** - it's worth a thousand words.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -37,6 +37,10 @@ After a bit of parsing, it sends results through _simplecov_ which generates an
|
|
37
37
|
|
38
38
|
And of course, you can take the most of _simplecov_ by adding a `.simplecov` file in your project's root (like [this](https://github.com/infertux/bashcov/blob/master/spec/test_app/.simplecov)).
|
39
39
|
|
40
|
+
## Todo
|
41
|
+
|
42
|
+
- semver
|
43
|
+
|
40
44
|
## License
|
41
45
|
|
42
46
|
MIT
|
data/bashcov.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
|
|
11
11
|
gem.description = %q{Code coverage tool for Bash}
|
12
12
|
gem.summary = gem.description
|
13
13
|
gem.homepage = "https://github.com/infertux/bashcov"
|
14
|
+
gem.license = 'MIT'
|
14
15
|
|
15
16
|
gem.files = `git ls-files`.split($/)
|
16
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -24,4 +25,6 @@ Gem::Specification.new do |gem|
|
|
24
25
|
gem.add_development_dependency 'rspec'
|
25
26
|
gem.add_development_dependency 'guard-rspec'
|
26
27
|
gem.add_development_dependency 'rb-inotify'
|
28
|
+
gem.add_development_dependency 'cane'
|
29
|
+
gem.add_development_dependency 'yard'
|
27
30
|
end
|
data/bin/bashcov
CHANGED
data/lib/bashcov.rb
CHANGED
@@ -6,23 +6,31 @@ require 'bashcov/line'
|
|
6
6
|
require 'bashcov/runner'
|
7
7
|
require 'bashcov/xtrace'
|
8
8
|
|
9
|
+
# Bashcov default module
|
10
|
+
# @note Keep it short!
|
9
11
|
module Bashcov
|
10
12
|
class << self
|
13
|
+
# @return [OpenStruct] Bashcov settings
|
11
14
|
attr_reader :options
|
12
15
|
|
16
|
+
# Sets default options overriding any existing ones.
|
17
|
+
# @return [void]
|
13
18
|
def set_default_options!
|
14
19
|
@options ||= OpenStruct.new
|
15
20
|
@options.skip_uncovered = false
|
16
21
|
@options.mute = false
|
17
22
|
end
|
18
23
|
|
24
|
+
# Parses the given CLI arguments and sets +options+.
|
25
|
+
# @param [Array] args list of arguments
|
26
|
+
# @raise [SystemExit] if invalid arguments are given
|
27
|
+
# @return [void]
|
19
28
|
def parse_options! args
|
20
29
|
OptionParser.new do |opts|
|
21
30
|
opts.banner = "Usage: #{opts.program_name} [options] <filename>"
|
22
31
|
opts.version = Bashcov::VERSION
|
23
32
|
|
24
|
-
opts.separator ""
|
25
|
-
opts.separator "Specific options:"
|
33
|
+
opts.separator "\nSpecific options:"
|
26
34
|
|
27
35
|
opts.on("-s", "--skip-uncovered", "Do not report uncovered files") do |s|
|
28
36
|
@options.skip_uncovered = s
|
@@ -32,8 +40,7 @@ module Bashcov
|
|
32
40
|
@options.mute = m
|
33
41
|
end
|
34
42
|
|
35
|
-
opts.separator ""
|
36
|
-
opts.separator "Common options:"
|
43
|
+
opts.separator "\nCommon options:"
|
37
44
|
|
38
45
|
opts.on_tail("-h", "--help", "Show this message") do
|
39
46
|
abort(opts.help)
|
@@ -53,20 +60,32 @@ module Bashcov
|
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
63
|
+
# @return [String] The project's root directory
|
56
64
|
def root_directory
|
57
65
|
Dir.getwd
|
58
66
|
end
|
59
67
|
|
68
|
+
# Program name including version for easy consistent output
|
69
|
+
# @return [String]
|
70
|
+
def name
|
71
|
+
"bashcov v#{VERSION}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Helper to get a pre-filled coverage array for a given file
|
75
|
+
# @todo This is generic and should be moved in some helpers file.
|
76
|
+
# @api private
|
77
|
+
# @param [String] filename The file to cover.
|
78
|
+
# @param [nil, Integer] fill Value to fill the array with.
|
79
|
+
# @return [Array] An array of the size of the given file.
|
80
|
+
# @example
|
81
|
+
# coverage_array('file.rb') #=> [0, 0, 0] # assuming file.rb has 3 lines
|
60
82
|
def coverage_array(filename, fill = Line::UNCOVERED)
|
61
83
|
lines = File.readlines(filename).size
|
62
84
|
[fill] * lines
|
63
85
|
end
|
64
|
-
|
65
|
-
def link
|
66
|
-
%Q|<a href="https://github.com/infertux/bashcov">bashcov</a> v#{VERSION}|
|
67
|
-
end
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
89
|
+
# Make sure default options are set
|
71
90
|
Bashcov.set_default_options!
|
72
91
|
|
data/lib/bashcov/lexer.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
module Bashcov
|
2
|
+
# Simple lexer which analyzes Bash files in order to get information for
|
3
|
+
# coverage
|
2
4
|
class Lexer
|
5
|
+
# @param [String] filename File to analyze
|
6
|
+
# @raise [ArgumentError] if the given +filename+ is invalid.
|
3
7
|
def initialize filename
|
4
8
|
@filename = File.expand_path(filename)
|
5
|
-
|
9
|
+
|
10
|
+
unless File.file?(@filename)
|
11
|
+
raise ArgumentError, "#{@filename} is not a file"
|
12
|
+
end
|
6
13
|
end
|
7
14
|
|
15
|
+
# @return [Array] Irrelevant lines
|
8
16
|
def irrelevant_lines
|
9
17
|
lines = []
|
10
18
|
IO.readlines(@filename).each_with_index do |line, lineno|
|
@@ -17,11 +25,11 @@ module Bashcov
|
|
17
25
|
|
18
26
|
def is_irrevelant? line
|
19
27
|
line.strip!
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
|
29
|
+
line.empty? or
|
30
|
+
start_with.any? { |token| line.start_with? token } or
|
31
|
+
is.any? { |keyword| line == keyword } or
|
32
|
+
line =~ /\A\w+\(\) {/ # function declared like this: "foo() {"
|
25
33
|
end
|
26
34
|
|
27
35
|
# Lines containing only one of these keywords are irrelevant for coverage
|
data/lib/bashcov/line.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
module Bashcov
|
2
|
+
# {Line} represents a line of code
|
2
3
|
module Line
|
3
|
-
#
|
4
|
-
|
4
|
+
# Uncovered line
|
5
|
+
# @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/coverage/rdoc/Coverage.html
|
5
6
|
UNCOVERED = 0
|
7
|
+
|
8
|
+
# Ignored line
|
9
|
+
# @see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/coverage/rdoc/Coverage.html
|
6
10
|
IGNORED = nil
|
7
11
|
end
|
8
12
|
end
|
data/lib/bashcov/runner.rb
CHANGED
@@ -1,64 +1,76 @@
|
|
1
1
|
require 'open4'
|
2
2
|
|
3
3
|
module Bashcov
|
4
|
+
# Runs a given command capturing output then computes code coverage.
|
4
5
|
class Runner
|
5
|
-
|
6
|
+
# @return [Array] +stdout+ from the last run
|
7
|
+
attr_reader :stdout
|
6
8
|
|
9
|
+
# @return [Array] +stderr+ from the last run
|
10
|
+
attr_reader :stderr
|
11
|
+
|
12
|
+
# @param [String] filename Command to run
|
7
13
|
def initialize filename
|
8
14
|
@filename = File.expand_path(filename)
|
9
15
|
end
|
10
16
|
|
17
|
+
# Runs the command capturing +stdout+ and +stderr+.
|
18
|
+
# @note Binds Bashcov +stdin+ to the program executed.
|
19
|
+
# @note Uses two threads to stream +stdout+ and +stderr+ output in
|
20
|
+
# realtime.
|
21
|
+
# @return [void]
|
11
22
|
def run
|
12
23
|
setup
|
13
24
|
|
14
25
|
Open4::popen4(@command) do |pid, stdin, stdout, stderr|
|
15
26
|
stdin = $stdin # bind stdin
|
16
27
|
|
17
|
-
[
|
28
|
+
[
|
18
29
|
Thread.new { # stdout
|
19
30
|
stdout.each do |line|
|
20
|
-
$stdout.puts line unless Bashcov.options.mute
|
21
31
|
@stdout << line
|
32
|
+
$stdout.puts line unless Bashcov.options.mute
|
22
33
|
end
|
23
34
|
},
|
24
35
|
Thread.new { # stderr
|
25
36
|
stderr.each do |line|
|
26
|
-
unless Bashcov.options.mute
|
27
|
-
xtrace = Xtrace.new [line]
|
28
|
-
$stderr.puts line if xtrace.xtrace_output.empty?
|
29
|
-
end
|
30
37
|
@stderr << line
|
38
|
+
next if Bashcov.options.mute
|
39
|
+
xtrace = Xtrace.new [line]
|
40
|
+
$stderr.puts line if xtrace.xtrace_output.empty?
|
31
41
|
end
|
32
42
|
}
|
33
43
|
].map(&:join)
|
34
44
|
end
|
35
45
|
end
|
36
46
|
|
47
|
+
# @return [Hash] Coverage hash of the last run
|
37
48
|
def result
|
38
|
-
if Bashcov.options.skip_uncovered
|
39
|
-
|
49
|
+
files = if Bashcov.options.skip_uncovered
|
50
|
+
{}
|
40
51
|
else
|
41
|
-
|
52
|
+
find_bash_files "#{Bashcov.root_directory}/**/*.sh"
|
42
53
|
end
|
43
54
|
|
44
55
|
files = add_coverage_result files
|
45
56
|
files = ignore_irrelevant_lines files
|
46
57
|
end
|
47
58
|
|
59
|
+
# @param [String] directory Directory to scan
|
60
|
+
# @return [Hash] Coverage hash of Bash files in the given +directory+. All
|
61
|
+
# files are marked as uncovered.
|
48
62
|
def find_bash_files directory
|
49
|
-
files
|
50
|
-
|
51
|
-
# grab all bash files in project root and mark them uncovered
|
52
|
-
Dir[directory].each do |file|
|
63
|
+
Dir[directory].inject({}) do |files, file|
|
53
64
|
absolute_path = File.expand_path(file)
|
54
65
|
next unless File.file?(absolute_path)
|
55
66
|
|
56
|
-
files
|
67
|
+
files.merge!(absolute_path => Bashcov.coverage_array(absolute_path))
|
57
68
|
end
|
58
|
-
|
59
|
-
files
|
60
69
|
end
|
61
70
|
|
71
|
+
# @param [Hash] files Initial coverage hash
|
72
|
+
# @return [Hash] Given hash including coverage result from {Xtrace}
|
73
|
+
# @see Xtrace
|
62
74
|
def add_coverage_result files
|
63
75
|
xtraced_files = Xtrace.new(@stderr).files
|
64
76
|
|
@@ -72,6 +84,9 @@ module Bashcov
|
|
72
84
|
files
|
73
85
|
end
|
74
86
|
|
87
|
+
# @param [Hash] files Initial coverage hash
|
88
|
+
# @return [Hash] Given hash ignoring irrelevant lines
|
89
|
+
# @see Lexer
|
75
90
|
def ignore_irrelevant_lines files
|
76
91
|
files.each do |filename, lines|
|
77
92
|
lexer = Lexer.new(filename)
|
data/lib/bashcov/version.rb
CHANGED
data/lib/bashcov/xtrace.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
module Bashcov
|
2
|
+
# This class manages +xtrace+ output.
|
3
|
+
#
|
4
|
+
# @see Runner
|
2
5
|
class Xtrace
|
6
|
+
# @param [Array] output Array of output lines.
|
7
|
+
# @raise [ArgumentError] if the given +output+ is not an array
|
3
8
|
def initialize output
|
4
|
-
raise "#{output} must be an array" unless output.is_a? Array
|
9
|
+
raise ArgumentError, "#{output} must be an array" unless output.is_a? Array
|
5
10
|
@lines = output
|
6
11
|
end
|
7
12
|
|
13
|
+
# Filters out non-xtrace lines.
|
14
|
+
# @return [Array] xtrace output
|
8
15
|
def xtrace_output
|
9
16
|
@lines.select { |line| line =~ Xtrace.line_regexp }
|
10
17
|
end
|
11
18
|
|
19
|
+
# Parses xtrace output and computes coverage
|
20
|
+
# @raise [RuntimeError] on invalid files
|
21
|
+
# @return [Hash] Hash of executed files with coverage information
|
12
22
|
def files
|
13
23
|
files = {}
|
14
24
|
|
@@ -29,6 +39,8 @@ module Bashcov
|
|
29
39
|
files
|
30
40
|
end
|
31
41
|
|
42
|
+
# @see http://www.gnu.org/software/bash/manual/bashref.html#index-PS4
|
43
|
+
# @return [String] +PS4+ variable used for xtrace output
|
32
44
|
def self.ps4
|
33
45
|
# We use a forward slash as delimiter since it's the only forbidden
|
34
46
|
# character in filenames on Unix and Windows.
|
data/spec/bashcov/lexer_spec.rb
CHANGED
@@ -15,6 +15,14 @@ shared_examples "a bash file" do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
describe Bashcov::Lexer do
|
18
|
+
describe "#initialize" do
|
19
|
+
it "raises if the file is invalid" do
|
20
|
+
expect {
|
21
|
+
Bashcov::Lexer.new 'inexistent_file.exe'
|
22
|
+
}.to raise_error ArgumentError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
18
26
|
expected_coverage.keys.each do |filename|
|
19
27
|
context filename do
|
20
28
|
it_behaves_like "a bash file" do
|
data/spec/bashcov_spec.rb
CHANGED
data/spec/support/test_app.rb
CHANGED
@@ -15,7 +15,7 @@ def uncovered_files
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def executed_files
|
18
|
-
bash_files - uncovered_files + ["#{scripts}/sourced.txt"]
|
18
|
+
bash_files - uncovered_files + ["#{scripts}/sourced.txt", "#{scripts}/executable"]
|
19
19
|
end
|
20
20
|
|
21
21
|
def bash_files
|
@@ -38,6 +38,8 @@ def expected_coverage
|
|
38
38
|
"#{test_app}/scripts/source.sh" => [nil, nil, 1, nil, 2, nil],
|
39
39
|
"#{test_app}/scripts/sourced.txt" => [nil, nil, 1, nil],
|
40
40
|
"#{test_app}/scripts/stdin.sh" => [nil, nil, 1, 1, 1, nil],
|
41
|
+
"#{test_app}/scripts/multiline.sh" => [nil, nil, 1, 2, 1, 1, 0, nil],
|
42
|
+
"#{test_app}/scripts/executable" => [nil, nil, 1, nil],
|
41
43
|
"#{test_app}/test_suite.sh" => [nil, nil, 2, nil, nil, 2, nil]
|
42
44
|
}
|
43
45
|
end
|
File without changes
|
data/spec/test_app/test_suite.sh
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bashcov
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: simplecov
|
@@ -107,6 +107,38 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: cane
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: yard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
110
142
|
description: Code coverage tool for Bash
|
111
143
|
email:
|
112
144
|
- cedric@felizard.fr
|
@@ -123,7 +155,6 @@ files:
|
|
123
155
|
- LICENSE.txt
|
124
156
|
- README.md
|
125
157
|
- Rakefile
|
126
|
-
- TODO
|
127
158
|
- bashcov.gemspec
|
128
159
|
- bin/bashcov
|
129
160
|
- lib/bashcov.rb
|
@@ -144,8 +175,10 @@ files:
|
|
144
175
|
- spec/test_app/never_called.sh
|
145
176
|
- spec/test_app/scripts/README.md
|
146
177
|
- spec/test_app/scripts/case.sh
|
178
|
+
- spec/test_app/scripts/executable
|
147
179
|
- spec/test_app/scripts/function.sh
|
148
180
|
- spec/test_app/scripts/long_line.sh
|
181
|
+
- spec/test_app/scripts/multiline.sh
|
149
182
|
- spec/test_app/scripts/nested/simple.sh
|
150
183
|
- spec/test_app/scripts/one_liner.sh
|
151
184
|
- spec/test_app/scripts/simple.sh
|
@@ -154,7 +187,8 @@ files:
|
|
154
187
|
- spec/test_app/scripts/stdin.sh
|
155
188
|
- spec/test_app/test_suite.sh
|
156
189
|
homepage: https://github.com/infertux/bashcov
|
157
|
-
licenses:
|
190
|
+
licenses:
|
191
|
+
- MIT
|
158
192
|
post_install_message:
|
159
193
|
rdoc_options: []
|
160
194
|
require_paths:
|
@@ -190,8 +224,10 @@ test_files:
|
|
190
224
|
- spec/test_app/never_called.sh
|
191
225
|
- spec/test_app/scripts/README.md
|
192
226
|
- spec/test_app/scripts/case.sh
|
227
|
+
- spec/test_app/scripts/executable
|
193
228
|
- spec/test_app/scripts/function.sh
|
194
229
|
- spec/test_app/scripts/long_line.sh
|
230
|
+
- spec/test_app/scripts/multiline.sh
|
195
231
|
- spec/test_app/scripts/nested/simple.sh
|
196
232
|
- spec/test_app/scripts/one_liner.sh
|
197
233
|
- spec/test_app/scripts/simple.sh
|
@@ -199,3 +235,4 @@ test_files:
|
|
199
235
|
- spec/test_app/scripts/sourced.txt
|
200
236
|
- spec/test_app/scripts/stdin.sh
|
201
237
|
- spec/test_app/test_suite.sh
|
238
|
+
has_rdoc:
|