lib/coverband/collectors/delta.rb
# frozen_string_literal: true
module Coverband
module Collectors
class Delta
@@previous_coverage = {}
@@stubs = {}
attr_reader :current_coverage
def initialize(current_coverage)
@current_coverage = current_coverage
end
class RubyCoverage
def self.results
if Coverband.configuration.use_oneshot_lines_coverage
::Coverage.result(clear: true, stop: false)
else
::Coverage.peek_result
end
end
end
def self.results(process_coverage = RubyCoverage)
coverage_results = process_coverage.results
new(coverage_results).results
end
def results
if Coverband.configuration.use_oneshot_lines_coverage
transform_oneshot_lines_results(current_coverage)
else
new_results = generate
@@previous_coverage = current_coverage unless Coverband.configuration.simulate_oneshot_lines_coverage
new_results
end
end
def self.reset
@@previous_coverage = {}
@@project_directory = File.expand_path(Coverband.configuration.root)
@@ignore_patterns = Coverband.configuration.ignore
end
private
def generate
current_coverage.each_with_object({}) do |(file, line_counts), new_results|
###
# Eager filter:
# Normally I would break this out into additional methods
# and improve the readability but this is in a tight loop
# on the critical performance path, and any refactoring I come up with
# would slow down the performance.
###
next unless @@ignore_patterns.none? { |pattern| file.match(pattern) } &&
file.start_with?(@@project_directory)
# This handles Coverage branch support, setup by default in
# simplecov 0.18.x
arr_line_counts = line_counts.is_a?(Hash) ? line_counts[:lines] : line_counts
new_results[file] = if @@previous_coverage && @@previous_coverage[file]
prev_line_counts = @@previous_coverage[file].is_a?(Hash) ? @@previous_coverage[file][:lines] : @@previous_coverage[file]
array_diff(arr_line_counts, prev_line_counts)
else
arr_line_counts
end
end
end
def array_diff(latest, original)
latest.map.with_index do |v, i|
[0, v - original[i]].max if v && original[i]
end
end
def transform_oneshot_lines_results(results)
results.each_with_object({}) do |(file, coverage), new_results|
###
# Eager filter:
# Normally I would break this out into additional methods
# and improve the readability but this is in a tight loop
# on the critical performance path, and any refactoring I come up with
# would slow down the performance.
###
next unless @@ignore_patterns.none? { |pattern| file.match(pattern) } &&
file.start_with?(@@project_directory)
@@stubs[file] ||= ::Coverage.line_stub(file)
transformed_line_counts = coverage[:oneshot_lines].each_with_object(@@stubs[file].dup) { |line_number, line_counts|
line_counts[line_number - 1] = 1
}
new_results[file] = transformed_line_counts
end
end
end
end
end