bashcov 1.2.1 → 1.3.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -3
  3. data/Gemfile +2 -0
  4. data/Guardfile +2 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +60 -5
  7. data/Rakefile +2 -0
  8. data/bashcov.gemspec +4 -3
  9. data/bin/bashcov +3 -2
  10. data/lib/bashcov/bash_info.rb +32 -0
  11. data/lib/bashcov/errors.rb +16 -0
  12. data/lib/bashcov/field_stream.rb +77 -0
  13. data/lib/bashcov/lexer.rb +13 -7
  14. data/lib/bashcov/line.rb +4 -2
  15. data/lib/bashcov/runner.rb +96 -21
  16. data/lib/bashcov/version.rb +4 -1
  17. data/lib/bashcov/xtrace.rb +150 -35
  18. data/lib/bashcov.rb +64 -31
  19. metadata +9 -58
  20. data/.gitignore +0 -19
  21. data/.rspec +0 -4
  22. data/.rubocop.yml +0 -27
  23. data/.travis.yml +0 -21
  24. data/spec/bashcov/lexer_spec.rb +0 -11
  25. data/spec/bashcov/runner_spec.rb +0 -98
  26. data/spec/bashcov_spec.rb +0 -82
  27. data/spec/spec_helper.rb +0 -25
  28. data/spec/support/common.rb +0 -7
  29. data/spec/support/test_app.rb +0 -35
  30. data/spec/test_app/.simplecov +0 -2
  31. data/spec/test_app/README.md +0 -1
  32. data/spec/test_app/never_called.sh +0 -4
  33. data/spec/test_app/scripts/README.md +0 -1
  34. data/spec/test_app/scripts/case.sh +0 -15
  35. data/spec/test_app/scripts/delete.sh +0 -9
  36. data/spec/test_app/scripts/executable +0 -4
  37. data/spec/test_app/scripts/exit_non_zero.sh +0 -3
  38. data/spec/test_app/scripts/function.sh +0 -20
  39. data/spec/test_app/scripts/long_line.sh +0 -7
  40. data/spec/test_app/scripts/multiline.sh +0 -24
  41. data/spec/test_app/scripts/nested/simple.sh +0 -13
  42. data/spec/test_app/scripts/one_liner.sh +0 -9
  43. data/spec/test_app/scripts/simple.sh +0 -13
  44. data/spec/test_app/scripts/source.sh +0 -6
  45. data/spec/test_app/scripts/sourced.txt +0 -4
  46. data/spec/test_app/scripts/unicode.sh +0 -4
  47. data/spec/test_app/test_suite.sh +0 -5
@@ -1,32 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "securerandom"
5
+
6
+ require "bashcov/errors"
7
+
1
8
  module Bashcov
2
9
  # This class manages +xtrace+ output.
3
10
  #
4
11
  # @see Runner
5
12
  class Xtrace
