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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +3 -2
- data/lib/simplecov.rb +29 -6
- data/lib/simplecov/configuration.rb +22 -6
- data/lib/simplecov/coverage_statistics.rb +56 -0
- data/lib/simplecov/file_list.rb +48 -22
- data/lib/simplecov/result.rb +1 -1
- data/lib/simplecov/source_file.rb +123 -105
- data/lib/simplecov/version.rb +1 -1
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce12d99507e5e8bd75399d80855c495907b8dda937fb5e2a33d2895e9f74e370
|
4
|
+
data.tar.gz: ae53aefe53c30c3b1d6c1c0b70aa34c1193642d4a879f77a0c3522960fc92773
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9a60e36936b9b5018a6998ade1742373bfa67b96688411ab42c90ac82ca6280abe9d407dcef4d45398ed28803ca876d6f82ce0cabc878d6141897cca4dab91e
|
7
|
+
data.tar.gz: 7056045c2385516ce0029af14558bd95c9c84bc85319d82bddfcf2011b7db87a5291168bb739c1ff02d8830e133065b3f2fda605e03b7c2e6ed094b61bff9240
|
data/CHANGELOG.md
CHANGED
@@ -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://
|
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]:
|
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
|
|
data/lib/simplecov.rb
CHANGED
@@ -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
|
235
|
-
|
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
|
-
|
244
|
-
|
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
|
366
|
-
|
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
|
370
|
-
|
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
|
data/lib/simplecov/file_list.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/simplecov/result.rb
CHANGED
@@ -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 :
|
12
|
+
attr_reader :coverage_data
|
13
13
|
|
14
|
-
def initialize(filename,
|
14
|
+
def initialize(filename, coverage_data)
|
15
15
|
@filename = filename
|
16
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
data/lib/simplecov/version.rb
CHANGED
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
|
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-
|
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
|
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
|
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
|
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
|
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:
|
115
|
+
version: '0'
|
115
116
|
requirements: []
|
116
117
|
rubygems_version: 3.1.2
|
117
118
|
signing_key:
|