simplecov 0.22.0 → 1.3.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/LICENSE +1 -1
- data/README.md +173 -875
- data/exe/simplecov +8 -0
- data/lib/minitest/simplecov_plugin.rb +18 -7
- data/lib/simplecov/atomic_file.rb +67 -0
- data/lib/simplecov/autostart.rb +9 -0
- data/lib/simplecov/baseline/parser.rb +58 -0
- data/lib/simplecov/baseline.rb +170 -0
- data/lib/simplecov/cli/affected/changed_files.rb +57 -0
- data/lib/simplecov/cli/affected/selection.rb +117 -0
- data/lib/simplecov/cli/affected.rb +148 -0
- data/lib/simplecov/cli/annotations.rb +166 -0
- data/lib/simplecov/cli/badge/svg.rb +70 -0
- data/lib/simplecov/cli/badge.rb +62 -0
- data/lib/simplecov/cli/clean.rb +86 -0
- data/lib/simplecov/cli/command_helpers.rb +91 -0
- data/lib/simplecov/cli/completions/scripts.rb +114 -0
- data/lib/simplecov/cli/completions.rb +83 -0
- data/lib/simplecov/cli/coverage.rb +83 -0
- data/lib/simplecov/cli/coverage_file.rb +109 -0
- data/lib/simplecov/cli/dead_code/output.rb +100 -0
- data/lib/simplecov/cli/dead_code.rb +139 -0
- data/lib/simplecov/cli/diff/output.rb +45 -0
- data/lib/simplecov/cli/diff.rb +115 -0
- data/lib/simplecov/cli/dotfile.rb +156 -0
- data/lib/simplecov/cli/git.rb +41 -0
- data/lib/simplecov/cli/history/output.rb +135 -0
- data/lib/simplecov/cli/history.rb +67 -0
- data/lib/simplecov/cli/merge.rb +115 -0
- data/lib/simplecov/cli/open.rb +45 -0
- data/lib/simplecov/cli/patch/changed_lines.rb +149 -0
- data/lib/simplecov/cli/patch/output.rb +151 -0
- data/lib/simplecov/cli/patch.rb +175 -0
- data/lib/simplecov/cli/ratchet/output.rb +44 -0
- data/lib/simplecov/cli/ratchet.rb +83 -0
- data/lib/simplecov/cli/report.rb +91 -0
- data/lib/simplecov/cli/run.rb +35 -0
- data/lib/simplecov/cli/serve/report_preparer.rb +30 -0
- data/lib/simplecov/cli/serve/static_file_handler.rb +128 -0
- data/lib/simplecov/cli/serve.rb +88 -0
- data/lib/simplecov/cli/show/annotator.rb +87 -0
- data/lib/simplecov/cli/show/sweep.rb +36 -0
- data/lib/simplecov/cli/show.rb +133 -0
- data/lib/simplecov/cli/status/facts.rb +87 -0
- data/lib/simplecov/cli/status.rb +93 -0
- data/lib/simplecov/cli/tests/redundancy.rb +78 -0
- data/lib/simplecov/cli/tests.rb +148 -0
- data/lib/simplecov/cli/uncovered/misses.rb +33 -0
- data/lib/simplecov/cli/uncovered.rb +127 -0
- data/lib/simplecov/cli/usage.rb +153 -0
- data/lib/simplecov/cli/watch/live_report.rb +73 -0
- data/lib/simplecov/cli/watch/narrator.rb +55 -0
- data/lib/simplecov/cli/watch/poller.rb +45 -0
- data/lib/simplecov/cli/watch/session.rb +134 -0
- data/lib/simplecov/cli/watch/test_plan.rb +43 -0
- data/lib/simplecov/cli/watch.rb +85 -0
- data/lib/simplecov/cli.rb +114 -0
- data/lib/simplecov/color.rb +65 -0
- data/lib/simplecov/combine/branches_combiner.rb +44 -21
- data/lib/simplecov/combine/coverage_accumulator.rb +175 -0
- data/lib/simplecov/combine/identity_interner.rb +27 -0
- data/lib/simplecov/combine/interned_counts.rb +28 -0
- data/lib/simplecov/combine/lines_combiner.rb +35 -29
- data/lib/simplecov/combine/methods_combiner.rb +48 -0
- data/lib/simplecov/combine/results_combiner.rb +9 -49
- data/lib/simplecov/combine.rb +0 -24
- data/lib/simplecov/command_guesser.rb +99 -42
- data/lib/simplecov/configuration/baseline.rb +31 -0
- data/lib/simplecov/configuration/coverage.rb +184 -0
- data/lib/simplecov/configuration/coverage_criteria.rb +143 -0
- data/lib/simplecov/configuration/deprecations.rb +21 -0
- data/lib/simplecov/configuration/eval_coverage.rb +37 -0
- data/lib/simplecov/configuration/filters.rb +131 -0
- data/lib/simplecov/configuration/formatting.rb +129 -0
- data/lib/simplecov/configuration/groups.rb +48 -0
- data/lib/simplecov/configuration/history.rb +44 -0
- data/lib/simplecov/configuration/ignored_entries.rb +72 -0
- data/lib/simplecov/configuration/merging.rb +197 -0
- data/lib/simplecov/configuration/missed_caps.rb +51 -0
- data/lib/simplecov/configuration/production.rb +23 -0
- data/lib/simplecov/configuration/test_tracking.rb +48 -0
- data/lib/simplecov/configuration/thresholds.rb +150 -0
- data/lib/simplecov/configuration/view_coverage.rb +37 -0
- data/lib/simplecov/configuration.rb +100 -443
- data/lib/simplecov/configuration_error.rb +5 -0
- data/lib/simplecov/context_map/union.rb +81 -0
- data/lib/simplecov/context_map.rb +187 -0
- data/lib/simplecov/coverage_json.rb +21 -0
- data/lib/simplecov/coverage_statistics.rb +24 -28
- data/lib/simplecov/coverage_violations.rb +254 -0
- data/lib/simplecov/current_run.rb +61 -0
- data/lib/simplecov/defaults.rb +20 -28
- data/lib/simplecov/deprecation.rb +63 -0
- data/lib/simplecov/directive/erb.rb +44 -0
- data/lib/simplecov/directive/haml.rb +33 -0
- data/lib/simplecov/directive/indented_template.rb +37 -0
- data/lib/simplecov/directive/slim.rb +35 -0
- data/lib/simplecov/directive/template.rb +29 -0
- data/lib/simplecov/directive.rb +152 -0
- data/lib/simplecov/exit_codes/baseline_check.rb +46 -0
- data/lib/simplecov/exit_codes/check.rb +39 -0
- data/lib/simplecov/exit_codes/exit_code_handling.rb +24 -5
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +17 -67
- data/lib/simplecov/exit_codes/maximum_missed_check.rb +26 -0
- data/lib/simplecov/exit_codes/maximum_missed_per_file_check.rb +34 -0
- data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +27 -0
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +20 -38
- data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +28 -0
- data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +37 -34
- data/lib/simplecov/exit_codes.rb +26 -0
- data/lib/simplecov/exit_handling.rb +163 -0
- data/lib/simplecov/file_list.rb +63 -48
- data/lib/simplecov/filter.rb +98 -42
- data/lib/simplecov/formatter/base.rb +100 -0
- data/lib/simplecov/formatter/baseline_formatter.rb +98 -0
- data/lib/simplecov/formatter/coverage_json_writer.rb +95 -0
- data/lib/simplecov/formatter/html_formatter/public/index.html +93 -0
- data/lib/simplecov/formatter/html_formatter/viewer_data_validator.rb +153 -0
- data/lib/simplecov/formatter/html_formatter.rb +88 -0
- data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +122 -0
- data/lib/simplecov/formatter/json_formatter/production_section_formatter.rb +48 -0
- data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +132 -0
- data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +97 -0
- data/lib/simplecov/formatter/json_formatter.rb +40 -0
- data/lib/simplecov/formatter/multi_formatter.rb +8 -10
- data/lib/simplecov/formatter/simple_formatter.rb +12 -15
- data/lib/simplecov/formatter.rb +21 -1
- data/lib/simplecov/group_names.rb +33 -0
- data/lib/simplecov/history.rb +115 -0
- data/lib/simplecov/last_run.rb +16 -5
- data/lib/simplecov/lines_classifier.rb +67 -19
- data/lib/simplecov/load_global_config.rb +12 -4
- data/lib/simplecov/parallel_adapters/base.rb +50 -0
- data/lib/simplecov/parallel_adapters/generic.rb +33 -0
- data/lib/simplecov/parallel_adapters/parallel_tests.rb +72 -0
- data/lib/simplecov/parallel_adapters.rb +54 -0
- data/lib/simplecov/parallel_coordination.rb +124 -0
- data/lib/simplecov/parallel_result_merger/worker_payload.rb +33 -0
- data/lib/simplecov/parallel_result_merger.rb +171 -0
- data/lib/simplecov/process.rb +34 -12
- data/lib/simplecov/production/error.rb +11 -0
- data/lib/simplecov/production/file_sink.rb +130 -0
- data/lib/simplecov/production.rb +249 -0
- data/lib/simplecov/profiles/bundler_filter.rb +1 -1
- data/lib/simplecov/profiles/hidden_filter.rb +1 -1
- data/lib/simplecov/profiles/rails.rb +13 -10
- data/lib/simplecov/profiles/root_filter.rb +2 -5
- data/lib/simplecov/profiles/strict.rb +22 -0
- data/lib/simplecov/profiles/test_frameworks.rb +1 -4
- data/lib/simplecov/profiles.rb +26 -19
- data/lib/simplecov/report_deferral.rb +45 -0
- data/lib/simplecov/report_stamp.rb +25 -0
- data/lib/simplecov/result/filter_config.rb +19 -0
- data/lib/simplecov/result/missing_source_files_reporter.rb +48 -0
- data/lib/simplecov/result/serialization.rb +43 -0
- data/lib/simplecov/result/source_file_builder.rb +46 -0
- data/lib/simplecov/result.rb +123 -47
- data/lib/simplecov/result_adapter.rb +130 -11
- data/lib/simplecov/result_merger/contexts.rb +22 -0
- data/lib/simplecov/result_merger/legacy_format_adapter.rb +24 -0
- data/lib/simplecov/result_merger/resultset_file.rb +67 -0
- data/lib/simplecov/result_merger/resultset_run_identity.rb +65 -0
- data/lib/simplecov/result_merger/resultset_store.rb +62 -0
- data/lib/simplecov/result_merger/unloaded_files.rb +95 -0
- data/lib/simplecov/result_merger.rb +120 -124
- data/lib/simplecov/result_processing.rb +188 -0
- data/lib/simplecov/run_identity.rb +75 -0
- data/lib/simplecov/simulate_coverage.rb +72 -17
- data/lib/simplecov/source_file/branch.rb +8 -35
- data/lib/simplecov/source_file/branch_builder.rb +95 -0
- data/lib/simplecov/source_file/builder_context.rb +28 -0
- data/lib/simplecov/source_file/line.rb +17 -32
- data/lib/simplecov/source_file/line_builder.rb +37 -0
- data/lib/simplecov/source_file/method.rb +54 -0
- data/lib/simplecov/source_file/method_builder.rb +51 -0
- data/lib/simplecov/source_file/ruby_data_parser.rb +103 -0
- data/lib/simplecov/source_file/skip_chunks.rb +72 -0
- data/lib/simplecov/source_file/source_loader.rb +89 -0
- data/lib/simplecov/source_file/statistics.rb +76 -0
- data/lib/simplecov/source_file.rb +64 -260
- data/lib/simplecov/static_coverage_extractor/condition_folding.rb +155 -0
- data/lib/simplecov/static_coverage_extractor/location_conventions.rb +191 -0
- data/lib/simplecov/static_coverage_extractor/method_collector.rb +45 -0
- data/lib/simplecov/static_coverage_extractor/prism_compat.rb +46 -0
- data/lib/simplecov/static_coverage_extractor/value_position.rb +61 -0
- data/lib/simplecov/static_coverage_extractor/visitor.rb +163 -0
- data/lib/simplecov/static_coverage_extractor.rb +78 -0
- data/lib/simplecov/test_tracker/accessors.rb +34 -0
- data/lib/simplecov/test_tracker/constant_watch.rb +49 -0
- data/lib/simplecov/test_tracker/delta.rb +69 -0
- data/lib/simplecov/test_tracker/framework_hooks.rb +130 -0
- data/lib/simplecov/test_tracker.rb +162 -0
- data/lib/simplecov/unloaded_file_injector.rb +62 -0
- data/lib/simplecov/useless_results_remover.rb +17 -7
- data/lib/simplecov/version.rb +1 -1
- data/lib/simplecov/view_coverage/template_compiler.rb +83 -0
- data/lib/simplecov/view_coverage.rb +55 -0
- data/lib/simplecov-html.rb +5 -0
- data/lib/simplecov.rb +143 -394
- data/lib/simplecov_json_formatter.rb +5 -0
- data/man/simplecov.1 +354 -0
- data/sig/simplecov.rbs +1710 -0
- metadata +183 -61
- data/CHANGELOG.md +0 -191
- data/doc/alternate-formatters.md +0 -71
- data/doc/commercial-services.md +0 -25
- data/doc/editor-integration.md +0 -18
- data/lib/simplecov/combine/files_combiner.rb +0 -24
- data/lib/simplecov/default_formatter.rb +0 -20
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
attr_writer :filters
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# Restrict the universe of files in the coverage report to those matching
|
|
9
|
+
# one or more globs, regexps, or block predicates. Multiple calls union;
|
|
10
|
+
# when any `cover` matcher is configured the report drops every file that
|
|
11
|
+
# doesn't match at least one of them.
|
|
12
|
+
#
|
|
13
|
+
# Strings are interpreted as shell globs, not substring matches, a
|
|
14
|
+
# deliberate departure from the legacy `add_filter` semantics.
|
|
15
|
+
#
|
|
16
|
+
# A string glob is also expanded on disk, so files that exist but were
|
|
17
|
+
# never required during the run still appear in the report at 0%. This is
|
|
18
|
+
# the "include unloaded files" half of the legacy `track_files` behavior.
|
|
19
|
+
#
|
|
20
|
+
def cover(*args, &block)
|
|
21
|
+
args.each { |arg| cover_filters << build_cover_filter(arg) }
|
|
22
|
+
cover_filters << BlockFilter.new(block) if block
|
|
23
|
+
cover_filters
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def cover_filters
|
|
27
|
+
@cover_filters ||= []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# The string globs passed to `cover`, used by the disk-discovery pass in
|
|
31
|
+
# `SimpleCov.tracked_file_paths` so files matching a `cover` glob appear in
|
|
32
|
+
# the report even when they were never required during the suite.
|
|
33
|
+
def cover_globs
|
|
34
|
+
collect_cover_globs(cover_filters)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def track_files(glob)
|
|
38
|
+
Deprecation.warn("`SimpleCov.track_files` is deprecated. " \
|
|
39
|
+
"#{track_files_replacement_hint(glob)}")
|
|
40
|
+
@tracked_files = glob
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# `track_files(nil)` is the documented way to clear a previously-set glob,
|
|
44
|
+
# but `cover(nil)` raises `ConfigurationError`, so don't point users at it.
|
|
45
|
+
def track_files_replacement_hint(glob)
|
|
46
|
+
if glob.nil?
|
|
47
|
+
"Replace with `SimpleCov.cover_filters.clear` — clearing the inclusion list."
|
|
48
|
+
else
|
|
49
|
+
"Replace with `SimpleCov.cover #{glob.inspect}` — `cover` includes unloaded files on disk " \
|
|
50
|
+
"(the historical `track_files` behavior) and also restricts the report to the matching set. " \
|
|
51
|
+
"If you want to keep additional files outside #{glob.inspect} in the report, pass every " \
|
|
52
|
+
"directory you care about, e.g. `cover #{glob.inspect}, \"app/**/*.rb\"`."
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Nil until `cover` names a glob: an unset ivar reads as nil, so the absence
|
|
57
|
+
# needs no guard of its own.
|
|
58
|
+
def tracked_files
|
|
59
|
+
@tracked_files
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def filters
|
|
63
|
+
@filters ||= []
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# Drop matching files from the coverage report. The inverse of `cover`.
|
|
68
|
+
# Accepts a String (path-segment substring), Regexp, block predicate, or
|
|
69
|
+
# Array of any of those.
|
|
70
|
+
#
|
|
71
|
+
def skip(filter_argument = nil, &)
|
|
72
|
+
filters << parse_filter(filter_argument, &)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def add_filter(filter_argument = nil, &block)
|
|
76
|
+
example = block ? "`SimpleCov.skip { ... }`" : "`SimpleCov.skip #{filter_argument.inspect}`"
|
|
77
|
+
Deprecation.warn("`SimpleCov.add_filter` is deprecated. " \
|
|
78
|
+
"Replace with `SimpleCov.skip` (same arguments, same behavior). Example: #{example}.")
|
|
79
|
+
skip(filter_argument, &block)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# `reject!` answers nil when it rejected nothing, which is the whole of
|
|
83
|
+
# "was anything removed".
|
|
84
|
+
def remove_filter(filter_argument)
|
|
85
|
+
rejected = filters.reject! do |filter|
|
|
86
|
+
filter.respond_to?(:filter_argument) && filter.filter_argument.eql?(filter_argument)
|
|
87
|
+
end
|
|
88
|
+
!rejected.nil?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def clear_filters
|
|
92
|
+
@filters = []
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Order matters: call this before your own `skip` invocations.
|
|
96
|
+
def no_default_skips
|
|
97
|
+
clear_filters
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def parse_filter(filter_argument = nil, &filter_proc)
|
|
103
|
+
filter = filter_argument || filter_proc
|
|
104
|
+
|
|
105
|
+
raise ArgumentError, "Please specify either a filter or a block to filter with" unless filter
|
|
106
|
+
|
|
107
|
+
Filter.build_filter(filter)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Strings are treated as globs, not substrings (that's `skip`'s
|
|
111
|
+
# semantics); everything else dispatches exactly like `add_filter`.
|
|
112
|
+
def build_cover_filter(arg)
|
|
113
|
+
Filter.build_filter(arg, string_filter: GlobFilter)
|
|
114
|
+
rescue ConfigurationError
|
|
115
|
+
raise ConfigurationError, "Unsupported `cover` argument #{arg.inspect}; " \
|
|
116
|
+
"expected a String glob, Regexp, Proc, " \
|
|
117
|
+
"SimpleCov::Filter, or Array of those."
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Descends into `ArrayFilter` wrappers built by `cover(["a", "b"])`.
|
|
121
|
+
def collect_cover_globs(filter_list)
|
|
122
|
+
filter_list.flat_map do |filter|
|
|
123
|
+
case filter
|
|
124
|
+
when GlobFilter then filter.filter_argument
|
|
125
|
+
when ArrayFilter then collect_cover_globs(filter.filter_argument)
|
|
126
|
+
else []
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../formatter/multi_formatter"
|
|
4
|
+
|
|
5
|
+
module SimpleCov
|
|
6
|
+
module Configuration
|
|
7
|
+
attr_writer :formatter, :print_error_status
|
|
8
|
+
|
|
9
|
+
BUILT_IN_FORMATS = {
|
|
10
|
+
html: :HTMLFormatter, json: :JSONFormatter, simple: :SimpleFormatter, baseline: :BaselineFormatter
|
|
11
|
+
}.freeze
|
|
12
|
+
private_constant :BUILT_IN_FORMATS
|
|
13
|
+
|
|
14
|
+
LAZY_FORMAT_REQUIRES = {html: "../../simplecov-html"}.freeze
|
|
15
|
+
private_constant :LAZY_FORMAT_REQUIRES
|
|
16
|
+
|
|
17
|
+
def formats(*names)
|
|
18
|
+
return formatters if names.empty?
|
|
19
|
+
|
|
20
|
+
self.formatters = names.map { |name| resolve_format(name) }
|
|
21
|
+
formatters
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def formatter(formatter = :__no_arg__)
|
|
25
|
+
case formatter
|
|
26
|
+
when :__no_arg__
|
|
27
|
+
@formatter
|
|
28
|
+
else
|
|
29
|
+
@formatter = formatter || nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def formatters(formatters = :__no_arg__)
|
|
34
|
+
case formatters
|
|
35
|
+
when :__no_arg__
|
|
36
|
+
configured = formatter
|
|
37
|
+
configured ? [configured] : []
|
|
38
|
+
else
|
|
39
|
+
self.formatters = formatters
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# `nil`, `false`, and `[]` all opt out of formatting entirely. `false` is
|
|
44
|
+
# normalized first, since `Array(false)` would otherwise smuggle it in as a
|
|
45
|
+
# "formatter" that can only fail.
|
|
46
|
+
def formatters=(formatters)
|
|
47
|
+
@formatter = combined_formatter(Array(formatters || nil))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def color(value = :__no_arg__)
|
|
51
|
+
return instance_variable_defined?(:@color) ? @color : :auto if value.eql?(:__no_arg__)
|
|
52
|
+
|
|
53
|
+
self.color = _ = value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def color=(value)
|
|
57
|
+
@color = value
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def print_errors(value = :__no_arg__)
|
|
61
|
+
return instance_variable_defined?(:@print_error_status) ? @print_error_status : true if value.eql?(:__no_arg__)
|
|
62
|
+
|
|
63
|
+
self.print_errors = _ = value
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def print_errors=(value)
|
|
67
|
+
@print_error_status = value
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def source_in_json(value = :__no_arg__)
|
|
71
|
+
return instance_variable_defined?(:@source_in_json) ? @source_in_json : true if value.eql?(:__no_arg__)
|
|
72
|
+
|
|
73
|
+
self.source_in_json = _ = value
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def source_in_json=(value)
|
|
77
|
+
@source_in_json = value
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def print_error_status
|
|
81
|
+
Deprecation.warn("`SimpleCov.print_error_status` is deprecated. " \
|
|
82
|
+
"Replace with `SimpleCov.print_errors` (same value).")
|
|
83
|
+
instance_variable_defined?(:@print_error_status) ? @print_error_status : true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def nocov_token(nocov_token = nil)
|
|
87
|
+
Deprecation.warn("`SimpleCov.nocov_token` and `SimpleCov.skip_token` are deprecated. " \
|
|
88
|
+
"Replace with `# simplecov:disable` / `# simplecov:enable` block comments.")
|
|
89
|
+
current_nocov_token(nocov_token)
|
|
90
|
+
end
|
|
91
|
+
alias_method :skip_token, :nocov_token
|
|
92
|
+
|
|
93
|
+
def current_nocov_token(value = nil)
|
|
94
|
+
return @nocov_token if instance_variable_defined?(:@nocov_token) && value.nil?
|
|
95
|
+
|
|
96
|
+
@nocov_token = value || "nocov"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
# An empty list is how a project opts out of formatting.
|
|
102
|
+
def combined_formatter(formatters)
|
|
103
|
+
return if formatters.empty?
|
|
104
|
+
|
|
105
|
+
Formatter::MultiFormatter.new(formatters)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def resolve_format(name)
|
|
109
|
+
return name unless name.instance_of?(Symbol)
|
|
110
|
+
|
|
111
|
+
constant = BUILT_IN_FORMATS[name]
|
|
112
|
+
unless constant
|
|
113
|
+
raise ConfigurationError,
|
|
114
|
+
"Unknown format #{name.inspect}. Built-in formats are :html, :json, :simple, and :baseline; " \
|
|
115
|
+
"pass a formatter class or instance for anything else."
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
require_html_formatter(name)
|
|
119
|
+
Formatter.const_get(constant)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# `formats :html` has to work in a process that never required the HTML
|
|
123
|
+
# formatter, which under SIMPLECOV_NO_DEFAULTS nothing else has.
|
|
124
|
+
def require_html_formatter(name)
|
|
125
|
+
path = LAZY_FORMAT_REQUIRES[name]
|
|
126
|
+
require_relative(path) if path
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
def groups
|
|
6
|
+
@groups ||= {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# The group set `SimpleCov.grouped` bins against when its caller names none.
|
|
10
|
+
# It reads through a method of its own because the keyword it defaults
|
|
11
|
+
# shadows `groups`, so the default has to name a receiver, and every
|
|
12
|
+
# spelling of that receiver is the same call.
|
|
13
|
+
#
|
|
14
|
+
# mutant:disable — for that reason: `SimpleCov.groups`, `self.groups` and
|
|
15
|
+
# `groups()` cannot be told apart.
|
|
16
|
+
def default_groups
|
|
17
|
+
groups
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def groups=(new_groups)
|
|
21
|
+
new_groups = new_groups.to_h { |name, filter| [GroupNames.normalize(name), filter] }
|
|
22
|
+
GroupNames.validate!(new_groups.keys)
|
|
23
|
+
@groups = new_groups
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Same matcher grammar as `skip`, but instead of dropping the matching files
|
|
27
|
+
# it bins them under `group_name` for the formatter. Files matched by no
|
|
28
|
+
# group fall into the implicit "Ungrouped" bucket.
|
|
29
|
+
def group(group_name, filter_argument = nil, &)
|
|
30
|
+
group_name = GroupNames.normalize(group_name)
|
|
31
|
+
GroupNames.validate!([group_name])
|
|
32
|
+
groups[group_name] = parse_filter(filter_argument, &)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add_group(group_name, filter_argument = nil, &block)
|
|
36
|
+
example = if block
|
|
37
|
+
"`SimpleCov.group #{group_name.inspect} { ... }`"
|
|
38
|
+
else
|
|
39
|
+
"`SimpleCov.group #{group_name.inspect}, #{filter_argument.inspect}`"
|
|
40
|
+
end
|
|
41
|
+
Deprecation.warn(
|
|
42
|
+
"`SimpleCov.add_group` is deprecated. " \
|
|
43
|
+
"Replace with `SimpleCov.group` (same arguments, same behavior). Example: #{example}."
|
|
44
|
+
)
|
|
45
|
+
group(group_name, filter_argument, &block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
DROP_BASELINES = %i[last_run median branch].freeze
|
|
6
|
+
|
|
7
|
+
# How many runs coverage/.history.json keeps, newest kept. 0 disables
|
|
8
|
+
# recording entirely, and anything but a count of runs is refused.
|
|
9
|
+
def history_limit(limit = nil)
|
|
10
|
+
return @history_limit ||= 100 if limit.nil?
|
|
11
|
+
|
|
12
|
+
self.history_limit = limit
|
|
13
|
+
_ = @history_limit
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def history_limit=(limit)
|
|
17
|
+
unless limit.instance_of?(Integer) && limit >= 0
|
|
18
|
+
raise ConfigurationError, "history_limit takes a non-negative integer, got #{limit.inspect}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@history_limit = limit
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# What `maximum_coverage_drop` measures the drop against: `:last_run` (the
|
|
25
|
+
# default) the previous run whatever it was, `:median` the median of the
|
|
26
|
+
# recorded history so one run that dipped for an unrelated reason cannot
|
|
27
|
+
# quietly become the baseline, and `:branch` the newest recorded run on the
|
|
28
|
+
# current git branch so a feature branch is compared with itself.
|
|
29
|
+
#
|
|
30
|
+
# The latter two read coverage/.history.json and find nothing to compare
|
|
31
|
+
# against while it is empty, which counts as "no previous run" the way a
|
|
32
|
+
# missing .last_run.json does.
|
|
33
|
+
def drop_baseline(mode = nil)
|
|
34
|
+
return @drop_baseline ||= :last_run if mode.nil?
|
|
35
|
+
|
|
36
|
+
unless DROP_BASELINES.include?(mode)
|
|
37
|
+
raise ConfigurationError,
|
|
38
|
+
"drop_baseline takes one of #{DROP_BASELINES}, got #{mode.inspect}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@drop_baseline = mode
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
IGNORABLE_BRANCH_TYPES = %i[implicit_else eval_generated].freeze
|
|
6
|
+
IGNORABLE_METHOD_TYPES = %i[eval_generated].freeze
|
|
7
|
+
|
|
8
|
+
# Deprecated in favour of `coverage(:branch) { ignore :implicit_else }`,
|
|
9
|
+
# which fixes the criterion by context the way the threshold verbs do. One
|
|
10
|
+
# difference rides out the deprecation period: the coverage block enables the
|
|
11
|
+
# criterion it names, while this legacy setter records without enabling.
|
|
12
|
+
def ignore_branches(*types)
|
|
13
|
+
Deprecation.warn("`SimpleCov.ignore_branches` is deprecated. " \
|
|
14
|
+
"Replace with `coverage(:branch) { ignore #{types.map(&:inspect).join(", ")} }`.")
|
|
15
|
+
store_ignored_branches(types)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ignored_branches
|
|
19
|
+
@ignored_branches ||= []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ignored_branch?(type)
|
|
23
|
+
ignored_branches.include?(type)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ignore_methods(*types)
|
|
27
|
+
Deprecation.warn("`SimpleCov.ignore_methods` is deprecated. " \
|
|
28
|
+
"Replace with `coverage(:method) { ignore #{types.map(&:inspect).join(", ")} }`.")
|
|
29
|
+
store_ignored_methods(types)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ignored_methods
|
|
33
|
+
@ignored_methods ||= []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ignored_method?(type)
|
|
37
|
+
ignored_methods.include?(type)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
# Variadic semantics: multiple calls union, duplicates are no-ops, unknown
|
|
43
|
+
# tokens raise.
|
|
44
|
+
def store_ignored_branches(types)
|
|
45
|
+
types.each { |type| raise_if_branch_type_unsupported(type) }
|
|
46
|
+
ignored_branches.concat(types).uniq!
|
|
47
|
+
ignored_branches
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def store_ignored_methods(types)
|
|
51
|
+
types.each { |type| raise_if_method_type_unsupported(type) }
|
|
52
|
+
ignored_methods.concat(types).uniq!
|
|
53
|
+
ignored_methods
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def raise_if_branch_type_unsupported(type)
|
|
57
|
+
return if IGNORABLE_BRANCH_TYPES.member?(type)
|
|
58
|
+
|
|
59
|
+
raise ConfigurationError,
|
|
60
|
+
"Unsupported branch type #{type.inspect} for `ignore_branches`. " \
|
|
61
|
+
"Supported values are #{IGNORABLE_BRANCH_TYPES.inspect}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def raise_if_method_type_unsupported(type)
|
|
65
|
+
return if IGNORABLE_METHOD_TYPES.member?(type)
|
|
66
|
+
|
|
67
|
+
raise ConfigurationError,
|
|
68
|
+
"Unsupported method type #{type.inspect} for `ignore_methods`. " \
|
|
69
|
+
"Supported values are #{IGNORABLE_METHOD_TYPES.inspect}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
#
|
|
6
|
+
# Whether SimpleCov should hook `Process._fork` to attach itself to
|
|
7
|
+
# subprocesses. Required when the suite uses parallel test workers (Rails'
|
|
8
|
+
# `parallelize(workers:)`). Defaults to false.
|
|
9
|
+
#
|
|
10
|
+
def merge_subprocesses(value = nil)
|
|
11
|
+
return @enable_for_subprocesses if instance_variable_defined?(:@enable_for_subprocesses) && value.nil?
|
|
12
|
+
|
|
13
|
+
self.merge_subprocesses = value
|
|
14
|
+
@enable_for_subprocesses
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# false stands in for nothing, so the answer is always a real opt-in or
|
|
18
|
+
# opt-out.
|
|
19
|
+
def merge_subprocesses=(value)
|
|
20
|
+
@enable_for_subprocesses = value || false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @api private
|
|
24
|
+
def enabled_for_subprocesses?
|
|
25
|
+
!!@enable_for_subprocesses
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Whether SimpleCov should auto-require the `parallel_tests` gem when it
|
|
30
|
+
# sees `TEST_ENV_NUMBER` / `PARALLEL_TEST_GROUPS` in the environment.
|
|
31
|
+
# Defaults to auto-detect (nil). See #1018.
|
|
32
|
+
#
|
|
33
|
+
def parallel_tests(value = :__no_arg__)
|
|
34
|
+
return @parallel_tests if value.eql?(:__no_arg__)
|
|
35
|
+
|
|
36
|
+
self.parallel_tests = _ = value
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def parallel_tests=(value)
|
|
40
|
+
@parallel_tests = value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def enable_for_subprocesses(value = nil)
|
|
44
|
+
Deprecation.warn("`SimpleCov.enable_for_subprocesses` is deprecated. " \
|
|
45
|
+
"Replace with `SimpleCov.merge_subprocesses` (same value, same behavior).")
|
|
46
|
+
merge_subprocesses(value)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def merging(use = nil)
|
|
50
|
+
self.merging = use unless use.nil?
|
|
51
|
+
# Unset reads as nil, and only an explicit `merging false` turns it off.
|
|
52
|
+
@use_merging = true if @use_merging.nil?
|
|
53
|
+
@use_merging
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def merging=(use)
|
|
57
|
+
@use_merging = use
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Whether SimpleCov's selected final process owns merge processing: waiting
|
|
62
|
+
# for sibling workers, building the merged result, formatting, enforcing
|
|
63
|
+
# thresholds, and writing `.last_run.json`.
|
|
64
|
+
#
|
|
65
|
+
# Defaults to true, except for recognized multi-worker parallel runs that
|
|
66
|
+
# explicitly write to a custom coverage destination while merging is
|
|
67
|
+
# enabled. Those runs are likely using an external `SimpleCov.collate` step
|
|
68
|
+
# to finalize the merge.
|
|
69
|
+
#
|
|
70
|
+
# Splatted rather than defaulted: false is a value someone sets on purpose,
|
|
71
|
+
# so "given nothing" cannot be told from it by looking at the argument.
|
|
72
|
+
def finalize_merge(*value)
|
|
73
|
+
unless value.empty?
|
|
74
|
+
explicit, = value
|
|
75
|
+
self.finalize_merge = _ = explicit
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return @finalize_merge if @finalize_merge_explicit
|
|
79
|
+
|
|
80
|
+
inferred = inferred_finalize_merge?
|
|
81
|
+
warn_about_inferred_finalize_merge unless inferred
|
|
82
|
+
inferred
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Writing is what makes the answer explicit rather than inferred.
|
|
86
|
+
def finalize_merge=(value)
|
|
87
|
+
@finalize_merge = value
|
|
88
|
+
@finalize_merge_explicit = true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def finalize_merge?
|
|
92
|
+
finalize_merge
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @api private
|
|
96
|
+
def merge_finalization_owner?
|
|
97
|
+
collating_result? || (finalize_merge? && final_result_process?)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def use_merging(use = nil)
|
|
101
|
+
Deprecation.warn("`SimpleCov.use_merging` is deprecated. " \
|
|
102
|
+
"Replace with `SimpleCov.merging` (same value, same behavior).")
|
|
103
|
+
merging(use)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# The maximum age (in seconds) of a resultset to still be included in
|
|
108
|
+
# merged results. Default is 600 seconds.
|
|
109
|
+
#
|
|
110
|
+
# A numeric SIMPLECOV_MERGE_TIMEOUT in the environment takes precedence
|
|
111
|
+
# over the configured value: `simplecov watch` re-runs test subsets across
|
|
112
|
+
# a long session and extends its child runs' merge window this way, where
|
|
113
|
+
# editing every watched project's configuration is not an option.
|
|
114
|
+
#
|
|
115
|
+
def merge_timeout(seconds = nil)
|
|
116
|
+
self.merge_timeout = seconds
|
|
117
|
+
# Memoized through a local rather than `|| (@merge_timeout ||= 600)`:
|
|
118
|
+
# steep 2.0's logic-type interpreter crashes on an or-assignment nested in
|
|
119
|
+
# a logical operand, and ivar narrowing doesn't carry across statements
|
|
120
|
+
# the way a local's does.
|
|
121
|
+
configured = @merge_timeout || 600
|
|
122
|
+
@merge_timeout = configured
|
|
123
|
+
env_merge_timeout || configured
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Anything but an Integer is ignored, the way the dual method always did.
|
|
127
|
+
def merge_timeout=(seconds)
|
|
128
|
+
@merge_timeout = seconds if seconds.instance_of?(Integer)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def env_merge_timeout
|
|
132
|
+
value = ENV.fetch("SIMPLECOV_MERGE_TIMEOUT", nil)
|
|
133
|
+
Integer(value, 10) if value&.match?(/\A\d+\z/)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
#
|
|
137
|
+
# How long (in seconds) the reporting process waits for the remaining
|
|
138
|
+
# parallel-test workers to write their resultsets before it proceeds with a
|
|
139
|
+
# partial merge. Default is 60 seconds. Raise it when a slow worker
|
|
140
|
+
# routinely finishes well after the others, so its coverage is still
|
|
141
|
+
# included and the threshold checks aren't skipped against a partial total.
|
|
142
|
+
#
|
|
143
|
+
def parallel_wait_timeout(seconds = nil)
|
|
144
|
+
self.parallel_wait_timeout = seconds
|
|
145
|
+
@parallel_wait_timeout ||= 60
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Anything but an Integer is ignored, the way the dual method always did.
|
|
149
|
+
def parallel_wait_timeout=(seconds)
|
|
150
|
+
@parallel_wait_timeout = seconds if seconds.instance_of?(Integer)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def inferred_finalize_merge?
|
|
156
|
+
return true unless merging
|
|
157
|
+
|
|
158
|
+
adapter = ParallelAdapters.current
|
|
159
|
+
return true unless adapter
|
|
160
|
+
return true unless adapter.expected_worker_count > 1
|
|
161
|
+
return true unless parallel_worker_environment?
|
|
162
|
+
return true unless explicit_custom_coverage_destination?
|
|
163
|
+
|
|
164
|
+
false
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def parallel_worker_environment?
|
|
168
|
+
ENV.key?("TEST_ENV_NUMBER") || ENV.key?("PARALLEL_TEST_GROUPS")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def explicit_custom_coverage_destination?
|
|
172
|
+
return false unless explicit_coverage_destination?
|
|
173
|
+
|
|
174
|
+
!coverage_path.eql?(File.expand_path("coverage", root))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def explicit_coverage_destination?
|
|
178
|
+
@coverage_path_explicit || @coverage_dir_explicit
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def warn_about_inferred_finalize_merge
|
|
182
|
+
return if @finalize_merge_inference_warned
|
|
183
|
+
return unless print_errors
|
|
184
|
+
|
|
185
|
+
@finalize_merge_inference_warned = true
|
|
186
|
+
warn Color.colorize(inferred_finalize_merge_warning, :yellow)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def inferred_finalize_merge_warning
|
|
190
|
+
"SimpleCov inferred `finalize_merge false` because this parallel worker is merging " \
|
|
191
|
+
"into a custom coverage destination. Set `SimpleCov.finalize_merge false` to keep " \
|
|
192
|
+
"external collation ownership, or `SimpleCov.finalize_merge true` if this worker " \
|
|
193
|
+
"should wait, merge, format, enforce thresholds, and write `.last_run.json`. " \
|
|
194
|
+
"See https://github.com/simplecov-ruby/simplecov#merge-finalization-ownership."
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
# Caps the total number of misses per criterion. Where a percent minimum
|
|
6
|
+
# asks for a ratio, this asks for an absolute burn-down number, which stays
|
|
7
|
+
# meaningful as the codebase grows and shrinks.
|
|
8
|
+
def maximum_missed(counts = nil)
|
|
9
|
+
return @maximum_missed ||= {} unless counts
|
|
10
|
+
|
|
11
|
+
@maximum_missed = normalized_missed_caps(counts, "maximum_missed")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Unlike a percent minimum, which systematically flatters big files, this
|
|
15
|
+
# holds every file to the same absolute budget. Files with a baseline entry
|
|
16
|
+
# are exempt per covered criterion, as they are from the per-file minimum.
|
|
17
|
+
def maximum_missed_per_file(counts = nil)
|
|
18
|
+
return @maximum_missed_per_file ||= {} unless counts
|
|
19
|
+
|
|
20
|
+
Deprecation.warn("`SimpleCov.maximum_missed_per_file` is deprecated. " \
|
|
21
|
+
"Replace it with:\n#{missed_per_file_replacement(counts)}")
|
|
22
|
+
@maximum_missed_per_file = normalized_missed_caps(counts, "maximum_missed_per_file")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def maximum_missed_per_file_overrides
|
|
26
|
+
@maximum_missed_per_file_overrides ||= {}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def normalized_missed_caps(counts, setting)
|
|
32
|
+
counts = {primary_coverage => counts} if counts.is_a?(Numeric)
|
|
33
|
+
counts.each_key { |criterion| raise_if_criterion_disabled(criterion) }
|
|
34
|
+
counts.each_value { |cap| raise_on_invalid_missed_cap(cap, setting) }
|
|
35
|
+
_ = counts
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def raise_on_invalid_missed_cap(cap, setting)
|
|
39
|
+
return if cap.instance_of?(Integer) && cap >= 0
|
|
40
|
+
|
|
41
|
+
raise ConfigurationError,
|
|
42
|
+
"#{setting} takes a non-negative integer count of misses, got #{cap.inspect}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def missed_per_file_replacement(counts)
|
|
46
|
+
counts = {primary_coverage => counts} if counts.is_a?(Numeric)
|
|
47
|
+
counts.map { |criterion, cap| " coverage(#{criterion.inspect}) { maximum_missed #{cap}, per: :file }" }
|
|
48
|
+
.join("\n")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
# The path to a production coverage store, the file a `SimpleCov::Production`
|
|
6
|
+
# sink wrote. Relative paths resolve against `SimpleCov.root`. The store is
|
|
7
|
+
# read at report time, and an unreadable or invalid file warns and leaves the
|
|
8
|
+
# section out, because a missing night's data should not fail the suite that
|
|
9
|
+
# measured the tests.
|
|
10
|
+
def production_coverage(path = nil)
|
|
11
|
+
return @production_coverage if path.nil?
|
|
12
|
+
|
|
13
|
+
self.production_coverage = path
|
|
14
|
+
@production_coverage
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def production_coverage=(path)
|
|
18
|
+
raise ConfigurationError, "production_coverage takes a path, got #{path.inspect}" unless path.is_a?(String)
|
|
19
|
+
|
|
20
|
+
@production_coverage = File.expand_path(path, root)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|