bashcov 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3681e4625478878ae7c5a9438d92c4e4a7997d4f
4
- data.tar.gz: 0e3658daf9c4a2826da7df042565f38d56e22327
3
+ metadata.gz: a38548d5c6225411e74a70bc3de2982531e83d15
4
+ data.tar.gz: b8df3975562e21dbbd9acde6fa4413d79d0197ab
5
5
  SHA512:
6
- metadata.gz: 2221d53847bfcfae69bb7594075e864dba7942aa83171ac9a75bd54ae4ded53b5904138a5856fd9e5bb2090910e306a533222bc87867d41fe51ddd4e48dfe2de
7
- data.tar.gz: 9110bebfcdce140144574f9d64702720a09f727db0562e73202df1ebb71482e57fedfd6d0c1921453da2e16b79bf21eaa294e3a9525d6d751f8170f9d8eafc49
6
+ metadata.gz: 0aac1da4bfb28a0edab21b6bf1c02bd2215a8d301176d005436b92da6f1c5b7a03c19aa60b3ad5ff88fa9e72e3029a4f5734b39ce41e6dc70ae6f66de8495163
7
+ data.tar.gz: 46decd7f48918f1e57af03033aecaaac8f3d761e8904458ce3c3acb95b1ad91d171853d2d57f5213419ea514722a946dc29d8ed98fd2a0dd79a824a48cac84e0
data/CHANGELOG.md CHANGED
@@ -1,7 +1,15 @@
1
- ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v1.3.1...master))
1
+ ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v1.4.0...master))
2
2
 
3
3
  * TBD
4
4
 
