Module: SimpleCov::Combine::BranchesCombiner

Defined in:
lib/simplecov/combine/branches_combiner.rb

Overview

Combine different branch coverage results on single file.

Should be called through CoverageAccumulator.

Class Method Summary collapse

Class Method Details

.absorb(target, coverage) ⇒ Hash

Folds coverage into target, an interned table keyed by condition identity. Kept interned (rather than turned back into tuple keys per merge) so a fold over N resultsets interns each condition once instead of re-interning the whole accumulated table N times.

Returns:

  • (Hash)

    target



39
40
41
42
43
44
45
46
47
48
# File 'lib/simplecov/combine/branches_combiner.rb', line 39

def absorb(target, coverage)
  return target unless coverage

  coverage.each do |condition, branches_inside|
    entry = target[identities[condition]] ||= new_condition(condition)
    InternedCounts.absorb_counts(entry[1], branches_inside, identities)
  end

  target
end

.combine(coverage_a, coverage_b) ⇒ Hash

Return merged branches or the existed branch if other is missing.

Branches inside files are always same if they exist, the difference only in coverage count. Branch coverage report for any conditional case is built from hash, it's key is a condition and it's body is a hash << keys from condition and value is coverage rate >>. ex: branches => { [:if, 3, 8, 6, 8, 36] => 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2, ... } We create copy of result and update it values depending on the combined branches coverage values.

Returns:

  • (Hash)


28
29
30
31
# File 'lib/simplecov/combine/branches_combiner.rb', line 28

def combine(coverage_a, coverage_b)
  merged = absorb({}, coverage_a) #: Hash[untyped, [untyped, Hash[untyped, untyped]]]
  materialize(absorb(merged, coverage_b))
end

.identitiesObject

Bounded by the project's branch count, like RubyDataParser's parse cache.



67
68
69
# File 'lib/simplecov/combine/branches_combiner.rb', line 67

def identities
  @identities ||= IdentityInterner.build { |tuple| tuple_identity(tuple) }
end

.materialize(target) ⇒ Hash

Turns an interned table back into the tuple-keyed hash the rest of SimpleCov reads. Done once, at the end of a fold.

Returns:

  • (Hash)


61
62
63
# File 'lib/simplecov/combine/branches_combiner.rb', line 61

def materialize(target)
  target.values.to_h { |condition, branches| [condition, branches.values.to_h] }
end

.new_condition(condition) ⇒ Object

Split out so the empty arm table has somewhere to carry its type annotation. Only allocated the first time a condition is seen.



52
53
54
55
# File 'lib/simplecov/combine/branches_combiner.rb', line 52

def new_condition(condition)
  arms = {} #: Hash[untyped, untyped]
  [condition, arms]
end

.tuple_identity(tuple) ⇒ Object

Branches match on source span, whatever ids the recording processes handed them (issue #1233).



73
74
75
76
# File 'lib/simplecov/combine/branches_combiner.rb', line 73

def tuple_identity(tuple)
  type, _id, start_line, start_column, end_line, end_column = SourceFile::RubyDataParser.call(tuple)
  [type, start_line, start_column, end_line, end_column].freeze
end