6
- # Prefix used for PS4.
7
- # @note The first caracter ('+') will be repeated to indicate the nesting
8
- # level.
9
- PREFIX = "+BASHCOV> "
10
-
11
- # [String] +PS4+ variable used for xtrace output
12
- # @see http://www.gnu.org/software/bash/manual/bashref.html#index-PS4
13
- # @see http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in
14
- # @note We use a forward slash as delimiter since it's the only forbidden
15
- # character in filenames on Unix and Windows.
16
- GET_ABS_DIR = "$(cd $(dirname ${BASH_SOURCE[0]}); pwd)"
17
- GET_BASE = "$(basename ${BASH_SOURCE[0]})"
18
- PS4 = %(#{PREFIX}#{GET_ABS_DIR}/#{GET_BASE}/${LINENO}: )
19
-
20
- # Regexp to match xtrace elements.
21
- LINE_REGEXP = %r{\A#{Regexp.escape(PREFIX[0])}+#{PREFIX[1..-1]}(?<filename>.+)\/(?<lineno>\d+): }
22
-
23
- # @return [Hash] Coverage of executed files
24
- attr_reader :coverage
25
-
26
- # Creates a temporary file for xtrace output.
27
- # @see http://stackoverflow.com/questions/6977561/pipe-vs-temporary-file
28
- def initialize
13
+ # [String] Character that will be used to indicate the nesting level of
14
+ # +xtrace+d instructions
15
+ DEPTH_CHAR = "+"
16
+
17
+ # [String] Prefix used in +PS4+ to identify relevant output
18
+ PREFIX = "BASHCOV>"
19
+
20
+ # [Array<String>] A collection of Bash internal variables to expand in the
21
+ # {PS4}
22
+ FIELDS = %w(${LINENO} ${BASH_SOURCE} ${PWD} ${OLDPWD}).freeze
23
+
24
+ class << self
25
+ attr_writer :delimiter, :ps4
26
+
27
+ # [String] A randomly-generated UUID or the ASCII RS (record separator)
28
+ # character, depending on whether the current Bash suffers from the
29
+ # truncated +PS4+ bug. Used for delimiting the fields of the +PS4+.
30
+ def delimiter
31
+ @delimiter ||= Bashcov.truncated_ps4? ? "\x1E" : SecureRandom.uuid
32
+ end
33
+
34
+ # @return [String] +PS4+ variable used for xtrace output. Expands to
35
+ # internal Bash variables +BASH_SOURCE+, +PWD+, +OLDPWD+, and +LINENO+,
36
+ # delimited by {delimiter}.
37
+ # @see http://www.gnu.org/software/bash/manual/bashref.html#index-PS4
38
+ def ps4
39
+ @ps4 ||= make_ps4(*FIELDS)
40
+ end
41
+
42
+ # @return [String] a {delimiter}-separated +String+ suitable for use as
43
+ # +PS4+
44
+ def make_ps4(*fields)
45
+ fields.reduce(DEPTH_CHAR + PREFIX) do |memo, field|
46
+ memo + delimiter + field
47
+ end + delimiter
48
+ end
49
+ end
50
+
51
+ # Regexp to match the beginning of the {.ps4}. {DEPTH_CHAR} will be
52
+ # repeated in proportion to the level of Bash call nesting.
53
+ PS4_START_REGEXP = /#{Regexp.escape(DEPTH_CHAR)}+#{Regexp.escape(PREFIX)}$/m
54
+
55
+ # Creates a pipe for xtrace output.
56
+ # @see http://stackoverflow.com/questions/6977562/pipe-vs-temporary-file
57
+ def initialize(field_stream)
58
+ @field_stream = field_stream
59
+
29
60
  @read, @write = IO.pipe
61
+
62
+ # Tracks coverage for each file under test
63
+ @files ||= {}
64
+
65
+ # Stacks for updating working directory changes
66
+ @pwd_stack ||= []
67
+ @oldpwd_stack ||= []
30
68
  end
31
69
 
32
70
  # @return [Fixnum] File descriptor of the write end of the pipe
@@ -40,24 +78,101 @@ module Bashcov
40
78
  @write.close
41
79
  end
42
80
 
43
- # Parses xtrace output and computes coverage.
44
- # @return [Hash] Hash of executed files with coverage information
81
+ # Read fields extracted from Bash's debugging output
82
+ # @return [Hash<Pathname, Array<Integer, nil>>] A hash mapping Bash scripts
83
+ # to Simplecov-style coverage stats
45
84
  def read
46
- @files = {}
47
-
48
- @read.each_line do |line|
49
- match = line.match(LINE_REGEXP)
50
- next if match.nil? # garbage line from multiline instruction
85
+ @field_stream.read = @read
51
86
 
52
- filename = File.expand_path(match[:filename], Bashcov.root_directory)
87
+ field_count = FIELDS.length
88
+ fields = @field_stream.each(
89
+ self.class.delimiter, field_count, PS4_START_REGEXP
90
+ )
53
91
 
54
- lineno = match[:lineno].to_i - 1
55
- @files[filename] ||= []
56
- @files[filename][lineno] ||= 0
57
- @files[filename][lineno] += 1
92
+ # +take(field_count)+ would be more natural here, but doesn't seem to
93
+ # play nicely with +Enumerator+s backed by +IO+ objects.
94
+ loop do
95
+ break if (hit = (1..field_count).map { fields.next }).empty?
96
+ parse_hit!(*hit)
58
97
  end
59
98
 
60
99
  @files
61
100
  end
101
+
102
+ private
103
+
104
+ # Parses the expanded {ps4} fields and updates the coverage-tracking
105
+ # {@files} hash
106
+ # @overload parse_hit!(lineno, bash_source, pwd, oldpwd)
107
+ # @param [String] lineno expanded +LINENO+
108
+ # @param [Pathname] bash_source expanded +BASH_SOURCE+
109
+ # @param [Pathname] pwd expanded +PWD+
110
+ # @param [Pathname] oldpwd expanded +OLDPWD+
111
+ # @return [void]
112
+ # @raise [XtraceError] when +lineno+ is not composed solely of digits,
113
+ # indicating that something has gone wrong with parsing the +PS4+ fields
114
+ def parse_hit!(lineno, *paths)
115
+ # If +LINENO+ isn't a series of digits, something has gone wrong. Add
116
+ # +@files+ to the exception in order to propagate the existing coverage
117
+ # data back to the {Bashcov::Runner} instance.
118
+ unless lineno =~ /\A\d+\z/
119
+ lineno_err = lineno.empty? ? nil : lineno
120
+
121
+ raise XtraceError.new(
122
+ "expected integer for LINENO, got `#{lineno_err.inspect}'", @files
123
+ )
124
+ end
125
+
126
+ # The next three fields will be $BASH_SOURCE, $PWD, $OLDPWD, and $LINENO
127
+ bash_source, pwd, oldpwd = paths.map { |p| Pathname.new(p) }
128
+
129
+ update_wd_stacks!(pwd, oldpwd)
130
+
131
+ script = find_script(bash_source)
132
+
133
+ # For one-liners, +LINENO+ == 0. Do this to avoid an +IndexError+;
134
+ # one-liners will be culled from the coverage results later on.
135
+ index = (lineno_i = lineno.to_i) > 1 ? lineno_i - 1 : 0
136
+
137
+ @files[script] ||= []
138
+ @files[script][index] ||= 0
139
+ @files[script][index] += 1
140
+ end
141
+
142
+ # Scans entries in the +PWD+ stack, checking whether +entry/$BASH_SOURCE+
143
+ # refers to an existing file. Scans the stack in reverse on the assumption
144
+ # that more-recent entries are more plausible candidates for base
145
+ # directories from which +BASH_SOURCE+ can be reached.
146
+ # @param [Pathname] bash_source expanded +BASH_SOURCE+
147
+ # @return [Pathname] the resolved path to +bash_source+, if it exists;
148
+ # otherwise, +bash_source+ cleaned of redundant slashes and dots
149
+ def find_script(bash_source)
150
+ script = @pwd_stack.reverse.map { |wd| wd + bash_source }.find(&:file?)
151
+ script.nil? ? bash_source.cleanpath : script.realpath
152
+ end
153
+
154
+ # Updates the stacks that track the history of values for +PWD+ and
155
+ # +OLDPWD+
156
+ # @param [Pathname] pwd expanded +PWD+
157
+ # @param [Pathname] oldpwd expanded +OLDPWD+
158
+ # @return [void]
159
+ def update_wd_stacks!(pwd, oldpwd)
160
+ @pwd_stack[0] ||= pwd
161
+ @oldpwd_stack[0] ||= oldpwd unless oldpwd.to_s.empty?
162
+
163
+ # We haven't changed working directories; short-circuit.
164
+ return if pwd == @pwd_stack[-1]
165
+
166
+ # If the current +pwd+ is identical to the top of the +@oldpwd_stack+ and
167
+ # the current +oldpwd+ is identical to the second-to-top entry, then a
168
+ # previous cd/pushd has been undone.
169
+ if pwd == @oldpwd_stack[-1] && oldpwd == @oldpwd_stack[-2]
170
+ @pwd_stack.pop
171
+ @oldpwd_stack.pop
172
+ else # New cd/pushd
173
+ @pwd_stack << pwd
174
+ @oldpwd_stack << oldpwd
175
+ end
176
+ end
62
177
  end
63
178
  end
data/lib/bashcov.rb CHANGED
@@ -1,29 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "optparse"
2
- require "ostruct"
3
- require "bashcov/version"
4
- require "bashcov/lexer"
5
- require "bashcov/line"
4
+ require "pathname"
5
+
6
+ require "bashcov/bash_info"
6
7
  require "bashcov/runner"
7
- require "bashcov/xtrace"
8
+ require "bashcov/version"
8
9
 
9
10
  # Bashcov default module
10
11
  # @note Keep it short!
11
12
  module Bashcov
12
- class << self
13
- # @return [OpenStruct] Bashcov settings
14
- attr_reader :options
13
+ extend Bashcov::BashInfo
15
14
 
16
- # @return [String] The project's root directory
17
- def root_directory
18
- @root_directory ||= Dir.pwd
19
- end
15
+ # A +Struct+ to store Bashcov configuration
16
+ Options = Struct.new(
17
+ *%i(skip_uncovered mute bash_path root_directory command)
18
+ )
20
19
 
21
- # Sets default options overriding any existing ones.
22
- # @return [void]
23
- def set_default_options!
24
- @options ||= OpenStruct.new
25
- @options.skip_uncovered = false
26
- @options.mute = false
20
+ class << self
21
+ # @return [Struct] The +Struct+ object representing Bashcov configuration
22
+ def options
23
+ set_default_options! unless defined?(@options)
24
+ @options
27
25
  end
28
26
 
29
27
  # Parses the given CLI arguments and sets +options+.
@@ -31,24 +29,54 @@ module Bashcov
31
29
  # @raise [SystemExit] if invalid arguments are given
32
30
  # @return [void]
33
31
  def parse_options!(args)
34
- option_parser.parse!(args)
32
+ begin
33
+ option_parser.parse!(args)
34
+ rescue OptionParser::ParseError, Errno::ENOENT => e
35
+ abort "#{option_parser.program_name}: #{e.message}"
36
+ end
35
37
 
36
38
  if args.empty?
37
39
  abort("You must give exactly one command to execute.")
38
40
  else
39
- @options.command = args.join(" ")
41
+ options.command = args.unshift(bash_path)
40
42
  end
41
43
  end
42
44
 
45
+ # @return [String] Program name
46
+ def program_name
47
+ "bashcov"
48
+ end
49
+
43
50
  # @return [String] Program name including version for easy consistent output
44
- def name
45
- "bashcov v#{VERSION}"
51
+ # @note +fullname+ instead of name to avoid clashing with +Module.name+
52
+ def fullname
53
+ "#{program_name} v#{VERSION}"
54
+ end
55
+
56
+ # Wipe the current options and reset default values
57
+ def set_default_options!
58
+ @options = Options.new
59
+
60
+ @options.skip_uncovered = false
61
+ @options.mute = false
62
+ @options.bash_path = "/bin/bash"
63
+ @options.root_directory = Dir.getwd
46
64
  end
47
65
 
48
66
  private
49
67
 
50
- def help(program_name)
51
- <<-HELP.gsub!(/^ +/, "").gsub!("\t", " " * 4)
68
+ # Passes off +respond_to?+ to {options} for missing methods
69
+ def respond_to_missing?(*args)
70
+ options.respond_to?(*args)
71
+ end
72
+
73
+ # Dispatches missing methods to {options}
74
+ def method_missing(method_name, *args, &block)
75
+ options.public_send(method_name, *args, &block)
76
+ end
77
+
78
+ def help
79
+ <<-HELP.gsub(/^ +/, "").gsub("\t", " " * 4)
52
80
  Usage: #{program_name} [options] [--] <command> [options]
53
81
  Examples:
54
82
  \t#{program_name} ./script.sh
@@ -60,17 +88,25 @@ module Bashcov
60
88
 
61
89
  def option_parser
62
90
  OptionParser.new do |opts|
63
- opts.program_name = "bashcov"
91
+ opts.program_name = program_name
64
92
  opts.version = Bashcov::VERSION
65
- opts.banner = help opts.program_name
93
+ opts.banner = help
66
94
 
67
95
  opts.separator "\nSpecific options:"
68
96
 
69
97
  opts.on("-s", "--skip-uncovered", "Do not report uncovered files") do |s|
70
- @options.skip_uncovered = s
98
+ options.skip_uncovered = s
71
99
  end
72
100
  opts.on("-m", "--mute", "Do not print script output") do |m|
73
- @options.mute = m
101
+ options.mute = m
102
+ end
103
+ opts.on("--bash-path PATH", "Path to Bash executable") do |p|
104
+ raise Errno::ENOENT, p unless File.file? p
105
+ options.bash_path = p
106
+ end
107
+ opts.on("--root PATH", "Project root directory") do |d|
108
+ raise Errno::ENOENT, d unless File.directory? d
109
+ options.root_directory = d
74
110
  end
75
111
 
76
112
  opts.separator "\nCommon options:"
@@ -86,6 +122,3 @@ module Bashcov
86
122
  end
87
123
  end
88
124
  end
89
-
90
- # Make sure default options are set
91
- Bashcov.set_default_options!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashcov
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric Félizard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-05 00:00:00.000000000 Z
11
+ date: 2016-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.10.0
19
+ version: '0.11'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.10.0
26
+ version: '0.11'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -144,10 +144,6 @@ executables:
144
144
  extensions: []
145
145
  extra_rdoc_files: []
146
146
  files:
147
- - ".gitignore"
148
- - ".rspec"
149
- - ".rubocop.yml"
150
- - ".travis.yml"
151
147
  - CHANGELOG.md
152
148
  - CONTRIBUTING.md
153
149
  - Gemfile
@@ -158,35 +154,14 @@ files:
158
154
  - bashcov.gemspec
159
155
  - bin/bashcov
160
156
  - lib/bashcov.rb
157
+ - lib/bashcov/bash_info.rb
158
+ - lib/bashcov/errors.rb
159
+ - lib/bashcov/field_stream.rb
161
160
  - lib/bashcov/lexer.rb
162
161
  - lib/bashcov/line.rb
163
162
  - lib/bashcov/runner.rb
164
163
  - lib/bashcov/version.rb
165
164
  - lib/bashcov/xtrace.rb
166
- - spec/bashcov/lexer_spec.rb
167
- - spec/bashcov/runner_spec.rb
168
- - spec/bashcov_spec.rb
169
- - spec/spec_helper.rb
170
- - spec/support/common.rb
171
- - spec/support/test_app.rb
172
- - spec/test_app/.simplecov
173
- - spec/test_app/README.md
174
- - spec/test_app/never_called.sh
175
- - spec/test_app/scripts/README.md
176
- - spec/test_app/scripts/case.sh
177
- - spec/test_app/scripts/delete.sh
178
- - spec/test_app/scripts/executable
179
- - spec/test_app/scripts/exit_non_zero.sh
180
- - spec/test_app/scripts/function.sh
181
- - spec/test_app/scripts/long_line.sh
182
- - spec/test_app/scripts/multiline.sh
183
- - spec/test_app/scripts/nested/simple.sh
184
- - spec/test_app/scripts/one_liner.sh
185
- - spec/test_app/scripts/simple.sh
186
- - spec/test_app/scripts/source.sh
187
- - spec/test_app/scripts/sourced.txt
188
- - spec/test_app/scripts/unicode.sh
189
- - spec/test_app/test_suite.sh
190
165
  homepage: https://github.com/infertux/bashcov
191
166
  licenses:
192
167
  - MIT
@@ -207,33 +182,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
182
  version: '0'
208
183
  requirements: []
209
184
  rubyforge_project:
210
- rubygems_version: 2.4.6
185
+ rubygems_version: 2.5.1
211
186
  signing_key:
212
187
  specification_version: 4
213
188
  summary: Code coverage tool for Bash
214
- test_files:
215
- - spec/bashcov/lexer_spec.rb
216
- - spec/bashcov/runner_spec.rb
217
- - spec/bashcov_spec.rb
218
- - spec/spec_helper.rb
219
- - spec/support/common.rb
220
- - spec/support/test_app.rb
221
- - spec/test_app/.simplecov
222
- - spec/test_app/README.md
223
- - spec/test_app/never_called.sh
224
- - spec/test_app/scripts/README.md
225
- - spec/test_app/scripts/case.sh
226
- - spec/test_app/scripts/delete.sh
227
- - spec/test_app/scripts/executable
228
- - spec/test_app/scripts/exit_non_zero.sh
229
- - spec/test_app/scripts/function.sh
230
- - spec/test_app/scripts/long_line.sh
231
- - spec/test_app/scripts/multiline.sh
232
- - spec/test_app/scripts/nested/simple.sh
233
- - spec/test_app/scripts/one_liner.sh
234
- - spec/test_app/scripts/simple.sh
235
- - spec/test_app/scripts/source.sh
236
- - spec/test_app/scripts/sourced.txt
237
- - spec/test_app/scripts/unicode.sh
238
- - spec/test_app/test_suite.sh
189
+ test_files: []
239
190
  has_rdoc:
data/.gitignore DELETED
@@ -1,19 +0,0 @@
1
- *.swp
2
- *.gem
3
- *.rbc
4
- .bundle
5
- .config
6
- .yardoc
7
- .rbx/
8
- Gemfile.lock
9
- InstalledFiles
10
- _yardoc
11
- coverage
12
- doc/
13
- lib/bundler/man
14
- pkg
15
- rdoc
16
- spec/reports
17
- test/tmp
18
- test/version_tmp
19
- tmp
data/.rspec DELETED
@@ -1,4 +0,0 @@
1
- --color
2
- --format d
3
- --order random
4
- --profile
data/.rubocop.yml DELETED
@@ -1,27 +0,0 @@
1
- Metrics/AbcSize:
2
- Enabled: false
3
-
4
- Metrics/MethodLength:
5
- Enabled: false
6
-
7
- Metrics/LineLength:
8
- Max: 120
9
- Exclude: [spec/**/*]
10
-
11
- Style/AccessModifierIndentation:
12
- EnforcedStyle: outdent
13
-
14
- Style/AndOr:
15
- EnforcedStyle: conditionals
16
-
17
- Style/SignalException:
18
- EnforcedStyle: only_raise
19
-
20
- Style/SpecialGlobalVars:
21
- Enabled: false
22
-
23
- Style/StringLiterals:
24
- EnforcedStyle: double_quotes
25
-
26
- Style/TrailingComma:
27
- Enabled: false
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- language: ruby
2
- after_script:
3
- - cane
4
- - yard stats --list-undoc
5
- rvm:
6
- - 1.9.3
7
- - 2.0.0
8
- - 2.1
9
- - 2.2
10
- - ruby-head
11
- - rbx
12
- - rbx-head
13
- matrix:
14
- allow_failures:
15
- - rvm: ruby-head
16
- - rvm: rbx
17
- - rvm: rbx-head
18
- notifications:
19
- email:
20
- on_success: always
21
- on_failure: always
@@ -1,11 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Bashcov::Lexer do
4
- describe "#initialize" do
5
- it "raises if the file is invalid" do
6
- expect do
7
- Bashcov::Lexer.new "inexistent_file.exe", nil
8
- end.to raise_error ArgumentError
9
- end
10
- end
11
- end
@@ -1,98 +0,0 @@
1
- require "spec_helper"
2
- require "benchmark"
3
-
4
- describe Bashcov::Runner do
5
- let(:runner) { Bashcov::Runner.new "bash #{test_suite}" }
6
-
7
- before :all do
8
- Dir.chdir File.dirname(test_suite)
9
- end
10
-
11
- describe "#run" do
12
- it "finds commands in $PATH" do
13
- expect(Bashcov::Runner.new("ls -l").run).to be_success
14
- end
15
-
16
- it "is fast", speed: :slow do
17
- ratio = 0
18
-
19
- 3.times do |iteration|
20
- t0 = Benchmark.realtime do
21
- pid = Process.spawn test_suite, out: "/dev/null", err: "/dev/null"
22
- Process.wait pid
23
- end
24
- expect($?).to be_success
25
-
26
- run = nil
27
- t1 = Benchmark.realtime { run = Bashcov::Runner.new(test_suite).run }
28
- expect(run).to be_success
29
-
30
- ratio = (ratio * iteration + t1 / t0) / (iteration + 1)
31
- end
32
-
33
- puts "#{ratio} times longer with Bashcov"
34
- # XXX no proper assertion - just outputs the ratio
35
- end
36
-
37
- context "without a SHELLOPTS variable" do
38
- before do
39
- ENV["SHELLOPTS"] = nil
40
- end
41
-
42
- it "adds the flags" do
43
- runner.run
44
- expect(ENV["SHELLOPTS"]).to eq("xtrace")
45
- end
46
- end
47
-
48
- context "with an existing SHELLOPTS variable" do
49
- before do
50
- ENV["SHELLOPTS"] = "posix"
51
- end
52
-
53
- it "merges the flags" do
54
- runner.run
55
- expect(ENV["SHELLOPTS"]).to eq("posix:xtrace")
56
- end
57
- end
58
- end
59
-
60
- describe "#result" do
61
- it "returns the expected coverage hash" do
62
- runner.run
63
- expect(runner.result).to eq expected_coverage
64
- end
65
-
66
- it "returns the correct coverage hash" do
67
- runner.run
68
-
69
- pending # TODO: need a context-aware lexer to parse multiline instructions
70
- expect(runner.result).to eq correct_coverage
71
- end
72
-
73
- context "with options.skip_uncovered = true" do
74
- before do
75
- Bashcov.options.skip_uncovered = true
76
- end
77
-
78
- it "does not include uncovered files" do
79
- runner.run
80
- expect(runner.result.keys & uncovered_files).to be_empty
81
- end
82
- end
83
-
84
- context "with options.mute = true" do
85
- before do
86
- Bashcov.options.mute = true
87
- end
88
-
89
- it "does not print the command output" do
90
- [$stdout, $stderr].each do |io|
91
- expect(io).not_to receive :write
92
- end
93
-
94
- runner.run
95
- end
96
- end
97
- end
98
- end