123456789_123456789_123456789_123456789_123456789_

Module: SimpleCov

Relationships & Source Files
Namespace Children
Modules:
Classes:
Exceptions:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: lib/simplecov.rb,
lib/simplecov/cli.rb,
lib/simplecov/color.rb,
lib/simplecov/combine.rb,
lib/simplecov/command_guesser.rb,
lib/simplecov/configuration.rb,
lib/simplecov/coverage_statistics.rb,
lib/simplecov/coverage_violations.rb,
lib/simplecov/deprecation.rb,
lib/simplecov/directive.rb,
lib/simplecov/exit_codes.rb,
lib/simplecov/exit_handling.rb,
lib/simplecov/file_list.rb,
lib/simplecov/filter.rb,
lib/simplecov/formatter.rb,
lib/simplecov/last_run.rb,
lib/simplecov/lines_classifier.rb,
lib/simplecov/parallel_adapters.rb,
lib/simplecov/parallel_coordination.rb,
lib/simplecov/process.rb,
lib/simplecov/profiles.rb,
lib/simplecov/result.rb,
lib/simplecov/result_adapter.rb,
lib/simplecov/result_merger.rb,
lib/simplecov/result_processing.rb,
lib/simplecov/simulate_coverage.rb,
lib/simplecov/source_file.rb,
lib/simplecov/static_coverage_extractor.rb,
lib/simplecov/useless_results_remover.rb,
lib/simplecov/version.rb,
lib/simplecov/cli/clean.rb,
lib/simplecov/cli/coverage.rb,
lib/simplecov/cli/diff.rb,
lib/simplecov/cli/dotfile.rb,
lib/simplecov/cli/merge.rb,
lib/simplecov/cli/open.rb,
lib/simplecov/cli/report.rb,
lib/simplecov/cli/run.rb,
lib/simplecov/cli/serve.rb,
lib/simplecov/cli/uncovered.rb,
lib/simplecov/combine/branches_combiner.rb,
lib/simplecov/combine/files_combiner.rb,
lib/simplecov/combine/lines_combiner.rb,
lib/simplecov/combine/methods_combiner.rb,
lib/simplecov/combine/results_combiner.rb,
lib/simplecov/configuration/coverage.rb,
lib/simplecov/configuration/coverage_criteria.rb,
lib/simplecov/configuration/filters.rb,
lib/simplecov/configuration/formatting.rb,
lib/simplecov/configuration/ignored_entries.rb,
lib/simplecov/configuration/merging.rb,
lib/simplecov/configuration/thresholds.rb,
lib/simplecov/exit_codes/exit_code_handling.rb,
lib/simplecov/exit_codes/maximum_coverage_drop_check.rb,
lib/simplecov/exit_codes/maximum_overall_coverage_check.rb,
lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb,
lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb,
lib/simplecov/exit_codes/minimum_overall_coverage_check.rb,
lib/simplecov/formatter/base.rb,
lib/simplecov/formatter/html_formatter.rb,
lib/simplecov/formatter/json_formatter.rb,
lib/simplecov/formatter/multi_formatter.rb,
lib/simplecov/formatter/simple_formatter.rb,
lib/simplecov/formatter/json_formatter/errors_formatter.rb,
lib/simplecov/formatter/json_formatter/result_hash_formatter.rb,
lib/simplecov/formatter/json_formatter/source_file_formatter.rb,
lib/simplecov/parallel_adapters/base.rb,
lib/simplecov/parallel_adapters/generic.rb,
lib/simplecov/parallel_adapters/parallel_tests.rb,
lib/simplecov/result/missing_source_files_reporter.rb,
lib/simplecov/result/source_file_builder.rb,
lib/simplecov/result_merger/legacy_format_adapter.rb,
lib/simplecov/result_merger/resultset_file.rb,
lib/simplecov/result_merger/resultset_store.rb,
lib/simplecov/source_file/branch.rb,
lib/simplecov/source_file/branch_builder.rb,
lib/simplecov/source_file/builder_context.rb,
lib/simplecov/source_file/line.rb,
lib/simplecov/source_file/line_builder.rb,
lib/simplecov/source_file/method.rb,
lib/simplecov/source_file/method_builder.rb,
lib/simplecov/source_file/ruby_data_parser.rb,
lib/simplecov/source_file/skip_chunks.rb,
lib/simplecov/source_file/source_loader.rb,
lib/simplecov/source_file/statistics.rb,
lib/simplecov/static_coverage_extractor/method_collector.rb,
lib/simplecov/static_coverage_extractor/visitor.rb

Overview

Code coverage for ruby. Please check out README for a full introduction.

Constant Summary

Class Attribute Summary

Configuration - Extended

active_session?

