Module: SimpleCov
Overview
Code coverage for ruby. Please check out README for a full introduction.
Constant Summary
-
CRITERION_TO_RUBY_COVERAGE =
# File 'lib/simplecov.rb', line 12{ branch: :branches, line: :lines, method: :methods, oneshot_line: :oneshot_lines }.freeze -
VERSION =
# File 'lib/simplecov/version.rb', line 4"1.0.0.rc3"
Class Attribute Summary
- .collating_result? ⇒ Boolean readonly
-
.defer_to_existing_report? ⇒ Boolean
readonly
Returns true when our process has no coverage data to contribute (after the resultset merge) and a newer report already exists on disk.
- .existing_report_newer_than_us? ⇒ Boolean readonly
-
.external_at_exit
rw
Should we take care of at_exit behavior or something else? Used by the minitest plugin.
-
.external_at_exit? ⇒ Boolean
rw
Coerce to a proper boolean so rspec-mocks 4's predicate matcher (
expect(...).not_to be_external_at_exit) accepts the result. - .final_result_process? ⇒ Boolean readonly Internal use only
-
.forked_subprocess? ⇒ Boolean
readonly
running (set by
ProcessForkHookin the child). -
.parallel_results_complete? ⇒ Boolean
readonly
before the wait deadline.
- .pid rw
-
.process_start_time
rw
When this process started tracking coverage.
-
.ready_to_process_results? ⇒ Boolean
readonly
only one that reports against thresholds, and only when its .wait_for_other_processes confirmed every sibling reported.
-
.result
readonly
Returns the result for the current coverage run, merging it across test suites from cache using
ResultMergerif use_merging is activated (default). -
.result? ⇒ Boolean
readonly
Returns nil if the result has not been computed, otherwise the result.
-
.minitest_autorun_pending? ⇒ Boolean
readonly
private
Rake::TestTaskrunsruby -e 'require "minitest/autorun"; ...', which means Minitest's at_exit registers before SimpleCov's.
Configuration - Extended
| active_session? | Whether SimpleCov has anything to do at exit: the Coverage module is actively tracking, or a |
| branch_coverage?, branch_coverage_supported?, | |
| coverage_for_eval_enabled? | simplecov:enable. |
| coverage_for_eval_supported?, | |
| enabled_for_subprocesses? | whether to install the fork hook. |
| filters | Returns the list of configured exclusion filters added via |
| filters=, finalize_merge?, | |
| formatter | Gets or sets the configured formatter. |
| formatter=, | |
| groups | Returns the configured groups. |
| groups=, merge_finalization_owner?, method_coverage?, method_coverage_supported?, | |
| print_error_status | DEPRECATED: alias for |
| print_error_status=, explicit_coverage_destination?, explicit_custom_coverage_destination?, inferred_finalize_merge?, parallel_worker_environment? | |
Class Method Summary
- .at_exit_behavior
-
.clear_result
Clear out the previously cached .result.
-
.collate(result_filenames, profile = nil, ignore_timeout: true)
Collate a series of
SimpleCovresult files into a singleSimpleCovoutput. -
.coverage_statistics_key(criterion)
:oneshot_linedata is folded into the:linebucket ofcoverage_statisticsbyResultAdapter, so use:lineto look up stats for either criterion. - .exit_and_report_previous_error(exit_status) Internal use only
- .exit_status_from_exception
-
.filtered(files)
Applies the configured filters to the given array of
SourceFileitems. -
.grouped(files, groups: SimpleCov.groups)
Bin the given source files by group filter.
-
.install_at_exit_hook
Install the at_exit hook that formats results and runs exit-code checks.
-
.load_profile(name)
Applies the profile of given name on
SimpleCovconfiguration. - .mark_forked_subprocess!
-
.next_subprocess_serial!
child inherits its own ordinal via copy-on-write.
-
.parallel_wait_timed_out?(deadline, expected, seen) ⇒ Boolean
the first timeout so the user knows the merged total is partial.
-
.previous_error?(error_exit_status) ⇒ Boolean
accepts it.
- .process_result(result)
- .process_results_and_report_error
- .result_exit_status(result)
- .round_coverage(coverage)
- .run_exit_tasks!
-
.start(profile = nil)
Sets up
SimpleCovto run against your project. -
.start_tracking
Begin coverage tracking without applying configuration.
-
.subprocess_serial
A monotonically increasing serial the parent assigns to each forked subprocess (see
ProcessForkHook). - .wait_for_other_processes Internal use only
-
.wait_for_parallel_results(expected)
before the deadline, false on timeout.
- .warn_about_deferred_report
- .warn_about_incomplete_parallel_results(expected, seen) Internal use only
- .warn_about_start_in_dot_simplecov
-
.with_dot_simplecov_autoload
Internal use only
Mark the duration of a
.simplecovauto-load so any .start call inside the file can warn about the impending migration to a config-only file. -
.write_last_run(result)
rounded down (see
#679) so the next run can compute drift. -
.add_not_loaded_files(result)
private
Finds files that were to be tracked but were not loaded, and initializes their line-by-line coverage to zero (or nil for comments / whitespace).
- .build_coverage_limits private
- .defer_to_minitest_after_run private
-
.discover_unloaded_paths(globs)
private
Expand the given globs relative to
SimpleCov.root, notDir.pwd— test runners that chdir (or CI scripts that invoke the suite from a subdir) would otherwise silently miss the unloaded-file injection and produce a different file set per environment. - .grouped_file_set(grouped) private
- .initial_setup(profile, &block) private
- .inject_unloaded_files(result, candidate_paths) private
-
.process_coverage_result(report:)
private
Run all the steps that handle processing the raw coverage result.
-
.start_coverage_measurement
private
Trigger
Coverage.startwith the configured criteria. -
.unloaded_file_discovery_globs
private
Globs to expand on disk when injecting unloaded files into the result.
-
.warn_if_jruby_full_trace_disabled
private
JRuby coverage data is unreliable unless full-trace mode is enabled.
Configuration - Extended
| add_filter | DEPRECATED: alias for |
| add_group | DEPRECATED: alias for |
| at_exit | Gets or sets the behavior to process coverage results. |
| at_fork | Gets or sets the behavior to start a new forked Process. |
| clear_coverage_criteria | Reset the criteria back to the lazy default ( |
| clear_filters | Remove every filter from the chain, including the defaults installed by .start. |
| color | Get or set whether |
| command_name | The name of the command (a.k.a. Test Suite) currently running. |
| configure | Allows you to configure simplecov in a block instead of prepending |
| cover | Restrict the universe of files in the coverage report to those matching one or more globs, regexps, or block predicates. |
| cover_filters | Returns the list of configured inclusion filters added via |
| cover_globs | Returns the list of string globs passed to |
| coverage | Configure (and, unless |
| coverage_criteria, coverage_criterion_enabled?, | |
| coverage_criterion_supported? | Ask the Coverage runtime itself whether a criterion is supported (Ruby >= 3.2). |
| coverage_dir | The name of the output and cache directory. |
| coverage_path | Returns the full path to the output directory. |
| current_nocov_token | Internal accessor used by |
| disable_coverage | Remove |
| enable_coverage | Enable one or more coverage criteria. |
| enable_coverage_for_eval | DEPRECATED: prefer |
| enable_for_subprocesses | DEPRECATED: alias for |
| expected_coverage | Pins the suite to an exact coverage figure by setting both |
| finalize_merge | Get or set whether this process owns final merge processing: waiting for sibling workers, building the merged result, formatting, enforcing thresholds, and writing |
| formatters | Sets the configured formatters. |
| formatters= | Sets the configured formatters. |
| group | Define a display group for files. |
| ignore_branches | Variadic; multiple calls union. |
| ignore_methods | See |
| ignored_branch?, ignored_branches, ignored_method?, ignored_methods, | |
| maximum_coverage | Defines the maximum overall coverage allowed for the testsuite to pass. |
| maximum_coverage_drop | Defines the maximum coverage drop at once allowed for the testsuite to pass. |
| merge_subprocesses | Get or set whether |
| merge_timeout | Defines the maximum age (in seconds) of a resultset to still be included in merged results. |
| merging | Get or set whether to merge results from multiple test suites (test:units, test:functionals, cucumber, ...) into a single coverage report. |
| minimum_coverage | Defines the minimum overall coverage required for the testsuite to pass. |
| minimum_coverage_by_file | Defines the minimum coverage per file required for the testsuite to pass. |
| minimum_coverage_by_file_overrides | Returns the per-path overrides set via |
| minimum_coverage_by_group | Defines the minimum coverage per group required for the testsuite to pass. |
| no_default_skips | Drop every filter previously installed (defaults plus anything earlier in this block) so subsequent |
| nocov_token | DEPRECATED: configure |
| parallel_tests | Get or set whether |
| parallel_wait_timeout | Defines how long (in seconds) the reporting process waits for the remaining parallel-test workers to write their resultsets before it proceeds with a partial merge. |
| primary_coverage, | |
| print_errors | Get or set whether |
| profiles | Returns the hash of available profiles. |
| project_name | Returns the project name — defaults to the last dirname in |
| raise_on_invalid_coverage, | |
| refuse_coverage_drop | Refuses any coverage drop. |
| remove_filter | Remove any filters whose |
| root | The root for the project. |
| skip | Drop matching files from the coverage report. |
| skip_token | Alias for Configuration#nocov_token. |
| source_in_json | Get or set whether |
| track_files | DEPRECATED: prefer |
| track_files_replacement_hint |
|
| tracked_files | Returns the glob used to include files that were not explicitly required. |
| use_merging | DEPRECATED: alias for |
| validate_coverage_criteria! | fast when the user has disabled every coverage criterion. |
| apply_threshold_options | Forward the one-liner threshold keywords ( |
| build_cover_filter | Build a filter for a |
| collect_cover_globs | Walk a list of cover filters and return the string globs they hold, descending into |
| default_primary_coverage | If |
| enable_coverage_criterion | Enable the criterion (or its oneshot / eval variant) and return the criterion symbol that thresholds should be stored under. |
| enable_eval_coverage | Shared implementation backing both |
| enable_eval_coverage_criterion, enable_oneshot_line, inferred_finalize_merge_warning, minimum_possible_coverage_exceeded, | |
| parse_filter | The actual filter processor. |
| partition_per_file_thresholds | Split a |
| per_file_coverage_replacement | Render the |
| per_group_coverage_replacement | Same, for a (deprecated) |
| raise_if_branch_type_unsupported, raise_if_criterion_disabled, raise_if_criterion_unsupported, raise_if_method_type_unsupported, render_coverage_blocks, | |
| restore_ivars | Copy instance variables back to block_context and restore our saved values. |
| store_minimum_per_file, store_minimum_per_group, | |
| store_overall_threshold | write the same |
| swap_ivars_from | Copy instance variables from block_context into self, saving any of ours that would be clobbered. |
| validate_per_file_key, warn_about_inferred_finalize_merge | |
Class Attribute Details
.collating_result? ⇒ Boolean (readonly)
# File 'lib/simplecov/result_processing.rb', line 63
def collating_result? defined?(@collating_result) && @collating_result end
.defer_to_existing_report? ⇒ Boolean (readonly)
Returns true when our process has no coverage data to contribute
(after the resultset merge) and a newer report already exists on
disk. Typically fires when .start ran in a parent
process — e.g. a Rakefile or Rails' Bundler.require — that
shelled out to the test runner. See issue #581.
# File 'lib/simplecov/exit_handling.rb', line 40
def defer_to_existing_report? return false unless existing_report_newer_than_us? res = result empty = res.nil? || res.files.empty? warn_about_deferred_report if empty empty end
.existing_report_newer_than_us? ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/simplecov/exit_handling.rb', line 49
def existing_report_newer_than_us? return false unless process_start_time last_run_path = File.join(coverage_path, ".last_run.json") File.exist?(last_run_path) && File.mtime(last_run_path) > process_start_time end
.external_at_exit (rw)
Should we take care of at_exit behavior or something else? Used by the minitest plugin. See lib/minitest/simplecov_plugin.rb.
# File 'lib/simplecov.rb', line 57
attr_accessor :external_at_exit
.external_at_exit? ⇒ Boolean (rw)
Coerce to a proper boolean so rspec-mocks 4's predicate matcher
(expect(...).not_to be_external_at_exit) accepts the result.
# File 'lib/simplecov.rb', line 68
def external_at_exit? !!@external_at_exit end
.final_result_process? ⇒ Boolean (readonly)
# File 'lib/simplecov/parallel_coordination.rb', line 12
def final_result_process? adapter = SimpleCov::ParallelAdapters.current # No recognized parallel-test adapter. A subprocess forked while # coverage was running is never the final reporter — the process that # spawned it merges every slice and produces the report. Without this, # fork-based runners that don't set TEST_ENV_NUMBER (e.g. Minitest's # `parallelize`) have every worker produce the final report and its # warnings. See issue #1171. return !forked_subprocess? unless adapter adapter.first_worker? end
.forked_subprocess? ⇒ Boolean (readonly)
running (set by ::SimpleCov::ProcessForkHook in the child). Such a child
stores its own slice but must not act as the final-result process: the
process that forked it merges every slice and produces the report. Only
consulted when no parallel-test adapter is active, since adapters answer
first_worker? themselves. See issue #1171.
# File 'lib/simplecov.rb', line 47
def forked_subprocess? !!(defined?(@forked_subprocess) && @forked_subprocess) end
.minitest_autorun_pending? ⇒ Boolean (readonly, private)
Rake::TestTask runs ruby -e 'require "minitest/autorun"; ...',
which means Minitest's at_exit registers before SimpleCov's. Since
at_exit fires LIFO, SimpleCov's hook would otherwise run before
::Minitest gets a chance to invoke the tests — and format an empty
resultset. When we can see that ::Minitest is loaded and its autorun
is armed, route the report through Minitest.after_run instead,
which fires after the suite completes. See issues #1099 and #1112.
.parallel_results_complete? ⇒ Boolean (readonly)
before the wait deadline. Defaults to true outside a parallel run (when .wait_for_other_processes is a no-op).
# File 'lib/simplecov/parallel_coordination.rb', line 48
def parallel_results_complete? defined?(@parallel_results_complete) ? @parallel_results_complete : true end
.pid (rw)
[ GitHub ]# File 'lib/simplecov.rb', line 19
attr_accessor :pid
.process_start_time (rw)
When this process started tracking coverage. Captured by .start so JSONFormatter can detect when an existing coverage.json was written by a sibling process running concurrently.
# File 'lib/simplecov.rb', line 23
attr_accessor :process_start_time
.ready_to_process_results? ⇒ Boolean (readonly)
only one that reports against thresholds, and only when its
.wait_for_other_processes confirmed every sibling reported.
When the wait times out, the merged total is partial and
comparing it against minimum_coverage / maximum_coverage
would surface a spurious "below minimum" violation about the
missing slice rather than a real shortfall.
# File 'lib/simplecov/exit_handling.rb', line 115
def ready_to_process_results? merge_finalization_owner? && final_result_process? && result? && (collating_result? || parallel_results_complete?) end
.result (readonly)
Returns the result for the current coverage run, merging it across test suites
from cache using ::SimpleCov::ResultMerger if use_merging is activated (default)
# File 'lib/simplecov/result_processing.rb', line 34
def result return @result if result? use_merging = merging # Collect our coverage result. When merging is off there is no merge # step, so this per-process result is the final one and reports any # dropped source files; otherwise the merged result does the reporting. process_coverage_result(report: !use_merging) if defined?(Coverage) && Coverage.running? # If we're using merging of results, store the current result # first (if there is one), then merge the results and return those if use_merging SimpleCov::ResultMerger.store_result(@result) if result? return @result unless finalize_merge? wait_for_other_processes @result = SimpleCov::ResultMerger.merged_result end @result end
.result? ⇒ Boolean (readonly)
Returns nil if the result has not been computed, otherwise the result.
# File 'lib/simplecov/result_processing.rb', line 58
def result? defined?(@result) && @result end
Class Method Details
.add_not_loaded_files(result) (private)
Finds files that were to be tracked but were not loaded, and initializes their line-by-line coverage to zero (or nil for comments / whitespace).
# File 'lib/simplecov/result_processing.rb', line 132
def add_not_loaded_files(result) globs = unloaded_file_discovery_globs return [result, Set.new] if globs.empty? inject_unloaded_files(result.dup, discover_unloaded_paths(globs)) end
.at_exit_behavior
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 20
def at_exit_behavior # If we are in a different process than called start, don't interfere. return if SimpleCov.pid != Process.pid # If Coverage is no longer running (e.g. someone manually stopped it # or a test consumed the result) then don't run exit tasks. return unless Coverage.running? # Stand down when we'd only clobber a fresher report. See # `defer_to_existing_report?` and issue #581. return if defer_to_existing_report? SimpleCov.run_exit_tasks! end
.build_coverage_limits (private)
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 147
def build_coverage_limits CoverageLimits.new( minimum_coverage: minimum_coverage, minimum_coverage_by_file: minimum_coverage_by_file, minimum_coverage_by_file_overrides: minimum_coverage_by_file_overrides, minimum_coverage_by_group: minimum_coverage_by_group, maximum_coverage: maximum_coverage, maximum_coverage_drop: maximum_coverage_drop ) end
.clear_result
Clear out the previously cached .result. Primarily useful in testing.
# File 'lib/simplecov/result_processing.rb', line 101
def clear_result @result = nil end
.collate(result_filenames, profile = nil, ignore_timeout: true)
Collate a series of SimpleCov result files into a single SimpleCov output.
See README for usage. By default collate ignores the merge_timeout
so all results in all files specified will be merged. Pass
ignore_timeout: false to honor it.
# File 'lib/simplecov/result_processing.rb', line 16
def collate(result_filenames, profile = nil, ignore_timeout: true, &) raise ArgumentError, "There are no reports to be merged" if result_filenames.empty? initial_setup(profile, &) # Use the ResultMerger to produce a single, merged result, ready to use. @result = ResultMerger.merge_and_store(*result_filenames, ignore_timeout: ignore_timeout) @collating_result = true run_exit_tasks! ensure @collating_result = false end
.coverage_statistics_key(criterion)
:oneshot_line data is folded into the :line bucket of
coverage_statistics by ::SimpleCov::ResultAdapter, so use :line to look
up stats for either criterion.
# File 'lib/simplecov.rb', line 62
def coverage_statistics_key(criterion) criterion == :oneshot_line ? :line : criterion end
.defer_to_minitest_after_run (private)
[ GitHub ]# File 'lib/simplecov.rb', line 193
def defer_to_minitest_after_run self.external_at_exit = true Minitest.after_run { SimpleCov.at_exit_behavior } end
.discover_unloaded_paths(globs) (private)
Expand the given globs relative to SimpleCov.root, not Dir.pwd —
test runners that chdir (or CI scripts that invoke the suite
from a subdir) would otherwise silently miss the unloaded-file
injection and produce a different file set per environment. See
issue #1106.
# File 'lib/simplecov/result_processing.rb', line 152
def discover_unloaded_paths(globs) globs.flat_map { |glob| Dir.glob(glob, base: root) }.uniq end
.exit_and_report_previous_error(exit_status)
[ GitHub ].exit_status_from_exception
[ GitHub ].filtered(files)
Applies the configured filters to the given array of ::SimpleCov::SourceFile items
.grouped(files, groups: SimpleCov.groups)
Bin the given source files by group filter. groups: defaults to
SimpleCov.groups; pass a Hash explicitly to bin against a
different group config (e.g., the snapshot a ::SimpleCov::Result captured at
construction). Files matched by no group fall into the implicit
"Ungrouped" bucket.
# File 'lib/simplecov/result_processing.rb', line 81
def grouped(files, groups: SimpleCov.groups) return {} if groups.empty? grouped = groups.transform_values do |filter| SimpleCov::FileList.new(files.select { |source_file| filter.matches?(source_file) }) end in_group = grouped_file_set(grouped) ungrouped = files.reject { |source_file| in_group.include?(source_file) } grouped["Ungrouped"] = SimpleCov::FileList.new(ungrouped) if ungrouped.any? grouped end
.grouped_file_set(grouped) (private)
[ GitHub ].initial_setup(profile, &block) (private)
[ GitHub ]# File 'lib/simplecov/result_processing.rb', line 120
def initial_setup(profile, &block) load_profile(profile) if profile configure(&block) if block end
.inject_unloaded_files(result, candidate_paths) (private)
[ GitHub ]# File 'lib/simplecov/result_processing.rb', line 156
def inject_unloaded_files(result, candidate_paths) not_loaded_files = candidate_paths.each_with_object(Set.new) do |file, set| absolute_path = File.(file, root) next if result.key?(absolute_path) result[absolute_path] = SimulateCoverage.call(absolute_path) set << absolute_path end [result, not_loaded_files] end
.install_at_exit_hook
Install the at_exit hook that formats results and runs exit-code checks. .start calls this automatically. Idempotent — safe to call multiple times. Callers that drive the formatting pipeline themselves (e.g., dogfood test setups) can skip it by using .start_tracking directly instead of .start.
# File 'lib/simplecov.rb', line 122
def install_at_exit_hook return if @at_exit_hook_installed @at_exit_hook_installed = true defer_to_minitest_after_run if minitest_autorun_pending? Kernel.at_exit do next if SimpleCov.external_at_exit? SimpleCov.at_exit_behavior end end
.load_profile(name)
Applies the profile of given name on SimpleCov configuration
# File 'lib/simplecov/result_processing.rb', line 96
def load_profile(name) profiles.load(name) end
.mark_forked_subprocess!
[ GitHub ]# File 'lib/simplecov.rb', line 52
def mark_forked_subprocess! @forked_subprocess = true end
.next_subprocess_serial!
child inherits its own ordinal via copy-on-write.
# File 'lib/simplecov.rb', line 37
def next_subprocess_serial! @subprocess_serial = subprocess_serial + 1 end
.parallel_wait_timed_out?(deadline, expected, seen) ⇒ Boolean
the first timeout so the user knows the merged total is partial.
# File 'lib/simplecov/parallel_coordination.rb', line 72
def parallel_wait_timed_out?(deadline, expected, seen) return false unless Process.clock_gettime(Process::CLOCK_MONOTONIC) > deadline warn_about_incomplete_parallel_results(expected, seen) true end
.previous_error?(error_exit_status) ⇒ Boolean
accepts it. test_unit sets status 0 on success, so SUCCESS must also be treated as "not a previous error".
.process_coverage_result(report:) (private)
Run all the steps that handle processing the raw coverage result.
report: is true only when this slice is the final result (merging
off); with merging on the merged result reports dropped source files,
so the per-process slice stays quiet to avoid one warning per worker.
# File 'lib/simplecov/result_processing.rb', line 172
def process_coverage_result(report:) @result = SimpleCov::UselessResultsRemover.call(Coverage.result) @result = SimpleCov::ResultAdapter.call(@result) result, not_loaded_files = add_not_loaded_files(@result) @result = SimpleCov::Result.new(result, not_loaded_files: not_loaded_files, report: report) end
.process_result(result)
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 135
def process_result(result) result_exit_status = result_exit_status(result) write_last_run(result) if result_exit_status == SimpleCov::ExitCodes::SUCCESS result_exit_status end
.process_results_and_report_error
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 120
def process_results_and_report_error exit_status = process_result(result) # Force exit with stored status (see github issue #5) return unless exit_status.positive? if print_errors warn SimpleCov::Color.colorize( "SimpleCov failed with exit #{exit_status} due to a coverage related error", :red ) end Kernel.exit exit_status end
.result_exit_status(result)
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 141
def result_exit_status(result) ExitCodes::ExitCodeHandling.call(result, coverage_limits: build_coverage_limits) end
.round_coverage(coverage)
[ GitHub ]# File 'lib/simplecov/result_processing.rb', line 114
def round_coverage(coverage) coverage.floor(2) end
.run_exit_tasks!
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 69
def run_exit_tasks! error_exit_status = exit_status_from_exception at_exit.call exit_and_report_previous_error(error_exit_status) if previous_error?(error_exit_status) process_results_and_report_error if ready_to_process_results? end
.start(profile = nil)
Sets up SimpleCov to run against your project. See README for
the full DSL, or:
SimpleCov.start
SimpleCov.start 'rails' # using a profile
SimpleCov.start { add_filter 'test' } # with a config block
# File 'lib/simplecov.rb', line 80
def start(profile = nil, &) warn_about_start_in_dot_simplecov if @autoloading_dot_simplecov initial_setup(profile, &) start_tracking install_at_exit_hook end
.start_coverage_measurement (private)
Trigger Coverage.start with the configured criteria. Every supported
runtime (CRuby >= 3.2, JRuby >= 10, TruffleRuby >= 22) accepts the
criteria-hash form, so no compatibility fallback is needed.
# File 'lib/simplecov.rb', line 169
def start_coverage_measurement start_arguments = coverage_criteria.to_h do |criterion| [CRITERION_TO_RUBY_COVERAGE.fetch(criterion), true] end start_arguments[:eval] = true if coverage_for_eval_enabled? Coverage.start(start_arguments) unless Coverage.running? end
.start_tracking
Begin coverage tracking without applying configuration. Pairs with
SimpleCov.configure { ... } for callers that want to separate
the two — for example a dogfood test that has already started
Coverage itself before requiring simplecov, but still wants the
process_start_time / pid / fork-hook bookkeeping.
# File 'lib/simplecov.rb', line 141
def start_tracking require "coverage" warn_if_jruby_full_trace_disabled validate_coverage_criteria! # simplecov:disable — fork-hook is enabled via SimpleCov.enable_for_subprocesses, off by default require_relative "simplecov/process" if SimpleCov.enabled_for_subprocesses? && ::Process.respond_to?(:_fork) # simplecov:enable # Trigger adapter selection now so the (possibly lazy) parallel_tests # gem load happens at start_tracking time rather than mid-suite. # `current` is memoized; subsequent calls are cheap. SimpleCov::ParallelAdapters.current @result = nil self.pid = Process.pid self.process_start_time = Time.now start_coverage_measurement end
.subprocess_serial
A monotonically increasing serial the parent assigns to each forked
subprocess (see ::SimpleCov::ProcessForkHook). The default at_fork
builds the worker's command_name from this rather than the OS pid:
the serial sequence is the same from one run to the next, so a re-run
overwrites the previous run's resultset entries instead of writing
uniquely-named ones that pile up until merge_timeout. See issue #1171.
# File 'lib/simplecov.rb', line 31
def subprocess_serial @subprocess_serial ||= 0 end
.unloaded_file_discovery_globs (private)
Globs to expand on disk when injecting unloaded files into the
result. Combines the legacy track_files glob (additive only)
with every string glob declared via cover (also restrictive,
but the restriction lives in Result#apply_cover_filters!).
# File 'lib/simplecov/result_processing.rb', line 143
def unloaded_file_discovery_globs [tracked_files, *cover_globs].compact end
.wait_for_other_processes
[ GitHub ]# File 'lib/simplecov/parallel_coordination.rb', line 26
def wait_for_other_processes adapter = SimpleCov::ParallelAdapters.current return unless adapter && final_result_process? # Native synchronization first (adapters that wrap a runner with a # real "wait" primitive — parallel_tests' # `wait_for_other_processes_to_finish` — implement this; adapters # without a native API no-op and rely on the polling fallback below). adapter.wait_for_siblings # The native wait can return before sibling at_exit handlers finish # writing resultsets, and adapters without a native wait have # nothing else. Either way, poll the resultset cache until all # expected workers have reported or a timeout is reached. Capture # the outcome so `ready_to_process_results?` can suppress min/max # threshold checks against a partial total. @parallel_results_complete = wait_for_parallel_results(adapter.expected_worker_count) end
.wait_for_parallel_results(expected)
before the deadline, false on timeout. Single-process runs
(expected <= 1) short-circuit to true with no waiting. The deadline
is SimpleCov.parallel_wait_timeout seconds out; raise that setting
when a slow worker routinely finishes well after the others.
# File 'lib/simplecov/parallel_coordination.rb', line 57
def wait_for_parallel_results(expected) return true unless expected > 1 # simplecov:disable branch — only false in real parallel runs deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + parallel_wait_timeout loop do seen = SimpleCov::ResultMerger.read_resultset.size return true if seen >= expected return false if parallel_wait_timed_out?(deadline, expected, seen) sleep 0.1 end end
.warn_about_deferred_report
[ GitHub ]# File 'lib/simplecov/exit_handling.rb', line 56
def warn_about_deferred_report return unless print_errors warn SimpleCov::Color.colorize( "Skipping SimpleCov report — this process tracked no application code and a newer " \ "report already exists at #{coverage_path}. This usually means SimpleCov.start ran in a " \ "parent process (e.g. a Rakefile or Rails' Bundler.require) that shelled out to the test " \ "runner. See https://github.com/simplecov-ruby/simplecov/issues/581.", :yellow ) end
.warn_about_incomplete_parallel_results(expected, seen)
[ GitHub ]# File 'lib/simplecov/parallel_coordination.rb', line 80
def warn_about_incomplete_parallel_results(expected, seen) return unless print_errors warn SimpleCov::Color.colorize( "Only #{seen} of #{expected} parallel-test workers reported within " \ "#{parallel_wait_timeout}s, so coverage totals are partial and minimum / " \ "maximum coverage checks are skipped for this run. Increase " \ "SimpleCov.parallel_wait_timeout if a worker routinely needs longer.", :yellow ) end
.warn_about_start_in_dot_simplecov
[ GitHub ]# File 'lib/simplecov.rb', line 103
def warn_about_start_in_dot_simplecov return if @dot_simplecov_start_warned @dot_simplecov_start_warned = true warn "[DEPRECATION] Calling `SimpleCov.start` from `.simplecov` is deprecated and will " \ "be removed in a future release. `.simplecov` should contain configuration only; " \ "move the `SimpleCov.start` call into your `spec_helper.rb` / `test_helper.rb`. " \ "Coverage tracking still begins for backward compatibility, but a future release " \ "will require the explicit `SimpleCov.start` from a test helper. " \ "See https://github.com/simplecov-ruby/simplecov/issues/581." end
.warn_if_jruby_full_trace_disabled (private)
JRuby coverage data is unreliable unless full-trace mode is enabled.
# File 'lib/simplecov.rb', line 202
def warn_if_jruby_full_trace_disabled return unless defined?(JRUBY_VERSION) && defined?(JRuby) # simplecov:disable — JRuby-only branch # simplecov:disable — JRuby-only branches; unreachable from CRuby return if org.jruby.RubyInstanceConfig.FULL_TRACE_ENABLED warn 'Coverage may be inaccurate; set the "--debug" command line option, ' \ 'or do JRUBY_OPTS="--debug" ' \ 'or set the "debug.fullTrace=true" option in your .jrubyrc' # simplecov:enable end
.with_dot_simplecov_autoload
# File 'lib/simplecov.rb', line 95
def with_dot_simplecov_autoload previous = @autoloading_dot_simplecov @autoloading_dot_simplecov = true yield ensure @autoloading_dot_simplecov = previous end
.write_last_run(result)
rounded down (see #679) so the next run can compute drift.
# File 'lib/simplecov/result_processing.rb', line 107
def write_last_run(result) SimpleCov::LastRun.write( result: result.coverage_statistics.transform_values { |stats| round_coverage(stats.percent) } ) end