Skip to content

Commit e60a427

Browse files
committed
Refactor coverage file validation in integration tests
Centralize coverage output validation in CollectCoverageTests via a new CheckCoverageResult helper. This improves robustness by checking output directory existence, file presence, and format-specific content for both JSON and Cobertura XML. Updated test methods to use this helper, added a constant for LCOV file name, and adjusted output path structure. Removed redundant assertions in favor of unified checks.
1 parent bef6a9f commit e60a427

File tree

1 file changed

+81
-16
lines changed

1 file changed

+81
-16
lines changed

test/coverlet.MTP.validation.tests/CollectCoverageTests.cs

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Copyright (c) Toni Solarin-Sodara
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using System;
45
using System.Diagnostics;
6+
using System.Text;
57
using System.Text.Json;
68
using System.Xml.Linq;
9+
using NuGet.Packaging.Signing;
710
using Xunit;
11+
using static System.Runtime.InteropServices.JavaScript.JSType;
812

913
namespace coverlet.MTP.validation.tests;
1014

@@ -20,6 +24,7 @@ public class CollectCoverageTests
2024
private readonly string _localPackagesPath;
2125
private const string CoverageJsonFileName = "coverage.json";
2226
private const string CoverageCoberturaFileName = "coverage.cobertura.xml";
27+
private const string CoverageLcovFileName = "coverage.info";
2328
private readonly string _repoRoot;
2429

2530
public CollectCoverageTests()
@@ -71,12 +76,7 @@ public async Task BasicCoverage_CollectsDataForCoveredLines()
7176
Assert.True(result.ExitCode == 0, $"Expected successful test run (exit code 0) but got {result.ExitCode} -> '{result.ErrorText}'.\n\n{result.CombinedOutput}");
7277
Assert.Contains("Passed!", result.StandardOutput);
7378

74-
string[] coverageFiles = Directory.GetFiles(testProject.OutputDirectory, CoverageJsonFileName, SearchOption.AllDirectories);
75-
Assert.NotEmpty(coverageFiles);
76-
77-
var coverageData = ParseCoverageJson(coverageFiles[0]);
78-
Assert.NotNull(coverageData);
79-
Assert.True(coverageData.RootElement.TryGetProperty("Modules", out _));
79+
CheckCoverageResult(testProject, result, CoverageJsonFileName);
8080
}
8181

8282
[Fact]
@@ -96,12 +96,7 @@ public async Task CoverageWithFormat_GeneratesCorrectOutputFormat()
9696
// Assert
9797
Assert.True(result.ExitCode == 0, $"Expected successful test run (exit code 0) but got {result.ExitCode} -> '{result.ErrorText}'.\n\n{result.CombinedOutput}");
9898

99-
string[] coverageFiles = Directory.GetFiles(testProject.OutputDirectory, CoverageCoberturaFileName, SearchOption.AllDirectories);
100-
Assert.NotEmpty(coverageFiles);
101-
102-
var xmlDoc = XDocument.Load(coverageFiles[0]);
103-
Assert.NotNull(xmlDoc.Root);
104-
Assert.Equal("coverage", xmlDoc.Root.Name.LocalName);
99+
CheckCoverageResult(testProject, result, CoverageCoberturaFileName);
105100
}
106101

107102
[Fact]
@@ -119,6 +114,8 @@ public async Task CoverageInstrumentation_TracksMethodHits()
119114
// Assert
120115
Assert.True(result.ExitCode == 0, $"Expected successful test run (exit code 0) but got {result.ExitCode} -> '{result.ErrorText}'.\n\n{result.CombinedOutput}");
121116

117+
CheckCoverageResult(testProject, result, CoverageJsonFileName);
118+
122119
string[] coverageFiles = Directory.GetFiles(testProject.OutputDirectory, CoverageJsonFileName, SearchOption.AllDirectories);
123120
var coverageData = ParseCoverageJson(coverageFiles[0]);
124121

@@ -172,6 +169,8 @@ public async Task BranchCoverage_TracksConditionalPaths()
172169
// Assert
173170
Assert.True(result.ExitCode == 0, $"Expected successful test run (exit code 0) but got {result.ExitCode} -> '{result.ErrorText}'.\n\n{result.CombinedOutput}");
174171

172+
CheckCoverageResult(testProject, result, CoverageJsonFileName);
173+
175174
string[] coverageFiles = Directory.GetFiles(testProject.OutputDirectory, CoverageJsonFileName, SearchOption.AllDirectories);
176175
var coverageData = ParseCoverageJson(coverageFiles[0]);
177176

@@ -229,10 +228,75 @@ public async Task MultipleCoverageFormats_GeneratesAllReports()
229228
// Assert
230229
Assert.True(result.ExitCode == 0, $"Expected successful test run (exit code 0) but got {result.ExitCode} -> '{result.ErrorText}'.\n\n{result.CombinedOutput}");
231230

