simplecov 0.19.0 → 0.21.2
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 +49 -506
- data/README.md +45 -9
- data/doc/alternate-formatters.md +5 -0
- data/lib/simplecov.rb +19 -16
- data/lib/simplecov/configuration.rb +44 -18
- data/lib/simplecov/default_formatter.rb +20 -0
- data/lib/simplecov/defaults.rb +5 -2
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +44 -11
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +26 -10
- data/lib/simplecov/file_list.rb +12 -6
- data/lib/simplecov/lines_classifier.rb +2 -2
- data/lib/simplecov/result.rb +2 -31
- data/lib/simplecov/result_merger.rb +121 -52
- data/lib/simplecov/source_file/line.rb +1 -1
- data/lib/simplecov/version.rb +1 -1
- metadata +20 -8
- data/CODE_OF_CONDUCT.md +0 -76
- data/CONTRIBUTING.md +0 -51
- data/ISSUE_TEMPLATE.md +0 -23
data/README.md
CHANGED
@@ -73,9 +73,10 @@ Getting started
|
|
73
73
|
analysis to happen on. When testing a server process (e.g. a JSON API
|
74
74
|
endpoint) via a separate test process (e.g. when using Selenium) where you
|
75
75
|
want to see all code executed by the `rails server`, and not just code
|
76
|
-
executed in your actual test files, you
|
76
|
+
executed in your actual test files, you need to require SimpleCov in the
|
77
|
+
server process. For rails for instance, you'll want to add something like this
|
77
78
|
to the top of `bin/rails`, but below the "shebang" line (`#! /usr/bin/env
|
78
|
-
ruby`):
|
79
|
+
ruby`) and after config/boot is required:
|
79
80
|
|
80
81
|
```ruby
|
81
82
|
if ENV['RAILS_ENV'] == 'test'
|
@@ -294,7 +295,6 @@ information to be lost.
|
|
294
295
|
Add branch coverage measurement statistics to your results. Supported in CRuby versions 2.5+.
|
295
296
|
|
296
297
|
```ruby
|
297
|
-
# or in configure or just SimpleCov.enable_coverage :branch
|
298
298
|
SimpleCov.start do
|
299
299
|
enable_coverage :branch
|
300
300
|
end
|
@@ -340,6 +340,22 @@ Hence, we recommend looking at both metrics together. Branch coverage might also
|
|
340
340
|
overall metric to look at - while you might be missing only 10% of your lines that might
|
341
341
|
account for 50% of your branches for instance.
|
342
342
|
|
343
|
+
## Primary Coverage
|
344
|
+
|
345
|
+
By default, the primary coverage type is `line`. To set the primary coverage to something else, use the following:
|
346
|
+
|
347
|
+
```ruby
|
348
|
+
# or in configure SimpleCov.primary_coverage :branch
|
349
|
+
SimpleCov.start do
|
350
|
+
enable_coverage :branch
|
351
|
+
primary_coverage :branch
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
Primary coverage determines what will come in first all output, and the type of coverage to check if you don't specify the type of coverage when customizing exit behavior (`SimpleCov.minimum_coverage 90`).
|
356
|
+
|
357
|
+
Note that coverage must first be enabled for non-default coverage types.
|
358
|
+
|
343
359
|
## Filters
|
344
360
|
|
345
361
|
Filters can be used to remove selected files from your coverage data. By default, a filter is applied that removes all
|
@@ -786,30 +802,36 @@ to help ensure coverage is relatively consistent, rather than being skewed by pa
|
|
786
802
|
|
787
803
|
```ruby
|
788
804
|
SimpleCov.minimum_coverage_by_file 80
|
805
|
+
# same as above (the default is to check line coverage by file)
|
806
|
+
SimpleCov.minimum_coverage_by_file line: 80
|
807
|
+
# check for a minimum line coverage by file of 90% and minimum 80% branch coverage
|
808
|
+
SimpleCov.minimum_coverage_by_file line: 90, branch: 80
|
789
809
|
```
|
790
810
|
|
791
|
-
(not yet supported for branch coverage)
|
792
|
-
|
793
811
|
### Maximum coverage drop
|
794
812
|
|
795
813
|
You can define the maximum coverage drop percentage at once. SimpleCov will return non-zero if exceeded.
|
796
814
|
|
797
815
|
```ruby
|
798
816
|
SimpleCov.maximum_coverage_drop 5
|
817
|
+
# same as above (the default is to check line drop)
|
818
|
+
SimpleCov.maximum_coverage_drop line: 5
|
819
|
+
# check for a maximum line drop of 5% and maximum 10% branch drop
|
820
|
+
SimpleCov.maximum_coverage_drop line: 5, branch: 10
|
799
821
|
```
|
800
822
|
|
801
|
-
(not yet supported for branch coverage)
|
802
|
-
|
803
823
|
### Refuse dropping coverage
|
804
824
|
|
805
825
|
You can also entirely refuse dropping coverage between test runs:
|
806
826
|
|
807
827
|
```ruby
|
808
828
|
SimpleCov.refuse_coverage_drop
|
829
|
+
# same as above (the default is to only refuse line drop)
|
830
|
+
SimpleCov.refuse_coverage_drop :line
|
831
|
+
# refuse drop for line and branch
|
832
|
+
SimpleCov.refuse_coverage_drop :line, :branch
|
809
833
|
```
|
810
834
|
|
811
|
-
(not yet supported for branch coverage)
|
812
|
-
|
813
835
|
## Using your own formatter
|
814
836
|
|
815
837
|
You can use your own formatter with:
|
@@ -833,6 +855,20 @@ SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
|
|
833
855
|
])
|
834
856
|
```
|
835
857
|
|
858
|
+
## JSON formatter
|
859
|
+
|
860
|
+
SimpleCov is packaged with a separate gem called [simplecov_json_formatter](https://github.com/codeclimate-community/simplecov_json_formatter) that provides you with a JSON formatter, this formatter could be useful for different use cases, such as for CI consumption or for reporting to external services.
|
861
|
+
|
862
|
+
In order to use it you will need to manually load the installed gem like so:
|
863
|
+
|
864
|
+
```ruby
|
865
|
+
require "simplecov_json_formatter"
|
866
|
+
SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter
|
867
|
+
```
|
868
|
+
|
869
|
+
> _Note:_ In case you plan to report your coverage results to CodeClimate services, know that SimpleCov will automatically use the
|
870
|
+
> JSON formatter along with the HTML formatter when the `CC_TEST_REPORTER_ID` variable is present in the environment.
|
871
|
+
|
836
872
|
## Available formatters, editor integrations and hosted services
|
837
873
|
|
838
874
|
* [Open Source formatter and integration plugins for SimpleCov](doc/alternate-formatters.md)
|
data/doc/alternate-formatters.md
CHANGED
@@ -60,6 +60,11 @@ A formatter that prints the coverage of the file under test when you run a singl
|
|
60
60
|
|
61
61
|
t_wada AA formatter for SimpleCov
|
62
62
|
|
63
|
+
#### [simplecov-tailwindcss](https://github.com/chiefpansancolt/simplecov-tailwindcss)
|
64
|
+
*by [Chiefpansancolt](https://github.com/chiefpansancolt)*
|
65
|
+
|
66
|
+
A TailwindCSS & TailwindUI Designed HTML formatter with clean and easy search of files with a tabular left Navigation.
|
67
|
+
|
63
68
|
#### [simplecov-material](https://github.com/chiefpansancolt/simplecov-material)
|
64
69
|
*by [Chiefpansancolt](https://github.com/chiefpansancolt)*
|
65
70
|
|
data/lib/simplecov.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "English"
|
4
4
|
|
5
5
|
# Coverage may be inaccurate under JRUBY.
|
6
|
-
if defined?(JRUBY_VERSION) && defined?(JRuby)
|
6
|
+
if defined?(JRUBY_VERSION) && defined?(JRuby) && !org.jruby.RubyInstanceConfig.FULL_TRACE_ENABLED
|
7
7
|
|
8
8
|
# @see https://github.com/jruby/jruby/issues/1196
|
9
9
|
# @see https://github.com/metricfu/metric_fu/pull/226
|
@@ -11,11 +11,9 @@ if defined?(JRUBY_VERSION) && defined?(JRuby)
|
|
11
11
|
# @see https://github.com/simplecov-ruby/simplecov/issues/86
|
12
12
|
# @see https://jira.codehaus.org/browse/JRUBY-6106
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
' or set the "debug.fullTrace=true" option in your .jrubyrc'
|
18
|
-
end
|
14
|
+
warn 'Coverage may be inaccurate; set the "--debug" command line option,' \
|
15
|
+
' or do JRUBY_OPTS="--debug"' \
|
16
|
+
' or set the "debug.fullTrace=true" option in your .jrubyrc'
|
19
17
|
end
|
20
18
|
|
21
19
|
#
|
@@ -50,7 +48,9 @@ module SimpleCov
|
|
50
48
|
def start(profile = nil, &block)
|
51
49
|
require "coverage"
|
52
50
|
initial_setup(profile, &block)
|
53
|
-
require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses?
|
51
|
+
require_relative "./simplecov/process" if SimpleCov.enabled_for_subprocesses? &&
|
52
|
+
::Process.respond_to?(:fork)
|
53
|
+
|
54
54
|
make_parallel_tests_available
|
55
55
|
|
56
56
|
@result = nil
|
@@ -61,6 +61,7 @@ module SimpleCov
|
|
61
61
|
|
62
62
|
#
|
63
63
|
# Collate a series of SimpleCov result files into a single SimpleCov output.
|
64
|
+
#
|
64
65
|
# You can optionally specify configuration with a block:
|
65
66
|
# SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"]
|
66
67
|
# OR
|
@@ -78,18 +79,17 @@ module SimpleCov
|
|
78
79
|
# available config options, or checkout the README for more in-depth
|
79
80
|
# information about coverage collation
|
80
81
|
#
|
81
|
-
|
82
|
-
|
82
|
+
# By default `collate` ignores the merge_timeout so all results of all files specified will be
|
83
|
+
# merged together. If you want to honor the merge_timeout then provide the keyword argument
|
84
|
+
# `ignore_timeout: false`.
|
85
|
+
#
|
86
|
+
def collate(result_filenames, profile = nil, ignore_timeout: true, &block)
|
87
|
+
raise "There are no reports to be merged" if result_filenames.empty?
|
83
88
|
|
84
89
|
initial_setup(profile, &block)
|
85
90
|
|
86
|
-
results = result_filenames.flat_map do |filename|
|
87
|
-
# Re-create each included instance of SimpleCov::Result from the stored run data.
|
88
|
-
Result.from_hash(JSON.parse(File.read(filename)) || {})
|
89
|
-
end
|
90
|
-
|
91
91
|
# Use the ResultMerger to produce a single, merged result, ready to use.
|
92
|
-
@result = ResultMerger.merge_and_store(*
|
92
|
+
@result = ResultMerger.merge_and_store(*result_filenames, ignore_timeout: ignore_timeout)
|
93
93
|
|
94
94
|
run_exit_tasks!
|
95
95
|
end
|
@@ -283,7 +283,10 @@ module SimpleCov
|
|
283
283
|
# @api private
|
284
284
|
#
|
285
285
|
def write_last_run(result)
|
286
|
-
SimpleCov::LastRun.write(result:
|
286
|
+
SimpleCov::LastRun.write(result:
|
287
|
+
result.coverage_statistics.transform_values do |stats|
|
288
|
+
round_coverage(stats.percent)
|
289
|
+
end)
|
287
290
|
end
|
288
291
|
|
289
292
|
#
|
@@ -10,7 +10,7 @@ module SimpleCov
|
|
10
10
|
# defined here are usable from SimpleCov directly. Please check out
|
11
11
|
# SimpleCov documentation for further info.
|
12
12
|
#
|
13
|
-
module Configuration
|
13
|
+
module Configuration
|
14
14
|
attr_writer :filters, :groups, :formatter, :print_error_status
|
15
15
|
|
16
16
|
#
|
@@ -22,6 +22,7 @@ module SimpleCov
|
|
22
22
|
def root(root = nil)
|
23
23
|
return @root if defined?(@root) && root.nil?
|
24
24
|
|
25
|
+
@coverage_path = nil # invalidate cache
|
25
26
|
@root = File.expand_path(root || Dir.getwd)
|
26
27
|
end
|
27
28
|
|
@@ -190,7 +191,7 @@ module SimpleCov
|
|
190
191
|
# end
|
191
192
|
#
|
192
193
|
def at_exit(&block)
|
193
|
-
return
|
194
|
+
return Proc.new unless running || block_given?
|
194
195
|
|
195
196
|
@at_exit = block if block_given?
|
196
197
|
@at_exit ||= proc { SimpleCov.result.format! }
|
@@ -199,8 +200,9 @@ module SimpleCov
|
|
199
200
|
# gets or sets the enabled_for_subprocess configuration
|
200
201
|
# when true, this will inject SimpleCov code into Process.fork
|
201
202
|
def enable_for_subprocesses(value = nil)
|
202
|
-
@enable_for_subprocesses
|
203
|
-
|
203
|
+
return @enable_for_subprocesses if defined?(@enable_for_subprocesses) && value.nil?
|
204
|
+
|
205
|
+
@enable_for_subprocesses = value || false
|
204
206
|
end
|
205
207
|
|
206
208
|
# gets the enabled_for_subprocess configuration
|
@@ -285,20 +287,22 @@ module SimpleCov
|
|
285
287
|
#
|
286
288
|
# Default is 0% (disabled)
|
287
289
|
#
|
288
|
-
|
289
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
290
290
|
def minimum_coverage(coverage = nil)
|
291
291
|
return @minimum_coverage ||= {} unless coverage
|
292
292
|
|
293
|
-
coverage = {
|
293
|
+
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
294
|
+
|
295
|
+
raise_on_invalid_coverage(coverage, "minimum_coverage")
|
296
|
+
|
297
|
+
@minimum_coverage = coverage
|
298
|
+
end
|
299
|
+
|
300
|
+
def raise_on_invalid_coverage(coverage, coverage_setting)
|
294
301
|
coverage.each_key { |criterion| raise_if_criterion_disabled(criterion) }
|
295
302
|
coverage.each_value do |percent|
|
296
|
-
minimum_possible_coverage_exceeded(
|
303
|
+
minimum_possible_coverage_exceeded(coverage_setting) if percent && percent > 100
|
297
304
|
end
|
298
|
-
|
299
|
-
@minimum_coverage = coverage
|
300
305
|
end
|
301
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
302
306
|
|
303
307
|
#
|
304
308
|
# Defines the maximum coverage drop at once allowed for the testsuite to pass.
|
@@ -307,7 +311,13 @@ module SimpleCov
|
|
307
311
|
# Default is 100% (disabled)
|
308
312
|
#
|
309
313
|
def maximum_coverage_drop(coverage_drop = nil)
|
310
|
-
@maximum_coverage_drop ||=
|
314
|
+
return @maximum_coverage_drop ||= {} unless coverage_drop
|
315
|
+
|
316
|
+
coverage_drop = {primary_coverage => coverage_drop} if coverage_drop.is_a?(Numeric)
|
317
|
+
|
318
|
+
raise_on_invalid_coverage(coverage_drop, "maximum_coverage_drop")
|
319
|
+
|
320
|
+
@maximum_coverage_drop = coverage_drop
|
311
321
|
end
|
312
322
|
|
313
323
|
#
|
@@ -318,16 +328,23 @@ module SimpleCov
|
|
318
328
|
# Default is 0% (disabled)
|
319
329
|
#
|
320
330
|
def minimum_coverage_by_file(coverage = nil)
|
321
|
-
|
322
|
-
|
331
|
+
return @minimum_coverage_by_file ||= {} unless coverage
|
332
|
+
|
333
|
+
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
334
|
+
|
335
|
+
raise_on_invalid_coverage(coverage, "minimum_coverage_by_file")
|
336
|
+
|
337
|
+
@minimum_coverage_by_file = coverage
|
323
338
|
end
|
324
339
|
|
325
340
|
#
|
326
341
|
# Refuses any coverage drop. That is, coverage is only allowed to increase.
|
327
342
|
# SimpleCov will return non-zero if the coverage decreases.
|
328
343
|
#
|
329
|
-
def refuse_coverage_drop
|
330
|
-
|
344
|
+
def refuse_coverage_drop(*criteria)
|
345
|
+
criteria = coverage_criteria if criteria.empty?
|
346
|
+
|
347
|
+
maximum_coverage_drop(criteria.map { |c| [c, 0] }.to_h)
|
331
348
|
end
|
332
349
|
|
333
350
|
#
|
@@ -374,7 +391,7 @@ module SimpleCov
|
|
374
391
|
# @param [Symbol] criterion
|
375
392
|
#
|
376
393
|
def coverage_criterion(criterion = nil)
|
377
|
-
return @coverage_criterion ||=
|
394
|
+
return @coverage_criterion ||= primary_coverage unless criterion
|
378
395
|
|
379
396
|
raise_if_criterion_unsupported(criterion)
|
380
397
|
|
@@ -387,8 +404,17 @@ module SimpleCov
|
|
387
404
|
coverage_criteria << criterion
|
388
405
|
end
|
389
406
|
|
407
|
+
def primary_coverage(criterion = nil)
|
408
|
+
if criterion.nil?
|
409
|
+
@primary_coverage ||= DEFAULT_COVERAGE_CRITERION
|
410
|
+
else
|
411
|
+
raise_if_criterion_disabled(criterion)
|
412
|
+
@primary_coverage = criterion
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
390
416
|
def coverage_criteria
|
391
|
-
@coverage_criteria ||= Set[
|
417
|
+
@coverage_criteria ||= Set[primary_coverage]
|
392
418
|
end
|
393
419
|
|
394
420
|
def coverage_criterion_enabled?(criterion)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "simplecov-html"
|
4
|
+
module SimpleCov
|
5
|
+
module Formatter
|
6
|
+
class << self
|
7
|
+
def from_env(env)
|
8
|
+
formatters = [SimpleCov::Formatter::HTMLFormatter]
|
9
|
+
|
10
|
+
# When running under a CI that uses CodeClimate, JSON output is expected
|
11
|
+
if env.fetch("CC_TEST_REPORTER_ID", nil)
|
12
|
+
require "simplecov_json_formatter"
|
13
|
+
formatters.push(SimpleCov::Formatter::JSONFormatter)
|
14
|
+
end
|
15
|
+
|
16
|
+
formatters
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/simplecov/defaults.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Load default formatter gem
|
4
|
-
require "simplecov-html"
|
5
4
|
require "pathname"
|
5
|
+
require_relative "default_formatter"
|
6
6
|
require_relative "profiles/root_filter"
|
7
7
|
require_relative "profiles/test_frameworks"
|
8
8
|
require_relative "profiles/bundler_filter"
|
@@ -11,7 +11,10 @@ require_relative "profiles/rails"
|
|
11
11
|
|
12
12
|
# Default configuration
|
13
13
|
SimpleCov.configure do
|
14
|
-
formatter SimpleCov::Formatter::
|
14
|
+
formatter SimpleCov::Formatter::MultiFormatter.new(
|
15
|
+
SimpleCov::Formatter.from_env(ENV)
|
16
|
+
)
|
17
|
+
|
15
18
|
load_profile "bundler_filter"
|
16
19
|
load_profile "hidden_filter"
|
17
20
|
# Exclude files outside of SimpleCov.root
|
@@ -11,15 +11,18 @@ module SimpleCov
|
|
11
11
|
def failing?
|
12
12
|
return false unless maximum_coverage_drop && last_run
|
13
13
|
|
14
|
-
|
14
|
+
coverage_drop_violations.any?
|
15
15
|
end
|
16
16
|
|
17
17
|
def report
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
coverage_drop_violations.each do |violation|
|
19
|
+
$stderr.printf(
|
20
|
+
"%<criterion>s coverage has dropped by %<drop_percent>.2f%% since the last time (maximum allowed: %<max_drop>.2f%%).\n",
|
21
|
+
criterion: violation[:criterion].capitalize,
|
22
|
+
drop_percent: SimpleCov.round_coverage(violation[:drop_percent]),
|
23
|
+
max_drop: violation[:max_drop]
|
24
|
+
)
|
25
|
+
end
|
23
26
|
end
|
24
27
|
|
25
28
|
def exit_code
|
@@ -36,14 +39,44 @@ module SimpleCov
|
|
36
39
|
@last_run = SimpleCov::LastRun.read
|
37
40
|
end
|
38
41
|
|
39
|
-
def
|
40
|
-
|
42
|
+
def coverage_drop_violations
|
43
|
+
@coverage_drop_violations ||=
|
44
|
+
compute_coverage_drop_data.select do |achieved|
|
45
|
+
achieved.fetch(:max_drop) < achieved.fetch(:drop_percent)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def compute_coverage_drop_data
|
50
|
+
maximum_coverage_drop.map do |criterion, percent|
|
51
|
+
{
|
52
|
+
criterion: criterion,
|
53
|
+
max_drop: percent,
|
54
|
+
drop_percent: drop_percent(criterion)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
41
58
|
|
42
|
-
|
59
|
+
# if anyone says "max_coverage_drop 0.000000000000000001" I appologize. Please don't.
|
60
|
+
MAX_DROP_ACCURACY = 10
|
61
|
+
def drop_percent(criterion)
|
62
|
+
drop = last_coverage(criterion) -
|
63
|
+
SimpleCov.round_coverage(
|
64
|
+
result.coverage_statistics.fetch(criterion).percent
|
65
|
+
)
|
66
|
+
|
67
|
+
# floats, I tell ya.
|
68
|
+
# irb(main):001:0* 80.01 - 80.0
|
69
|
+
# => 0.010000000000005116
|
70
|
+
drop.floor(MAX_DROP_ACCURACY)
|
43
71
|
end
|
44
72
|
|
45
|
-
def
|
46
|
-
|
73
|
+
def last_coverage(criterion)
|
74
|
+
last_coverage_percent = last_run[:result][criterion]
|
75
|
+
|
76
|
+
# fallback for old file format
|
77
|
+
last_coverage_percent = last_run[:result][:covered_percent] if !last_coverage_percent && criterion == :line
|
78
|
+
|
79
|
+
last_coverage_percent || 0
|
47
80
|
end
|
48
81
|
end
|
49
82
|
end
|