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/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/visitor.rb

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

    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 #1065 for the parallel_rspec / GenericAdapter case where there is no native wait primitive and this poll is the only synchronization available.

    # File 'lib/simplecov/parallel_coordination.rb', line 19
    60
  • VERSION =
    # File 'lib/simplecov/version.rb', line 4
    "1.0.0.rc1"

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?,
filters

Returns the list of configured exclusion filters added via skip (or the deprecated add_filter).

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

print_error_status=,
enabled_for_subprocesses?

whether to install the fork hook.

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.

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.

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.

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

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.

[ GitHub ]

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

[ GitHub ]

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

[ GitHub ]

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

def external_at_exit?
  !!@external_at_exit
end

.final_result_process?Boolean (readonly)

This method is for internal use only.
[ GitHub ]

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

[ GitHub ]

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

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)

This method is for internal use only.

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

[ GitHub ]

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

attr_accessor :process_start_time

.ready_to_process_results?Boolean (readonly)

This method is for internal use 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 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)

[ GitHub ]

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

[ GitHub ]

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

[ GitHub ]

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

[ GitHub ]

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

Raises:

  • (ArgumentError)
[ GitHub ]

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

[ GitHub ]

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

[ GitHub ]

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

This method is for internal use only.
[ GitHub ]

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

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

This method is for internal use only.
[ GitHub ]

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

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 54

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

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

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

[ GitHub ]

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

def load_profile(name)
  profiles.load(name)
end

.parallel_wait_timed_out?(deadline, expected, seen) ⇒ Boolean

This method is for internal use only.

the first timeout so the user knows the merged total is partial.

[ GitHub ]

  
# 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

This method is for internal use only.

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 94

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

.process_coverage_result (private)

Run all the steps that handle processing the raw coverage result.

[ GitHub ]

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

This method is for internal use only.
[ 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)

This method is for internal use only.
[ GitHub ]

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

def round_coverage(coverage)
  coverage.floor(2)
end

.run_exit_tasks!

This method is for internal use only.
[ GitHub ]

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

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

[ GitHub ]

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

[ GitHub ]

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

[ GitHub ]

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

def unloaded_file_discovery_globs
  [tracked_files, *cover_globs].compact
end

.wait_for_other_processes

This method is for internal use only.
[ GitHub ]

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

This method is for internal use only.

before the deadline, false on timeout. Single-process runs (expected <= 1) short-circuit to true with no waiting.

[ GitHub ]

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

This method is for internal use only.
[ GitHub ]

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

[ GitHub ]

  
# 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

This method is for internal use only.

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

This method is for internal use only.

rounded down (see #679) so the next run can compute drift.

[ GitHub ]

  
# 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