# frozen_string_literal: true
# Outputs data in json format similar to what is shown in the HTML page
# Top level and file level coverage numbers
module Coverband
module Reporters
class JSONReport < Base
attr_accessor :filtered_report_files, :options, :page, :as_report, :store, :filename, :base_path, :line_coverage,
:for_merged_report
def initialize(store, options = {})
self.options = options
self.page = options.fetch(:page) { nil }
self.filename = options.fetch(:filename) { nil }
self.as_report = options.fetch(:as_report) { false }
self.line_coverage = options.fetch(:line_coverage) { false }
self.for_merged_report = options.fetch(:for_merged_report) { false }
self.base_path = options.fetch(:base_path) { "./" }
self.store = store
coverband_reports = Coverband::Reporters::Base.report(store, options)
# NOTE: paged reports can't find and add in files that has never been loaded
self.filtered_report_files = if page || filename
coverband_reports
else
self.class.fix_reports(coverband_reports)
end
end
def report
report_as_json
end
def merge_reports(first_report, second_report, options = {})
merged_data = {}
merged_data[Coverband::RUNTIME_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::RUNTIME_TYPE.to_s],
second_report[Coverband::RUNTIME_TYPE.to_s],
{skip_expansion: true}
)
if first_report[Coverband::EAGER_TYPE.to_s] && second_report[Coverband::EAGER_TYPE.to_s]
merged_data[Coverband::EAGER_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::EAGER_TYPE.to_s],
second_report[Coverband::EAGER_TYPE.to_s],
{skip_expansion: true}
)
end
if first_report[Coverband::MERGED_TYPE.to_s] && second_report[Coverband::MERGED_TYPE.to_s]
merged_data[Coverband::MERGED_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::MERGED_TYPE.to_s],
second_report[Coverband::MERGED_TYPE.to_s],
{skip_expansion: true}
)
end
merged_data
end
private
def coverage_css_class(covered_percent)
if covered_percent.nil?
""
elsif covered_percent > 90
"green"
elsif covered_percent > 80
"yellow"
else
"red"
end
end
def report_as_json
return filtered_report_files.to_json if for_merged_report
result = Coverband::Utils::Results.new(filtered_report_files)
source_files = result.source_files
data = {
**coverage_totals(source_files),
files: coverage_files(result, source_files)
}
if as_report
row_data = []
data[:files].each_pair do |key, data|
source_class = data[:never_loaded] ? "strong red" : "strong"
data_loader_url = "#{base_path}load_file_details?filename=#{data[:filename]}"
link = "#{key}"
# Hack to ensure the sorting works on percentage columns, the span is hidden but colors the cell and the text is used for sorting
covered_percent = "#{data[:covered_percent]} "
runtime_percentage = "#{data[:runtime_percentage]} "
row_data << [
link,
covered_percent,
runtime_percentage,
data[:lines_of_code].to_s,
(data[:lines_covered] + data[:lines_missed]).to_s,
data[:lines_covered].to_s,
data[:lines_runtime].to_s,
data[:lines_missed].to_s,
data[:covered_strength].to_s
]
end
filesreported = store.cached_file_count
data["iTotalRecords"] = filesreported
data["iTotalDisplayRecords"] = filesreported
data["aaData"] = row_data
data.delete(:files)
data = data.as_json
end
data.to_json
end
def coverage_totals(source_files)
{
total_files: source_files.length,
lines_of_code: source_files.lines_of_code,
lines_covered: source_files.covered_lines,
lines_missed: source_files.missed_lines,
covered_strength: source_files.covered_strength,
covered_percent: source_files.covered_percent
}
end
# Using a hash indexed by file name for quick lookups
def coverage_files(result, source_files)
source_files.each_with_object({}) do |source_file, hash|
runtime_coverage = result.file_with_type(source_file, Coverband::RUNTIME_TYPE)&.covered_lines_count || 0
data = {
filename: source_file.filename,
hash: Digest::SHA1.hexdigest(source_file.filename),
never_loaded: source_file.never_loaded,
runtime_percentage: result.runtime_relevant_coverage(source_file),
lines_of_code: source_file.lines.count,
lines_covered: source_file.covered_lines.count,
lines_runtime: runtime_coverage,
lines_missed: source_file.missed_lines.count,
covered_percent: source_file.covered_percent,
covered_strength: source_file.covered_strength
}
data[:coverage] = source_file.coverage if line_coverage
hash[source_file.short_name] = data
end
end
end
end
end