bashcov 0.0.1 → 0.0.2
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/.gitignore +1 -0
- data/Guardfile +10 -0
- data/README.md +2 -2
- data/bashcov.gemspec +2 -0
- data/lib/bashcov/lexer.rb +3 -2
- data/lib/bashcov/line.rb +2 -0
- data/lib/bashcov/runner.rb +46 -25
- data/lib/bashcov/version.rb +1 -1
- data/lib/bashcov/xtrace.rb +2 -1
- data/lib/bashcov.rb +1 -1
- data/spec/bashcov/lexer_spec.rb +21 -13
- data/spec/bashcov/runner_spec.rb +65 -11
- data/spec/bashcov/xtrace_spec.rb +12 -10
- data/spec/bashcov_spec.rb +10 -0
- data/spec/spec_helper.rb +2 -16
- data/spec/support/test_app.rb +41 -0
- metadata +39 -2
data/.gitignore
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# More info at https://github.com/guard/guard#readme
|
2
|
+
|
3
|
+
guard 'rspec', :version => 2 do
|
4
|
+
watch(%r{^spec/.+_spec\.rb$})
|
5
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
6
|
+
watch(%r{^lib/(.+)/(.+)\.rb$}) { |m| "spec/#{m[1]}/#{m[2]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
watch(%r{^spec/support/.+\.rb$}) { "spec" }
|
9
|
+
end
|
10
|
+
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
[bashcov] is [simplecov] for Bash.
|
4
4
|
|
5
|
+
**[Demo](http://infertux.github.com/bashcov/test_app/)**
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
`$ gem install bashcov`
|
@@ -12,8 +14,6 @@
|
|
12
14
|
|
13
15
|
This will create a directory named `coverage/` containing HTML files.
|
14
16
|
|
15
|
-
Example output: [demo](http://infertux.github.com/bashcov/test_app/)
|
16
|
-
|
17
17
|
## Rationale
|
18
18
|
|
19
19
|
I'm a big fan of both Ruby's _simplecov_ and Bash.
|
data/bashcov.gemspec
CHANGED
data/lib/bashcov/lexer.rb
CHANGED
@@ -2,6 +2,7 @@ module Bashcov
|
|
2
2
|
class Lexer
|
3
3
|
def initialize filename
|
4
4
|
@filename = File.expand_path(filename)
|
5
|
+
raise "#{@filename} is not a file" unless File.file?(@filename)
|
5
6
|
end
|
6
7
|
|
7
8
|
def irrelevant_lines
|
@@ -18,7 +19,7 @@ module Bashcov
|
|
18
19
|
line.strip!
|
19
20
|
return true if line.empty?
|
20
21
|
return true if start_with.any? { |token| line.start_with? token }
|
21
|
-
return true if is.any? { |keyword| line
|
22
|
+
return true if is.any? { |keyword| line == keyword }
|
22
23
|
return true if line =~ /\A\w+\(\) {/ # function declared like this: "foo() {"
|
23
24
|
false
|
24
25
|
end
|
@@ -28,7 +29,7 @@ module Bashcov
|
|
28
29
|
%w(esac fi then do done else { })
|
29
30
|
end
|
30
31
|
|
31
|
-
# Lines starting with one of these
|
32
|
+
# Lines starting with one of these tokens are irrelevant for coverage
|
32
33
|
def start_with
|
33
34
|
%w(# function)
|
34
35
|
end
|
data/lib/bashcov/line.rb
CHANGED
data/lib/bashcov/runner.rb
CHANGED
@@ -9,50 +9,71 @@ module Bashcov
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def run
|
12
|
-
|
13
|
-
ENV['SHELLOPTS'] = 'braceexpand:hashall:interactive-comments:posix:verbose:xtrace'
|
12
|
+
inject_shellopts_flags
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
env = { 'PS4' => Xtrace.ps4 }
|
15
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(env, @filename)
|
16
|
+
exit_status = wait_thr.value # block until process returns
|
17
|
+
@output = stderr.dup
|
17
18
|
end
|
18
19
|
|
19
20
|
def result
|
20
|
-
|
21
|
-
|
21
|
+
files = find_bash_files "#{Bashcov.root_directory}/**/*.sh"
|
22
|
+
files = add_coverage_result files
|
23
|
+
files = ignore_irrelevant_lines files
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_bash_files directory
|
27
|
+
files = {}
|
28
|
+
|
29
|
+
# grab all bash files in project root and mark them uncovered
|
30
|
+
(Dir[directory] - [@filename]).each do |file|
|
31
|
+
absolute_path = File.expand_path(file)
|
32
|
+
next unless File.file?(absolute_path)
|
22
33
|
|
23
|
-
|
34
|
+
files[absolute_path] = Bashcov.coverage_array(absolute_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
files
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_coverage_result files
|
24
41
|
xtraced_files = Xtrace.new(@output).files
|
42
|
+
xtraced_files.delete @filename # drop the test suite file
|
43
|
+
|
25
44
|
xtraced_files.each do |file, lines|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@files[file][index] = line if line
|
45
|
+
lines.each_with_index do |line, lineno|
|
46
|
+
files[file] ||= Bashcov.coverage_array(file) # non .sh files but executed though
|
47
|
+
files[file][lineno] = line if line
|
30
48
|
end
|
31
49
|
end
|
32
50
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
51
|
+
files
|
52
|
+
end
|
53
|
+
|
54
|
+
def ignore_irrelevant_lines files
|
55
|
+
files.each do |filename, lines|
|
37
56
|
lexer = Lexer.new(filename)
|
38
57
|
lexer.irrelevant_lines.each do |lineno|
|
39
|
-
|
58
|
+
files[filename][lineno] = Bashcov::Line::IGNORED
|
40
59
|
end
|
41
60
|
end
|
42
61
|
end
|
43
62
|
|
44
|
-
|
45
|
-
files = {}
|
46
|
-
|
47
|
-
(Dir["#{Bashcov.root_directory}/**/*.sh"] - [@filename]).each do |file|
|
48
|
-
absolute_path = File.expand_path(file)
|
49
|
-
next unless File.file?(absolute_path)
|
63
|
+
private
|
50
64
|
|
51
|
-
|
52
|
-
|
65
|
+
def inject_shellopts_flags
|
66
|
+
# SHELLOPTS must be exported so we use Ruby's ENV variable
|
67
|
+
existing_flags = (ENV['SHELLOPTS'] || '').split(shellopts_separator)
|
68
|
+
ENV['SHELLOPTS'] = (existing_flags | shellopts_flags).join(shellopts_separator)
|
69
|
+
end
|
53
70
|
|
54
|
-
|
71
|
+
def shellopts_flags
|
72
|
+
%w(verbose xtrace)
|
55
73
|
end
|
56
74
|
|
75
|
+
def shellopts_separator
|
76
|
+
':'
|
77
|
+
end
|
57
78
|
end
|
58
79
|
end
|
data/lib/bashcov/version.rb
CHANGED
data/lib/bashcov/xtrace.rb
CHANGED
@@ -11,7 +11,8 @@ module Bashcov
|
|
11
11
|
next unless match = line.match(Xtrace.line_regexp)
|
12
12
|
|
13
13
|
filename = File.expand_path(match[:filename], Bashcov.root_directory)
|
14
|
-
next
|
14
|
+
next if File.directory? filename
|
15
|
+
raise "#{filename} is not a file" unless File.file? filename
|
15
16
|
|
16
17
|
lineno = match[:lineno].to_i
|
17
18
|
lineno -= 1 if lineno > 0
|
data/lib/bashcov.rb
CHANGED
data/spec/bashcov/lexer_spec.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
3
|
+
shared_examples "a bash file" do
|
4
4
|
describe "#irrelevant_lines" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
['sourced.txt', [0, 1, 3]]
|
9
|
-
|
10
|
-
].each do |filename, lines|
|
11
|
-
context "for #{filename}" do
|
12
|
-
it "returns irrelevant lines" do
|
13
|
-
lexer = Bashcov::Lexer.new File.join(scripts, filename)
|
14
|
-
lexer.irrelevant_lines.should =~ lines
|
15
|
-
end
|
16
|
-
end
|
5
|
+
it "returns irrelevant lines" do
|
6
|
+
lexer = Bashcov::Lexer.new File.join(scripts, filename)
|
7
|
+
lexer.irrelevant_lines.should =~ irrelevant_lines
|
17
8
|
end
|
18
9
|
end
|
19
10
|
end
|
20
11
|
|
12
|
+
describe Bashcov::Lexer do
|
13
|
+
it_behaves_like "a bash file" do
|
14
|
+
let(:filename) { 'simple.sh' }
|
15
|
+
let(:irrelevant_lines) { [0, 1, 2, 3, 6, 8, 9, 11, 12] }
|
16
|
+
end
|
17
|
+
|
18
|
+
it_behaves_like "a bash file" do
|
19
|
+
let(:filename) { 'function.sh' }
|
20
|
+
let(:irrelevant_lines) { [0, 1, 2, 4, 5, 6, 9, 10, 13] }
|
21
|
+
end
|
22
|
+
|
23
|
+
it_behaves_like "a bash file" do
|
24
|
+
let(:filename) { 'sourced.txt' }
|
25
|
+
let(:irrelevant_lines) { [0, 1, 3] }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/spec/bashcov/runner_spec.rb
CHANGED
@@ -1,27 +1,81 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Bashcov::Runner do
|
4
|
-
|
5
|
-
|
4
|
+
let(:runner) { Bashcov::Runner.new test_suite }
|
5
|
+
let(:bash_files_glob) { "#{Bashcov.root_directory}/**/*.sh" }
|
6
|
+
|
7
|
+
describe "#run" do
|
8
|
+
context "without a SHELLOPTS variable" do
|
9
|
+
before do
|
10
|
+
ENV['SHELLOPTS'] = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds the flags" do
|
14
|
+
runner.run
|
15
|
+
ENV['SHELLOPTS'].should == 'verbose:xtrace'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with an existing SHELLOPTS variable" do
|
20
|
+
before do
|
21
|
+
ENV['SHELLOPTS'] = 'posix:verbose'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "merges the flags" do
|
25
|
+
runner.run
|
26
|
+
ENV['SHELLOPTS'].should == 'posix:verbose:xtrace'
|
27
|
+
end
|
28
|
+
end
|
6
29
|
end
|
7
30
|
|
8
31
|
describe "#find_bash_files" do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
32
|
+
let(:files) { runner.find_bash_files bash_files_glob }
|
33
|
+
subject { files }
|
34
|
+
|
35
|
+
it { should be_a Hash }
|
36
|
+
|
37
|
+
it "contains bash files" do
|
38
|
+
subject.keys.should =~ bash_files
|
39
|
+
end
|
40
|
+
|
41
|
+
it "marks files as uncovered" do
|
42
|
+
subject.values.each do |lines|
|
13
43
|
lines.each { |line| line.should == Bashcov::Line::UNCOVERED }
|
14
44
|
end
|
15
45
|
end
|
16
46
|
end
|
17
47
|
|
48
|
+
describe "#add_coverage_result" do
|
49
|
+
let(:files) {
|
50
|
+
runner.run
|
51
|
+
files = runner.find_bash_files bash_files_glob
|
52
|
+
runner.add_coverage_result files
|
53
|
+
}
|
54
|
+
subject { files }
|
55
|
+
|
56
|
+
it { should be_a Hash }
|
57
|
+
|
58
|
+
it "contains all files" do
|
59
|
+
subject.keys.should =~ all_files
|
60
|
+
end
|
61
|
+
|
62
|
+
it "adds correct coverage results" do
|
63
|
+
subject.each do |file, lines|
|
64
|
+
lines.each_with_index do |line, lineno|
|
65
|
+
[
|
66
|
+
Bashcov::Line::UNCOVERED,
|
67
|
+
expected_coverage[file][lineno]
|
68
|
+
].should include line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
18
74
|
describe "#result" do
|
19
|
-
it "returns a valid hash" do
|
20
|
-
|
21
|
-
result = @runner.result
|
75
|
+
it "returns a valid coverage hash" do
|
76
|
+
runner.run
|
22
77
|
|
23
|
-
result.
|
24
|
-
result.size.should == 8 # FIXME
|
78
|
+
runner.result.should == expected_coverage
|
25
79
|
end
|
26
80
|
end
|
27
81
|
end
|
data/spec/bashcov/xtrace_spec.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Bashcov::Xtrace do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
4
|
+
let(:xtrace) {
|
5
|
+
runner = Bashcov::Runner.new test_suite
|
6
|
+
runner.run
|
7
|
+
Bashcov::Xtrace.new runner.output
|
8
|
+
}
|
10
9
|
|
11
10
|
describe "#files" do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
let(:files) { xtrace.files }
|
12
|
+
subject { files }
|
13
|
+
|
14
|
+
it { should be_a Hash }
|
15
|
+
|
16
|
+
it "contains expected files" do
|
17
|
+
subject.keys.should =~ executed_files | [test_suite]
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
unless RUBY_ENGINE == 'rbx' # coverage support is broken on rbx
|
2
2
|
require 'simplecov'
|
3
3
|
SimpleCov.start do
|
4
|
-
minimum_coverage
|
4
|
+
minimum_coverage 100
|
5
5
|
add_group "Sources", "lib"
|
6
6
|
add_group "Tests", "spec"
|
7
7
|
end
|
@@ -9,19 +9,5 @@ end
|
|
9
9
|
|
10
10
|
require 'bashcov'
|
11
11
|
|
12
|
-
|
13
|
-
File.expand_path("../test_app", __FILE__)
|
14
|
-
end
|
15
|
-
|
16
|
-
def scripts
|
17
|
-
"#{test_app}/scripts"
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_suite
|
21
|
-
"#{test_app}/test_suite.sh"
|
22
|
-
end
|
23
|
-
|
24
|
-
def executed_files
|
25
|
-
Dir["#{scripts}/**/*"].select { |file| File.file? file }
|
26
|
-
end
|
12
|
+
Dir["./spec/support/**/*.rb"].each { |file| require file }
|
27
13
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
def test_app
|
2
|
+
File.expand_path("../../test_app", __FILE__)
|
3
|
+
end
|
4
|
+
|
5
|
+
def scripts
|
6
|
+
"#{test_app}/scripts"
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_suite
|
10
|
+
"#{test_app}/test_suite.sh"
|
11
|
+
end
|
12
|
+
|
13
|
+
def executed_files
|
14
|
+
files_in("#{scripts}/**/*")
|
15
|
+
end
|
16
|
+
|
17
|
+
def bash_files
|
18
|
+
files_in("#{test_app}/**/*.sh") - [test_suite]
|
19
|
+
end
|
20
|
+
|
21
|
+
def all_files
|
22
|
+
files_in("#{test_app}/**/*") - [test_suite]
|
23
|
+
end
|
24
|
+
|
25
|
+
def files_in directory
|
26
|
+
Dir[directory].select { |file| File.file? file }
|
27
|
+
end
|
28
|
+
|
29
|
+
def expected_coverage
|
30
|
+
{
|
31
|
+
"#{test_app}/never_called.sh" => [nil, nil, 0, nil],
|
32
|
+
"#{test_app}/scripts/function.sh" => [nil, nil, nil, 2, nil, nil, nil, 1, 1, nil, nil, 1, 1, nil],
|
33
|
+
"#{test_app}/scripts/long_line.sh" => [nil, nil, 1, 1, 1, 0, nil],
|
34
|
+
"#{test_app}/scripts/nested/simple.sh" => [nil, nil, nil, nil, 1, 1, nil, 0, nil, nil, 1, nil, nil],
|
35
|
+
"#{test_app}/scripts/one_liner.sh" => [nil, nil, 2, nil, 1, nil, 0, nil, nil],
|
36
|
+
"#{test_app}/scripts/simple.sh" => [nil, nil, nil, nil, 1, 1, nil, 0, nil, nil, 1, nil, nil],
|
37
|
+
"#{test_app}/scripts/source.sh" => [nil, nil, 1, nil, 2, nil],
|
38
|
+
"#{test_app}/scripts/sourced.txt" => [nil, nil, 1, nil]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
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.2
|
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: 2012-12-
|
12
|
+
date: 2012-12-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: simplecov
|
@@ -59,6 +59,38 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: guard-rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rb-inotify
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
62
94
|
description: Code coverage tool for Bash
|
63
95
|
email:
|
64
96
|
- cedric@felizard.fr
|
@@ -71,6 +103,7 @@ files:
|
|
71
103
|
- .rspec
|
72
104
|
- .travis.yml
|
73
105
|
- Gemfile
|
106
|
+
- Guardfile
|
74
107
|
- LICENSE.txt
|
75
108
|
- README.md
|
76
109
|
- Rakefile
|
@@ -86,7 +119,9 @@ files:
|
|
86
119
|
- spec/bashcov/lexer_spec.rb
|
87
120
|
- spec/bashcov/runner_spec.rb
|
88
121
|
- spec/bashcov/xtrace_spec.rb
|
122
|
+
- spec/bashcov_spec.rb
|
89
123
|
- spec/spec_helper.rb
|
124
|
+
- spec/support/test_app.rb
|
90
125
|
- spec/test_app/.simplecov
|
91
126
|
- spec/test_app/never_called.sh
|
92
127
|
- spec/test_app/scripts/function.sh
|
@@ -125,7 +160,9 @@ test_files:
|
|
125
160
|
- spec/bashcov/lexer_spec.rb
|
126
161
|
- spec/bashcov/runner_spec.rb
|
127
162
|
- spec/bashcov/xtrace_spec.rb
|
163
|
+
- spec/bashcov_spec.rb
|
128
164
|
- spec/spec_helper.rb
|
165
|
+
- spec/support/test_app.rb
|
129
166
|
- spec/test_app/.simplecov
|
130
167
|
- spec/test_app/never_called.sh
|
131
168
|
- spec/test_app/scripts/function.sh
|