Class: Henitai::PerTestCoverage

Inherits:
Object
  • Object
show all
Defined in:
lib/henitai/per_test_coverage.rb,
sig/henitai.rbs

Overview

Read-side view of the per-test coverage map (henitai_per_test.json): which test files reach which source lines. The single implementation of the line-intersection check, shared by test selection (PerTestCoverageSelector) and survivor verdict reuse (IncrementalFilter), so both callers always agree on what "covers" means.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(reports_dir:, coverage_report_reader: CoverageReportReader.new) ⇒ PerTestCoverage

Returns a new instance of PerTestCoverage.

Parameters:

  • reports_dir: (String)
  • coverage_report_reader: (CoverageReportReader) (defaults to: CoverageReportReader.new)


10
11
12
13
# File 'lib/henitai/per_test_coverage.rb', line 10

def initialize(reports_dir:, coverage_report_reader: CoverageReportReader.new)
  @reports_dir = reports_dir
  @coverage_report_reader = coverage_report_reader
end

Instance Attribute Details

#coverage_report_readerCoverageReportReader (readonly)

Returns the value of attribute coverage_report_reader.



56
57
58
# File 'lib/henitai/per_test_coverage.rb', line 56

def coverage_report_reader
  @coverage_report_reader
end

#reports_dirString (readonly)

Returns the value of attribute reports_dir.

Returns:

  • (String)


56
57
58
# File 'lib/henitai/per_test_coverage.rb', line 56

def reports_dir
  @reports_dir
end

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/henitai/per_test_coverage.rb', line 15

def available?
  !map.empty?
end

#coverage_lines_for(test, mutant) ⇒ Array[Integer]

Parameters:

  • (String)
  • (Object)

Returns:

  • (Array[Integer])


66
67
68
69
# File 'lib/henitai/per_test_coverage.rb', line 66

def coverage_lines_for(test, mutant)
  source_map = map[test.to_s] || {}
  Array(source_map[File.expand_path(mutant.location[:file])]).uniq
end

#covers?(test, mutant) ⇒ Boolean

True when the given test file's recorded coverage intersects the mutant's current line range.

Parameters:

  • (String)
  • (Object)

Returns:

  • (Boolean)


48
49
50
51
52
# File 'lib/henitai/per_test_coverage.rb', line 48

def covers?(test, mutant)
  return false unless location_available?(mutant)

  coverage_lines_for(test, mutant).intersect?(mutant_lines(mutant))
end

#location_available?(mutant) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


58
59
60
61
62
63
64
# File 'lib/henitai/per_test_coverage.rb', line 58

def location_available?(mutant)
  mutant.respond_to?(:location) &&
    mutant.location.is_a?(Hash) &&
    mutant.location[:file] &&
    mutant.location[:start_line] &&
    mutant.location[:end_line]
end

#mapHash[String, Hash[String, Array[Integer]]]

Returns:

  • (Hash[String, Hash[String, Array[Integer]]])


75
76
77
78
79
# File 'lib/henitai/per_test_coverage.rb', line 75

def map
  @map ||= coverage_report_reader.test_lines_by_file(
    File.join(reports_dir, PerTestCoverageCollector::REPORT_FILE_NAME)
  )
end

#mutant_lines(mutant) ⇒ Array[Integer]

Parameters:

  • (Object)

Returns:

  • (Array[Integer])


71
72
73
# File 'lib/henitai/per_test_coverage.rb', line 71

def mutant_lines(mutant)
  (mutant.location[:start_line]..mutant.location[:end_line]).to_a
end

#source_files_covered_by(test_file) ⇒ Array<String>

The source files the given test file's recorded coverage reaches. Test keys are matched path-insensitively (relative or absolute form); returned source paths are absolute, as recorded.

Parameters:

  • (Object)

Returns:

  • (Array<String>)

    sorted; empty when the test is unknown or the map is unavailable.



37
38
39
40
41
42
43
44
# File 'lib/henitai/per_test_coverage.rb', line 37

def source_files_covered_by(test_file)
  wanted = File.expand_path(test_file.to_s)
  map.select { |test, _| File.expand_path(test) == wanted }
     .values
     .flat_map(&:keys)
     .uniq
     .sort
end

#tests_covering(mutant) ⇒ Array<String>

The full-map intersection set: every test file whose covered lines intersect the mutant's current line range.

Parameters:

  • (Object)

Returns:

  • (Array<String>)

    sorted test file paths; empty when the map or the mutant's location is unavailable — callers must treat that as "unknown", never as "not covered".



25
26
27
28
29
# File 'lib/henitai/per_test_coverage.rb', line 25

def tests_covering(mutant)
  return [] unless location_available?(mutant)

  map.keys.select { |test| covers?(test, mutant) }.sort
end