5
+ ## v1.4.0, 2016-10-08 ([changes](https://github.com/infertux/bashcov/compare/v1.3.1...v1.4.0))
6
+
7
+ * [BUGFIX] Fix incorrect coverage for case statements (#21)
8
+ * [BUGFIX] Fix rare race condition leading to a crash when a file is deleted at the wrong moment
9
+ * [FEATURE] Add support for heredoc and multiline strings in general (#2)
10
+ * [MISC] Set up Travis CI to test Bashcov with Bash 4.0 through 4.4
11
+ * [MISC] Drop support for old Ruby versions (2.0 and 2.1)
12
+
5
13
  ## v1.3.1, 2016-02-19 ([changes](https://github.com/infertux/bashcov/compare/v1.3.0...v1.3.1))
6
14
 
7
15
  * [FEATURE] Add support back for Ruby 2.0.0 until it's officially EOL
data/bashcov.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.executables = gem.files.grep(%r{\Abin/}).map { |f| File.basename(f) }
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.required_ruby_version = ">= 2.0.0"
21
+ gem.required_ruby_version = ">= 2.2.5"
22
22
 
23
23
  gem.add_dependency "simplecov", "~> 0.11"
24
24
 
@@ -6,15 +6,9 @@ module Bashcov
6
6
  # runtime
7
7
  # @note receiver is expected to implement +bash_path+
8
8
  module BashInfo
9
- # @return [Array<String>] An array representing the components of
10
- # +BASH_VERSINFO+
11
- def bash_versinfo
12
- `#{bash_path} -c 'echo "${BASH_VERSINFO[@]}"'`.chomp.split
13
- end
14
-
15
9
  # @return [Boolean] Whether Bash supports +BASH_XTRACEFD+
16
10
  def bash_xtracefd?
17
- bash_versinfo[0..1].join.to_i >= 41
11
+ BASH_VERSION >= "4.1"
18
12
  end
19
13
 
20
14
  # @param [Integer] length the number of bytes to test; default 128
@@ -63,8 +63,8 @@ module Bashcov
63
63
  matched_start = nil
64
64
  seen_fields = 0
65
65
  elsif seen_fields < field_count
66
- yield field
67
- seen_fields += 1
66
+ yield field
67
+ seen_fields += 1
68
68
  end
69
69
  end
70
70
 
data/lib/bashcov/lexer.rb CHANGED
@@ -22,34 +22,58 @@ module Bashcov
22
22
  @filename = filename
23
23
  @coverage = coverage
24
24
 
25
- unless File.file?(@filename)
25
+ unless File.file?(@filename) # rubocop:disable Style/GuardClause
26
26
  raise ArgumentError, "#{@filename} is not a file"
27
27
  end
28
28
  end
29
29
 
30
- # Yields uncovered relevant lines.
31
- # @note Uses +@coverage+ to avoid wasting time parsing executed lines.
30
+ # Process and complete initial coverage.
32
31
  # @return [void]
33
- def uncovered_relevant_lines
34
- lineno = 0
35
- File.open(@filename, "rb").each_line do |line|
36
- if @coverage[lineno] == Bashcov::Line::IGNORED && relevant?(line)
37
- yield lineno
38
- end
39
- lineno += 1
32
+ def complete_coverage
33
+ lines = File.read(@filename).lines
34
+
35
+ lines.each_with_index do |line, lineno|
36
+ mark_multiline(lines, lineno, /\A[^\n]+<<-?'?(\w+)'?\s*$.*\1/m) # heredoc
37
+ mark_multiline(lines, lineno, /\A[^\n]+\\$(\s*['"][^'"]*['"]\s*\\$){1,}\s*['"][^'"]*['"]\s*$/) # multiline string
38
+
39
+ mark_line(line, lineno)
40
40
  end
41
41
  end
42
42
 
43
43
  private
44
44
 
45
+ def mark_multiline(lines, lineno, regexp)
46
+ seek_forward = lines[lineno..-1].join
47
+ return unless (multiline_match = seek_forward.match(regexp))
48
+
49
+ length = multiline_match.to_s.count($/)
50
+ (lineno + 1).upto(lineno + length).each do |sub_lineno|
51
+ # mark subsequent lines with the same coverage as the first line
52
+ @coverage[sub_lineno] = @coverage[lineno]
53
+ end
54
+ end
55
+
56
+ def mark_line(line, lineno)
57
+ return unless @coverage[lineno] == Bashcov::Line::IGNORED
58
+
59
+ @coverage[lineno] = Bashcov::Line::UNCOVERED if relevant?(line)
60
+ end
61
+
45
62
  def relevant?(line)
63
+ line.sub!(/ #.*\Z/, "") # remove comments
46
64
  line.strip!
47
65
 
48
- !line.empty? and
49
- !IGNORE_IS.include? line and
50
- !line.start_with?(*IGNORE_START_WITH) and
51
- !line.end_with?(*IGNORE_END_WITH) and
52
- line !~ /\A\w+\(\)/ # function declared without the 'function' keyword
66
+ relevant = true
67
+
68
+ relevant &= false if line.empty? ||
69
+ IGNORE_IS.include?(line) ||
70
+ line.start_with?(*IGNORE_START_WITH) ||
71
+ line.end_with?(*IGNORE_END_WITH)
72
+
73
+ relevant &= false if line =~ /\A\w+\(\)/ # function declared without the `function` keyword
74
+ relevant &= false if line =~ /\A[^\)]+\)\Z/ # case statement selector, e.g. `--help)`
75
+
76
+ relevant
53
77
  end
54
78
  end
55
79
  end
@@ -99,7 +99,7 @@ module Bashcov
99
99
  end
100
100
  end
101
101
 
102
- inject_xtrace_flag! do
102
+ with_xtrace_flag do
103
103
  yield
104
104
  end
105
105
  end
@@ -108,7 +108,7 @@ module Bashcov
108
108
  # @yield [void] adds "xtrace" to +SHELLOPTS+ and then runs the provided
109
109
  # block
110
110
  # @return [Object, ...] the value returned by the calling block
111
- def inject_xtrace_flag!
111
+ def with_xtrace_flag
112
112
  existing_flags_s = ENV["SHELLOPTS"]
113
113
  existing_flags = (existing_flags_s || "").split(":")
114
114
  ENV["SHELLOPTS"] = (existing_flags | ["xtrace"]).join(":")
@@ -146,9 +146,7 @@ module Bashcov
146
146
  def mark_relevant_lines!
147
147
  @coverage.each_pair do |filename, coverage|
148
148
  lexer = Lexer.new(filename, coverage)
149
- lexer.uncovered_relevant_lines do |lineno|
150
- @coverage[filename][lineno] = Bashcov::Line::UNCOVERED
151
- end
149
+ lexer.complete_coverage
152
150
  end
153
151
  end
154
152
 
@@ -3,5 +3,5 @@
3
3
  # :nodoc:
4
4
  module Bashcov
5
5
  # Current Bashcov version
6
- VERSION = "1.3.1"
6
+ VERSION = "1.4.0".freeze
7
7
  end
@@ -12,10 +12,10 @@ module Bashcov
12
12
  class Xtrace
13
13
  # [String] Character that will be used to indicate the nesting level of
14
14
  # +xtrace+d instructions
15
- DEPTH_CHAR = "+"
15
+ DEPTH_CHAR = "+".freeze
16
16
 
17
17
  # [String] Prefix used in +PS4+ to identify relevant output
18
- PREFIX = "BASHCOV>"
18
+ PREFIX = "BASHCOV>".freeze
19
19
 
20
20
  # [Array<String>] A collection of Bash internal variables to expand in the
21
21
  # {PS4}
@@ -115,11 +115,11 @@ module Bashcov
115
115
  # If +LINENO+ isn't a series of digits, something has gone wrong. Add
116
116
  # +@files+ to the exception in order to propagate the existing coverage
117
117
  # data back to the {Bashcov::Runner} instance.
118
- unless lineno =~ /\A\d+\z/
119
- lineno_err = lineno.empty? ? nil : lineno
120
-
118
+ if lineno =~ /\A\d+\z/
119
+ lineno = lineno.to_i
120
+ else
121
121
  raise XtraceError.new(
122
- "expected integer for LINENO, got `#{lineno_err.inspect}'", @files
122
+ "expected integer for LINENO, got #{lineno.inspect}", @files
123
123
  )
124
124
  end
125
125
 
@@ -132,7 +132,7 @@ module Bashcov
132
132
 
133
133
  # For one-liners, +LINENO+ == 0. Do this to avoid an +IndexError+;
134
134
  # one-liners will be culled from the coverage results later on.
135
- index = (lineno_i = lineno.to_i) > 1 ? lineno_i - 1 : 0
135
+ index = (lineno > 1 ? lineno - 1 : 0)
136
136
 
137
137
  @files[script] ||= []
138
138
  @files[script][index] ||= 0
@@ -148,7 +148,14 @@ module Bashcov
148
148
  # otherwise, +bash_source+ cleaned of redundant slashes and dots
149
149
  def find_script(bash_source)
150
150
  script = @pwd_stack.reverse.map { |wd| wd + bash_source }.find(&:file?)
151
- script.nil? ? bash_source.cleanpath : script.realpath
151
+
152
+ return bash_source.cleanpath if script.nil?
153
+
154
+ begin
155
+ script.realpath
156
+ rescue Errno::ENOENT # catch race condition if the file has been deleted
157
+ bash_source.cleanpath
158
+ end
152
159
  end
153
160
 
154
161
  # Updates the stacks that track the history of values for +PWD+ and
data/lib/bashcov.rb CHANGED
@@ -18,6 +18,15 @@ module Bashcov
18
18
  )
