module SimpleCov::CoverageViolations
def compute_drop(criterion, result, last_run)
def compute_drop(criterion, result, last_run) stats_key = SimpleCov.coverage_statistics_key(criterion) last_coverage_percent = last_run.dig(:result, stats_key) last_coverage_percent ||= last_run.dig(:result, :covered_percent) if stats_key == :line return unless last_coverage_percent current = percent_for(result, criterion) or return (last_coverage_percent - current).floor(10) end
def effective_per_file_thresholds(file, defaults, overrides)
most-specific or latest-declared override wins per criterion). Returns
the file's project path into the running effective threshold (so the
Walk the overrides in declaration order, merging each one that matches
def effective_per_file_thresholds(file, defaults, overrides) return defaults if overrides.empty? path = file.project_filename overrides.reduce(defaults) do |acc, (pattern, criterion_thresholds)| path_matches?(path, pattern) ? acc.merge(criterion_thresholds) : acc end end
def file_minimum_violation(file, criterion, expected)
def file_minimum_violation(file, criterion, expected) actual = percent_for(file, criterion) or return return unless actual < expected { criterion: criterion, expected: expected, actual: actual, filename: file.filename, project_filename: file.project_filename } end
def group_minimum_violations(group_name, group, minimums)
def group_minimum_violations(group_name, group, minimums) minimums.filter_map do |criterion, expected| actual = percent_for(group, criterion) or next {group_name: group_name, criterion: criterion, expected: expected, actual: actual} if actual < expected end end
def lookup_group(result, group_name)
def lookup_group(result, group_name) group = result.groups[group_name] unless group warn "minimum_coverage_by_group: no group named '#{group_name}' exists. " \ "Available groups: #{result.groups.keys.join(', ')}" end group end
def maximum_drop(result, thresholds, last_run: SimpleCov::LastRun.read)
-
(Array- {:criterion, :maximum, :actual} where `actual`)
def maximum_drop(result, thresholds, last_run: SimpleCov::LastRun.read) return [] unless last_run thresholds.filter_map do |criterion, maximum| actual = compute_drop(criterion, result, last_run) {criterion: criterion, maximum: maximum, actual: actual} if actual && actual > maximum end end
def maximum_overall(result, thresholds)
-
(Array- {:criterion, :expected, :actual})
def maximum_overall(result, thresholds) thresholds.filter_map do |criterion, expected| actual = percent_for(result, criterion) or next {criterion: criterion, expected: expected, actual: actual} if actual > expected end end
def minimum_by_file(result, defaults, overrides = {})
-
(Array- {:criterion, :expected, :actual, :filename, :project_filename})
def minimum_by_file(result, defaults, overrides = {}) result.files.flat_map do |file| effective = effective_per_file_thresholds(file, defaults, overrides) effective.filter_map { |criterion, expected| file_minimum_violation(file, criterion, expected) } end end
def minimum_by_group(result, thresholds)
-
(Array- {:group_name, :criterion, :expected, :actual})
def minimum_by_group(result, thresholds) thresholds.flat_map do |group_name, minimums| group = lookup_group(result, group_name) none = [] # : Array[Hash[Symbol, untyped]] group ? group_minimum_violations(group_name, group, minimums) : none end end
def minimum_overall(result, thresholds)
-
(Array- {:criterion, :expected, :actual})
def minimum_overall(result, thresholds) thresholds.filter_map do |criterion, expected| actual = percent_for(result, criterion) or next {criterion: criterion, expected: expected, actual: actual} if actual < expected end end
def path_matches?(project_filename, pattern)
The configuration setter rejects anything other than String/Regexp,
match `project_filename` exactly. Regexps are tested via `match?`.
ending in `/` are treated as directory prefixes; otherwise they must
Per-path matching for `minimum_coverage_by_file` overrides. Strings
def path_matches?(project_filename, pattern) return project_filename.match?(pattern) if pattern.is_a?(Regexp) return project_filename.start_with?(pattern) if pattern.end_with?("/") project_filename == pattern end
def percent_for(stats_source, criterion)
`raise_if_criterion_disabled` check still catches the genuine
module doesn't emit branch data). The config-time
100` under the "strict" profile on JRuby, where the Coverage
actually measured by the runtime (e.g. `minimum_coverage branch:
caller silently skips — when the criterion was configured but not
object (Result, SourceFile, FileList). Returns nil — and the
Look up a criterion's percent on any coverage_statistics-bearing
def percent_for(stats_source, criterion) stats = stats_source.coverage_statistics[SimpleCov.coverage_statistics_key(criterion)] round(stats.percent) if stats end
def round(percent)
def round(percent) SimpleCov.round_coverage(percent) end