Skip to content

Commit 6e7a9ab

Browse files
committed
Use CoverageData everywhere for consistency
This allows us to get rid off duplicated and inconsistent calculations. As a side effect of this, #565 is fixed now. So, fixes #565. The bigger purpose is multi step though where the access to coverage data is normalized and hence methods that work with expecting a minimum amount of coverage and formatters can work with the known good same data base as opposed to memoizing all different method names. At first I wanted to only do it for FileList and leave the rest for later. But the strength computation needed the total number of lines of code and so to pass it in I'd have had to calculate it but I wanted to calculate it only in CoverageData and there the avalanche started.... Commit also includes moving methods around in SourceFile to be private - it happened in the moment, forgive me for no extra commit (it was hard to determine what I could delete/what I need to adjust etc.).
1 parent badb052 commit 6e7a9ab

File tree

4 files changed

+174
-159
lines changed

4 files changed

+174
-159
lines changed

lib/simplecov/coverage_data.rb

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,44 @@ module SimpleCov
1313
class CoverageData
1414
attr_reader :total, :covered, :missed, :strength, :percent
1515

16+
def self.from(coverage_data)
17+
sum_covered, sum_missed, sum_total_strength =
18+
coverage_data.reduce([0, 0, 0.0]) do |(covered, missed, total_strength), file_coverage_data|
19+
[
20+
covered + file_coverage_data.covered,
21+
missed + file_coverage_data.missed,
22+
# gotta remultiply with loc because files have different strenght and loc
23+
# giving them a different "weight" in total
24+
total_strength + (file_coverage_data.strength * file_coverage_data.total)
25+
]
26+
end
27+
28+
new(covered: sum_covered, missed: sum_missed, total_strength: sum_total_strength)
29+
end
30+
1631
# Requires only covered, missed and strength to be initialized.
1732
#
1833
# Other values are computed by this class.
19-
def initialize(covered:, missed:, strength: nil)
34+
def initialize(covered:, missed:, total_strength: 0.0)
2035
@covered = covered
2136
@missed = missed
22-
@strength = strength
2337
@total = covered + missed
2438
@percent = compute_percent(covered, total)
39+
@strength = compute_strength(total_strength, @total)
2540
end
2641

42+
private
43+
2744
def compute_percent(covered, total)
2845
return 100.0 if total.zero?
2946

3047
Float(covered * 100.0 / total)
3148
end
49+
50+
def compute_strength(total_strength, total)
51+
return 0.0 if total.zero?
52+
53+
Float(total_strength.to_f / total)
54+
end
3255
end
3356
end

lib/simplecov/file_list.rb

Lines changed: 19 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class FileList
1313
# also delegating methods implemented in Enumerable as they have
1414
# custom Array implementations which are presumably better/more
1515
# resource efficient
16-
:size, :map,
16+
:size, :map, :count,
1717
# surprisingly not in Enumerable
1818
:empty?, :length,
1919
# still act like we're kinda an array
@@ -24,24 +24,17 @@ def initialize(files)
2424
end
2525

2626
def coverage
27-
{
28-
**line_coverage,
29-
**branch_coverage
30-
}
27+
@coverage ||= compute_coverage
3128
end
3229

3330
# Returns the count of lines that have coverage
3431
def covered_lines
35-
return 0.0 if empty?
36-
37-
map { |f| f.covered_lines.count }.inject(:+)
32+
coverage[:line]&.covered
3833
end
3934

4035
# Returns the count of lines that have been missed
4136
def missed_lines
42-
return 0.0 if empty?
43-
44-
map { |f| f.missed_lines.count }.inject(:+)
37+
coverage[:line]&.missed
4538
end
4639

4740
# Returns the count of lines that are not relevant for coverage
@@ -71,75 +64,51 @@ def least_covered_file
7164

7265
# Returns the overall amount of relevant lines of code across all files in this list
7366
def lines_of_code
74-
covered_lines + missed_lines
67+
coverage[:line]&.total
7568
end
7669

7770
# Computes the coverage based upon lines covered and lines missed
7871
# @return [Float]
7972
def covered_percent
80-
percent(covered_lines, lines_of_code)
73+
coverage[:line]&.percent
8174
end
8275

8376
# Computes the strength (hits / line) based upon lines covered and lines missed
8477
# @return [Float]
8578
def covered_strength
86-
return 0.0 if empty? || lines_of_code.zero?
87-
88-
Float(map { |f| f.covered_strength * f.lines_of_code }.inject(:+) / lines_of_code)
79+
coverage[:line]&.strength
8980
end
9081

9182
# Return total count of branches in all files
9283
def total_branches
93-
return 0 if empty?
94-
95-
map { |file| file.total_branches.count }.inject(:+)
84+
coverage[:branch]&.total
9685
end
9786

9887
# Return total count of covered branches
9988
def covered_branches
100-
return 0 if empty?
101-
102-
map { |file| file.covered_branches.count }.inject(:+)
89+
coverage[:branch]&.covered
10390
end
10491

10592
# Return total count of covered branches
10693
def missed_branches
107-
return 0 if empty?
108-
109-
map { |file| file.missed_branches.count }.inject(:+)
94+
coverage[:branch]&.missed
11095
end
11196

11297
def branch_covered_percent
113-
percent(covered_branches, total_branches)
98+
coverage[:branch]&.percent
11499
end
115100

116101
private
117102

118-
def percent(covered, total)
119-
return 100.0 if empty? || total.zero?
120-
121-
Float(covered * 100.0 / total)
122-
end
123-
124-
def line_coverage
125-
{
126-
line: CoverageData.new(
127-
strength: covered_strength,
128-
covered: covered_lines,
129-
missed: missed_lines
130-
)
131-
}
132-
end
133-
134-
def branch_coverage
135-
return nil unless SimpleCov.branch_coverage?
103+
def compute_coverage
104+
total_coverage_data = @files.each_with_object(line: [], branch: []) do |file, together|
105+
together[:line] << file.coverage[:line]
106+
together[:branch] << file.coverage[:branch] if SimpleCov.branch_coverage?
107+
end
136108

137-
{
138-
branch: CoverageData.new(
139-
covered: covered_branches,
140-
missed: missed_branches
141-
)
142-
}
109+
coverage_data = {line: CoverageData.from(total_coverage_data[:line])}
110+
coverage_data[:branch] = CoverageData.from(total_coverage_data[:branch]) if SimpleCov.branch_coverage?
111+
coverage_data
143112
end
144113
end
145114
end

0 commit comments

Comments
 (0)