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 CHANGED
@@ -1,4 +1,7 @@
1
1
  language: ruby
2
+ after_script:
3
+ - cane
4
+ - yard stats --list-undoc
2
5
  rvm:
3
6
  - 1.9.3
4
7
  - 2.0.0
@@ -7,4 +10,3 @@ rvm:
7
10
  matrix:
8
11
  allow_failures:
9
12
  - rvm: ruby-head
10
- - rvm: rbx-19mode
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [bashcov] is [simplecov] for Bash.
4
4
 
5
- **[Demo](http://infertux.github.com/bashcov/test_app/)**
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
@@ -13,7 +13,7 @@ coverage = runner.result
13
13
 
14
14
  require 'simplecov'
15
15
 
16
- SimpleCov.command_name Bashcov.link
16
+ SimpleCov.command_name Bashcov.name
17
17
  # SimpleCov.filters = [] # TODO make sure default filters are okay
18
18
  SimpleCov::Result.new(coverage).format!
19
19
 
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
- raise "#{@filename} is not a file" unless File.file?(@filename)
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
- return true if line.empty?
21
- return true if start_with.any? { |token| line.start_with? token }
22
- return true if is.any? { |keyword| line == keyword }
23
- return true if line =~ /\A\w+\(\) {/ # function declared like this: "foo() {"
24
- false
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
- # see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/coverage/rdoc/Coverage.html
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
@@ -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
- attr_reader :stdout, :stderr
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
- [ # we need threads here to stream output in realtime
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
- files = {}
49
+ files = if Bashcov.options.skip_uncovered
50
+ {}
40
51
  else
41
- files = find_bash_files "#{Bashcov.root_directory}/**/*.sh"
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[absolute_path] = Bashcov.coverage_array(absolute_path)
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)
@@ -1,3 +1,4 @@
1
1
  module Bashcov
2
- VERSION = "0.0.3"
2
+ # Bashcov version
3
+ VERSION = "0.0.4"
3
4
  end
@@ -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.
@@ -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
@@ -69,9 +69,9 @@ describe Bashcov do
69
69
  end
70
70
  end
71
71
 
72
- describe ".link" do
72
+ describe ".name" do
73
73
  it "includes the version" do
74
- Bashcov.link.should include Bashcov::VERSION
74
+ Bashcov.name.should include Bashcov::VERSION
75
75
  end
76
76
  end
77
77
  end
@@ -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
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ echo "Although I'm extension-less, I am an executable Bash script"
4
+
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+
3
+ [ false = true ] || \
4
+ [[ 42 -eq 1337 ]] || [[ 1 -eq 1 ]] \
5
+ && true && \
6
+ echo 'what?' || \
7
+ echo 'no!'
8
+
File without changes
@@ -3,5 +3,5 @@
3
3
  cd $(dirname $0)
4
4
 
5
5
  # `date` is sent on stdin for each file
6
- date | find scripts -name "*.sh" -exec '{}' \;
6
+ date | find scripts -type f -executable -exec '{}' \;
7
7
 
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.3
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: 2012-12-14 00:00:00.000000000 Z
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:
data/TODO DELETED
@@ -1,3 +0,0 @@
1
- see if we could implement some features of https://en.wikipedia.org/wiki/Gcov
2
- tidy up things
3
- more comprehensive specs