simplecov 0.22.0 → 1.0.0.rc1
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 +81 -1
- data/LICENSE +1 -1
- data/README.md +1009 -511
- data/doc/alternate-formatters.md +0 -5
- data/doc/commercial-services.md +5 -5
- data/exe/simplecov +11 -0
- data/lib/minitest/simplecov_plugin.rb +13 -5
- data/lib/simplecov/autostart.rb +11 -0
- data/lib/simplecov/cli/clean.rb +47 -0
- data/lib/simplecov/cli/coverage.rb +91 -0
- data/lib/simplecov/cli/diff.rb +151 -0
- data/lib/simplecov/cli/dotfile.rb +100 -0
- data/lib/simplecov/cli/merge.rb +116 -0
- data/lib/simplecov/cli/open.rb +50 -0
- data/lib/simplecov/cli/report.rb +84 -0
- data/lib/simplecov/cli/run.rb +36 -0
- data/lib/simplecov/cli/serve.rb +139 -0
- data/lib/simplecov/cli/uncovered.rb +107 -0
- data/lib/simplecov/cli.rb +150 -0
- data/lib/simplecov/color.rb +74 -0
- data/lib/simplecov/combine/branches_combiner.rb +3 -2
- data/lib/simplecov/combine/files_combiner.rb +7 -1
- data/lib/simplecov/combine/lines_combiner.rb +19 -17
- data/lib/simplecov/combine/methods_combiner.rb +26 -0
- data/lib/simplecov/combine/results_combiner.rb +5 -4
- data/lib/simplecov/command_guesser.rb +46 -32
- data/lib/simplecov/configuration/coverage.rb +171 -0
- data/lib/simplecov/configuration/coverage_criteria.rb +156 -0
- data/lib/simplecov/configuration/filters.rb +195 -0
- data/lib/simplecov/configuration/formatting.rb +119 -0
- data/lib/simplecov/configuration/ignored_entries.rb +63 -0
- data/lib/simplecov/configuration/merging.rb +74 -0
- data/lib/simplecov/configuration/thresholds.rb +174 -0
- data/lib/simplecov/configuration.rb +79 -405
- data/lib/simplecov/coverage_statistics.rb +12 -9
- data/lib/simplecov/coverage_violations.rb +148 -0
- data/lib/simplecov/defaults.rb +27 -20
- data/lib/simplecov/directive.rb +162 -0
- data/lib/simplecov/exit_codes/exit_code_handling.rb +8 -2
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +19 -57
- data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +45 -0
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +17 -27
- data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +41 -0
- data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +38 -21
- data/lib/simplecov/exit_codes.rb +3 -0
- data/lib/simplecov/exit_handling.rb +158 -0
- data/lib/simplecov/file_list.rb +61 -17
- data/lib/simplecov/filter.rb +69 -24
- data/lib/simplecov/formatter/base.rb +101 -0
- data/lib/simplecov/formatter/html_formatter/public/application.css +1 -0
- data/lib/simplecov/formatter/html_formatter/public/application.js +18 -0
- data/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
- data/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
- data/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
- data/lib/simplecov/formatter/html_formatter/public/index.html +56 -0
- data/lib/simplecov/formatter/html_formatter.rb +79 -0
- data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +84 -0
- data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +127 -0
- data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +99 -0
- data/lib/simplecov/formatter/json_formatter.rb +77 -0
- data/lib/simplecov/formatter/multi_formatter.rb +4 -5
- data/lib/simplecov/formatter/simple_formatter.rb +9 -11
- data/lib/simplecov/formatter.rb +4 -0
- data/lib/simplecov/last_run.rb +10 -3
- data/lib/simplecov/lines_classifier.rb +26 -13
- data/lib/simplecov/load_global_config.rb +9 -4
- data/lib/simplecov/parallel_adapters/base.rb +51 -0
- data/lib/simplecov/parallel_adapters/generic.rb +42 -0
- data/lib/simplecov/parallel_adapters/parallel_tests.rb +77 -0
- data/lib/simplecov/parallel_adapters.rb +83 -0
- data/lib/simplecov/parallel_coordination.rb +95 -0
- data/lib/simplecov/process.rb +20 -14
- data/lib/simplecov/profiles/bundler_filter.rb +1 -1
- data/lib/simplecov/profiles/hidden_filter.rb +1 -1
- data/lib/simplecov/profiles/rails.rb +24 -10
- data/lib/simplecov/profiles/root_filter.rb +6 -5
- data/lib/simplecov/profiles/strict.rb +32 -0
- data/lib/simplecov/profiles/test_frameworks.rb +1 -4
- data/lib/simplecov/profiles.rb +32 -3
- data/lib/simplecov/result/missing_source_files_reporter.rb +49 -0
- data/lib/simplecov/result/source_file_builder.rb +51 -0
- data/lib/simplecov/result.rb +97 -19
- data/lib/simplecov/result_adapter.rb +68 -6
- data/lib/simplecov/result_merger/legacy_format_adapter.rb +28 -0
- data/lib/simplecov/result_merger/resultset_file.rb +38 -0
- data/lib/simplecov/result_merger/resultset_store.rb +50 -0
- data/lib/simplecov/result_merger.rb +46 -90
- data/lib/simplecov/result_processing.rb +162 -0
- data/lib/simplecov/simulate_coverage.rb +54 -8
- data/lib/simplecov/source_file/branch.rb +1 -3
- data/lib/simplecov/source_file/branch_builder.rb +114 -0
- data/lib/simplecov/source_file/builder_context.rb +28 -0
- data/lib/simplecov/source_file/line.rb +7 -2
- data/lib/simplecov/source_file/line_builder.rb +43 -0
- data/lib/simplecov/source_file/method.rb +52 -0
- data/lib/simplecov/source_file/method_builder.rb +58 -0
- data/lib/simplecov/source_file/ruby_data_parser.rb +88 -0
- data/lib/simplecov/source_file/skip_chunks.rb +77 -0
- data/lib/simplecov/source_file/source_loader.rb +63 -0
- data/lib/simplecov/source_file/statistics.rb +57 -0
- data/lib/simplecov/source_file.rb +66 -232
- data/lib/simplecov/static_coverage_extractor/visitor.rb +193 -0
- data/lib/simplecov/static_coverage_extractor.rb +111 -0
- data/lib/simplecov/useless_results_remover.rb +16 -7
- data/lib/simplecov/version.rb +1 -1
- data/lib/simplecov-html.rb +4 -0
- data/lib/simplecov.rb +131 -377
- data/lib/simplecov_json_formatter.rb +4 -0
- data/schemas/coverage-v1.0.schema.json +300 -0
- data/schemas/coverage.schema.json +300 -0
- metadata +88 -56
- data/lib/simplecov/default_formatter.rb +0 -20
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../formatter/multi_formatter"
|
|
4
|
+
|
|
5
|
+
module SimpleCov
|
|
6
|
+
# Formatter selection (`formatter` / `formatters`), reporting toggles
|
|
7
|
+
# (`print_errors`), and the deprecated `# :nocov:` token hook.
|
|
8
|
+
module Configuration
|
|
9
|
+
attr_writer :formatter, :print_error_status
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Gets or sets the configured formatter. Pass `false` (or `nil`) to
|
|
13
|
+
# opt out of formatting entirely — worker processes in big parallel
|
|
14
|
+
# CI setups (see #964) only need their `.resultset.json` on disk so
|
|
15
|
+
# a final `SimpleCov.collate` job can produce the report; running
|
|
16
|
+
# them without a formatter saves the per-job HTML/multi-formatter
|
|
17
|
+
# overhead.
|
|
18
|
+
#
|
|
19
|
+
def formatter(formatter = :__no_arg__)
|
|
20
|
+
return @formatter if formatter == :__no_arg__
|
|
21
|
+
|
|
22
|
+
@formatter = formatter || nil # normalize `false` to `nil`
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Sets the configured formatters. Pass `[]` to opt out of
|
|
26
|
+
# formatting entirely; see `formatter` for the rationale.
|
|
27
|
+
def formatters(formatters = :__no_arg__)
|
|
28
|
+
return Array(formatter) if formatters == :__no_arg__
|
|
29
|
+
|
|
30
|
+
self.formatters = formatters
|
|
31
|
+
formatters
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Sets the configured formatters. Equivalent to `formatters [...]`.
|
|
35
|
+
def formatters=(formatters)
|
|
36
|
+
@formatter = formatters.empty? ? nil : SimpleCov::Formatter::MultiFormatter.new(formatters)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Get or set whether SimpleCov colorizes its stderr diagnostics. Accepts
|
|
41
|
+
# `true` (always on), `false` (always off), or `:auto` (default: defer
|
|
42
|
+
# to `SimpleCov::Color`, which checks `$stderr.tty?` with `NO_COLOR`
|
|
43
|
+
# and `FORCE_COLOR` overrides). An explicit `true`/`false` wins over
|
|
44
|
+
# both auto-detection and the env vars, which is the right escape
|
|
45
|
+
# hatch when stderr is being piped through a wrapper that still
|
|
46
|
+
# renders ANSI in its own terminal (parallel_tests with
|
|
47
|
+
# `--combine-stderr`, log multiplexers, some CI runners). See #1157.
|
|
48
|
+
#
|
|
49
|
+
def color(value = :__no_arg__)
|
|
50
|
+
return defined?(@color) ? @color : :auto if value == :__no_arg__
|
|
51
|
+
|
|
52
|
+
@color = value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Get or set whether SimpleCov prints its own diagnostic warnings to
|
|
57
|
+
# stderr. Covers per-check threshold violations, the trailing
|
|
58
|
+
# "SimpleCov failed with exit ..." summary, and the deferred-report /
|
|
59
|
+
# previous-error notices. Defaults to true. Set to false to silence
|
|
60
|
+
# SimpleCov entirely when parsing tooling output (see issue #1155).
|
|
61
|
+
#
|
|
62
|
+
def print_errors(value = :__no_arg__)
|
|
63
|
+
return defined?(@print_error_status) ? @print_error_status : true if value == :__no_arg__
|
|
64
|
+
|
|
65
|
+
@print_error_status = value
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# Get or set whether `coverage.json` includes the full source-text
|
|
70
|
+
# array for every file. Defaults to true. Set to false when a
|
|
71
|
+
# downstream tool reads the project's source files directly and
|
|
72
|
+
# only needs the coverage metrics, so `coverage.json` doesn't carry
|
|
73
|
+
# a copy of the source tree (which dominates the payload on larger
|
|
74
|
+
# projects).
|
|
75
|
+
#
|
|
76
|
+
# The HTML viewer's `coverage_data.js` always includes source —
|
|
77
|
+
# the client-side renderer needs it. Only `coverage.json` honors
|
|
78
|
+
# this setting.
|
|
79
|
+
#
|
|
80
|
+
# SimpleCov.start do
|
|
81
|
+
# source_in_json false
|
|
82
|
+
# end
|
|
83
|
+
#
|
|
84
|
+
def source_in_json(value = :__no_arg__)
|
|
85
|
+
return defined?(@source_in_json) ? @source_in_json : true if value == :__no_arg__
|
|
86
|
+
|
|
87
|
+
@source_in_json = value
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# DEPRECATED: alias for `print_errors`. Same value, same behavior.
|
|
91
|
+
def print_error_status
|
|
92
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.print_error_status` is deprecated. " \
|
|
93
|
+
"Replace with `SimpleCov.print_errors` (same value)."
|
|
94
|
+
defined?(@print_error_status) ? @print_error_status : true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# DEPRECATED: configure `# :nocov:` token override. Prefer
|
|
99
|
+
# `# simplecov:disable` / `# simplecov:enable` block comments (see
|
|
100
|
+
# SimpleCov::Directive). The `# :nocov:` toggle and this hook will
|
|
101
|
+
# be removed in a future release.
|
|
102
|
+
#
|
|
103
|
+
def nocov_token(nocov_token = nil)
|
|
104
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.nocov_token` and `SimpleCov.skip_token` are deprecated. " \
|
|
105
|
+
"Replace with `# simplecov:disable` / `# simplecov:enable` block comments."
|
|
106
|
+
current_nocov_token(nocov_token)
|
|
107
|
+
end
|
|
108
|
+
alias skip_token nocov_token
|
|
109
|
+
|
|
110
|
+
# Internal accessor used by SimpleCov to recognise `# :nocov:`
|
|
111
|
+
# markers without emitting the public-API deprecation warning. Will
|
|
112
|
+
# be removed alongside the deprecated `nocov_token` setter.
|
|
113
|
+
def current_nocov_token(value = nil)
|
|
114
|
+
return @nocov_token if defined?(@nocov_token) && value.nil?
|
|
115
|
+
|
|
116
|
+
@nocov_token = value || "nocov"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
# Coverage-entry filters scoped to branch / method criteria. See
|
|
5
|
+
# `ignore_branches` and `ignore_methods`, and #1033 /
|
|
6
|
+
# #1046 for the synthetic-entry detection rationale.
|
|
7
|
+
module Configuration
|
|
8
|
+
# Branch types accepted by `ignore_branches`.
|
|
9
|
+
IGNORABLE_BRANCH_TYPES = %i[implicit_else eval_generated].freeze
|
|
10
|
+
# Method types accepted by `ignore_methods`.
|
|
11
|
+
IGNORABLE_METHOD_TYPES = %i[eval_generated].freeze
|
|
12
|
+
|
|
13
|
+
# Variadic; multiple calls union. Setting is recorded regardless
|
|
14
|
+
# of whether branch coverage is enabled at call time. See #1033, #1046.
|
|
15
|
+
def ignore_branches(*types)
|
|
16
|
+
types.each { |type| raise_if_branch_type_unsupported(type) }
|
|
17
|
+
ignored_branches.concat(types).uniq!
|
|
18
|
+
ignored_branches
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ignored_branches
|
|
22
|
+
@ignored_branches ||= []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ignored_branch?(type)
|
|
26
|
+
ignored_branches.include?(type)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# See `ignore_branches`. The only supported method-type token today
|
|
30
|
+
# is `:eval_generated`; see #1046 for the rationale.
|
|
31
|
+
def ignore_methods(*types)
|
|
32
|
+
types.each { |type| raise_if_method_type_unsupported(type) }
|
|
33
|
+
ignored_methods.concat(types).uniq!
|
|
34
|
+
ignored_methods
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ignored_methods
|
|
38
|
+
@ignored_methods ||= []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def ignored_method?(type)
|
|
42
|
+
ignored_methods.include?(type)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def raise_if_branch_type_unsupported(type)
|
|
48
|
+
return if IGNORABLE_BRANCH_TYPES.member?(type)
|
|
49
|
+
|
|
50
|
+
raise SimpleCov::ConfigurationError,
|
|
51
|
+
"Unsupported branch type #{type.inspect} for `ignore_branches`. " \
|
|
52
|
+
"Supported values are #{IGNORABLE_BRANCH_TYPES.inspect}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def raise_if_method_type_unsupported(type)
|
|
56
|
+
return if IGNORABLE_METHOD_TYPES.member?(type)
|
|
57
|
+
|
|
58
|
+
raise SimpleCov::ConfigurationError,
|
|
59
|
+
"Unsupported method type #{type.inspect} for `ignore_methods`. " \
|
|
60
|
+
"Supported values are #{IGNORABLE_METHOD_TYPES.inspect}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
# Result merging and subprocess / parallel-test coordination:
|
|
5
|
+
# `merging`, `merge_subprocesses`, `merge_timeout`, `parallel_tests`.
|
|
6
|
+
module Configuration
|
|
7
|
+
#
|
|
8
|
+
# Get or set whether SimpleCov should hook `Process._fork` to
|
|
9
|
+
# attach itself to subprocesses. Required when the suite uses
|
|
10
|
+
# parallel test workers (e.g. Rails' `parallelize(workers:)`).
|
|
11
|
+
# Defaults to false.
|
|
12
|
+
#
|
|
13
|
+
def merge_subprocesses(value = nil)
|
|
14
|
+
return @enable_for_subprocesses if defined?(@enable_for_subprocesses) && value.nil?
|
|
15
|
+
|
|
16
|
+
@enable_for_subprocesses = value || false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @api private — predicate used by `start_tracking` to decide
|
|
20
|
+
# whether to install the fork hook.
|
|
21
|
+
def enabled_for_subprocesses?
|
|
22
|
+
defined?(@enable_for_subprocesses) ? @enable_for_subprocesses : false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Get or set whether SimpleCov should auto-require the
|
|
27
|
+
# `parallel_tests` gem when it sees `TEST_ENV_NUMBER` /
|
|
28
|
+
# `PARALLEL_TEST_GROUPS` in the environment. Defaults to auto-detect
|
|
29
|
+
# (nil). See #1018.
|
|
30
|
+
#
|
|
31
|
+
def parallel_tests(value = :__no_arg__)
|
|
32
|
+
return defined?(@parallel_tests) ? @parallel_tests : nil if value == :__no_arg__
|
|
33
|
+
|
|
34
|
+
@parallel_tests = value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# DEPRECATED: alias for `merge_subprocesses`. Same value/behavior.
|
|
38
|
+
def enable_for_subprocesses(value = nil)
|
|
39
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.enable_for_subprocesses` is deprecated. " \
|
|
40
|
+
"Replace with `SimpleCov.merge_subprocesses` (same value, same behavior)."
|
|
41
|
+
return @enable_for_subprocesses if defined?(@enable_for_subprocesses) && value.nil?
|
|
42
|
+
|
|
43
|
+
@enable_for_subprocesses = value || false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Get or set whether to merge results from multiple test suites
|
|
48
|
+
# (test:units, test:functionals, cucumber, ...) into a single
|
|
49
|
+
# coverage report. Defaults to true.
|
|
50
|
+
#
|
|
51
|
+
def merging(use = nil)
|
|
52
|
+
@use_merging = use unless use.nil?
|
|
53
|
+
@use_merging = true unless defined?(@use_merging) && @use_merging == false
|
|
54
|
+
@use_merging
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# DEPRECATED: alias for `merging`. Same value, same behavior.
|
|
58
|
+
def use_merging(use = nil)
|
|
59
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.use_merging` is deprecated. " \
|
|
60
|
+
"Replace with `SimpleCov.merging` (same value, same behavior)."
|
|
61
|
+
@use_merging = use unless use.nil?
|
|
62
|
+
@use_merging = true unless defined?(@use_merging) && @use_merging == false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Defines the maximum age (in seconds) of a resultset to still be
|
|
67
|
+
# included in merged results. Default is 600 seconds (10 minutes).
|
|
68
|
+
#
|
|
69
|
+
def merge_timeout(seconds = nil)
|
|
70
|
+
@merge_timeout = seconds if seconds.is_a?(Integer)
|
|
71
|
+
@merge_timeout ||= 600
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
# Coverage threshold configuration: `minimum_coverage`,
|
|
5
|
+
# `maximum_coverage`, `expected_coverage`, `maximum_coverage_drop`,
|
|
6
|
+
# `minimum_coverage_by_file`, `minimum_coverage_by_group`,
|
|
7
|
+
# `refuse_coverage_drop`, and friends.
|
|
8
|
+
module Configuration
|
|
9
|
+
#
|
|
10
|
+
# Defines the minimum overall coverage required for the testsuite to pass.
|
|
11
|
+
# Returns non-zero if the current coverage is below this threshold.
|
|
12
|
+
# Default is 0% (disabled).
|
|
13
|
+
#
|
|
14
|
+
def minimum_coverage(coverage = nil)
|
|
15
|
+
return @minimum_coverage ||= {} unless coverage
|
|
16
|
+
|
|
17
|
+
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
|
18
|
+
raise_on_invalid_coverage(coverage, "minimum_coverage")
|
|
19
|
+
@minimum_coverage = coverage
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def raise_on_invalid_coverage(coverage, coverage_setting)
|
|
23
|
+
coverage.each_key { |criterion| raise_if_criterion_disabled(criterion) }
|
|
24
|
+
coverage.each_value do |percent|
|
|
25
|
+
minimum_possible_coverage_exceeded(coverage_setting) if percent && percent > 100
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Defines the maximum overall coverage allowed for the testsuite to
|
|
31
|
+
# pass. Useful paired with `minimum_coverage` (or via
|
|
32
|
+
# `expected_coverage`) to pin coverage to an exact value, so an
|
|
33
|
+
# unexpected jump up fails the build. See #187.
|
|
34
|
+
#
|
|
35
|
+
def maximum_coverage(coverage = nil)
|
|
36
|
+
return @maximum_coverage ||= {} unless coverage
|
|
37
|
+
|
|
38
|
+
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
|
39
|
+
raise_on_invalid_coverage(coverage, "maximum_coverage")
|
|
40
|
+
@maximum_coverage = coverage
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# Pins the suite to an exact coverage figure by setting both
|
|
45
|
+
# `minimum_coverage` and `maximum_coverage`. See #187.
|
|
46
|
+
#
|
|
47
|
+
def expected_coverage(coverage = nil)
|
|
48
|
+
return minimum_coverage if coverage.nil?
|
|
49
|
+
|
|
50
|
+
minimum_coverage(coverage)
|
|
51
|
+
maximum_coverage(coverage)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#
|
|
55
|
+
# Defines the maximum coverage drop at once allowed for the
|
|
56
|
+
# testsuite to pass. Default is 100% (disabled).
|
|
57
|
+
#
|
|
58
|
+
def maximum_coverage_drop(coverage_drop = nil)
|
|
59
|
+
return @maximum_coverage_drop ||= {} unless coverage_drop
|
|
60
|
+
|
|
61
|
+
coverage_drop = {primary_coverage => coverage_drop} if coverage_drop.is_a?(Numeric)
|
|
62
|
+
raise_on_invalid_coverage(coverage_drop, "maximum_coverage_drop")
|
|
63
|
+
@maximum_coverage_drop = coverage_drop
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# Defines the minimum coverage per file required for the testsuite
|
|
68
|
+
# to pass. Accepts a Numeric (global threshold on the primary
|
|
69
|
+
# criterion), a Symbol-keyed Hash (per-criterion globals), or a
|
|
70
|
+
# Hash mixing Symbol keys with String / Regexp keys to declare
|
|
71
|
+
# per-path overrides. See README and #575.
|
|
72
|
+
#
|
|
73
|
+
def minimum_coverage_by_file(coverage = nil)
|
|
74
|
+
return @minimum_coverage_by_file ||= {} unless coverage
|
|
75
|
+
|
|
76
|
+
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
|
77
|
+
defaults, overrides = partition_per_file_thresholds(coverage)
|
|
78
|
+
|
|
79
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.minimum_coverage_by_file` is deprecated. " \
|
|
80
|
+
"Replace it with:\n#{per_file_coverage_replacement(defaults, overrides)}"
|
|
81
|
+
|
|
82
|
+
raise_on_invalid_coverage(defaults, "minimum_coverage_by_file")
|
|
83
|
+
overrides.each_value { |criteria| raise_on_invalid_coverage(criteria, "minimum_coverage_by_file") }
|
|
84
|
+
|
|
85
|
+
@minimum_coverage_by_file = defaults
|
|
86
|
+
@minimum_coverage_by_file_overrides = overrides
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns the per-path overrides set via `minimum_coverage_by_file`.
|
|
90
|
+
def minimum_coverage_by_file_overrides
|
|
91
|
+
@minimum_coverage_by_file_overrides ||= {}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#
|
|
95
|
+
# Defines the minimum coverage per group required for the testsuite
|
|
96
|
+
# to pass. Default is 0% (disabled).
|
|
97
|
+
#
|
|
98
|
+
def minimum_coverage_by_group(coverage = nil)
|
|
99
|
+
return @minimum_coverage_by_group ||= {} unless coverage
|
|
100
|
+
|
|
101
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] `SimpleCov.minimum_coverage_by_group` is deprecated. " \
|
|
102
|
+
"Replace it with:\n#{per_group_coverage_replacement(coverage)}"
|
|
103
|
+
@minimum_coverage_by_group = coverage.dup.transform_values do |group_coverage|
|
|
104
|
+
group_coverage = {primary_coverage => group_coverage} if group_coverage.is_a?(Numeric)
|
|
105
|
+
raise_on_invalid_coverage(group_coverage, "minimum_coverage_by_group")
|
|
106
|
+
group_coverage
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
#
|
|
111
|
+
# Refuses any coverage drop. Coverage is only allowed to increase.
|
|
112
|
+
#
|
|
113
|
+
def refuse_coverage_drop(*criteria)
|
|
114
|
+
criteria = coverage_criteria if criteria.empty?
|
|
115
|
+
maximum_coverage_drop(criteria.to_h { |c| [c, 0] })
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
# Split a `minimum_coverage_by_file` argument into Symbol-keyed
|
|
121
|
+
# criterion defaults and String/Regexp-keyed per-path overrides;
|
|
122
|
+
# normalize Numeric override values to `{primary_coverage => N}`
|
|
123
|
+
# so downstream code only has one shape to handle.
|
|
124
|
+
def partition_per_file_thresholds(coverage)
|
|
125
|
+
coverage.each_key { |key| validate_per_file_key(key) }
|
|
126
|
+
defaults, raw = coverage.partition { |key, _| key.is_a?(Symbol) }.map(&:to_h)
|
|
127
|
+
overrides = raw.transform_values { |value| value.is_a?(Numeric) ? {primary_coverage => value} : value }
|
|
128
|
+
[defaults, overrides]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def validate_per_file_key(key)
|
|
132
|
+
return if key.is_a?(Symbol) || key.is_a?(String) || key.is_a?(Regexp)
|
|
133
|
+
|
|
134
|
+
raise SimpleCov::ConfigurationError,
|
|
135
|
+
"minimum_coverage_by_file keys must be Symbol (criterion), String, or Regexp; got #{key.inspect}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def minimum_possible_coverage_exceeded(coverage_option)
|
|
139
|
+
warn "The coverage you set for #{coverage_option} is greater than 100%"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Render the `coverage` configuration equivalent to a (deprecated)
|
|
143
|
+
# `minimum_coverage_by_file` argument so the deprecation warning can be
|
|
144
|
+
# copy-pasted verbatim into the user's config.
|
|
145
|
+
def per_file_coverage_replacement(defaults, overrides)
|
|
146
|
+
by_criterion = Hash.new { |hash, criterion| hash[criterion] = [] }
|
|
147
|
+
defaults.each { |criterion, percent| by_criterion[criterion] << "minimum_per_file #{percent}" }
|
|
148
|
+
overrides.each do |target, criteria|
|
|
149
|
+
criteria.each do |criterion, percent|
|
|
150
|
+
by_criterion[criterion] << "minimum_per_file #{percent}, only: #{target.inspect}"
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
render_coverage_blocks(by_criterion)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Same, for a (deprecated) `minimum_coverage_by_group` argument.
|
|
157
|
+
def per_group_coverage_replacement(coverage)
|
|
158
|
+
by_criterion = Hash.new { |hash, criterion| hash[criterion] = [] }
|
|
159
|
+
coverage.each do |group_name, group_coverage|
|
|
160
|
+
group_coverage = {primary_coverage => group_coverage} if group_coverage.is_a?(Numeric)
|
|
161
|
+
group_coverage.each do |criterion, percent|
|
|
162
|
+
by_criterion[criterion] << "minimum_per_group #{percent}, only: #{group_name.inspect}"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
render_coverage_blocks(by_criterion)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def render_coverage_blocks(by_criterion)
|
|
169
|
+
by_criterion.map do |criterion, statements|
|
|
170
|
+
" coverage(#{criterion.inspect}) { #{statements.join('; ')} }"
|
|
171
|
+
end.join("\n")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|