simplecov 0.18.0.beta1 → 0.18.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -1
- data/README.md +103 -18
- data/lib/simplecov/combine/files_combiner.rb +3 -4
- data/lib/simplecov/combine/results_combiner.rb +10 -10
- data/lib/simplecov/configuration.rb +43 -11
- data/lib/simplecov/coverage_statistics.rb +56 -0
- data/lib/simplecov/defaults.rb +3 -1
- data/lib/simplecov/file_list.rb +48 -22
- data/lib/simplecov/last_run.rb +1 -1
- data/lib/simplecov/result.rb +35 -19
- data/lib/simplecov/result_adapter.rb +1 -1
- data/lib/simplecov/result_merger.rb +7 -1
- data/lib/simplecov/simulate_coverage.rb +2 -2
- data/lib/simplecov/source_file/branch.rb +4 -26
- data/lib/simplecov/source_file.rb +134 -147
- data/lib/simplecov/useless_results_remover.rb +1 -1
- data/lib/simplecov/version.rb +1 -1
- data/lib/simplecov.rb +103 -21
- 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,45 @@
|
|
|
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
|
+
|
|
19
|
+
0.18.0.beta3 (2020-01-20)
|
|
20
|
+
========================
|
|
21
|
+
|
|
22
|
+
## Enhancements
|
|
23
|
+
* Instead of ignoring old `.resultset.json`s that are inside the merge timeout, adapt and respect them
|
|
24
|
+
|
|
25
|
+
## Bugfixes
|
|
26
|
+
* Remove the constant warning printing if you still have a `.resultset.json` in pre 0.18 layout that is within your merge timeout
|
|
27
|
+
|
|
28
|
+
0.18.0.beta2 (2020-01-19)
|
|
29
|
+
===================
|
|
30
|
+
|
|
31
|
+
## Enhancements
|
|
32
|
+
* only turn on the requested coverage criteria (when activating branch coverage before SimpleCov would also instruct Ruby to take Method coverage)
|
|
33
|
+
* Change how branch coverage is displayed, now it's `branch_type: hit_count` which should be more self explanatory. See [#830](https://github.com/colszowka/simplecov/pull/830) for an example and feel free to give feedback!
|
|
34
|
+
* Allow early running exit tasks and avoid the `at_exit` hook through the `SimpleCov.run_exit_tasks!` method. (thanks [@macumber](https://github.com/macumber))
|
|
35
|
+
* Allow manual collation of result sets through the `SimpleCov.collate` entrypoint. See the README for more details (thanks [@ticky](https://github.com/ticky))
|
|
36
|
+
* Within `case`, even if there is no `else` branch declared show missing coverage for it (aka no branch of it). See [#825](https://github.com/colszowka/simplecov/pull/825)
|
|
37
|
+
* Stop symbolizing all keys when loading cache (should lead to be faster and consume less memory)
|
|
38
|
+
* Cache whether we can use/are using branch coverage (should be slightly faster)
|
|
39
|
+
|
|
40
|
+
## Bugfixes
|
|
41
|
+
* Fix a crash that happened when an old version of our internal cache file `.resultset.json` was still present
|
|
42
|
+
|
|
1
43
|
0.18.0.beta1 (2020-01-05)
|
|
2
44
|
===================
|
|
3
45
|
|
|
@@ -8,7 +50,7 @@ This release is still beta because we'd love for you to test out branch coverage
|
|
|
8
50
|
On a personal note from [@PragTob](https://github.com/PragTob/) thanks to [ruby together](https://rubytogether.org/) for sponsoring this work on SimpleCov making it possible to deliver this and subsequent releases.
|
|
9
51
|
|
|
10
52
|
## Breaking
|
|
11
|
-
* Dropped
|
|
53
|
+
* Dropped support for all EOL'ed rubies meaning we only support 2.4+. Simplecov can no longer be installed on older rubies, but older simplecov releases should still work. (thanks [@deivid-rodriguez](https://github.com/deivid-rodriguez))
|
|
12
54
|
* Dropped the `rake simplecov` task that "magically" integreated with rails. It was always undocumented, caused some issues and [had some issues](https://github.com/colszowka/simplecov/issues/689#issuecomment-561572327). Use the integration as described in the README please :)
|
|
13
55
|
|
|
14
56
|
## Enhancements
|
data/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
SimpleCov [](https://badge.fury.io/rb/simplecov) [](https://badge.fury.io/rb/simplecov) [][Continuous Integration] [](https://codeclimate.com/github/colszowka/simplecov) [](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 [](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
|
|
|
@@ -170,6 +171,17 @@ to use SimpleCov with them. Here's an overview of the known ones:
|
|
|
170
171
|
<a href="https://github.com/colszowka/simplecov/pull/185">#185</a>
|
|
171
172
|
</td>
|
|
172
173
|
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<th>
|
|
176
|
+
knapsack_pro
|
|
177
|
+
</th>
|
|
178
|
+
<td>
|
|
179
|
+
To make SimpleCov work with Knapsack Pro Queue Mode to split tests in parallel on CI jobs you need to provide CI node index number to the <code>SimpleCov.command_name</code> in <code>KnapsackPro::Hooks::Queue.before_queue</code> hook.
|
|
180
|
+
</td>
|
|
181
|
+
<td>
|
|
182
|
+
<a href="https://knapsackpro.com/faq/question/how-to-use-simplecov-in-queue-mode">Tip</a>
|
|
183
|
+
</td>
|
|
184
|
+
</tr>
|
|
173
185
|
<tr>
|
|
174
186
|
<th>
|
|
175
187
|
RubyMine
|
|
@@ -308,12 +320,16 @@ return if number.odd?
|
|
|
308
320
|
```
|
|
309
321
|
|
|
310
322
|
If all the code in that method was covered you'd never know if the guard clause was ever
|
|
311
|
-
triggered
|
|
323
|
+
triggered! With line coverage as just evaluating the condition marks it as covered.
|
|
312
324
|
|
|
313
|
-
In the HTML report the lines of code will be annotated like `hit_count
|
|
325
|
+
In the HTML report the lines of code will be annotated like `branch_type: hit_count`:
|
|
314
326
|
|
|
315
|
-
* `2
|
|
316
|
-
* `0
|
|
327
|
+
* `then: 2` - the then branch (of an `if`) was executed twice
|
|
328
|
+
* `else: 0` - the else branch (of an `if` or `case`) was never executed
|
|
329
|
+
|
|
330
|
+
Not that even if you don't declare an `else` branch it will still show up in the coverage
|
|
331
|
+
reports meaning that the condition of the `if` was not hit or that no `when` of `case`
|
|
332
|
+
was hit during the test runs.
|
|
317
333
|
|
|
318
334
|
**Is branch coverage strictly better?** No. Branch coverage really only concerns itself with
|
|
319
335
|
conditionals - meaning coverage of sequential code is of no interest to it. A file without
|
|
@@ -461,12 +477,11 @@ end
|
|
|
461
477
|
|
|
462
478
|
You normally want to have your coverage analyzed across ALL of your test suites, right?
|
|
463
479
|
|
|
464
|
-
Simplecov automatically caches coverage results in your
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
There are two things to note here though:
|
|
480
|
+
Simplecov automatically caches coverage results in your
|
|
481
|
+
(coverage_path)/.resultset.json, and will merge or override those with
|
|
482
|
+
subsequent runs, depending on whether simplecov considers those subsequent runs
|
|
483
|
+
as different test suites or as the same test suite as the cached results. To
|
|
484
|
+
make this distinction, simplecov has the concept of "test suite names".
|
|
470
485
|
|
|
471
486
|
### Test suite names
|
|
472
487
|
|
|
@@ -520,14 +535,84 @@ SimpleCov.command_name "features" + (ENV['TEST_ENV_NUMBER'] || '')
|
|
|
520
535
|
|
|
521
536
|
[simplecov-html] prints the used test suites in the footer of the generated coverage report.
|
|
522
537
|
|
|
523
|
-
### Timeout for merge
|
|
524
538
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
539
|
+
### Merging test runs under the same execution environment
|
|
540
|
+
|
|
541
|
+
Test results are automatically merged with previous runs in the same execution
|
|
542
|
+
environment when generating the result, so when coverage is set up properly for
|
|
543
|
+
Cucumber and your unit / functional / integration tests, all of those test
|
|
544
|
+
suites will be taken into account when building the coverage report.
|
|
545
|
+
|
|
546
|
+
#### Timeout for merge
|
|
547
|
+
|
|
548
|
+
Of course, your cached coverage data is likely to become invalid at some point. Thus, when automatically merging
|
|
549
|
+
subsequent test runs, result sets that are older than `SimpleCov.merge_timeout` will not be used any more. By default,
|
|
550
|
+
the timeout is 600 seconds (10 minutes), and you can raise (or lower) it by specifying `SimpleCov.merge_timeout 3600`
|
|
551
|
+
(1 hour), or, inside a configure/start block, with just `merge_timeout 3600`.
|
|
552
|
+
|
|
553
|
+
You can deactivate this automatic merging altogether with `SimpleCov.use_merging false`.
|
|
554
|
+
|
|
555
|
+
### Merging test runs under different execution environments
|
|
556
|
+
|
|
557
|
+
If your tests are done in parallel across multiple build machines, you can fetch them all and merge them into a single
|
|
558
|
+
result set using the `SimpleCov.collate` method. This can be added to a Rakefile or script file, having downloaded a set of
|
|
559
|
+
`.resultset.json` files from each parallel test run.
|
|
560
|
+
|
|
561
|
+
```ruby
|
|
562
|
+
# lib/tasks/coverage_report.rake
|
|
563
|
+
namespace :coverage do
|
|
564
|
+
desc "Collates all result sets generated by the different test runners"
|
|
565
|
+
task :report do
|
|
566
|
+
require 'simplecov'
|
|
567
|
+
|
|
568
|
+
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"]
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
`SimpleCov.collate` also takes an optional simplecov profile and an optional
|
|
574
|
+
block for configuration, just the same as `SimpleCov.start` or
|
|
575
|
+
`SimpleCov.configure`. This means you can configure a separate formatter for
|
|
576
|
+
the collated output. For instance, you can make the formatter in
|
|
577
|
+
`SimpleCov.start` the `SimpleCov::Formatter::SimpleFormatter`, and only use more
|
|
578
|
+
complex formatters in the final `SimpleCov.collate` run.
|
|
579
|
+
|
|
580
|
+
```ruby
|
|
581
|
+
# spec/spec_helper.rb
|
|
582
|
+
require 'simplecov'
|
|
583
|
+
|
|
584
|
+
SimpleCov.start 'rails' do
|
|
585
|
+
# Disambiguates individual test runs
|
|
586
|
+
command_name "Job #{ENV["TEST_ENV_NUMBER"]}" if ENV["TEST_ENV_NUMBER"]
|
|
587
|
+
|
|
588
|
+
if ENV['CI']
|
|
589
|
+
formatter SimpleCov::Formatter::SimpleFormatter
|
|
590
|
+
else
|
|
591
|
+
formatter SimpleCov::Formatter::MultiFormatter.new([
|
|
592
|
+
SimpleCov::Formatter::SimpleFormatter,
|
|
593
|
+
SimpleCov::Formatter::HTMLFormatter
|
|
594
|
+
])
|
|
595
|
+
end
|
|
529
596
|
|
|
530
|
-
|
|
597
|
+
track_files "**/*.rb"
|
|
598
|
+
end
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
```ruby
|
|
602
|
+
# lib/tasks/coverage_report.rake
|
|
603
|
+
namespace :coverage do
|
|
604
|
+
task :report do
|
|
605
|
+
require 'simplecov'
|
|
606
|
+
|
|
607
|
+
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"], 'rails' do
|
|
608
|
+
formatter SimpleCov::Formatter::MultiFormatter.new([
|
|
609
|
+
SimpleCov::Formatter::SimpleFormatter,
|
|
610
|
+
SimpleCov::Formatter::HTMLFormatter
|
|
611
|
+
])
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
```
|
|
531
616
|
|
|
532
617
|
## Running coverage only on demand
|
|
533
618
|
|
|
@@ -15,10 +15,9 @@ module SimpleCov
|
|
|
15
15
|
# @return [Hash]
|
|
16
16
|
#
|
|
17
17
|
def combine(coverage_a, coverage_b)
|
|
18
|
-
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
18
|
+
combination = {"lines" => Combine.combine(LinesCombiner, coverage_a["lines"], coverage_b["lines"])}
|
|
19
|
+
combination["branches"] = Combine.combine(BranchesCombiner, coverage_a["branches"], coverage_b["branches"]) if SimpleCov.branch_coverage?
|
|
20
|
+
combination
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
@@ -20,26 +20,26 @@ module SimpleCov
|
|
|
20
20
|
# @return [Hash]
|
|
21
21
|
#
|
|
22
22
|
def combine(*results)
|
|
23
|
-
results.reduce({}) do |
|
|
24
|
-
combine_result_sets(
|
|
23
|
+
results.reduce({}) do |combined_results, next_result|
|
|
24
|
+
combine_result_sets(combined_results, next_result)
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
#
|
|
29
29
|
# Manage combining results on files level
|
|
30
30
|
#
|
|
31
|
-
# @param [Hash]
|
|
32
|
-
# @param [Hash]
|
|
31
|
+
# @param [Hash] combined_results
|
|
32
|
+
# @param [Hash] result
|
|
33
33
|
#
|
|
34
34
|
# @return [Hash]
|
|
35
35
|
#
|
|
36
|
-
def combine_result_sets(
|
|
37
|
-
results_files =
|
|
36
|
+
def combine_result_sets(combined_results, result)
|
|
37
|
+
results_files = combined_results.keys | result.keys
|
|
38
38
|
|
|
39
|
-
results_files.each_with_object({}) do |file_name,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
results_files.each_with_object({}) do |file_name, file_combination|
|
|
40
|
+
file_combination[file_name] = combine_file_coverage(
|
|
41
|
+
combined_results[file_name],
|
|
42
|
+
result[file_name]
|
|
43
43
|
)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -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
|
#
|
|
@@ -313,7 +320,7 @@ module SimpleCov
|
|
|
313
320
|
# * :line - coverage based on lines aka has this line been executed?
|
|
314
321
|
# * :branch - coverage based on branches aka has this branch (think conditions) been executed?
|
|
315
322
|
#
|
|
316
|
-
# If not set the default is
|
|
323
|
+
# If not set the default is `:line`
|
|
317
324
|
#
|
|
318
325
|
# @param [Symbol] criterion
|
|
319
326
|
#
|
|
@@ -335,23 +342,48 @@ module SimpleCov
|
|
|
335
342
|
@coverage_criteria ||= Set[DEFAULT_COVERAGE_CRITERION]
|
|
336
343
|
end
|
|
337
344
|
|
|
345
|
+
def coverage_criterion_enabled?(criterion)
|
|
346
|
+
coverage_criteria.member?(criterion)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def clear_coverage_criteria
|
|
350
|
+
@coverage_criteria = nil
|
|
351
|
+
end
|
|
352
|
+
|
|
338
353
|
def branch_coverage?
|
|
339
|
-
branch_coverage_supported? &&
|
|
354
|
+
branch_coverage_supported? && coverage_criterion_enabled?(:branch)
|
|
340
355
|
end
|
|
341
356
|
|
|
342
|
-
def
|
|
343
|
-
|
|
344
|
-
|
|
357
|
+
def coverage_start_arguments_supported?
|
|
358
|
+
# safe to cache as within one process this value should never
|
|
359
|
+
# change
|
|
360
|
+
return @coverage_start_arguments_supported if defined?(@coverage_start_arguments_supported)
|
|
361
|
+
|
|
362
|
+
@coverage_start_arguments_supported = begin
|
|
363
|
+
require "coverage"
|
|
364
|
+
!Coverage.method(:start).arity.zero?
|
|
365
|
+
end
|
|
345
366
|
end
|
|
346
367
|
|
|
368
|
+
alias branch_coverage_supported? coverage_start_arguments_supported?
|
|
369
|
+
|
|
347
370
|
private
|
|
348
371
|
|
|
349
|
-
def
|
|
350
|
-
|
|
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
|
|
351
379
|
end
|
|
352
380
|
|
|
353
|
-
def
|
|
354
|
-
|
|
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
|
|
355
387
|
end
|
|
356
388
|
|
|
357
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/defaults.rb
CHANGED
|
@@ -25,7 +25,9 @@ at_exit do
|
|
|
25
25
|
# If we are in a different process than called start, don't interfere.
|
|
26
26
|
next if SimpleCov.pid != Process.pid
|
|
27
27
|
|
|
28
|
-
SimpleCov
|
|
28
|
+
# If SimpleCov is no longer running then don't run exit tasks
|
|
29
|
+
next unless SimpleCov.running
|
|
30
|
+
|
|
29
31
|
SimpleCov.run_exit_tasks!
|
|
30
32
|
end
|
|
31
33
|
|
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/last_run.rb
CHANGED
data/lib/simplecov/result.rb
CHANGED
|
@@ -20,15 +20,16 @@ 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
|
|
27
27
|
# coverage data)
|
|
28
28
|
def initialize(original_result)
|
|
29
|
-
|
|
30
|
-
@
|
|
31
|
-
|
|
29
|
+
result = adapt_result(original_result)
|
|
30
|
+
@original_result = result.freeze
|
|
31
|
+
@files = SimpleCov::FileList.new(result.map do |filename, coverage|
|
|
32
|
+
SimpleCov::SourceFile.new(filename, JSON.parse(JSON.dump(coverage))) if File.file?(filename)
|
|
32
33
|
end.compact.sort_by(&:filename))
|
|
33
34
|
filter!
|
|
34
35
|
end
|
|
@@ -61,36 +62,51 @@ module SimpleCov
|
|
|
61
62
|
|
|
62
63
|
# Returns a hash representation of this Result that can be used for marshalling it into JSON
|
|
63
64
|
def to_hash
|
|
64
|
-
{
|
|
65
|
+
{
|
|
66
|
+
command_name => {
|
|
67
|
+
"coverage" => coverage,
|
|
68
|
+
"timestamp" => created_at.to_i
|
|
69
|
+
}
|
|
70
|
+
}
|
|
65
71
|
end
|
|
66
72
|
|
|
67
73
|
# Loads a SimpleCov::Result#to_hash dump
|
|
68
74
|
def self.from_hash(hash)
|
|
69
75
|
command_name, data = hash.first
|
|
70
76
|
|
|
71
|
-
result = SimpleCov::Result.new(
|
|
72
|
-
symbolize_names_of_coverage_results(data["coverage"])
|
|
73
|
-
)
|
|
77
|
+
result = SimpleCov::Result.new(data["coverage"])
|
|
74
78
|
|
|
75
79
|
result.command_name = command_name
|
|
76
80
|
result.created_at = Time.at(data["timestamp"])
|
|
77
81
|
result
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
# We changed the format of the raw result data in simplecov, as people are likely
|
|
87
|
+
# to have "old" resultsets lying around (but not too old so that they're still
|
|
88
|
+
# considered we can adapt them).
|
|
89
|
+
# See https://github.com/colszowka/simplecov/pull/824#issuecomment-576049747
|
|
90
|
+
def adapt_result(result)
|
|
91
|
+
if pre_simplecov_0_18_result?(result)
|
|
92
|
+
adapt_pre_simplecov_0_18_result(result)
|
|
93
|
+
else
|
|
94
|
+
result
|
|
90
95
|
end
|
|
91
96
|
end
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
# pre 0.18 coverage data pointed from file directly to an array of line coverage
|
|
99
|
+
def pre_simplecov_0_18_result?(result)
|
|
100
|
+
_key, data = result.first
|
|
101
|
+
|
|
102
|
+
data.is_a?(Array)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def adapt_pre_simplecov_0_18_result(result)
|
|
106
|
+
result.map do |file_path, line_coverage_data|
|
|
107
|
+
[file_path, {"lines" => line_coverage_data}]
|
|
108
|
+
end.to_h
|
|
109
|
+
end
|
|
94
110
|
|
|
95
111
|
def coverage
|
|
96
112
|
keys = original_result.keys & filenames
|
|
@@ -20,7 +20,7 @@ module SimpleCov
|
|
|
20
20
|
|
|
21
21
|
result.each_with_object({}) do |(file_name, cover_statistic), adapted_result|
|
|
22
22
|
if cover_statistic.is_a?(Array)
|
|
23
|
-
adapted_result.merge!(file_name => {
|
|
23
|
+
adapted_result.merge!(file_name => {"lines" => cover_statistic})
|
|
24
24
|
else
|
|
25
25
|
adapted_result.merge!(file_name => cover_statistic)
|
|
26
26
|
end
|