231+
//CheckCoverageResult(testProject, result, CoverageJsonFileName);
232+
232233
// Verify all formats are generated
233-
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, "coverage.json", SearchOption.AllDirectories));
234-
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, "coverage.cobertura.xml", SearchOption.AllDirectories));
235-
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, "coverage.info", SearchOption.AllDirectories));
234+
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, CoverageJsonFileName, SearchOption.AllDirectories));
235+
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, CoverageCoberturaFileName, SearchOption.AllDirectories));
236+
Assert.NotEmpty(Directory.GetFiles(testProject.OutputDirectory, CoverageLcovFileName, SearchOption.AllDirectories));
237+
}
238+
239+
private void CheckCoverageResult(TestProject testProject, TestResult result, string filename)
240+
{
241+
// Check if output directory exists before searching for coverage files
242+
Assert.True(
243+
Directory.Exists(testProject.OutputDirectory),
244+
$"Coverage output directory does not exist: {testProject.OutputDirectory}\n" +
245+
$"This may indicate that coverage collection failed or the test executable was not built correctly.\n\n" +
246+
$"Test Output:\n{result.CombinedOutput}");
247+
248+
string[] coverageFiles = Directory.GetFiles(testProject.OutputDirectory, filename, SearchOption.AllDirectories);
249+
Assert.True(
250+
coverageFiles.Length > 0,
251+
$"No coverage file '{CoverageJsonFileName}' found in '{testProject.OutputDirectory}'.\n" +
252+
$"Coverage collection may have failed. Check if --coverlet-coverage flag is being processed correctly.\n\n" +
253+
$"Test Output:\n{result.CombinedOutput}");
254+
255+
if (filename == CoverageJsonFileName)
256+
{
257+
// empty JSON file example:
258+
// {}
259+
var coverageData = ParseCoverageJson(coverageFiles[0]);
260+
Assert.NotNull(coverageData);
261+
Assert.True(coverageData.RootElement.TryGetProperty("Modules", out _), $"{CoverageJsonFileName} file has no 'Modules'");
262+
}
263+
if (filename == CoverageCoberturaFileName)
264+
{
265+
// parse XML file and ensure it has valid elements
266+
// invalid file XML example:
267+
// <?xml version="1.0" encoding="utf-8"?>
268+
// <coverage line-rate="0" branch-rate="0" version="1.9" timestamp="1766234003" lines-covered="0" lines-valid="0" branches-covered="0" branches-valid="0">
269+
// <sources />
270+
// <packages />
271+
// </coverage>
272+
XDocument coberturaDoc = XDocument.Load(coverageFiles[0]);
273+
Assert.NotNull(coberturaDoc.Root);
274+
Assert.True(coberturaDoc.Root.Name.LocalName == "coverage", $"{CoverageCoberturaFileName} XML root element is not 'coverage'");
275+
276+
// Check that sources element exists and has at least one source entry
277+
XElement? sourcesElement = coberturaDoc.Root.Element("sources");
278+
Assert.True(
279+
sourcesElement != null,
280+
$"{CoverageCoberturaFileName} XML file is missing 'sources' element.\n" +
281+
$"Coverage file: {coverageFiles[0]}\n\n" +
282+
$"Test Output:\n{result.CombinedOutput}");
283+
284+
bool hasSourceEntries = sourcesElement.Elements("source").Any();
285+
Assert.True(
286+
hasSourceEntries,
287+
$"{CoverageCoberturaFileName} XML 'sources' element is empty - no source directories were recorded.\n" +
288+
$"This indicates coverage instrumentation may have failed.\n" +
289+
$"Coverage file: {coverageFiles[0]}\n\n" +
290+
$"Test Output:\n{result.CombinedOutput}");
291+
292+
// Also check that packages element has content
293+
XElement? packagesElement = coberturaDoc.Root.Element("packages");
294+
Assert.True(
295+
packagesElement != null && packagesElement.Elements("package").Any(),
296+
$"{CoverageCoberturaFileName} XML 'packages' element is empty - no coverage data was collected.\n" +
297+
$"Coverage file: {coverageFiles[0]}\n\n" +
298+
$"Test Output:\n{result.CombinedOutput}");
299+
}
236300
}
237301

238302
#region Helper Methods
@@ -303,7 +367,8 @@ private TestProject CreateTestProject(
303367

304368
File.WriteAllText(Path.Combine(tempPath, "Tests.cs"), testCode);
305369

306-
string outputPath = Path.Combine(tempPath, "bin", _buildConfiguration.ToLower());
370+
// sample 'artifacts\tmp\debug\CoverletMTP_Test_42ddc59580ad4d7696ccebaadcc8e4f6\bin\TestProject\debug'
371+
string outputPath = Path.Combine(tempPath, "bin", "TestProject", _buildConfiguration.ToLower());
307372
return new TestProject(projectFile, outputPath);
308373
}
309374

0 commit comments

Comments
 (0)