-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileCoverage.java
More file actions
134 lines (118 loc) · 4.53 KB
/
Copy pathFileCoverage.java
File metadata and controls
134 lines (118 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package io.github.randomcodespace.sonarpredict.cli.coverage;
import java.util.NavigableSet;
import java.util.TreeSet;
/**
* Line coverage for a single source file: which of its coverable lines were
* exercised by the test suite.
*
* <p>Coverage is held as two line-number sets — the coverable lines and the
* subset of those that were covered — so that two reports covering the same
* file can be merged losslessly: a line covered in <em>either</em> report
* counts as covered (see {@link CoverageImporter}). Parsers that do not retain
* line numbers (none currently) may use {@link #ofCounts} to build an entry
* from bare covered/coverable counts; such an entry cannot be line-merged and
* is treated as opaque.
*/
public final class FileCoverage {
private final String path;
private final NavigableSet<Integer> coverable;
private final NavigableSet<Integer> covered;
// Set only for count-based entries that carry no line identity.
private final int opaqueCovered;
private final int opaqueCoverable;
private final boolean lineAware;
/**
* Builds a line-aware entry from explicit line-number sets.
*
* @param path the source file path, as named by the coverage report
* @param covered the line numbers covered at least once
* @param coverable the line numbers the report considers coverable
*/
public FileCoverage(String path, NavigableSet<Integer> covered,
NavigableSet<Integer> coverable) {
this.path = path;
this.coverable = new TreeSet<>(coverable);
this.covered = new TreeSet<>(covered);
this.covered.retainAll(this.coverable);
this.lineAware = true;
this.opaqueCovered = 0;
this.opaqueCoverable = 0;
}
private FileCoverage(String path, int covered, int coverable) {
if (covered < 0 || coverable < 0) {
throw new IllegalArgumentException(
"coverage counts cannot be negative: " + path);
}
if (covered > coverable) {
throw new IllegalArgumentException(
"covered lines exceed coverable lines: " + path);
}
this.path = path;
this.coverable = new TreeSet<>();
this.covered = new TreeSet<>();
this.lineAware = false;
this.opaqueCovered = covered;
this.opaqueCoverable = coverable;
}
/**
* Builds an opaque, count-only entry — for callers and tests that have only
* aggregate counts and never need line-level merge.
*/
public static FileCoverage ofCounts(String path, int covered, int coverable) {
return new FileCoverage(path, covered, coverable);
}
/** The source file path, as named by the coverage report. */
public String path() {
return path;
}
/** The count of coverable lines hit at least once. */
public int coveredLines() {
return lineAware ? covered.size() : opaqueCovered;
}
/** The count of lines the report considers coverable. */
public int coverableLines() {
return lineAware ? coverable.size() : opaqueCoverable;
}
/** Whether this entry carries line numbers and can be line-merged. */
boolean isLineAware() {
return lineAware;
}
/** The covered line numbers; empty for an opaque entry. */
NavigableSet<Integer> coveredLineNumbers() {
return new TreeSet<>(covered);
}
/** The coverable line numbers; empty for an opaque entry. */
NavigableSet<Integer> coverableLineNumbers() {
return new TreeSet<>(coverable);
}
/**
* The covered fraction as a percentage in {@code [0, 100]}. A file with no
* coverable lines is reported as fully covered (100%) so it never drags a
* merged report below threshold.
*/
public double percent() {
int total = coverableLines();
return total == 0 ? 100.0 : 100.0 * coveredLines() / total;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FileCoverage other)) {
return false;
}
return path.equals(other.path)
&& coveredLines() == other.coveredLines()
&& coverableLines() == other.coverableLines();
}
@Override
public int hashCode() {
return java.util.Objects.hash(path, coveredLines(), coverableLines());
}
@Override
public String toString() {
return "FileCoverage[" + path + ", " + coveredLines()
+ "/" + coverableLines() + "]";
}
}