bashcov 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|