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 CHANGED
@@ -4,6 +4,7 @@
4
4
  .bundle
5
5
  .config
6
6
  .yardoc
7
+ .rbx/
7
8
  Gemfile.lock
8
9
  InstalledFiles
9
10
  _yardoc
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
@@ -21,4 +21,6 @@ Gem::Specification.new do |gem|
21
21
 
22
22
  gem.add_development_dependency 'rake'
23
23
  gem.add_development_dependency 'rspec'
24
+ gem.add_development_dependency 'guard-rspec'
25
+ gem.add_development_dependency 'rb-inotify'
24
26
  end
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 =~ /\A#{keyword}\Z/ }
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 keywords are irrelevant for coverage
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
@@ -1,5 +1,7 @@
1
1
  module Bashcov
2
2
  module Line
3
+ # see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/coverage/rdoc/Coverage.html
4
+
3
5
  UNCOVERED = 0
4
6
  IGNORED = nil
5
7
  end
@@ -9,50 +9,71 @@ module Bashcov
9
9
  end
10
10
 
11
11
  def run
12
- # SHELLOPTS must be exported so we use Ruby's ENV variable
13
- ENV['SHELLOPTS'] = 'braceexpand:hashall:interactive-comments:posix:verbose:xtrace'
12
+ inject_shellopts_flags
14
13
 
15
- command = "PS4='#{Xtrace.ps4}' #{@filename}"
16
- _, _, @output = Open3.popen3(command)
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
- # 1. Grab all bash files in project root and mark them uncovered
21
- @files = find_bash_files
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
- # 2. Add coverage information from run
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
- next if file == @filename
27
- lines.each_with_index do |line, index|
28
- @files[file] ||= Bashcov.coverage_array(file) # non .sh files but executed though
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
- # 3. Ignore irrelevant lines
34
- @files.each do |filename, lines|
35
- warn filename unless File.file?(filename)
36
- next unless File.file?(filename)
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
- @files[filename][lineno] = Bashcov::Line::IGNORED
58
+ files[filename][lineno] = Bashcov::Line::IGNORED
40
59
  end
41
60
  end
42
61
  end
43
62
 
44
- def find_bash_files
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
- files[absolute_path] = Bashcov.coverage_array(absolute_path)
52
- end
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
- files
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
@@ -1,3 +1,3 @@
1
1
  module Bashcov
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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 unless File.file? filename
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
@@ -16,7 +16,7 @@ module Bashcov
16
16
  end
17
17
 
18
18
  def link
19
- '<a href="https://github.com/infertux/bashcov">bashcov</a>'
19
+ %Q|<a href="https://github.com/infertux/bashcov">bashcov</a> v#{VERSION}|
20
20
  end
21
21
  end
22
22
  end
@@ -1,20 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Bashcov::Lexer do
3
+ shared_examples "a bash file" do
4
4
  describe "#irrelevant_lines" do
5
- [
6
- ['simple.sh', [0, 1, 2, 3, 6, 8, 9, 11, 12]],
7
- ['function.sh', [0, 1, 2, 4, 5, 6, 9, 10, 13]],
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
+
@@ -1,27 +1,81 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Bashcov::Runner do
4
- before do
5
- @runner ||= Bashcov::Runner.new test_suite
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
- it "returns the list of .sh files in the root directory" do
10
- files = @runner.find_bash_files
11
- files.class.should == Hash
12
- files.values.each do |lines|
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
- @runner.run
21
- result = @runner.result
75
+ it "returns a valid coverage hash" do
76
+ runner.run
22
77
 
23
- result.class.should == Hash
24
- result.size.should == 8 # FIXME
78
+ runner.result.should == expected_coverage
25
79
  end
26
80
  end
27
81
  end
@@ -1,18 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Bashcov::Xtrace do
4
- before do
5
- @runner ||= Bashcov::Runner.new test_suite
6
- @runner.run
7
-
8
- @xtrace ||= Bashcov::Xtrace.new @runner.output
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
- it "returns a list of executed files" do
13
- files = @xtrace.files
14
- files.class.should == Hash
15
- files.keys.should =~ executed_files + [test_suite]
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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bashcov do
4
+ describe ".link" do
5
+ it "includes the version" do
6
+ Bashcov.link.should include Bashcov::VERSION
7
+ end
8
+ end
9
+ end
10
+
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 98
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
- def test_app
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.1
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-08 00:00:00.000000000 Z
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