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 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