simplecov 0.18.0.beta3 → 0.18.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
  SHA256:
3
- metadata.gz: a5ac4654ad44859d2e7b68cc5375314766127720e33d51080cc02120d35cc9cb
4
- data.tar.gz: 89ceeaf8b9b1a76bd05a4f078c50a80050bd247ef067164201f9721ce7378b5b
3
+ metadata.gz: ce12d99507e5e8bd75399d80855c495907b8dda937fb5e2a33d2895e9f74e370
4
+ data.tar.gz: ae53aefe53c30c3b1d6c1c0b70aa34c1193642d4a879f77a0c3522960fc92773
5
5
  SHA512:
6
- metadata.gz: 8afee26e98b841b002d097d589afbbc8b892452897423c927b817b51696bb7063e3f2e849f462434b765fb09970fbb6759d31d5362ea5c6e90eb65e82824eb78
7
- data.tar.gz: ed2f4ffab150fd1da883604eccec94a087184aeaadb4b4d6f1f7273efa6020d1034b9e2eebbc8b88a9c63c54d545ccd6db4f5db58ee29f8182703ed40281342e
6
+ metadata.gz: e9a60e36936b9b5018a6998ade1742373bfa67b96688411ab42c90ac82ca6280abe9d407dcef4d45398ed28803ca876d6f82ce0cabc878d6141897cca4dab91e
7
+ data.tar.gz: 7056045c2385516ce0029af14558bd95c9c84bc85319d82bddfcf2011b7db87a5291168bb739c1ff02d8830e133065b3f2fda605e03b7c2e6ed094b61bff9240
@@ -1,3 +1,21 @@
1
+ 0.18.0 (2020-01-28)
2
+ ===================
3
+
4
+ Huge release! Highlights are support for branch coverage (Ruby 2.5+) and dropping support for EOL'ed Ruby versions (< 2.4).
5
+ Please also read the other beta patch notes.
6
+
7
+ ## Enhancements
8
+ * You can now define the minimum expected coverage by criterion like `minimum_coverage line: 90, branch: 80`
9
+ * Memoized some internal data structures that didn't change to reduce SimpleCov overhead
10
+ * Both `FileList` and `SourceFile` now have a `coverage` method that returns a hash that points from a coverage criterion to a `CoverageStatistics` object for uniform access to overall coverage statistics for both line and branch coverage
11
+
12
+ ## Bugfixes
13
+ * we were losing precision by rounding the covered strength early, that has been removed. **For Formatters** this also means that you may need to round it yourself now.
14
+ * Removed an inconsistency in how we treat skipped vs. irrelevant lines (see [#565](https://github.com/colszowka/simplecov/issues/565)) - SimpleCov's definition of 100% is now "You covered everything that you could" so if coverage is 0/0 that's counted as a 100% no matter if the lines were irrelevant or ignored/skipped
15
+
16
+ ## Noteworthy
17
+ * `FileList` stopped inheriting from Array, it includes Enumerable so if you didn't use Array specific methods on it in formatters you should be fine
18
+
1
19
  0.18.0.beta3 (2020-01-20)
2
20
  ========================
3
21
 
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
- SimpleCov [![Gem Version](https://badge.fury.io/rb/simplecov.svg)](https://badge.fury.io/rb/simplecov) [![Build Status](https://travis-ci.org/colszowka/simplecov.svg?branch=master)][Continuous Integration] [![Code Climate](https://codeclimate.com/github/colszowka/simplecov.svg)](https://codeclimate.com/github/colszowka/simplecov) [![Inline docs](http://inch-ci.org/github/colszowka/simplecov.svg)](http://inch-ci.org/github/colszowka/simplecov)
1
+ SimpleCov [![Gem Version](https://badge.fury.io/rb/simplecov.svg)](https://badge.fury.io/rb/simplecov) [![Build Status](https://github.com/colszowka/simplecov/workflows/stable/badge.svg?branch=master)][Continuous Integration] [![Code Climate](https://codeclimate.com/github/colszowka/simplecov.svg)](https://codeclimate.com/github/colszowka/simplecov) [![Inline docs](http://inch-ci.org/github/colszowka/simplecov.svg)](http://inch-ci.org/github/colszowka/simplecov)
2
2
  =========
3
+
3
4
  **Code coverage for Ruby**
4
5
 
5
6
  * [Source Code]
@@ -14,7 +15,7 @@ SimpleCov [![Gem Version](https://badge.fury.io/rb/simplecov.svg)](https://badge
14
15
  [Configuration]: http://rubydoc.info/gems/simplecov/SimpleCov/Configuration "Configuration options API documentation"
15
16
  [Changelog]: https://github.com/colszowka/simplecov/blob/master/CHANGELOG.md "Project Changelog"
16
17
  [Rubygem]: http://rubygems.org/gems/simplecov "SimpleCov @ rubygems.org"
17
- [Continuous Integration]: http://travis-ci.org/colszowka/simplecov "SimpleCov is built around the clock by travis-ci.org"
18
+ [Continuous Integration]: https://github.com/colszowka/simplecov/actions?query=workflow%3Astable "SimpleCov is built around the clock by github.com"
18
19
  [Dependencies]: https://gemnasium.com/colszowka/simplecov "SimpleCov dependencies on Gemnasium"
19
20
  [simplecov-html]: https://github.com/colszowka/simplecov-html "SimpleCov HTML Formatter Source Code @ GitHub"
20
21
 
@@ -231,12 +231,8 @@ module SimpleCov
231
231
  # rubocop:disable Metrics/MethodLength
232
232
  def result_exit_status(result, covered_percent)
233
233
  covered_percentages = result.covered_percentages.map { |percentage| percentage.floor(2) }
234
- if covered_percent < SimpleCov.minimum_coverage
235
- $stderr.printf(
236
- "Coverage (%<covered>.2f%%) is below the expected minimum coverage (%<minimum_coverage>.2f%%).\n",
237
- covered: covered_percent,
238
- minimum_coverage: SimpleCov.minimum_coverage
239
- )
234
+ if (minimum_violations = minimum_coverage_violated(result)).any?
235
+ report_minimum_violated(minimum_violations)
240
236
  SimpleCov::ExitCodes::MINIMUM_COVERAGE
241
237
  elsif covered_percentages.any? { |p| p < SimpleCov.minimum_coverage_by_file }
242
238
  $stderr.printf(
@@ -409,13 +405,40 @@ module SimpleCov
409
405
  def result_with_not_loaded_files
410
406
  @result = SimpleCov::Result.new(add_not_loaded_files(@result))
411
407
  end
408
+
409
+ def minimum_coverage_violated(result)
410
+ coverage_achieved = minimum_coverage.map do |criterion, percent|
411
+ {
412
+ criterion: criterion,
413
+ minimum_expected: percent,
414
+ actual: result.coverage_statistics[criterion].percent
415
+ }
416
+ end
417
+
418
+ coverage_achieved.select do |achieved|
419
+ achieved.fetch(:actual) < achieved.fetch(:minimum_expected)
420
+ end
421
+ end
422
+
423
+ def report_minimum_violated(violations)
424
+ violations.each do |violation|
425
+ $stderr.printf(
426
+ "%<criterion>s coverage (%<covered>.2f%%) is below the expected minimum coverage (%<minimum_coverage>.2f%%).\n",
427
+ covered: violation.fetch(:actual).floor(2),
428
+ minimum_coverage: violation.fetch(:minimum_expected),
429
+ criterion: violation.fetch(:criterion).capitalize
430
+ )
431
+ end
432
+ end
412
433
  end
413
434
  end
414
435
 
415
436
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
416
437
  require "set"
438
+ require "forwardable"
417
439
  require "simplecov/configuration"
418
440
  SimpleCov.extend SimpleCov::Configuration
441
+ require "simplecov/coverage_statistics"
419
442
  require "simplecov/exit_codes"
420
443
  require "simplecov/profiles"
421
444
  require "simplecov/source_file/line"
@@ -240,8 +240,15 @@ module SimpleCov
240
240
  # Default is 0% (disabled)
241
241
  #
242
242
  def minimum_coverage(coverage = nil)
243
- minimum_possible_coverage_exceeded("minimum_coverage") if coverage && coverage > 100
244
- @minimum_coverage ||= (coverage || 0).to_f.round(2)
243
+ return @minimum_coverage ||= {} unless coverage
244
+
245
+ coverage = {DEFAULT_COVERAGE_CRITERION => coverage} if coverage.is_a?(Numeric)
246
+ coverage.keys.each { |criterion| raise_if_criterion_disabled(criterion) }
247
+ coverage.values.each do |percent|
248
+ minimum_possible_coverage_exceeded("minimum_coverage") if percent && percent > 100
249
+ end
250
+
251
+ @minimum_coverage = coverage
245
252
  end
246
253
 
247
254
  #
@@ -362,12 +369,21 @@ module SimpleCov
362
369
 
363
370
  private
364
371
 
365
- def raise_if_criterion_unsupported(criterion)
366
- raise_criterion_unsupported(criterion) unless SUPPORTED_COVERAGE_CRITERIA.member?(criterion)
372
+ def raise_if_criterion_disabled(criterion)
373
+ raise_if_criterion_unsupported(criterion)
374
+ # rubocop:disable Style/IfUnlessModifier
375
+ unless coverage_criterion_enabled?(criterion)
376
+ raise "Coverage criterion #{criterion}, is disabled! Please enable it first through enable_coverage #{criterion} (if supported)"
377
+ end
378
+ # rubocop:enable Style/IfUnlessModifier
367
379
  end
368
380
 
369
- def raise_criterion_unsupported(criterion)
370
- raise "Unsupported coverage criterion #{criterion}, supported values are #{SUPPORTED_COVERAGE_CRITERIA}"
381
+ def raise_if_criterion_unsupported(criterion)
382
+ # rubocop:disable Style/IfUnlessModifier
383
+ unless SUPPORTED_COVERAGE_CRITERIA.member?(criterion)
384
+ raise "Unsupported coverage criterion #{criterion}, supported values are #{SUPPORTED_COVERAGE_CRITERIA}"
385
+ end
386
+ # rubocop:enable Style/IfUnlessModifier
371
387
  end
372
388
 
373
389
  def minimum_possible_coverage_exceeded(coverage_option)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleCov
4
+ # Holds the individual data of a coverage result.
5
+ #
6
+ # This is uniform across coverage criteria as they all have:
7
+ #
8
+ # * total - how many things to cover there are (total relevant loc/branches)
9
+ # * covered - how many of the coverables are hit
10
+ # * missed - how many of the coverables are missed
11
+ # * percent - percentage as covered/missed
12
+ # * strength - average hits per/coverable (will not exist for one shot lines format)
13
+ class CoverageStatistics
14
+ attr_reader :total, :covered, :missed, :strength, :percent
15
+
16
+ def self.from(coverage_statistics)
17
+ sum_covered, sum_missed, sum_total_strength =
18
+ coverage_statistics.reduce([0, 0, 0.0]) do |(covered, missed, total_strength), file_coverage_statistics|
19
+ [
20
+ covered + file_coverage_statistics.covered,
21
+ missed + file_coverage_statistics.missed,
22
+ # gotta remultiply with loc because files have different strenght and loc
23
+ # giving them a different "weight" in total
24
+ total_strength + (file_coverage_statistics.strength * file_coverage_statistics.total)
25
+ ]
26
+ end
27
+
28
+ new(covered: sum_covered, missed: sum_missed, total_strength: sum_total_strength)
29
+ end
30
+
31
+ # Requires only covered, missed and strength to be initialized.
32
+ #
33
+ # Other values are computed by this class.
34
+ def initialize(covered:, missed:, total_strength: 0.0)
35
+ @covered = covered
36
+ @missed = missed
37
+ @total = covered + missed
38
+ @percent = compute_percent(covered, total)
39
+ @strength = compute_strength(total_strength, @total)
40
+ end
41
+
42
+ private
43
+
44
+ def compute_percent(covered, total)
45
+ return 100.0 if total.zero?
46
+
47
+ covered * 100.0 / total
48
+ end
49
+
50
+ def compute_strength(total_strength, total)
51
+ return 0.0 if total.zero?
52
+
53
+ total_strength.to_f / total
54
+ end
55
+ end
56
+ end
@@ -3,19 +3,38 @@
3
3
  module SimpleCov
4
4
  # An array of SimpleCov SourceFile instances with additional collection helper
5
5
  # methods for calculating coverage across them etc.
6
- class FileList < Array
6
+ class FileList
7
+ include Enumerable
8
+ extend Forwardable
9
+
10
+ def_delegators :@files,
11
+ # For Enumerable
12
+ :each,
13
+ # also delegating methods implemented in Enumerable as they have
14
+ # custom Array implementations which are presumably better/more
15
+ # resource efficient
16
+ :size, :map, :count,
17
+ # surprisingly not in Enumerable
18
+ :empty?, :length,
19
+ # still act like we're kinda an array
20
+ :to_a, :to_ary
21
+
22
+ def initialize(files)
23
+ @files = files
24
+ end
25
+
26
+ def coverage_statistics
27
+ @coverage_statistics ||= compute_coverage_statistics
28
+ end
29
+
7
30
  # Returns the count of lines that have coverage
8
31
  def covered_lines
9
- return 0.0 if empty?
10
-
11
- map { |f| f.covered_lines.count }.inject(:+)
32
+ coverage_statistics[:line]&.covered
12
33
  end
13
34
 
14
35
  # Returns the count of lines that have been missed
15
36
  def missed_lines
16
- return 0.0 if empty?
17
-
18
- map { |f| f.missed_lines.count }.inject(:+)
37
+ coverage_statistics[:line]&.missed
19
38
  end
20
39
 
21
40
  # Returns the count of lines that are not relevant for coverage
@@ -45,44 +64,51 @@ module SimpleCov
45
64
 
46
65
  # Returns the overall amount of relevant lines of code across all files in this list
47
66
  def lines_of_code
48
- covered_lines + missed_lines
67
+ coverage_statistics[:line]&.total
49
68
  end
50
69
 
51
70
  # Computes the coverage based upon lines covered and lines missed
52
71
  # @return [Float]
53
72
  def covered_percent
54
- return 100.0 if empty? || lines_of_code.zero?
55
-
56
- Float(covered_lines * 100.0 / lines_of_code)
73
+ coverage_statistics[:line]&.percent
57
74
  end
58
75
 
59
76
  # Computes the strength (hits / line) based upon lines covered and lines missed
60
77
  # @return [Float]
61
78
  def covered_strength
62
- return 0.0 if empty? || lines_of_code.zero?
63
-
64
- Float(map { |f| f.covered_strength * f.lines_of_code }.inject(:+) / lines_of_code)
79
+ coverage_statistics[:line]&.strength
65
80
  end
66
81
 
67
82
  # Return total count of branches in all files
68
83
  def total_branches
69
- return 0 if empty?
70
-
71
- map { |file| file.total_branches.count }.inject(:+)
84
+ coverage_statistics[:branch]&.total
72
85
  end
73
86
 
74
87
  # Return total count of covered branches
75
88
  def covered_branches
76
- return 0 if empty?
77
-
78
- map { |file| file.covered_branches.count }.inject(:+)
89
+ coverage_statistics[:branch]&.covered
79
90
  end
80
91
 
81
92
  # Return total count of covered branches
82
93
  def missed_branches
83
- return 0 if empty?
94
+ coverage_statistics[:branch]&.missed
95
+ end
96
+
97
+ def branch_covered_percent
98
+ coverage_statistics[:branch]&.percent
99
+ end
100
+
101
+ private
102
+
103
+ def compute_coverage_statistics
104
+ total_coverage_statistics = @files.each_with_object(line: [], branch: []) do |file, together|
105
+ together[:line] << file.coverage_statistics[:line]
106
+ together[:branch] << file.coverage_statistics[:branch] if SimpleCov.branch_coverage?
107
+ end
84
108
 
85
- map { |file| file.missed_branches.count }.inject(:+)
109
+ coverage_statistics = {line: CoverageStatistics.from(total_coverage_statistics[:line])}
110
+ coverage_statistics[:branch] = CoverageStatistics.from(total_coverage_statistics[:branch]) if SimpleCov.branch_coverage?
111
+ coverage_statistics
86
112
  end
87
113
  end
88
114
  end
@@ -20,7 +20,7 @@ module SimpleCov
20
20
  # Explicitly set the command name that was used for this coverage result. Defaults to SimpleCov.command_name
21
21
  attr_writer :command_name
22
22
 
23
- def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines, :total_branches, :covered_branches, :missed_branches
23
+ def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines, :total_branches, :covered_branches, :missed_branches, :coverage_statistics
24
24
  def_delegator :files, :lines_of_code, :total_lines
25
25
 
26
26
  # Initialize a new SimpleCov::Result from given Coverage.result (a Hash of filenames each containing an array of
@@ -9,11 +9,11 @@ module SimpleCov
9
9
  # The full path to this source file (e.g. /User/colszowka/projects/simplecov/lib/simplecov/source_file.rb)
10
10
  attr_reader :filename
11
11
  # The array of coverage data received from the Coverage.result
12
- attr_reader :coverage
12
+ attr_reader :coverage_data
13
13
 
14
- def initialize(filename, coverage)
14
+ def initialize(filename, coverage_data)
15
15
  @filename = filename
16
- @coverage = coverage
16
+ @coverage_data = coverage_data
17
17
  end
18
18
 
19
19
  # The path to this source file relative to the projects directory
@@ -29,6 +29,14 @@ module SimpleCov
29
29
  end
30
30
  alias source src
31
31
 
32
+ def coverage_statistics
33
+ @coverage_statistics ||=
34
+ {
35
+ **line_coverage_statistics,
36
+ **branch_coverage_statistics
37
+ }
38
+ end
39
+
32
40
  # Returns all source lines for this file as instances of SimpleCov::SourceFile::Line,
33
41
  # and thus including coverage data. Aliased as :source_lines
34
42
  def lines
@@ -60,44 +68,7 @@ module SimpleCov
60
68
 
61
69
  # Returns the number of relevant lines (covered + missed)
62
70
  def lines_of_code
63
- covered_lines.size + missed_lines.size
64
- end
65
-
66
- def build_lines
67
- coverage_exceeding_source_warn if coverage["lines"].size > src.size
68
- lines = src.map.with_index(1) do |src, i|
69
- SimpleCov::SourceFile::Line.new(src, i, coverage["lines"][i - 1])
70
- end
71
- process_skipped_lines(lines)
72
- end
73
-
74
- # no_cov_chunks is zero indexed to work directly with the array holding the lines
75
- def no_cov_chunks
76
- @no_cov_chunks ||= build_no_cov_chunks
77
- end
78
-
79
- def build_no_cov_chunks
80
- no_cov_lines = src.map.with_index(1).select { |line, _index| LinesClassifier.no_cov_line?(line) }
81
-
82
- warn "uneven number of nocov comments detected" if no_cov_lines.size.odd?
83
-
84
- no_cov_lines.each_slice(2).map do |(_line_start, index_start), (_line_end, index_end)|
85
- index_start..index_end
86
- end
87
- end
88
-
89
- def process_skipped_lines(lines)
90
- # the array the lines are kept in is 0-based whereas the line numbers in the nocov
91
- # chunks are 1-based and are expected to be like this in other parts (and it's also
92
- # arguably more understandable)
93
- no_cov_chunks.each { |chunk| lines[(chunk.begin - 1)..(chunk.end - 1)].each(&:skipped!) }
94
-
95
- lines
96
- end
97
-
98
- # Warning to identify condition from Issue #56
99
- def coverage_exceeding_source_warn
100
- warn "Warning: coverage data provided by Coverage [#{coverage['lines'].size}] exceeds number of lines in #{filename} [#{src.size}]"
71
+ coverage_statistics[:line]&.total
101
72
  end
102
73
 
103
74
  # Access SimpleCov::SourceFile::Line source lines by line number
@@ -107,27 +78,17 @@ module SimpleCov
107
78
 
108
79
  # The coverage for this file in percent. 0 if the file has no coverage lines
109
80
  def covered_percent
110
- return 100.0 if no_lines?
111
-
112
- return 0.0 if relevant_lines.zero?
113
-
114
- Float(covered_lines.size * 100.0 / relevant_lines.to_f)
81
+ coverage_statistics[:line]&.percent
115
82
  end
116
83
 
117
84
  def covered_strength
118
- return 0.0 if relevant_lines.zero?
119
-
120
- (lines_strength / relevant_lines.to_f).round(1)
85
+ coverage_statistics[:line]&.strength
121
86
  end
122
87
 
123
88
  def no_lines?
124
89
  lines.length.zero? || (lines.length == never_lines.size)
125
90
  end
126
91
 
127
- def lines_strength
128
- lines.map(&:coverage).compact.reduce(:+)
129
- end
130
-
131
92
  def relevant_lines
132
93
  lines.size - never_lines.size - skipped_lines.size
133
94
  end
@@ -143,16 +104,13 @@ module SimpleCov
143
104
  end
144
105
 
145
106
  def branches_coverage_percent
146
- return 100.0 if no_branches?
147
- return 0.0 if covered_branches.empty?
148
-
149
- Float(covered_branches.size * 100.0 / total_branches.size.to_f)
107
+ coverage_statistics[:branch]&.percent
150
108
  end
151
109
 
152
110
  #
153
111
  # Return the relevant branches to source file
154
112
  def total_branches
155
- covered_branches + missed_branches
113
+ @total_branches ||= covered_branches + missed_branches
156
114
  end
157
115
 
158
116
  #
@@ -161,14 +119,104 @@ module SimpleCov
161
119
  @branches_report ||= build_branches_report
162
120
  end
163
121
 
164
- ## Related to source file branches statistics
122
+ #
123
+ # Select the covered branches
124
+ # Here we user tree schema because some conditions like case may have additional
125
+ # else that is not in declared inside the code but given by default by coverage report
126
+ #
127
+ # @return [Array]
128
+ #
129
+ def covered_branches
130
+ @covered_branches ||= branches.select(&:covered?)
131
+ end
132
+
133
+ #
134
+ # Select the missed branches with coverage equal to zero
135
+ #
136
+ # @return [Array]
137
+ #
138
+ def missed_branches
139
+ @missed_branches ||= branches.select(&:missed?)
140
+ end
141
+
142
+ def branches_for_line(line_number)
143
+ branches_report.fetch(line_number, [])
144
+ end
145
+
146
+ #
147
+ # Check if any branches missing on given line number
148
+ #
149
+ # @param [Integer] line_number
150
+ #
151
+ # @return [Boolean]
152
+ #
153
+ def line_with_missed_branch?(line_number)
154
+ branches_for_line(line_number).select { |_type, count| count.zero? }.any?
155
+ end
156
+
157
+ private
158
+
159
+ # no_cov_chunks is zero indexed to work directly with the array holding the lines
160
+ def no_cov_chunks
161
+ @no_cov_chunks ||= build_no_cov_chunks
162
+ end
163
+
164
+ def build_no_cov_chunks
165
+ no_cov_lines = src.map.with_index(1).select { |line, _index| LinesClassifier.no_cov_line?(line) }
166
+
167
+ warn "uneven number of nocov comments detected" if no_cov_lines.size.odd?
168
+
169
+ no_cov_lines.each_slice(2).map do |(_line_start, index_start), (_line_end, index_end)|
170
+ index_start..index_end
171
+ end
172
+ end
173
+
174
+ def build_lines
175
+ coverage_exceeding_source_warn if coverage_data["lines"].size > src.size
176
+ lines = src.map.with_index(1) do |src, i|
177
+ SimpleCov::SourceFile::Line.new(src, i, coverage_data["lines"][i - 1])
178
+ end
179
+ process_skipped_lines(lines)
180
+ end
181
+
182
+ def process_skipped_lines(lines)
183
+ # the array the lines are kept in is 0-based whereas the line numbers in the nocov
184
+ # chunks are 1-based and are expected to be like this in other parts (and it's also
185
+ # arguably more understandable)
186
+ no_cov_chunks.each { |chunk| lines[(chunk.begin - 1)..(chunk.end - 1)].each(&:skipped!) }
187
+
188
+ lines
189
+ end
190
+
191
+ def lines_strength
192
+ lines.map(&:coverage).compact.reduce(:+)
193
+ end
194
+
195
+ # Warning to identify condition from Issue #56
196
+ def coverage_exceeding_source_warn
197
+ warn "Warning: coverage data provided by Coverage [#{coverage_data['lines'].size}] exceeds number of lines in #{filename} [#{src.size}]"
198
+ end
199
+
200
+ #
201
+ # Build full branches report
202
+ # Root branches represent the wrapper of all condition state that
203
+ # have inside the branches
204
+ #
205
+ # @return [Hash]
206
+ #
207
+ def build_branches_report
208
+ branches.reject(&:skipped?).each_with_object({}) do |branch, coverage_statistics|
209
+ coverage_statistics[branch.report_line] ||= []
210
+ coverage_statistics[branch.report_line] << branch.report
211
+ end
212
+ end
165
213
 
166
214
  #
167
215
  # Call recursive method that transform our static hash to array of objects
168
216
  # @return [Array]
169
217
  #
170
218
  def build_branches
171
- coverage_branch_data = coverage.fetch("branches", {})
219
+ coverage_branch_data = coverage_data.fetch("branches", {})
172
220
  branches = coverage_branch_data.flat_map do |condition, coverage_branches|
173
221
  build_branches_from(condition, coverage_branches)
174
222
  end
@@ -230,53 +278,23 @@ module SimpleCov
230
278
  )
231
279
  end
232
280
 
233
- #
234
- # Select the covered branches
235
- # Here we user tree schema because some conditions like case may have additional
236
- # else that is not in declared inside the code but given by default by coverage report
237
- #
238
- # @return [Array]
239
- #
240
- def covered_branches
241
- @covered_branches ||= branches.select(&:covered?)
242
- end
243
-
244
- #
245
- # Select the missed branches with coverage equal to zero
246
- #
247
- # @return [Array]
248
- #
249
- def missed_branches
250
- @missed_branches ||= branches.select(&:missed?)
251
- end
252
-
253
- def branches_for_line(line_number)
254
- branches_report.fetch(line_number, [])
255
- end
256
-
257
- #
258
- # Check if any branches missing on given line number
259
- #
260
- # @param [Integer] line_number
261
- #
262
- # @return [Boolean]
263
- #
264
- def line_with_missed_branch?(line_number)
265
- branches_for_line(line_number).select { |_type, count| count.zero? }.any?
281
+ def line_coverage_statistics
282
+ {
283
+ line: CoverageStatistics.new(
284
+ total_strength: lines_strength,
285
+ covered: covered_lines.size,
286
+ missed: missed_lines.size
287
+ )
288
+ }
266
289
  end
267
290
 
268
- #
269
- # Build full branches report
270
- # Root branches represent the wrapper of all condition state that
271
- # have inside the branches
272
- #
273
- # @return [Hash]
274
- #
275
- def build_branches_report
276
- branches.reject(&:skipped?).each_with_object({}) do |branch, coverage_statistics|
277
- coverage_statistics[branch.report_line] ||= []
278
- coverage_statistics[branch.report_line] << branch.report
279
- end
291
+ def branch_coverage_statistics
292
+ {
293
+ branch: CoverageStatistics.new(
294
+ covered: covered_branches.size,
295
+ missed: missed_branches.size
296
+ )
297
+ }
280
298
  end
281
299
  end
282
300
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleCov
4
- VERSION = "0.18.0.beta3"
4
+ VERSION = "0.18.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplecov
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0.beta3
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christoph Olszowka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-20 00:00:00.000000000 Z
11
+ date: 2020-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.11.0.beta2
33
+ version: 0.11.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.11.0.beta2
40
+ version: 0.11.0
41
41
  description: Code coverage for Ruby with a powerful configuration library and automatic
42
42
  merging of coverage across test suites
43
43
  email:
@@ -63,6 +63,7 @@ files:
63
63
  - lib/simplecov/combine/results_combiner.rb
64
64
  - lib/simplecov/command_guesser.rb
65
65
  - lib/simplecov/configuration.rb
66
+ - lib/simplecov/coverage_statistics.rb
66
67
  - lib/simplecov/defaults.rb
67
68
  - lib/simplecov/exit_codes.rb
68
69
  - lib/simplecov/file_list.rb
@@ -95,9 +96,9 @@ licenses:
95
96
  metadata:
96
97
  bug_tracker_uri: https://github.com/colszowka/simplecov/issues
97
98
  changelog_uri: https://github.com/colszowka/simplecov/blob/master/CHANGELOG.md
98
- documentation_uri: https://www.rubydoc.info/gems/simplecov/0.18.0.beta3
99
+ documentation_uri: https://www.rubydoc.info/gems/simplecov/0.18.0
99
100
  mailing_list_uri: https://groups.google.com/forum/#!forum/simplecov
100
- source_code_uri: https://github.com/colszowka/simplecov/tree/v0.18.0.beta3
101
+ source_code_uri: https://github.com/colszowka/simplecov/tree/v0.18.0
101
102
  post_install_message:
102
103
  rdoc_options: []
103
104
  require_paths:
@@ -109,9 +110,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
110
  version: 2.4.0
110
111
  required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  requirements:
112
- - - ">"
113
+ - - ">="
113
114
  - !ruby/object:Gem::Version
114
- version: 1.3.1
115
+ version: '0'
115
116
  requirements: []
116
117
  rubygems_version: 3.1.2
117
118
  signing_key: