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 -
PARALLEL_RESULTS_WAIT_TIMEOUT =
private
Internal use only
# File 'lib/simplecov/parallel_coordination.rb', line 19
How long the first worker is willing to wait for all sibling workers' resultsets to appear in the cache before proceeding with whatever it has. Tuned generously enough that slow CI runners with one straggler don't trip the "incomplete results" path on a routine basis. See
#1065for the parallel_rspec / GenericAdapter case where there is no native wait primitive and this poll is the only synchronization available.60 -
VERSION =
# File 'lib/simplecov/version.rb', line 4"1.0.0.rc1"
Class Attribute Summary
-
.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. - .pid rw
-
.process_start_time
rw
When this process started tracking coverage.
-
.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. - .final_result_process? ⇒ Boolean readonly Internal use only Internal use only
-
.parallel_results_complete? ⇒ Boolean
readonly
Internal use only
before the wait deadline.
-
.ready_to_process_results? ⇒ Boolean
readonly
Internal use only
one that reports against thresholds, and only when its .wait_for_other_processes confirmed every sibling reported.
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?, | |
| filters | Returns the list of configured exclusion filters added via |
| filters=, | |
| formatter | Gets or sets the configured formatter. |
| formatter=, | |
| groups | Returns the configured groups. |
| groups=, method_coverage?, method_coverage_supported?, | |
| print_error_status | DEPRECATED: alias for |
| print_error_status=, | |
| enabled_for_subprocesses? | whether to install the fork hook. |
Class Method Summary
- .at_exit_behavior
-
.clear_result
Clear out the previously cached .result.
-
.collate(result_filenames, profile = nil, ignore_timeout: true, &block)
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. -
.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. - .process_results_and_report_error
- .result_exit_status(result)
-
.start(profile = nil)
Sets up
SimpleCovto run against your project. -
.start_tracking
Begin coverage tracking without applying configuration.
- .warn_about_deferred_report
- .warn_about_start_in_dot_simplecov
-
.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
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.
- .exit_and_report_previous_error(exit_status) Internal use only Internal use only
- .exit_status_from_exception Internal use only
-
.parallel_wait_timed_out?(deadline, expected, seen) ⇒ Boolean
Internal use only
the first timeout so the user knows the merged total is partial.
-
.previous_error?(error_exit_status) ⇒ Boolean
Internal use only
accepts it.
- .process_result(result) Internal use only
- .round_coverage(coverage) Internal use only
- .run_exit_tasks! Internal use only
- .wait_for_other_processes Internal use only Internal use only
-
.wait_for_parallel_results(expected)
Internal use only
before the deadline, false on timeout.
- .warn_about_incomplete_parallel_results(expected, seen) Internal use only Internal use only
-
.with_dot_simplecov_autoload
Internal use only
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)
Internal use only
rounded down (see
#679) so the next run can compute drift.
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 |
| 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 |
| 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 |
| 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, 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, | |
| swap_ivars_from | Copy instance variables from block_context into self, saving any of ours that would be clobbered. |
| validate_per_file_key, | |
| validate_coverage_criteria! | fast when the user has disabled every coverage criterion. |
| store_overall_threshold | write the same |
Class Attribute Details
.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 41
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 50
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 26
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 37
def external_at_exit? !!@external_at_exit end
.final_result_process? ⇒ Boolean (readonly)
# File 'lib/simplecov/parallel_coordination.rb', line 23
def final_result_process? adapter = SimpleCov::ParallelAdapters.current return true unless adapter adapter.first_worker? 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 53
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)
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 116
def ready_to_process_results? final_result_process? && 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 31
def result return @result if result? # Collect our coverage result process_coverage_result 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 merging wait_for_other_processes SimpleCov::ResultMerger.store_result(@result) if result? @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 49
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 118
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 21
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 87
def clear_result @result = nil end
.collate(result_filenames, profile = nil, ignore_timeout: true, &block)
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, &block) raise ArgumentError, "There are no reports to be merged" if result_filenames.empty? initial_setup(profile, &block) # Use the ResultMerger to produce a single, merged result, ready to use. @result = ResultMerger.merge_and_store(*result_filenames, ignore_timeout: ignore_timeout) run_exit_tasks! 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 31
def coverage_statistics_key(criterion) criterion == :oneshot_line ? :line : criterion end
.defer_to_minitest_after_run (private)
[ GitHub ]# File 'lib/simplecov.rb', line 162
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 138
def discover_unloaded_paths(globs) globs.flat_map { |glob| Dir.glob(glob, base: root) }.uniq end
.exit_and_report_previous_error(exit_status)
.exit_status_from_exception
.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 67
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 106
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 142
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 91
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 82
def load_profile(name) profiles.load(name) 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 75
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 (private)
Run all the steps that handle processing the raw coverage result.
# File 'lib/simplecov/result_processing.rb', line 155
def process_coverage_result @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) end
.process_result(result)
# 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)
# File 'lib/simplecov/result_processing.rb', line 100
def round_coverage(coverage) coverage.floor(2) end
.run_exit_tasks!
# File 'lib/simplecov/exit_handling.rb', line 70
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 49
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.1, JRuby >= 9.4, TruffleRuby >= 22) accepts the
criteria-hash form, so no compatibility fallback is needed.
# File 'lib/simplecov.rb', line 138
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 110
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
.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 129
def unloaded_file_discovery_globs [tracked_files, *cover_globs].compact end
.wait_for_other_processes
# File 'lib/simplecov/parallel_coordination.rb', line 31
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.
# File 'lib/simplecov/parallel_coordination.rb', line 60
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_RESULTS_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 57
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)
# File 'lib/simplecov/parallel_coordination.rb', line 83
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_RESULTS_WAIT_TIMEOUT}s. Coverage totals are partial; " \ "minimum / maximum coverage checks are skipped for this run.", :yellow ) end
.warn_about_start_in_dot_simplecov
[ GitHub ]# File 'lib/simplecov.rb', line 72
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 171
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 64
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 93
def write_last_run(result) SimpleCov::LastRun.write( result: result.coverage_statistics.transform_values { |stats| round_coverage(stats.percent) } ) end