simplecov 1.1.1 → 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/README.md +148 -5
- data/exe/simplecov +0 -3
- data/lib/minitest/simplecov_plugin.rb +12 -9
- data/lib/simplecov/atomic_file.rb +16 -19
- data/lib/simplecov/autostart.rb +5 -7
- 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 +23 -24
- data/lib/simplecov/cli/command_helpers.rb +55 -19
- data/lib/simplecov/cli/completions/scripts.rb +114 -0
- data/lib/simplecov/cli/completions.rb +83 -0
- data/lib/simplecov/cli/coverage.rb +25 -28
- data/lib/simplecov/cli/coverage_file.rb +58 -14
- 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 +35 -67
- data/lib/simplecov/cli/dotfile.rb +83 -38
- 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 +34 -39
- data/lib/simplecov/cli/open.rb +12 -15
- 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 +18 -24
- data/lib/simplecov/cli/run.rb +8 -9
- data/lib/simplecov/cli/serve/report_preparer.rb +7 -6
- data/lib/simplecov/cli/serve/static_file_handler.rb +62 -56
- data/lib/simplecov/cli/serve.rb +27 -24
- 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 +58 -34
- 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 +43 -92
- data/lib/simplecov/color.rb +19 -37
- data/lib/simplecov/combine/branches_combiner.rb +7 -31
- data/lib/simplecov/combine/coverage_accumulator.rb +49 -142
- data/lib/simplecov/combine/identity_interner.rb +10 -13
- data/lib/simplecov/combine/interned_counts.rb +7 -9
- data/lib/simplecov/combine/lines_combiner.rb +20 -44
- data/lib/simplecov/combine/methods_combiner.rb +9 -35
- data/lib/simplecov/combine/results_combiner.rb +4 -21
- data/lib/simplecov/combine.rb +0 -6
- data/lib/simplecov/command_guesser.rb +20 -34
- data/lib/simplecov/configuration/baseline.rb +31 -0
- data/lib/simplecov/configuration/coverage.rb +91 -79
- data/lib/simplecov/configuration/coverage_criteria.rb +43 -54
- data/lib/simplecov/configuration/deprecations.rb +21 -0
- data/lib/simplecov/configuration/eval_coverage.rb +7 -11
- data/lib/simplecov/configuration/filters.rb +40 -73
- data/lib/simplecov/configuration/formatting.rb +74 -83
- data/lib/simplecov/configuration/groups.rb +19 -13
- data/lib/simplecov/configuration/history.rb +44 -0
- data/lib/simplecov/configuration/ignored_entries.rb +31 -22
- data/lib/simplecov/configuration/merging.rb +94 -62
- 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 +33 -62
- data/lib/simplecov/configuration/view_coverage.rb +37 -0
- data/lib/simplecov/configuration.rb +70 -76
- 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 +2 -5
- data/lib/simplecov/coverage_statistics.rb +14 -24
- data/lib/simplecov/coverage_violations.rb +160 -65
- data/lib/simplecov/current_run.rb +61 -0
- data/lib/simplecov/defaults.rb +4 -23
- data/lib/simplecov/deprecation.rb +45 -27
- 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 +47 -62
- data/lib/simplecov/exit_codes/baseline_check.rb +46 -0
- data/lib/simplecov/exit_codes/check.rb +17 -11
- data/lib/simplecov/exit_codes/exit_code_handling.rb +21 -8
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +7 -10
- 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 +7 -12
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +11 -10
- data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +7 -9
- data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +16 -17
- data/lib/simplecov/exit_codes.rb +16 -10
- data/lib/simplecov/exit_handling.rb +94 -59
- data/lib/simplecov/file_list.rb +20 -51
- data/lib/simplecov/filter.rb +43 -66
- data/lib/simplecov/formatter/base.rb +37 -55
- data/lib/simplecov/formatter/baseline_formatter.rb +98 -0
- data/lib/simplecov/formatter/coverage_json_writer.rb +29 -31
- data/lib/simplecov/formatter/html_formatter/public/index.html +15 -9
- data/lib/simplecov/formatter/html_formatter/viewer_data_validator.rb +74 -17
- data/lib/simplecov/formatter/html_formatter.rb +24 -41
- data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +50 -16
- data/lib/simplecov/formatter/json_formatter/production_section_formatter.rb +48 -0
- data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +43 -29
- data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +14 -10
- data/lib/simplecov/formatter/json_formatter.rb +7 -13
- data/lib/simplecov/formatter/multi_formatter.rb +5 -11
- data/lib/simplecov/formatter/simple_formatter.rb +2 -8
- data/lib/simplecov/formatter.rb +14 -10
- data/lib/simplecov/group_names.rb +13 -12
- data/lib/simplecov/history.rb +115 -0
- data/lib/simplecov/last_run.rb +6 -9
- data/lib/simplecov/lines_classifier.rb +31 -16
- data/lib/simplecov/load_global_config.rb +7 -7
- data/lib/simplecov/parallel_adapters/base.rb +13 -41
- data/lib/simplecov/parallel_adapters/generic.rb +7 -19
- data/lib/simplecov/parallel_adapters/parallel_tests.rb +21 -42
- data/lib/simplecov/parallel_adapters.rb +24 -55
- data/lib/simplecov/parallel_coordination.rb +39 -49
- data/lib/simplecov/parallel_result_merger/worker_payload.rb +33 -0
- data/lib/simplecov/parallel_result_merger.rb +67 -126
- data/lib/simplecov/process.rb +14 -32
- 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/rails.rb +4 -15
- data/lib/simplecov/profiles/root_filter.rb +0 -4
- data/lib/simplecov/profiles/strict.rb +11 -21
- data/lib/simplecov/profiles.rb +11 -33
- data/lib/simplecov/report_deferral.rb +11 -15
- data/lib/simplecov/report_stamp.rb +6 -9
- data/lib/simplecov/result/filter_config.rb +19 -0
- data/lib/simplecov/result/missing_source_files_reporter.rb +8 -9
- data/lib/simplecov/result/serialization.rb +43 -0
- data/lib/simplecov/result/source_file_builder.rb +7 -12
- data/lib/simplecov/result.rb +74 -117
- data/lib/simplecov/result_adapter.rb +56 -68
- data/lib/simplecov/result_merger/contexts.rb +22 -0
- data/lib/simplecov/result_merger/legacy_format_adapter.rb +4 -8
- data/lib/simplecov/result_merger/resultset_file.rb +20 -27
- data/lib/simplecov/result_merger/resultset_run_identity.rb +23 -25
- data/lib/simplecov/result_merger/resultset_store.rb +23 -14
- data/lib/simplecov/result_merger/unloaded_files.rb +24 -32
- data/lib/simplecov/result_merger.rb +59 -58
- data/lib/simplecov/result_processing.rb +92 -122
- data/lib/simplecov/run_identity.rb +16 -18
- data/lib/simplecov/simulate_coverage.rb +34 -50
- data/lib/simplecov/source_file/branch.rb +8 -33
- data/lib/simplecov/source_file/branch_builder.rb +28 -47
- data/lib/simplecov/source_file/builder_context.rb +13 -13
- data/lib/simplecov/source_file/line.rb +13 -33
- data/lib/simplecov/source_file/line_builder.rb +9 -15
- data/lib/simplecov/source_file/method.rb +3 -7
- data/lib/simplecov/source_file/method_builder.rb +6 -15
- data/lib/simplecov/source_file/ruby_data_parser.rb +59 -66
- data/lib/simplecov/source_file/skip_chunks.rb +29 -29
- data/lib/simplecov/source_file/source_loader.rb +45 -35
- data/lib/simplecov/source_file/statistics.rb +20 -9
- data/lib/simplecov/source_file.rb +21 -51
- data/lib/simplecov/static_coverage_extractor/condition_folding.rb +55 -139
- data/lib/simplecov/static_coverage_extractor/location_conventions.rb +76 -121
- data/lib/simplecov/static_coverage_extractor/method_collector.rb +9 -26
- data/lib/simplecov/static_coverage_extractor/prism_compat.rb +15 -24
- data/lib/simplecov/static_coverage_extractor/value_position.rb +25 -38
- data/lib/simplecov/static_coverage_extractor/visitor.rb +45 -65
- data/lib/simplecov/static_coverage_extractor.rb +43 -75
- 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 +18 -31
- data/lib/simplecov/useless_results_remover.rb +7 -6
- 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 +1 -0
- data/lib/simplecov.rb +57 -113
- data/lib/simplecov_json_formatter.rb +1 -0
- data/man/simplecov.1 +354 -0
- data/sig/simplecov.rbs +528 -595
- metadata +79 -6
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
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
4
|
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
5
|
def minimum_coverage(coverage = nil)
|
|
15
6
|
return @minimum_coverage ||= {} unless coverage
|
|
16
7
|
|
|
@@ -25,10 +16,10 @@ module SimpleCov
|
|
|
25
16
|
end
|
|
26
17
|
|
|
27
18
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
19
|
+
# The maximum overall coverage allowed for the testsuite to pass. Useful
|
|
20
|
+
# paired with `minimum_coverage` (or via `expected_coverage`) to pin
|
|
21
|
+
# coverage to an exact value, so an unexpected jump up fails the build
|
|
22
|
+
# (#187).
|
|
32
23
|
#
|
|
33
24
|
def maximum_coverage(coverage = nil)
|
|
34
25
|
return @maximum_coverage ||= {} unless coverage
|
|
@@ -36,10 +27,6 @@ module SimpleCov
|
|
|
36
27
|
@maximum_coverage = normalized_threshold(coverage, "maximum_coverage")
|
|
37
28
|
end
|
|
38
29
|
|
|
39
|
-
#
|
|
40
|
-
# Pins the suite to an exact coverage figure by setting both
|
|
41
|
-
# `minimum_coverage` and `maximum_coverage`. See #187.
|
|
42
|
-
#
|
|
43
30
|
def expected_coverage(coverage = nil)
|
|
44
31
|
return minimum_coverage if coverage.nil?
|
|
45
32
|
|
|
@@ -47,10 +34,6 @@ module SimpleCov
|
|
|
47
34
|
maximum_coverage(coverage)
|
|
48
35
|
end
|
|
49
36
|
|
|
50
|
-
#
|
|
51
|
-
# Defines the maximum coverage drop at once allowed for the
|
|
52
|
-
# testsuite to pass. Default is 100% (disabled).
|
|
53
|
-
#
|
|
54
37
|
def maximum_coverage_drop(coverage_drop = nil)
|
|
55
38
|
return @maximum_coverage_drop ||= {} unless coverage_drop
|
|
56
39
|
|
|
@@ -58,11 +41,10 @@ module SimpleCov
|
|
|
58
41
|
end
|
|
59
42
|
|
|
60
43
|
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# per-path overrides. See README and #575.
|
|
44
|
+
# The minimum coverage per file required for the testsuite to pass.
|
|
45
|
+
# Accepts a Numeric (global threshold on the primary criterion), a
|
|
46
|
+
# Symbol-keyed Hash (per-criterion globals), or a Hash mixing Symbol keys
|
|
47
|
+
# with String / Regexp keys to declare per-path overrides (#575).
|
|
66
48
|
#
|
|
67
49
|
def minimum_coverage_by_file(coverage = nil)
|
|
68
50
|
return @minimum_coverage_by_file ||= {} unless coverage
|
|
@@ -70,8 +52,8 @@ module SimpleCov
|
|
|
70
52
|
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
|
71
53
|
defaults, overrides = partition_per_file_thresholds(coverage)
|
|
72
54
|
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
Deprecation.warn("`SimpleCov.minimum_coverage_by_file` is deprecated. " \
|
|
56
|
+
"Replace it with:\n#{per_file_coverage_replacement(defaults, overrides)}")
|
|
75
57
|
|
|
76
58
|
raise_on_invalid_coverage(defaults, "minimum_coverage_by_file")
|
|
77
59
|
overrides.each_value { |criteria| raise_on_invalid_coverage(criteria, "minimum_coverage_by_file") }
|
|
@@ -80,91 +62,80 @@ module SimpleCov
|
|
|
80
62
|
@minimum_coverage_by_file_overrides = overrides
|
|
81
63
|
end
|
|
82
64
|
|
|
83
|
-
# Returns the per-path overrides set via `minimum_coverage_by_file`.
|
|
84
65
|
def minimum_coverage_by_file_overrides
|
|
85
66
|
@minimum_coverage_by_file_overrides ||= {}
|
|
86
67
|
end
|
|
87
68
|
|
|
88
|
-
#
|
|
89
|
-
# Defines the minimum coverage per group required for the testsuite
|
|
90
|
-
# to pass. Default is 0% (disabled).
|
|
91
|
-
#
|
|
92
69
|
def minimum_coverage_by_group(coverage = nil)
|
|
93
70
|
return @minimum_coverage_by_group ||= {} unless coverage
|
|
94
71
|
|
|
95
|
-
|
|
96
|
-
|
|
72
|
+
Deprecation.warn("`SimpleCov.minimum_coverage_by_group` is deprecated. " \
|
|
73
|
+
"Replace it with:\n#{per_group_coverage_replacement(coverage)}")
|
|
97
74
|
@minimum_coverage_by_group = coverage.to_h do |group_name, group_coverage|
|
|
98
75
|
[GroupNames.normalize(group_name), normalized_threshold(group_coverage, "minimum_coverage_by_group")]
|
|
99
76
|
end
|
|
100
77
|
end
|
|
101
78
|
|
|
102
|
-
#
|
|
103
|
-
# Refuses any coverage drop. Coverage is only allowed to increase.
|
|
104
|
-
#
|
|
105
79
|
def refuse_coverage_drop(*criteria)
|
|
106
80
|
criteria = coverage_criteria if criteria.empty?
|
|
107
81
|
maximum_coverage_drop(criteria.to_h { |c| [c, 0] })
|
|
108
82
|
end
|
|
109
83
|
|
|
110
|
-
|
|
84
|
+
private
|
|
111
85
|
|
|
112
|
-
#
|
|
113
|
-
# a bare Numeric targets the primary criterion, and the resulting
|
|
86
|
+
# A bare Numeric targets the primary criterion, and the resulting
|
|
114
87
|
# per-criterion hash is validated before it is stored.
|
|
115
88
|
def normalized_threshold(coverage, setting)
|
|
116
89
|
coverage = {primary_coverage => coverage} if coverage.is_a?(Numeric)
|
|
117
|
-
raise_on_invalid_coverage(
|
|
118
|
-
coverage
|
|
90
|
+
coverage.tap { |thresholds| raise_on_invalid_coverage(thresholds, setting) }
|
|
119
91
|
end
|
|
120
92
|
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
# so downstream code only has one shape to handle.
|
|
93
|
+
# Splits into Symbol-keyed criterion defaults and String/Regexp-keyed
|
|
94
|
+
# per-path overrides, normalizing Numeric override values to
|
|
95
|
+
# `{primary_coverage => N}` so downstream code has one shape to handle.
|
|
125
96
|
def partition_per_file_thresholds(coverage)
|
|
126
97
|
coverage.each_key { |key| validate_per_file_key(key) }
|
|
127
|
-
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
defaults =
|
|
131
|
-
raw =
|
|
98
|
+
# The assertions restate what the partition predicate guarantees: Symbol
|
|
99
|
+
# keys carry per-criterion Numeric defaults, the rest are paths.
|
|
100
|
+
symbol_pairs, path_pairs = coverage.partition { |key, _| key.instance_of?(Symbol) }
|
|
101
|
+
defaults = symbol_pairs.to_h #: coverage_thresholds
|
|
102
|
+
raw = path_pairs.to_h #: Hash[String | Regexp, Numeric | coverage_thresholds]
|
|
132
103
|
overrides = raw.transform_values { |value| value.is_a?(Numeric) ? {primary_coverage => value} : value }
|
|
133
104
|
[defaults, overrides]
|
|
134
105
|
end
|
|
135
106
|
|
|
136
107
|
def validate_per_file_key(key)
|
|
137
|
-
|
|
108
|
+
# Symbols have no subclasses; paths and patterns may.
|
|
109
|
+
return if key.instance_of?(Symbol) || key.is_a?(String) || key.is_a?(Regexp)
|
|
138
110
|
|
|
139
|
-
raise
|
|
140
|
-
|
|
111
|
+
raise ConfigurationError,
|
|
112
|
+
"minimum_coverage_by_file keys must be Symbol (criterion), String, or Regexp; got #{key.inspect}"
|
|
141
113
|
end
|
|
142
114
|
|
|
143
115
|
def minimum_possible_coverage_exceeded(coverage_option)
|
|
144
116
|
warn "The coverage you set for #{coverage_option} is greater than 100%"
|
|
145
117
|
end
|
|
146
118
|
|
|
147
|
-
#
|
|
148
|
-
# `minimum_coverage_by_file` argument so the deprecation warning can be
|
|
119
|
+
# Renders the `coverage` configuration equivalent to a deprecated
|
|
120
|
+
# `minimum_coverage_by_file` argument, so the deprecation warning can be
|
|
149
121
|
# copy-pasted verbatim into the user's config.
|
|
150
122
|
def per_file_coverage_replacement(defaults, overrides)
|
|
151
123
|
by_criterion = {} #: Hash[Symbol, Array[String]]
|
|
152
|
-
defaults.each { |criterion, percent| (by_criterion[criterion] ||= []) << "
|
|
124
|
+
defaults.each { |criterion, percent| (by_criterion[criterion] ||= []) << "minimum #{percent}, per: :file" }
|
|
153
125
|
overrides.each do |target, criteria|
|
|
154
126
|
criteria.each do |criterion, percent|
|
|
155
|
-
(by_criterion[criterion] ||= []) << "
|
|
127
|
+
(by_criterion[criterion] ||= []) << "minimum #{percent}, per: #{target.inspect}"
|
|
156
128
|
end
|
|
157
129
|
end
|
|
158
130
|
render_coverage_blocks(by_criterion)
|
|
159
131
|
end
|
|
160
132
|
|
|
161
|
-
# Same, for a (deprecated) `minimum_coverage_by_group` argument.
|
|
162
133
|
def per_group_coverage_replacement(coverage)
|
|
163
134
|
by_criterion = {} #: Hash[Symbol, Array[String]]
|
|
164
135
|
coverage.each do |group_name, thresholds|
|
|
165
136
|
normalized = (thresholds.is_a?(Numeric) ? {primary_coverage => thresholds} : thresholds) #: coverage_thresholds
|
|
166
137
|
normalized.each do |criterion, percent|
|
|
167
|
-
(by_criterion[criterion] ||= []) << "
|
|
138
|
+
(by_criterion[criterion] ||= []) << "minimum #{percent}, per: group(#{group_name.inspect})"
|
|
168
139
|
end
|
|
169
140
|
end
|
|
170
141
|
render_coverage_blocks(by_criterion)
|
|
@@ -172,7 +143,7 @@ module SimpleCov
|
|
|
172
143
|
|
|
173
144
|
def render_coverage_blocks(by_criterion)
|
|
174
145
|
by_criterion.map do |criterion, statements|
|
|
175
|
-
" coverage(#{criterion.inspect}) { #{statements.join(
|
|
146
|
+
" coverage(#{criterion.inspect}) { #{statements.join("; ")} }"
|
|
176
147
|
end.join("\n")
|
|
177
148
|
end
|
|
178
149
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
module Configuration
|
|
5
|
+
DEFAULT_VIEW_GLOBS = %w[app/views/**/*.{erb,haml,slim}].freeze
|
|
6
|
+
|
|
7
|
+
# Reports coverage for ActionView templates, defaulting to a Rails app's
|
|
8
|
+
# views. Globs are expanded against `SimpleCov.root`, and one naming an
|
|
9
|
+
# extension no handler is registered for (as the default does whenever a
|
|
10
|
+
# project has no Haml or Slim) leaves those files out rather than reporting
|
|
11
|
+
# them as empty.
|
|
12
|
+
#
|
|
13
|
+
# Templates the suite renders are measured through eval coverage, which this
|
|
14
|
+
# enables. Templates it never renders are compiled at the end of the run so
|
|
15
|
+
# they appear at 0% instead of going missing.
|
|
16
|
+
def cover_views(*globs)
|
|
17
|
+
globs = globs.flatten.compact
|
|
18
|
+
globs = DEFAULT_VIEW_GLOBS.dup if globs.empty?
|
|
19
|
+
@view_globs = globs
|
|
20
|
+
enable_eval_coverage
|
|
21
|
+
globs
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Nil rather than an empty Array when `cover_views` was never called, so
|
|
25
|
+
# "not asked for" stays distinguishable from "asked for, with nothing to
|
|
26
|
+
# match".
|
|
27
|
+
def view_globs
|
|
28
|
+
@view_globs
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# False when eval coverage couldn't be enabled, where `cover_views` has
|
|
32
|
+
# already warned and the templates would come back empty rather than at 0%.
|
|
33
|
+
def view_coverage?
|
|
34
|
+
!view_globs.nil? && coverage_for_eval_enabled?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -3,82 +3,81 @@
|
|
|
3
3
|
require "fileutils"
|
|
4
4
|
|
|
5
5
|
module SimpleCov
|
|
6
|
-
#
|
|
7
|
-
# Bundles the configuration options used for SimpleCov. All methods
|
|
8
|
-
# defined here are usable from SimpleCov directly. Please check out
|
|
9
|
-
# SimpleCov documentation for further info.
|
|
10
|
-
#
|
|
11
6
|
module Configuration
|
|
12
|
-
#
|
|
13
|
-
# The root for the project. This defaults to the
|
|
14
|
-
# current working directory.
|
|
15
|
-
#
|
|
16
|
-
# Configure with SimpleCov.root('/my/project/path')
|
|
17
|
-
#
|
|
18
7
|
def root(root = nil)
|
|
19
|
-
return @root if
|
|
8
|
+
return @root if instance_variable_defined?(:@root) && root.nil?
|
|
20
9
|
|
|
10
|
+
self.root = root
|
|
11
|
+
@root
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# nil means the working directory, the default the reader would have derived.
|
|
15
|
+
def root=(root)
|
|
21
16
|
@coverage_path = nil unless @coverage_path_explicit # invalidate cache
|
|
22
17
|
@root = File.expand_path(root || Dir.getwd)
|
|
23
18
|
end
|
|
24
19
|
|
|
25
|
-
#
|
|
26
|
-
# The name of the output and cache directory. Defaults to 'coverage'
|
|
27
|
-
#
|
|
28
|
-
# Configure with SimpleCov.coverage_dir('cov')
|
|
29
|
-
#
|
|
30
20
|
def coverage_dir(dir = nil)
|
|
31
|
-
return @coverage_dir if
|
|
21
|
+
return @coverage_dir if instance_variable_defined?(:@coverage_dir) && dir.nil?
|
|
22
|
+
|
|
23
|
+
self.coverage_dir = dir
|
|
24
|
+
@coverage_dir
|
|
25
|
+
end
|
|
32
26
|
|
|
27
|
+
# nil means the default 'coverage', recorded as a derivation rather than a
|
|
28
|
+
# choice.
|
|
29
|
+
def coverage_dir=(dir)
|
|
33
30
|
@coverage_path = nil unless @coverage_path_explicit # invalidate cache
|
|
34
31
|
@coverage_dir_explicit = true unless dir.nil?
|
|
35
32
|
@coverage_dir = dir || "coverage"
|
|
36
33
|
end
|
|
37
34
|
|
|
38
35
|
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
# out-of-tree build directories. See #716.
|
|
36
|
+
# Defaults to `SimpleCov.root` + `SimpleCov.coverage_dir`, but callers can
|
|
37
|
+
# override with an arbitrary absolute path, handy for out-of-tree build
|
|
38
|
+
# directories (#716).
|
|
43
39
|
#
|
|
44
|
-
# Reading is pure: the directory is only created when a path is
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# themselves, so read-only CLI subcommands that interpolate the
|
|
49
|
-
# path into status text don't materialize a stray `coverage/`
|
|
50
|
-
# directory.
|
|
40
|
+
# Reading is pure: the directory is only created when a path is explicitly
|
|
41
|
+
# assigned. The codepaths that write into it ensure existence themselves,
|
|
42
|
+
# so read-only CLI subcommands that interpolate the path into status text
|
|
43
|
+
# don't materialize a stray `coverage/` directory.
|
|
51
44
|
#
|
|
52
45
|
def coverage_path(path = nil)
|
|
53
|
-
if path
|
|
54
|
-
expanded = File.expand_path(path)
|
|
55
|
-
@coverage_path = expanded
|
|
56
|
-
@coverage_path_explicit = true
|
|
57
|
-
FileUtils.mkdir_p expanded
|
|
58
|
-
end
|
|
46
|
+
self.coverage_path = path if path
|
|
59
47
|
|
|
60
48
|
@coverage_path ||= File.expand_path(coverage_dir, root)
|
|
61
49
|
end
|
|
62
50
|
|
|
51
|
+
# Assigning is the signal the caller intends to write there, so the
|
|
52
|
+
# directory is created.
|
|
53
|
+
def coverage_path=(path)
|
|
54
|
+
expanded = File.expand_path(path)
|
|
55
|
+
@coverage_path = expanded
|
|
56
|
+
@coverage_path_explicit = true
|
|
57
|
+
FileUtils.mkdir_p expanded
|
|
58
|
+
end
|
|
59
|
+
|
|
63
60
|
#
|
|
64
|
-
# The name of the command (a.k.a. Test Suite) currently running.
|
|
65
|
-
#
|
|
66
|
-
# with SimpleCov.command_name("test:units").
|
|
61
|
+
# The name of the command (a.k.a. Test Suite) currently running. Used for
|
|
62
|
+
# result merging and caching. Auto-detected.
|
|
67
63
|
#
|
|
68
64
|
def command_name(name = nil)
|
|
69
|
-
|
|
70
|
-
@command_name ||=
|
|
65
|
+
self.command_name = name unless name.nil?
|
|
66
|
+
@command_name ||= CommandGuesser.guess
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def command_name=(name)
|
|
70
|
+
@command_name = name
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
# Returns the hash of available profiles
|
|
74
73
|
def profiles
|
|
75
|
-
@profiles ||=
|
|
74
|
+
@profiles ||= Profiles.new
|
|
76
75
|
end
|
|
77
76
|
|
|
78
77
|
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
78
|
+
# Configure simplecov in a block instead of prepending SimpleCov to each
|
|
79
|
+
# config method. Parameterized blocks retain their caller context and
|
|
80
|
+
# receive this configuration target explicitly.
|
|
82
81
|
#
|
|
83
82
|
def configure(&block)
|
|
84
83
|
raise ArgumentError, "configuration block required" unless block
|
|
@@ -91,61 +90,49 @@ module SimpleCov
|
|
|
91
90
|
self
|
|
92
91
|
end
|
|
93
92
|
|
|
94
|
-
#
|
|
95
|
-
# Gets or sets the behavior to process coverage results.
|
|
96
|
-
# By default, it stores/merges the current result and formats only
|
|
97
|
-
# from the final reporting process.
|
|
98
|
-
#
|
|
99
93
|
def at_exit(&block)
|
|
100
94
|
@at_exit = block if block
|
|
101
95
|
configured = @at_exit
|
|
102
96
|
return configured if configured
|
|
103
|
-
return
|
|
97
|
+
return -> {} unless active_session?
|
|
104
98
|
|
|
105
|
-
@at_exit =
|
|
99
|
+
@at_exit = lambda do
|
|
106
100
|
result = SimpleCov.result
|
|
107
101
|
result.format! if result && SimpleCov.merge_finalization_owner?
|
|
108
102
|
end
|
|
109
103
|
end
|
|
110
104
|
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
# (e.g. by `SimpleCov.collate`, which never starts Coverage).
|
|
105
|
+
# The Coverage module is actively tracking, or a `@result` has already been
|
|
106
|
+
# assembled (`SimpleCov.collate` never starts Coverage).
|
|
114
107
|
def active_session?
|
|
115
|
-
SimpleCov.result? ||
|
|
108
|
+
!!SimpleCov.result? || coverage_running?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# A configuration loaded on its own may have no Coverage to ask, which is
|
|
112
|
+
# not something a suite that measures coverage can be.
|
|
113
|
+
def coverage_running?
|
|
114
|
+
defined?(Coverage) ? Coverage.running? : false
|
|
116
115
|
end
|
|
117
116
|
|
|
118
|
-
#
|
|
119
|
-
# Gets or sets the behavior to start a new forked Process.
|
|
120
|
-
# Defaults to adding " (subprocess: #{serial})" to command_name and
|
|
121
|
-
# starting SimpleCov in quiet mode.
|
|
122
|
-
#
|
|
123
117
|
def at_fork(&block)
|
|
124
118
|
@at_fork = block if block
|
|
125
119
|
@at_fork ||= lambda { |_pid|
|
|
126
|
-
# Needs a name that's unique per worker within a run yet identical
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
#
|
|
120
|
+
# Needs a name that's unique per worker within a run yet identical across
|
|
121
|
+
# runs. Built from SimpleCov's stable fork serial rather than the OS pid:
|
|
122
|
+
# with the pid, every run produced uniquely-named results that never
|
|
123
|
+
# overwrote the previous run's, so they piled up in .resultset.json
|
|
124
|
+
# until merge_timeout and the merged report's file set drifted from run
|
|
125
|
+
# to run (#1171).
|
|
132
126
|
SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{SimpleCov.subprocess_serial})"
|
|
133
|
-
# be quiet, the parent process will use the regular formatter
|
|
134
127
|
SimpleCov.print_errors false
|
|
135
|
-
SimpleCov.formatter
|
|
128
|
+
SimpleCov.formatter Formatter::SimpleFormatter
|
|
136
129
|
SimpleCov.minimum_coverage 0
|
|
137
130
|
SimpleCov.start
|
|
138
131
|
}
|
|
139
132
|
end
|
|
140
133
|
|
|
141
|
-
#
|
|
142
|
-
# Returns the project name — defaults to the last dirname in
|
|
143
|
-
# SimpleCov.root, capitalized with underscores → spaces.
|
|
144
|
-
#
|
|
134
|
+
# Only a String renames, and a name already chosen survives anything else.
|
|
145
135
|
def project_name(new_name = nil)
|
|
146
|
-
current = defined?(@project_name) ? @project_name : nil
|
|
147
|
-
return current if current && new_name.nil?
|
|
148
|
-
|
|
149
136
|
@project_name = new_name if new_name.is_a?(String)
|
|
150
137
|
@project_name ||= File.basename(root).capitalize.tr("_", " ")
|
|
151
138
|
end
|
|
@@ -160,4 +147,11 @@ require_relative "configuration/groups"
|
|
|
160
147
|
require_relative "configuration/formatting"
|
|
161
148
|
require_relative "configuration/ignored_entries"
|
|
162
149
|
require_relative "configuration/merging"
|
|
150
|
+
require_relative "configuration/test_tracking"
|
|
163
151
|
require_relative "configuration/thresholds"
|
|
152
|
+
require_relative "configuration/baseline"
|
|
153
|
+
require_relative "configuration/deprecations"
|
|
154
|
+
require_relative "configuration/history"
|
|
155
|
+
require_relative "configuration/missed_caps"
|
|
156
|
+
require_relative "configuration/production"
|
|
157
|
+
require_relative "configuration/view_coverage"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
class ContextMap
|
|
5
|
+
# Accumulates the context maps of every result a merge absorbs, under the
|
|
6
|
+
# all-or-nothing rule the resultset format needs: the merged result carries
|
|
7
|
+
# the union of the maps when every merged result recorded one, and no map at
|
|
8
|
+
# all otherwise. Keeping a partial union would present one worker's map as
|
|
9
|
+
# the whole run's, silently omitting the tests of the results that didn't
|
|
10
|
+
# record.
|
|
11
|
+
class Union
|
|
12
|
+
attr_reader :carrying, :entries
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@map = ContextMap.new
|
|
16
|
+
@complete = true
|
|
17
|
+
@carrying = 0
|
|
18
|
+
@entries = 0
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def collector
|
|
22
|
+
->(surviving) { absorb_resultset(surviving) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def absorb_resultset(resultset)
|
|
26
|
+
resultset.each_value { |data| absorb_entry(data) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def absorb_entry(data)
|
|
30
|
+
@entries += 1
|
|
31
|
+
map = ContextMap.from_hash(data["contexts"])
|
|
32
|
+
return @complete = false unless map
|
|
33
|
+
|
|
34
|
+
@carrying += 1
|
|
35
|
+
@map.absorb(map)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The parallel merge builds one union per worker over its slice and ships it
|
|
39
|
+
# back, so the parent combines unions rather than re-reading entries.
|
|
40
|
+
def absorb_union(other)
|
|
41
|
+
@entries += other.entries
|
|
42
|
+
@carrying += other.carrying
|
|
43
|
+
@complete &&= other.complete?
|
|
44
|
+
@map.absorb(other.partial_map)
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def complete?
|
|
49
|
+
@complete
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The union when every absorbed result carried a map, nil otherwise. Dropping
|
|
53
|
+
# warns when the merge mixed results with and without maps, since that
|
|
54
|
+
# usually means `track_tests` is on in some workers and not others; a merge
|
|
55
|
+
# where nothing recorded stays quiet.
|
|
56
|
+
def map
|
|
57
|
+
return @map if @complete
|
|
58
|
+
|
|
59
|
+
warn_about_partial_maps
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
protected
|
|
63
|
+
|
|
64
|
+
# Protected: only another union folding this one in may read it.
|
|
65
|
+
def partial_map
|
|
66
|
+
@map
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def warn_about_partial_maps
|
|
72
|
+
return unless @carrying.positive? && SimpleCov.print_errors
|
|
73
|
+
|
|
74
|
+
warn "[SimpleCov]: Dropped the per-test map from the merged result: " \
|
|
75
|
+
"only #{@carrying} of #{@entries} merged results carry one. The map is " \
|
|
76
|
+
"kept only when every merged result records it, so enable `track_tests` " \
|
|
77
|
+
"in every suite that should contribute."
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|