Whether SimpleCov has anything to do at exit: the Coverage module is actively tracking, or a @result has already been assembled (e.g.

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 skip (or the deprecated add_filter).

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_errors.

print_error_status=, explicit_coverage_destination?, explicit_custom_coverage_destination?, inferred_finalize_merge?, parallel_worker_environment?

Class Method Summary

Configuration - Extended

add_filter

DEPRECATED: alias for skip.

add_group

DEPRECATED: alias for group.

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 (Set[:line]).

clear_filters

Remove every filter from the chain, including the defaults installed by .start.

color

Get or set whether SimpleCov colorizes its stderr diagnostics.

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 SimpleCov to each config method.

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.

cover_globs

Returns the list of string globs passed to cover — used by the disk-discovery pass in .add_not_loaded_files so files matching a cover glob appear in the report even when they were never required during the suite.

coverage

Configure (and, unless enabled: false, enable) a coverage criterion.

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 SimpleCov to recognise # :nocov: markers without emitting the public-API deprecation warning.

disable_coverage

Remove criterion from the set of enabled coverage criteria.

enable_coverage

Enable one or more coverage criteria.

enable_coverage_for_eval

DEPRECATED: prefer enable_coverage :eval.

enable_for_subprocesses

DEPRECATED: alias for merge_subprocesses.

expected_coverage

Pins the suite to an exact coverage figure by setting both minimum_coverage and maximum_coverage.

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 .last_run.json.

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 ignore_branches.

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 SimpleCov should hook Process._fork to attach itself to subprocesses.

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_file.

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 skip calls start from a clean slate.

nocov_token

DEPRECATED: configure # :nocov: token override.

parallel_tests

Get or set whether SimpleCov should auto-require the parallel_tests gem when it sees TEST_ENV_NUMBER / PARALLEL_TEST_GROUPS in the environment.

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 SimpleCov prints its own diagnostic warnings to stderr.

profiles

Returns the hash of available profiles.

project_name

Returns the project name — defaults to the last dirname in SimpleCov.root, capitalized with underscores → spaces.

raise_on_invalid_coverage,
refuse_coverage_drop

Refuses any coverage drop.

remove_filter

Remove any filters whose filter_argument equals the given value.

root

The root for the project.

skip

Drop matching files from the coverage report.

skip_token
source_in_json

Get or set whether coverage.json includes the full source-text array for every file.

track_files

DEPRECATED: prefer cover, which both includes unloaded files (the historical track_files behavior) and restricts the report to the matching set.

track_files_replacement_hint

track_files(nil) is the documented way to clear a previously-set glob, but cover(nil) raises ConfigurationError, so don't point users at it.

tracked_files

Returns the glob used to include files that were not explicitly required.

use_merging

DEPRECATED: alias for merging.

validate_coverage_criteria!

fast when the user has disabled every coverage criterion.

apply_threshold_options

Forward the one-liner threshold keywords (coverage <code>:branch</code>, minimum: 80) to the matching CoverageCriterion verbs, rejecting anything that isn't a recognized threshold option.

build_cover_filter

Build a filter for a cover argument.

collect_cover_globs

Walk a list of cover filters and return the string globs they hold, descending into ArrayFilter wrappers built by cover(["a", "b"]).

default_primary_coverage

If :line is enabled, it's the default primary; otherwise fall back to whichever criterion the user actually enabled (in insertion order).

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_coverage :eval and the deprecated enable_coverage_for_eval.

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 minimum_coverage_by_file argument into Symbol-keyed criterion defaults and String/Regexp-keyed per-path overrides; normalize Numeric override values to {primary_coverage => N} so downstream code only has one shape to handle.

per_file_coverage_replacement

Render the coverage configuration equivalent to a (deprecated) minimum_coverage_by_file argument so the deprecation warning can be copy-pasted verbatim into the user's config.

per_group_coverage_replacement

Same, for a (deprecated) minimum_coverage_by_group argument.

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 @minimum_coverage / @maximum_coverage / ...

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)

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# File 'lib/simplecov.rb', line 68

def external_at_exit?
  !!@external_at_exit
end

.final_result_process?Boolean (readonly)

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# File 'lib/simplecov.rb', line 186

def minitest_autorun_pending?
  return false unless defined?(Minitest) && Minitest.respond_to?(:after_run)
  return false unless Minitest.class_variable_defined?(:@@installed_at_exit)

  Minitest.class_variable_get(:@@installed_at_exit)
end

.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).

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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)

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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).

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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 ]

  
# File 'lib/simplecov/exit_handling.rb', line 98

def exit_and_report_previous_error(exit_status)
  if print_errors
    warn SimpleCov::Color.colorize(
      "Stopped processing SimpleCov as a previous error not related to SimpleCov has been detected",
      :yellow
    )
  end
  Kernel.exit(exit_status)
end

.exit_status_from_exception

[ GitHub ]

  
# File 'lib/simplecov/exit_handling.rb', line 79

def exit_status_from_exception
  @exit_exception = $ERROR_INFO
  return nil unless @exit_exception

  if @exit_exception.is_a?(SystemExit)
    @exit_exception.status
  else
    SimpleCov::ExitCodes::EXCEPTION
  end
end

.filtered(files)

Applies the configured filters to the given array of ::SimpleCov::SourceFile items

[ GitHub ]

  
# File 'lib/simplecov/result_processing.rb', line 68

def filtered(files)
  result = files.clone
  filters.each do |filter|
    result = result.reject { |source_file| filter.matches?(source_file) }
  end
  SimpleCov::FileList.new result
end

.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.

[ GitHub ]

  
# 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 ]

  
# File 'lib/simplecov/result_processing.rb', line 125

def grouped_file_set(grouped)
  grouped.values.each_with_object(Set.new) { |file_list, set| set.merge(file_list) }
end

.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.expand_path(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.

[ GitHub ]

  
# 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

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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".

[ GitHub ]

  
# File 'lib/simplecov/exit_handling.rb', line 93

def previous_error?(error_exit_status)
  !!(error_exit_status && error_exit_status != SimpleCov::ExitCodes::SUCCESS)
end

.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.

[ GitHub ]

  
# 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
[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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!).

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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

Mark the duration of a .simplecov auto-load so any .start call inside the file can warn about the impending migration to a config-only file. Tracking still begins for backward compatibility; the warning is the cue to move .start into a test helper. See #581.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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