19
19
 
20
20
  class << self
21
+ # Define option accessors
22
+ Options.new.members.each do |option|
23
+ [option, "#{option}="].each do |method|
24
+ define_method method do |*args|
25
+ options.public_send(*[method, *args])
26
+ end
27
+ end
28
+ end
29
+
21
30
  # @return [Struct] The +Struct+ object representing Bashcov configuration
22
31
  def options
23
32
  set_default_options! unless defined?(@options)
@@ -50,7 +59,7 @@ module Bashcov
50
59
  # @return [String] Program name including version for easy consistent output
51
60
  # @note +fullname+ instead of name to avoid clashing with +Module.name+
52
61
  def fullname
53
- "#{program_name} v#{VERSION}"
62
+ "#{program_name} #{VERSION} (bash #{BASH_VERSION})"
54
63
  end
55
64
 
56
65
  # Wipe the current options and reset default values
@@ -65,16 +74,6 @@ module Bashcov
65
74
 
66
75
  private
67
76
 
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
77
  def help
79
78
  <<-HELP.gsub(/^ +/, "").gsub("\t", " " * 4)
80
79
  Usage: #{program_name} [options] [--] <command> [options]
@@ -121,4 +120,7 @@ module Bashcov
121
120
  end
122
121
  end
123
122
  end
123
+
124
+ # Current Bash version (e.g. 4.2)
125
+ BASH_VERSION = `#{bash_path} -c 'echo -n ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}'`.freeze
124
126
  end
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.3.1
4
+ version: 1.4.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: 2016-02-19 00:00:00.000000000 Z
11
+ date: 2016-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov
@@ -174,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
174
  requirements:
175
175
  - - ">="
176
176
  - !ruby/object:Gem::Version
177
- version: 2.0.0
177
+ version: 2.2.5
178
178
  required_rubygems_version: !ruby/object:Gem::Requirement
179
179
  requirements:
180
180
  - - ">="
@@ -187,4 +187,3 @@ signing_key:
187
187
  specification_version: 4
188
188
  summary: Code coverage tool for Bash
189
189
  test_files: []
190
- has_rdoc: