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 365{ branch: :branches, line: :lines }.freeze
-
VERSION =
# File 'lib/simplecov/version.rb', line 4"0.22.0"
Class Attribute Summary
-
.external_at_exit?
rw
Alias for .external_at_exit.
- .pid rw
-
.result
readonly
Returns the result for the current coverage run, merging it across test suites from cache using
ResultMerger
if use_merging is activated (default). -
.result? ⇒ Boolean
readonly
Returns nil if the result has not been computed Otherwise, returns the result.
- .running rw
- .coverage_running? ⇒ Boolean readonly private
- .probably_running_parallel_tests? ⇒ Boolean readonly private
- .final_result_process? ⇒ Boolean readonly Internal use only Internal use only
- .ready_to_process_results? ⇒ Boolean readonly Internal use only Internal use only
Configuration
- Extended
branch_coverage?, branch_coverage_supported?, coverage_for_eval_enabled?, coverage_for_eval_supported?, coverage_start_arguments_supported?, | |
enabled_for_subprocesses? | gets the enabled_for_subprocess configuration. |
filters | Returns the list of configured filters. |
filters=, | |
formatter | Gets or sets the configured formatter. |
formatter=, | |
formatters | Gets the configured formatters. |
formatters= | Sets the configured formatters. |
groups | Returns the configured groups. |
groups=, | |
print_error_status | Whether we should print non-success status codes. |
print_error_status= |
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
SimpleCov
result files into a singleSimpleCov
output. -
.external_at_exit
(also: .external_at_exit?)
rw
Basically, should we take care of at_exit behavior or something else? Used by the minitest plugin.
-
.filtered(files)
Applies the configured filters to the given array of
SourceFile
items. -
.grouped(files)
Applies the configured groups to the given array of
SourceFile
items. - .load_adapter(name)
-
.load_profile(name)
Applies the profile of given name on
SimpleCov
configuration. - .process_results_and_report_error
- .result_exit_status(result)
-
.start(profile = nil, &block)
Sets up
SimpleCov
to run against your project. -
.adapt_coverage_result ⇒ Hash
private
Unite the result so it wouldn’t matter what coverage type was called.
-
.add_not_loaded_files(result)
private
Finds files that were to be tracked but were not loaded and initializes the line-by-line coverage to zero (if relevant) or nil (comments / whitespace etc).
- .initial_setup(profile, &block) private
- .lookup_corresponding_ruby_coverage_name(criterion) private
-
.make_parallel_tests_available
private
parallel_tests isn’t always available, see: github.com/grosser/parallel_tests/issues/772.
-
.process_coverage_result ⇒ Hash
private
Call steps that handle process coverage result.
-
.remove_useless_results ⇒ Hash
private
Filter
coverage result The result before filter also has result of coverage for files are not related to the project like loaded gems coverage. -
.result_with_not_loaded_files ⇒ Hash
private
Initialize result with files that are not included by coverage and added inside the config block.
-
.start_coverage_measurement
private
Trigger
Coverage.start
depends on given config coverage_criterion. - .start_coverage_with_criteria private
-
.exit_and_report_previous_error(exit_status)
Internal use only
Internal use only
Thinking: Move this behavior earlier so if there was an error we do nothing?
-
.exit_status_from_exception
Internal use only
Internal use only
Returns the exit status from the exit exception.
- .previous_error?(error_exit_status) ⇒ Boolean Internal use only Internal use only
-
.process_result(result)
Internal use only
Internal use only
Usage:
-
.round_coverage(coverage)
Internal use only
Internal use only
Rounding down to be extra strict, see #679.
-
.run_exit_tasks!
Internal use only
Internal use only
Called from at_exit block.
- .wait_for_other_processes Internal use only Internal use only
- .write_last_run(result) Internal use only Internal use only
Configuration
- Extended
adapters, | |
add_filter | Add a filter to the processing chain. |
add_group | Define a group for files. |
at_exit | Gets or sets the behavior to process coverage results. |
at_fork | Gets or sets the behavior to start a new forked |
clear_coverage_criteria, | |
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 |
coverage_criteria, | |
coverage_criterion | Define which coverage criterion should be evaluated. |
coverage_criterion_enabled?, | |
coverage_dir | The name of the output and cache directory. |
coverage_path | Returns the full path to the output directory using |
enable_coverage, enable_coverage_for_eval, | |
enable_for_subprocesses | gets or sets the enabled_for_subprocess configuration when true, this will inject |
maximum_coverage_drop | Defines the maximum coverage drop at once allowed for the testsuite to pass. |
merge_timeout | Defines the maximum age (in seconds) of a resultset to still be included in merged results. |
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. |
nocov_token | Certain code blocks (i.e. Ruby-implementation specific code) can be excluded from the coverage metrics by wrapping it inside # :nocov: comment blocks. |
primary_coverage, | |
profiles | Returns the hash of available profiles. |
project_name | Returns the project name - currently assuming the last dirname in the |
raise_on_invalid_coverage, | |
refuse_coverage_drop | Refuses any coverage drop. |
root | The root for the project. |
skip_token | Alias for Configuration#nocov_token. |
track_files | Coverage results will always include files matched by this glob, whether or not they were explicitly required. |
tracked_files | Returns the glob that will be used to include files that were not explicitly required. |
use_merging | Defines whether to use result merging so all your test suites (test:units, test:functionals, cucumber, …) are joined and combined into a single coverage report. |
minimum_possible_coverage_exceeded, | |
parse_filter | The actual filter processor. |
raise_if_criterion_disabled, raise_if_criterion_unsupported |
Class Attribute Details
.coverage_running? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/simplecov.rb', line 359
def coverage_running? # for ruby versions which do not implement Coverage.running?, # Coverage.start may be called multiple times without raising. Coverage.respond_to?(:running?) && Coverage.running? end
.external_at_exit? (rw)
Alias for .external_at_exit.
# File 'lib/simplecov.rb', line 29
alias external_at_exit? external_at_exit
.final_result_process? ⇒ Boolean
(readonly)
# File 'lib/simplecov.rb', line 268
def final_result_process? # checking for ENV["TEST_ENV_NUMBER"] to determine if the tests are being run in parallel !defined?(ParallelTests) || !ENV["TEST_ENV_NUMBER"] || ParallelTests.last_process? end
.pid (rw)
[ GitHub ]# File 'lib/simplecov.rb', line 24
attr_accessor :running, :pid
.probably_running_parallel_tests? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/simplecov.rb', line 440
def probably_running_parallel_tests? ENV.fetch("TEST_ENV_NUMBER", nil) && ENV.fetch("PARALLEL_TEST_GROUPS", nil) end
.ready_to_process_results? ⇒ Boolean
(readonly)
# File 'lib/simplecov.rb', line 229
def ready_to_process_results? final_result_process? && result? 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.rb', line 101
def result return @result if result? # Collect our coverage result process_coverage_result if 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 wait_for_other_processes SimpleCov::ResultMerger.store_result(@result) if result? @result = SimpleCov::ResultMerger.merged_result end @result ensure self.running = false end
.result? ⇒ Boolean
(readonly)
Returns nil if the result has not been computed Otherwise, returns the result
# File 'lib/simplecov.rb', line 124
def result? defined?(@result) && @result end
.running (rw)
[ GitHub ]# File 'lib/simplecov.rb', line 24
attr_accessor :running, :pid
Class Method Details
.adapt_coverage_result ⇒ Hash
(private)
Unite the result so it wouldn’t matter what coverage type was called
# File 'lib/simplecov.rb', line 405
def adapt_coverage_result @result = SimpleCov::ResultAdapter.call(Coverage.result) end
.add_not_loaded_files(result) (private)
Finds files that were to be tracked but were not loaded and initializes the line-by-line coverage to zero (if relevant) or nil (comments / whitespace etc).
.at_exit_behavior
[ GitHub ]# File 'lib/simplecov.rb', line 174
def at_exit_behavior # If we are in a different process than called start, don't interfere. return if SimpleCov.pid != Process.pid # If SimpleCov is no longer running then don't run exit tasks SimpleCov.run_exit_tasks! if SimpleCov.running end
.clear_result
Clear out the previously cached .result. Primarily useful in testing
# File 'lib/simplecov.rb', line 170
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.
You can optionally specify configuration with a block:
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"]
OR
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"], 'rails' # using rails profile
OR
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"] do
add_filter 'test'
end
OR
SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"], 'rails' do
add_filter 'test'
end
Please check out the RDoc for ::SimpleCov::Configuration
to find about available config options, or checkout the README for more in-depth information about coverage collation
By default collate
ignores the merge_timeout so all results of all files specified will be merged together. If you want to honor the merge_timeout then provide the keyword argument ignore_timeout: false
.
# File 'lib/simplecov.rb', line 86
def collate(result_filenames, profile = nil, ignore_timeout: true, &block) raise "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
.exit_and_report_previous_error(exit_status)
Thinking: Move this behavior earlier so if there was an error we do nothing?
# File 'lib/simplecov.rb', line 223
def exit_and_report_previous_error(exit_status) warn("Stopped processing SimpleCov as a previous error not related to SimpleCov has been detected") if print_error_status Kernel.exit(exit_status) end
.exit_status_from_exception
Returns the exit status from the exit exception
.external_at_exit (rw) Also known as: .external_at_exit?
Basically, 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 28
attr_accessor :external_at_exit
.filtered(files)
Applies the configured filters to the given array of ::SimpleCov::SourceFile
items
.grouped(files)
Applies the configured groups to the given array of ::SimpleCov::SourceFile
items
# File 'lib/simplecov.rb', line 142
def grouped(files) grouped = {} grouped_files = [] groups.each do |name, filter| grouped[name] = SimpleCov::FileList.new(files.select { |source_file| filter.matches?(source_file) }) grouped_files += grouped[name] end if !groups.empty? && !(other_files = files.reject { |source_file| grouped_files.include?(source_file) }).empty? grouped["Ungrouped"] = SimpleCov::FileList.new(other_files) end grouped end
.initial_setup(profile, &block) (private)
[ GitHub ]# File 'lib/simplecov.rb', line 302
def initial_setup(profile, &block) load_profile(profile) if profile configure(&block) if block self.running = true end
.load_adapter(name)
[ GitHub ]# File 'lib/simplecov.rb', line 162
def load_adapter(name) warn "#{Kernel.caller.first}: [DEPRECATION] #load_adapter is deprecated. Use #load_profile instead." load_profile(name) end
.load_profile(name)
Applies the profile of given name on SimpleCov
configuration
# File 'lib/simplecov.rb', line 158
def load_profile(name) profiles.load(name) end
.lookup_corresponding_ruby_coverage_name(criterion) (private)
[ GitHub ]# File 'lib/simplecov.rb', line 369
def lookup_corresponding_ruby_coverage_name(criterion) CRITERION_TO_RUBY_COVERAGE.fetch(criterion) end
.make_parallel_tests_available (private)
parallel_tests isn’t always available, see: github.com/grosser/parallel_tests/issues/772
# File 'lib/simplecov.rb', line 431
def make_parallel_tests_available return if defined?(ParallelTests) return unless probably_running_parallel_tests? require "parallel_tests" rescue LoadError warn("SimpleCov guessed you were running inside parallel tests but couldn't load it. Please file a bug report with us!") end
.previous_error?(error_exit_status) ⇒ Boolean
.process_coverage_result ⇒ Hash
(private)
Call steps that handle process coverage result
# File 'lib/simplecov.rb', line 394
def process_coverage_result adapt_coverage_result remove_useless_results result_with_not_loaded_files end
.process_result(result)
Usage:
exit_status = SimpleCov.process_result(SimpleCov.result, exit_status)
# File 'lib/simplecov.rb', line 248
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.rb', line 233
def process_results_and_report_error exit_status = process_result(result) # Force exit with stored status (see github issue #5) if exit_status.positive? warn("SimpleCov failed with exit #{exit_status} due to a coverage related error") if print_error_status Kernel.exit exit_status end end
.remove_useless_results ⇒ Hash
(private)
::SimpleCov::Filter
coverage result The result before filter also has result of coverage for files are not related to the project like loaded gems coverage.
# File 'lib/simplecov.rb', line 416
def remove_useless_results @result = SimpleCov::UselessResultsRemover.call(@result) end
.result_exit_status(result)
[ GitHub ]# File 'lib/simplecov.rb', line 256
def result_exit_status(result) coverage_limits = CoverageLimits.new( minimum_coverage: minimum_coverage, minimum_coverage_by_file: minimum_coverage_by_file, maximum_coverage_drop: maximum_coverage_drop ) ExitCodes::ExitCodeHandling.call(result, coverage_limits: coverage_limits) end
.result_with_not_loaded_files ⇒ Hash
(private)
Initialize result with files that are not included by coverage and added inside the config block
# File 'lib/simplecov.rb', line 426
def result_with_not_loaded_files @result = SimpleCov::Result.new(add_not_loaded_files(@result)) end
.round_coverage(coverage)
Rounding down to be extra strict, see #679
# File 'lib/simplecov.rb', line 296
def round_coverage(coverage) coverage.floor(2) end
.run_exit_tasks!
Called from at_exit block
# File 'lib/simplecov.rb', line 186
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, &block)
Sets up SimpleCov
to run against your project. You can optionally specify a profile to use as well as configuration with a block:
SimpleCov.start
OR
SimpleCov.start 'rails' # using rails profile
OR
SimpleCov.start do
add_filter 'test'
end
OR
SimpleCov.start 'rails' do
add_filter 'test'
end
Please check out the RDoc for ::SimpleCov::Configuration
to find about available config options
# File 'lib/simplecov.rb', line 48
def start(profile = nil, &block) require "coverage" initial_setup(profile, &block) require_relative "simplecov/process" if SimpleCov.enabled_for_subprocesses? && ::Process.respond_to?(:fork) make_parallel_tests_available @result = nil self.pid = Process.pid start_coverage_measurement end
.start_coverage_measurement (private)
Trigger Coverage.start
depends on given config coverage_criterion
With Positive branch it supports all coverage measurement types With Negative branch it supports only line coverage measurement type
# File 'lib/simplecov.rb', line 314
def start_coverage_measurement # This blog post gives a good run down of the coverage criterias introduced # in Ruby 2.5: https://blog.bigbinary.com/2018/04/11/ruby-2-5-supports-measuring-branch-and-method-coverages.html # There is also a nice writeup of the different coverage criteria made in this # comment https://github.com/simplecov-ruby/simplecov/pull/692#discussion_r281836176 : # Ruby < 2.5: # https://github.com/ruby/ruby/blob/v1_9_3_374/ext/coverage/coverage.c # traditional mode (Array) # # Ruby 2.5: # https://bugs.ruby-lang.org/issues/13901 # https://github.com/ruby/ruby/blob/v2_5_3/ext/coverage/coverage.c # default: traditional/compatible mode (Array) # :lines - like traditional mode but using Hash # :branches # :methods # :all - same as lines + branches + methods # # Ruby >= 2.6: # https://bugs.ruby-lang.org/issues/15022 # https://github.com/ruby/ruby/blob/v2_6_3/ext/coverage/coverage.c # default: traditional/compatible mode (Array) # :lines - like traditional mode but using Hash # :branches # :methods # :oneshot_lines - can not be combined with lines # :all - same as lines + branches + methods # if coverage_start_arguments_supported? start_coverage_with_criteria else Coverage.start unless coverage_running? end end
.start_coverage_with_criteria (private)
[ GitHub ]# File 'lib/simplecov.rb', line 349
def start_coverage_with_criteria start_arguments = coverage_criteria.map do |criterion| [lookup_corresponding_ruby_coverage_name(criterion), true] end.to_h start_arguments[:eval] = true if coverage_for_eval_enabled? Coverage.start(start_arguments) unless coverage_running? end
.wait_for_other_processes
# File 'lib/simplecov.rb', line 276
def wait_for_other_processes return unless defined?(ParallelTests) && final_result_process? ParallelTests.wait_for_other_processes_to_finish end
.write_last_run(result)
# File 'lib/simplecov.rb', line 285
def write_last_run(result) SimpleCov::LastRun.write(result: result.coverage_statistics.transform_values do |stats| round_coverage(stats.percent) end) end