ultra-pro-pkg 0.0.1
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 +7 -0
- data/simplecov-1.0.0/LICENSE +20 -0
- data/simplecov-1.0.0/README.md +1524 -0
- data/simplecov-1.0.0/doc/alternate-formatters.md +66 -0
- data/simplecov-1.0.0/doc/commercial-services.md +25 -0
- data/simplecov-1.0.0/doc/editor-integration.md +18 -0
- data/simplecov-1.0.0/exe/simplecov +11 -0
- data/simplecov-1.0.0/lib/minitest/simplecov_plugin.rb +171 -0
- data/simplecov-1.0.0/lib/simplecov/autostart.rb +11 -0
- data/simplecov-1.0.0/lib/simplecov/cli/clean.rb +47 -0
- data/simplecov-1.0.0/lib/simplecov/cli/coverage.rb +91 -0
- data/simplecov-1.0.0/lib/simplecov/cli/diff.rb +151 -0
- data/simplecov-1.0.0/lib/simplecov/cli/dotfile.rb +100 -0
- data/simplecov-1.0.0/lib/simplecov/cli/merge.rb +116 -0
- data/simplecov-1.0.0/lib/simplecov/cli/open.rb +50 -0
- data/simplecov-1.0.0/lib/simplecov/cli/report.rb +84 -0
- data/simplecov-1.0.0/lib/simplecov/cli/run.rb +36 -0
- data/simplecov-1.0.0/lib/simplecov/cli/serve.rb +139 -0
- data/simplecov-1.0.0/lib/simplecov/cli/uncovered.rb +107 -0
- data/simplecov-1.0.0/lib/simplecov/cli.rb +150 -0
- data/simplecov-1.0.0/lib/simplecov/color.rb +74 -0
- data/simplecov-1.0.0/lib/simplecov/combine/branches_combiner.rb +54 -0
- data/simplecov-1.0.0/lib/simplecov/combine/files_combiner.rb +30 -0
- data/simplecov-1.0.0/lib/simplecov/combine/lines_combiner.rb +45 -0
- data/simplecov-1.0.0/lib/simplecov/combine/methods_combiner.rb +26 -0
- data/simplecov-1.0.0/lib/simplecov/combine/results_combiner.rb +61 -0
- data/simplecov-1.0.0/lib/simplecov/combine.rb +30 -0
- data/simplecov-1.0.0/lib/simplecov/command_guesser.rb +78 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/coverage.rb +171 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/coverage_criteria.rb +156 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/filters.rb +197 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/formatting.rb +119 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/ignored_entries.rb +63 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/merging.rb +164 -0
- data/simplecov-1.0.0/lib/simplecov/configuration/thresholds.rb +174 -0
- data/simplecov-1.0.0/lib/simplecov/configuration.rb +184 -0
- data/simplecov-1.0.0/lib/simplecov/coverage_statistics.rb +59 -0
- data/simplecov-1.0.0/lib/simplecov/coverage_violations.rb +148 -0
- data/simplecov-1.0.0/lib/simplecov/defaults.rb +60 -0
- data/simplecov-1.0.0/lib/simplecov/deprecation.rb +45 -0
- data/simplecov-1.0.0/lib/simplecov/directive.rb +162 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/exit_code_handling.rb +35 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +45 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +45 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +44 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +41 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +70 -0
- data/simplecov-1.0.0/lib/simplecov/exit_codes.rb +18 -0
- data/simplecov-1.0.0/lib/simplecov/exit_handling.rb +158 -0
- data/simplecov-1.0.0/lib/simplecov/file_list.rb +164 -0
- data/simplecov-1.0.0/lib/simplecov/filter.rb +139 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/base.rb +101 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/application.css +1 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/application.js +18 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/index.html +56 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter.rb +79 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/errors_formatter.rb +84 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +128 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +99 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter.rb +87 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/multi_formatter.rb +31 -0
- data/simplecov-1.0.0/lib/simplecov/formatter/simple_formatter.rb +23 -0
- data/simplecov-1.0.0/lib/simplecov/formatter.rb +14 -0
- data/simplecov-1.0.0/lib/simplecov/last_run.rb +35 -0
- data/simplecov-1.0.0/lib/simplecov/lines_classifier.rb +60 -0
- data/simplecov-1.0.0/lib/simplecov/load_global_config.rb +13 -0
- data/simplecov-1.0.0/lib/simplecov/no_defaults.rb +4 -0
- data/simplecov-1.0.0/lib/simplecov/parallel_adapters/base.rb +61 -0
- data/simplecov-1.0.0/lib/simplecov/parallel_adapters/generic.rb +44 -0
- data/simplecov-1.0.0/lib/simplecov/parallel_adapters/parallel_tests.rb +93 -0
- data/simplecov-1.0.0/lib/simplecov/parallel_adapters.rb +83 -0
- data/simplecov-1.0.0/lib/simplecov/parallel_coordination.rb +129 -0
- data/simplecov-1.0.0/lib/simplecov/process.rb +37 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/bundler_filter.rb +5 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/hidden_filter.rb +5 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/rails.rb +32 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/root_filter.rb +11 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/strict.rb +32 -0
- data/simplecov-1.0.0/lib/simplecov/profiles/test_frameworks.rb +5 -0
- data/simplecov-1.0.0/lib/simplecov/profiles.rb +64 -0
- data/simplecov-1.0.0/lib/simplecov/result/missing_source_files_reporter.rb +49 -0
- data/simplecov-1.0.0/lib/simplecov/result/source_file_builder.rb +51 -0
- data/simplecov-1.0.0/lib/simplecov/result.rb +183 -0
- data/simplecov-1.0.0/lib/simplecov/result_adapter.rb +92 -0
- data/simplecov-1.0.0/lib/simplecov/result_merger/legacy_format_adapter.rb +28 -0
- data/simplecov-1.0.0/lib/simplecov/result_merger/resultset_file.rb +38 -0
- data/simplecov-1.0.0/lib/simplecov/result_merger/resultset_store.rb +50 -0
- data/simplecov-1.0.0/lib/simplecov/result_merger.rb +162 -0
- data/simplecov-1.0.0/lib/simplecov/result_processing.rb +179 -0
- data/simplecov-1.0.0/lib/simplecov/simulate_coverage.rb +75 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/branch.rb +82 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/branch_builder.rb +114 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/builder_context.rb +28 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/line.rb +77 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/line_builder.rb +43 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/method.rb +52 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/method_builder.rb +58 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/ruby_data_parser.rb +88 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/skip_chunks.rb +75 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/source_loader.rb +63 -0
- data/simplecov-1.0.0/lib/simplecov/source_file/statistics.rb +57 -0
- data/simplecov-1.0.0/lib/simplecov/source_file.rb +189 -0
- data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor/method_collector.rb +55 -0
- data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor/visitor.rb +171 -0
- data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor.rb +110 -0
- data/simplecov-1.0.0/lib/simplecov/useless_results_remover.rb +27 -0
- data/simplecov-1.0.0/lib/simplecov/version.rb +5 -0
- data/simplecov-1.0.0/lib/simplecov-html.rb +4 -0
- data/simplecov-1.0.0/lib/simplecov.rb +255 -0
- data/simplecov-1.0.0/lib/simplecov_json_formatter.rb +4 -0
- data/simplecov-1.0.0/schemas/coverage-v1.0.schema.json +306 -0
- data/simplecov-1.0.0/schemas/coverage.schema.json +306 -0
- data/ultra-pro-pkg.gemspec +12 -0
- metadata +156 -0
|
@@ -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,164 @@
|
|
|
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
|
+
SimpleCov::Deprecation.warn("`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
|
+
#
|
|
58
|
+
# Get or set whether this process owns final merge processing:
|
|
59
|
+
# waiting for sibling workers, building the merged result, formatting,
|
|
60
|
+
# enforcing thresholds, and writing `.last_run.json`.
|
|
61
|
+
#
|
|
62
|
+
# Defaults to true, except for recognized multi-worker parallel runs
|
|
63
|
+
# that explicitly write to a custom coverage destination while merging
|
|
64
|
+
# is enabled. Those runs are likely using an external `SimpleCov.collate`
|
|
65
|
+
# step to finalize the merge.
|
|
66
|
+
#
|
|
67
|
+
def finalize_merge(value = :__no_arg__)
|
|
68
|
+
unless value == :__no_arg__
|
|
69
|
+
@finalize_merge = value
|
|
70
|
+
@finalize_merge_explicit = true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return @finalize_merge if defined?(@finalize_merge_explicit) && @finalize_merge_explicit
|
|
74
|
+
|
|
75
|
+
inferred = inferred_finalize_merge?
|
|
76
|
+
warn_about_inferred_finalize_merge unless inferred
|
|
77
|
+
inferred
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def finalize_merge?
|
|
81
|
+
finalize_merge
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @api private
|
|
85
|
+
def merge_finalization_owner?
|
|
86
|
+
collating_result? || finalize_merge?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# DEPRECATED: alias for `merging`. Same value, same behavior.
|
|
90
|
+
def use_merging(use = nil)
|
|
91
|
+
SimpleCov::Deprecation.warn("`SimpleCov.use_merging` is deprecated. " \
|
|
92
|
+
"Replace with `SimpleCov.merging` (same value, same behavior).")
|
|
93
|
+
@use_merging = use unless use.nil?
|
|
94
|
+
@use_merging = true unless defined?(@use_merging) && @use_merging == false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# Defines the maximum age (in seconds) of a resultset to still be
|
|
99
|
+
# included in merged results. Default is 600 seconds (10 minutes).
|
|
100
|
+
#
|
|
101
|
+
def merge_timeout(seconds = nil)
|
|
102
|
+
@merge_timeout = seconds if seconds.is_a?(Integer)
|
|
103
|
+
@merge_timeout ||= 600
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# Defines how long (in seconds) the reporting process waits for the
|
|
108
|
+
# remaining parallel-test workers to write their resultsets before it
|
|
109
|
+
# proceeds with a partial merge. Default is 60 seconds. Raise it when a
|
|
110
|
+
# slow worker routinely finishes well after the others, so its coverage
|
|
111
|
+
# is still included and the minimum / maximum coverage checks aren't
|
|
112
|
+
# skipped against a partial total.
|
|
113
|
+
#
|
|
114
|
+
def parallel_wait_timeout(seconds = nil)
|
|
115
|
+
@parallel_wait_timeout = seconds if seconds.is_a?(Integer)
|
|
116
|
+
@parallel_wait_timeout ||= 60
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def inferred_finalize_merge?
|
|
122
|
+
return true unless merging
|
|
123
|
+
|
|
124
|
+
adapter = SimpleCov::ParallelAdapters.current
|
|
125
|
+
return true unless adapter
|
|
126
|
+
return true unless adapter.expected_worker_count > 1
|
|
127
|
+
return true unless parallel_worker_environment?
|
|
128
|
+
return true unless explicit_custom_coverage_destination?
|
|
129
|
+
|
|
130
|
+
false
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def parallel_worker_environment?
|
|
134
|
+
ENV.key?("TEST_ENV_NUMBER") || ENV.key?("PARALLEL_TEST_GROUPS")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def explicit_custom_coverage_destination?
|
|
138
|
+
return false unless explicit_coverage_destination?
|
|
139
|
+
|
|
140
|
+
coverage_path != File.expand_path("coverage", root)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def explicit_coverage_destination?
|
|
144
|
+
(defined?(@coverage_path_explicit) && @coverage_path_explicit) ||
|
|
145
|
+
(defined?(@coverage_dir_explicit) && @coverage_dir_explicit)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def warn_about_inferred_finalize_merge
|
|
149
|
+
return if defined?(@finalize_merge_inference_warned) && @finalize_merge_inference_warned
|
|
150
|
+
return unless print_errors
|
|
151
|
+
|
|
152
|
+
@finalize_merge_inference_warned = true
|
|
153
|
+
warn SimpleCov::Color.colorize(inferred_finalize_merge_warning, :yellow)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def inferred_finalize_merge_warning
|
|
157
|
+
"SimpleCov inferred `finalize_merge false` because this parallel worker is merging " \
|
|
158
|
+
"into a custom coverage destination. Set `SimpleCov.finalize_merge false` to keep " \
|
|
159
|
+
"external collation ownership, or `SimpleCov.finalize_merge true` if this worker " \
|
|
160
|
+
"should wait, merge, format, enforce thresholds, and write `.last_run.json`. " \
|
|
161
|
+
"See https://github.com/simplecov-ruby/simplecov#merge-finalization-ownership."
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
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
|
+
SimpleCov::Deprecation.warn("`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
|
+
SimpleCov::Deprecation.warn("`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
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
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
|
+
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
|
+
def root(root = nil)
|
|
19
|
+
return @root if defined?(@root) && root.nil?
|
|
20
|
+
|
|
21
|
+
@coverage_path = nil unless @coverage_path_explicit # invalidate cache
|
|
22
|
+
@root = File.expand_path(root || Dir.getwd)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# The name of the output and cache directory. Defaults to 'coverage'
|
|
27
|
+
#
|
|
28
|
+
# Configure with SimpleCov.coverage_dir('cov')
|
|
29
|
+
#
|
|
30
|
+
def coverage_dir(dir = nil)
|
|
31
|
+
return @coverage_dir if defined?(@coverage_dir) && dir.nil?
|
|
32
|
+
|
|
33
|
+
@coverage_path = nil unless @coverage_path_explicit # invalidate cache
|
|
34
|
+
@coverage_dir_explicit = true unless dir.nil?
|
|
35
|
+
@coverage_dir = dir || "coverage"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Returns the full path to the output directory. By default
|
|
40
|
+
# constructed from `SimpleCov.root` + `SimpleCov.coverage_dir`, but
|
|
41
|
+
# callers can override with an arbitrary absolute path — handy for
|
|
42
|
+
# out-of-tree build directories. See #716.
|
|
43
|
+
#
|
|
44
|
+
# Reading is pure: the directory is only created when a path is
|
|
45
|
+
# explicitly assigned (the user has signaled they intend to write
|
|
46
|
+
# there). The codepaths that actually write into the directory
|
|
47
|
+
# (formatters, `LastRun`, `ResultsetStore`) ensure existence
|
|
48
|
+
# themselves, so read-only CLI subcommands that interpolate the
|
|
49
|
+
# path into status text don't materialize a stray `coverage/`
|
|
50
|
+
# directory.
|
|
51
|
+
#
|
|
52
|
+
def coverage_path(path = nil)
|
|
53
|
+
if path
|
|
54
|
+
@coverage_path = File.expand_path(path)
|
|
55
|
+
@coverage_path_explicit = true
|
|
56
|
+
FileUtils.mkdir_p @coverage_path
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@coverage_path ||= File.expand_path(coverage_dir, root)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# The name of the command (a.k.a. Test Suite) currently running.
|
|
64
|
+
# Used for result merging and caching. Auto-detected; set explicitly
|
|
65
|
+
# with SimpleCov.command_name("test:units").
|
|
66
|
+
#
|
|
67
|
+
def command_name(name = nil)
|
|
68
|
+
@name = name unless name.nil?
|
|
69
|
+
@name ||= SimpleCov::CommandGuesser.guess
|
|
70
|
+
@name
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns the hash of available profiles
|
|
74
|
+
def profiles
|
|
75
|
+
@profiles ||= SimpleCov::Profiles.new
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Allows you to configure simplecov in a block instead of
|
|
80
|
+
# prepending SimpleCov to each config method.
|
|
81
|
+
#
|
|
82
|
+
def configure(&block)
|
|
83
|
+
block_context = block.binding.receiver
|
|
84
|
+
|
|
85
|
+
# If the block was defined in our own context, instance_exec is sufficient
|
|
86
|
+
return instance_exec(&block) if equal?(block_context)
|
|
87
|
+
|
|
88
|
+
# Copy the caller's instance variables in so that references like @filter
|
|
89
|
+
# inside the block resolve to the caller's values, not ours.
|
|
90
|
+
saved = swap_ivars_from(block_context)
|
|
91
|
+
instance_exec(&block)
|
|
92
|
+
ensure
|
|
93
|
+
restore_ivars(block_context, saved) if defined?(saved) && saved
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
# Gets or sets the behavior to process coverage results.
|
|
98
|
+
# By default, it stores/merges the current result and formats only
|
|
99
|
+
# from the final reporting process.
|
|
100
|
+
#
|
|
101
|
+
def at_exit(&block)
|
|
102
|
+
@at_exit = block if block
|
|
103
|
+
return @at_exit if @at_exit
|
|
104
|
+
return proc {} unless active_session?
|
|
105
|
+
|
|
106
|
+
@at_exit = proc do
|
|
107
|
+
result = SimpleCov.result
|
|
108
|
+
result.format! if result && SimpleCov.merge_finalization_owner? && SimpleCov.final_result_process?
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Whether SimpleCov has anything to do at exit: the Coverage module
|
|
113
|
+
# is actively tracking, or a `@result` has already been assembled
|
|
114
|
+
# (e.g. by `SimpleCov.collate`, which never starts Coverage).
|
|
115
|
+
def active_session?
|
|
116
|
+
SimpleCov.result? || (defined?(Coverage) && Coverage.running?)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# Gets or sets the behavior to start a new forked Process.
|
|
121
|
+
# Defaults to adding " (subprocess: #{serial})" to command_name and
|
|
122
|
+
# starting SimpleCov in quiet mode.
|
|
123
|
+
#
|
|
124
|
+
def at_fork(&block)
|
|
125
|
+
@at_fork = block if block
|
|
126
|
+
@at_fork ||= lambda { |_pid|
|
|
127
|
+
# Needs a name that's unique per worker within a run yet identical
|
|
128
|
+
# across runs. Build it from SimpleCov's stable fork serial rather
|
|
129
|
+
# than the OS pid: with the pid, every run produced uniquely-named
|
|
130
|
+
# results that never overwrote the previous run's, so they piled up
|
|
131
|
+
# in .resultset.json until merge_timeout and the merged report's
|
|
132
|
+
# file set drifted from run to run. See issue #1171.
|
|
133
|
+
SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{SimpleCov.subprocess_serial})"
|
|
134
|
+
# be quiet, the parent process will use the regular formatter
|
|
135
|
+
SimpleCov.print_errors false
|
|
136
|
+
SimpleCov.formatter SimpleCov::Formatter::SimpleFormatter
|
|
137
|
+
SimpleCov.minimum_coverage 0
|
|
138
|
+
SimpleCov.start
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
# Returns the project name — defaults to the last dirname in
|
|
144
|
+
# SimpleCov.root, capitalized with underscores → spaces.
|
|
145
|
+
#
|
|
146
|
+
def project_name(new_name = nil)
|
|
147
|
+
return @project_name if defined?(@project_name) && @project_name && new_name.nil?
|
|
148
|
+
|
|
149
|
+
@project_name = new_name if new_name.is_a?(String)
|
|
150
|
+
@project_name ||= File.basename(root).capitalize.tr("_", " ")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
# Copy instance variables from block_context into self, saving any
|
|
156
|
+
# of ours that would be clobbered. Returns the saved values for
|
|
157
|
+
# later restoration.
|
|
158
|
+
def swap_ivars_from(block_context)
|
|
159
|
+
saved = {}
|
|
160
|
+
our_ivars = instance_variables
|
|
161
|
+
block_context.instance_variables.each do |ivar|
|
|
162
|
+
saved[ivar] = instance_variable_get(ivar) if our_ivars.include?(ivar)
|
|
163
|
+
instance_variable_set(ivar, block_context.instance_variable_get(ivar))
|
|
164
|
+
end
|
|
165
|
+
saved
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Copy instance variables back to block_context and restore our saved values.
|
|
169
|
+
def restore_ivars(block_context, saved)
|
|
170
|
+
block_context.instance_variables.each do |ivar|
|
|
171
|
+
block_context.instance_variable_set(ivar, instance_variable_get(ivar))
|
|
172
|
+
end
|
|
173
|
+
saved.each { |ivar, value| instance_variable_set(ivar, value) }
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
require_relative "configuration/coverage"
|
|
179
|
+
require_relative "configuration/coverage_criteria"
|
|
180
|
+
require_relative "configuration/filters"
|
|
181
|
+
require_relative "configuration/formatting"
|
|
182
|
+
require_relative "configuration/ignored_entries"
|
|
183
|
+
require_relative "configuration/merging"
|
|
184
|
+
require_relative "configuration/thresholds"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleCov
|
|
4
|
+
# Holds the individual data of a coverage result.
|
|
5
|
+
#
|
|
6
|
+
# This is uniform across coverage criteria as they all have:
|
|
7
|
+
#
|
|
8
|
+
# * total - how many things to cover there are (total relevant loc/branches)
|
|
9
|
+
# * covered - how many of the coverables are hit
|
|
10
|
+
# * missed - how many of the coverables are missed
|
|
11
|
+
# * omitted - how many lines cannot be covered (blank lines/comments); only meaningful for line coverage
|
|
12
|
+
# * percent - percentage as covered/missed
|
|
13
|
+
# * strength - average hits per/coverable (will not exist for one shot lines format)
|
|
14
|
+
class CoverageStatistics
|
|
15
|
+
attr_reader :total, :covered, :missed, :omitted, :strength, :percent
|
|
16
|
+
|
|
17
|
+
def self.from(coverage_statistics)
|
|
18
|
+
sum_covered, sum_missed, sum_omitted, sum_total_strength =
|
|
19
|
+
coverage_statistics.reduce([0, 0, 0, 0.0]) do |(covered, missed, omitted, total_strength), stats|
|
|
20
|
+
[
|
|
21
|
+
covered + stats.covered,
|
|
22
|
+
missed + stats.missed,
|
|
23
|
+
omitted + stats.omitted,
|
|
24
|
+
# gotta remultiply with loc because files have different strength and loc
|
|
25
|
+
# giving them a different "weight" in total
|
|
26
|
+
total_strength + (stats.strength * stats.total)
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
new(covered: sum_covered, missed: sum_missed, omitted: sum_omitted, total_strength: sum_total_strength)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Requires only covered, missed and strength to be initialized.
|
|
34
|
+
#
|
|
35
|
+
# Other values are computed by this class.
|
|
36
|
+
def initialize(covered:, missed:, omitted: 0, total_strength: 0.0, percent: nil)
|
|
37
|
+
@covered = covered
|
|
38
|
+
@missed = missed
|
|
39
|
+
@omitted = omitted
|
|
40
|
+
@total = covered + missed
|
|
41
|
+
@percent = percent || compute_percent(covered, missed, total)
|
|
42
|
+
@strength = compute_strength(total_strength, total)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def compute_percent(covered, missed, total)
|
|
48
|
+
return 100.0 if missed.zero?
|
|
49
|
+
|
|
50
|
+
covered * 100.0 / total
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def compute_strength(total_strength, total)
|
|
54
|
+
return 0.0 if total.zero?
|
|
55
|
+
|
|
56
|
+
total_strength.to_f / total
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|