Skip to content

Commit 223a6c3

Browse files
committed
Fix case-sensitive treatment of file names in coverage reports
File names are now treated as case-insensitive on windows.
1 parent 0eec50a commit 223a6c3

File tree

5 files changed

+111
-7
lines changed

5 files changed

+111
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Incorrect case-sensitive treatment of file names in coverage reports.
13+
1014
## [1.12.1] - 2024-12-06
1115

1216
### Fixed

delphi-frontend/src/main/java/au/com/integradev/delphi/coverage/DelphiCodeCoverageParser.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424

2525
import au.com.integradev.delphi.msbuild.DelphiProjectHelper;
2626
import com.google.common.base.Splitter;
27+
import com.google.common.base.Suppliers;
28+
import com.google.common.collect.ImmutableSortedMap;
2729
import java.io.File;
30+
import java.util.Map;
31+
import java.util.function.Supplier;
2832
import javax.xml.XMLConstants;
2933
import javax.xml.parsers.DocumentBuilder;
3034
import javax.xml.parsers.DocumentBuilderFactory;
@@ -42,9 +46,19 @@
4246
public class DelphiCodeCoverageParser implements DelphiCoverageParser {
4347
private static final Logger LOG = LoggerFactory.getLogger(DelphiCodeCoverageParser.class);
4448
private final DelphiProjectHelper delphiProjectHelper;
49+
private final Supplier<Map<String, InputFile>> fileNameToInputFile;
4550

4651
public DelphiCodeCoverageParser(DelphiProjectHelper delphiProjectHelper) {
4752
this.delphiProjectHelper = delphiProjectHelper;
53+
this.fileNameToInputFile = Suppliers.memoize(this::indexInputFiles);
54+
}
55+
56+
private Map<String, InputFile> indexInputFiles() {
57+
var builder = ImmutableSortedMap.<String, InputFile>orderedBy(String.CASE_INSENSITIVE_ORDER);
58+
for (InputFile inputFile : delphiProjectHelper.inputFiles()) {
59+
builder.put(inputFile.filename(), inputFile);
60+
}
61+
return builder.build();
4862
}
4963

5064
@Override
@@ -89,12 +103,12 @@ private void parseReportFile(SensorContext sensorContext, File reportFile) {
89103

90104
private void parseFileNode(SensorContext sensorContext, Node srcFile) {
91105
String fileName = srcFile.getAttributes().getNamedItem("name").getTextContent();
92-
InputFile sourceFile = delphiProjectHelper.getFileFromBasename(fileName);
93-
106+
InputFile sourceFile = fileNameToInputFile.get().get(fileName);
94107
if (sourceFile == null) {
95108
LOG.debug("File not found in project: {}", fileName);
96109
return;
97110
}
111+
98112
LOG.debug("Parsing line hit information for file: {}", fileName);
99113

100114
NewCoverage newCoverage = sensorContext.newCoverage();

delphi-frontend/src/main/java/au/com/integradev/delphi/msbuild/DelphiProjectHelper.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,6 @@ public InputFile getFile(String path) {
365365
return fs.inputFile(fs.predicates().hasURI(Paths.get(path).toUri()));
366366
}
367367

368-
public InputFile getFileFromBasename(String basename) {
369-
return fs.inputFile(fs.predicates().hasFilename(basename));
370-
}
371-
372368
public String encoding() {
373369
return fs != null ? fs.encoding().name() : Charset.defaultCharset().name();
374370
}

delphi-frontend/src/test/java/au/com/integradev/delphi/coverage/delphicodecoveragetool/DelphiCoverageToolParserTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class DelphiCoverageToolParserTest {
5656
private static final String INVALID_STRUCTURE = BASE_REPORT_PATH + "InvalidStructure.xml";
5757
private static final String NORMAL_COVERAGE = BASE_REPORT_PATH + "NormalCoverage.xml";
5858
private static final String NORMAL_COVERAGE_PART_2 = BASE_REPORT_PATH + "NormalCoverage2.xml";
59+
private static final String MISMATCHED_CASING_COVERAGE =
60+
BASE_REPORT_PATH + "MismatchedCasingCoverage.xml";
5961

6062
private static final String GLOBALS_FILENAME = "Globals.pas";
6163
private static final String GLOBALS_FILE_KEY = ":" + GLOBALS_FILENAME;
@@ -92,10 +94,11 @@ void setup() throws IOException {
9294
delphiProjectHelper =
9395
new DelphiProjectHelper(
9496
context.config(), context.fileSystem(), environmentVariableProvider);
95-
parser = new DelphiCodeCoverageParser(delphiProjectHelper);
9697

9798
addFile(ROOT_NAME + "/" + GLOBALS_FILENAME);
9899
addFile(ROOT_NAME + "/" + MAIN_WINDOW_FILENAME);
100+
101+
parser = new DelphiCodeCoverageParser(delphiProjectHelper);
99102
}
100103

101104
@Test
@@ -124,6 +127,22 @@ void testLineHitsFromDifferentReportsAreMerged() {
124127
assertThat(context.lineHits(GLOBALS_FILE_KEY, 23)).isEqualTo((Integer) 1);
125128
}
126129

130+
@Test
131+
void testMismatchedCasingAllowed() {
132+
parser.parse(context, DelphiUtils.getResource(MISMATCHED_CASING_COVERAGE));
133+
134+
assertThat(context.lineHits(GLOBALS_FILE_KEY, 16)).isEqualTo(1);
135+
assertThat(context.lineHits(GLOBALS_FILE_KEY, 17)).isEqualTo(1);
136+
assertThat(context.lineHits(GLOBALS_FILE_KEY, 23)).isZero();
137+
138+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 31)).isEqualTo(1);
139+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 36)).isEqualTo(1);
140+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 37)).isEqualTo(1);
141+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 38)).isEqualTo(1);
142+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 39)).isEqualTo(1);
143+
assertThat(context.lineHits(MAIN_WINDOW_FILE_KEY, 40)).isEqualTo(1);
144+
}
145+
127146
void testReportFileIsIgnored(File file) {
128147
SensorContext mockContext = mock(SensorContext.class);
129148
assertThatCode(() -> parser.parse(mockContext, file)).doesNotThrowAnyException();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="Windows-1252" standalone="no"?>
2+
<report>
3+
<stats>
4+
<packages value="1"/>
5+
<classes value="2"/>
6+
<methods value="3"/>
7+
<srcfiles value="4"/>
8+
<srclines value="5"/>
9+
<totallines value="6"/>
10+
<coveredlines value="7"/>
11+
<coveredpercent value="8"/>
12+
</stats>
13+
<data>
14+
<all name="all classes">
15+
<coverage type="class, %" value="41% (41/101)"/>
16+
<coverage type="method, %" value="18% (112/636)"/>
17+
<coverage type="block, %" value="12% (815/6924)"/>
18+
<coverage type="line, %" value="12% (815/6924)"/>
19+
<package name="[default]">
20+
<coverage type="class, %" value="100% (5/5)"/>
21+
<coverage type="method, %" value="74% (14/19)"/>
22+
<coverage type="block, %" value="66% (93/140)"/>
23+
<coverage type="line, %" value="66% (93/140)"/>
24+
<srcfile name="MainWindow.pas">
25+
<coverage type="class, %" value="100% (5/5)"/>
26+
<coverage type="method, %" value="74% (14/19)"/>
27+
<coverage type="block, %" value="66% (93/140)"/>
28+
<coverage type="line, %" value="66% (93/140)"/>
29+
<class name="TMainWindow">
30+
<coverage type="class, %" value="100% (1/1)"/>
31+
<coverage type="method, %" value="100% (1/1)"/>
32+
<coverage type="block, %" value="56% (5/9)"/>
33+
<coverage type="line, %" value="56% (5/9)"/>
34+
<method name="foo2">
35+
<coverage type="method, %" value="100% (1/1)"/>
36+
<coverage type="block, %" value="56% (5/9)"/>
37+
<coverage type="line, %" value="56% (5/9)"/>
38+
<line number="36" covered="True"/>
39+
<line number="37" covered="False"/>
40+
<line number="38" covered="True"/>
41+
<line number="39" covered="False"/>
42+
</method>
43+
</class>
44+
</srcfile>
45+
<srcfile name="Globals.pas">
46+
<coverage type="class, %" value="100% (5/5)"/>
47+
<coverage type="method, %" value="74% (14/19)"/>
48+
<coverage type="block, %" value="66% (93/140)"/>
49+
<coverage type="line, %" value="66% (93/140)"/>
50+
<class name="TGlobals">
51+
<coverage type="class, %" value="100% (1/1)"/>
52+
<coverage type="method, %" value="100% (1/1)"/>
53+
<coverage type="block, %" value="56% (5/9)"/>
54+
<coverage type="line, %" value="56% (5/9)"/>
55+
<method name="globalProcedure">
56+
<coverage type="method, %" value="100% (2/2)"/>
57+
<coverage type="block, %" value="100% (1/1)"/>
58+
<coverage type="line, %" value="100% (2/2)"/>
59+
<line number="19" covered="True"/>
60+
<line number="20" covered="True"/>
61+
</method>
62+
</class>
63+
</srcfile>
64+
</package>
65+
</all>
66+
<linehits>
67+
<file name="GlObAlS.pas">16=1;17=1;23=0</file>
68+
<file name="maINwInDoW.pas">31=1;36=1;37=1;38=1;39=1;40=1</file>
69+
</linehits>
70+
</data>
71+
</report>

0 commit comments

Comments
 (0)