From 2829ab32fd689105ec33ff251289d8983ff49b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Fri, 24 Nov 2017 13:01:13 +0100 Subject: [PATCH] SONARVB-258: Add warn log if code coverage doesn't cover any MAIN file (#988) --- .../tests/CoverageReportImportSensor.java | 20 ++++++-- .../tests/CoverageReportImportSensorTest.java | 46 +++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/sonar-dotnet-tests-library/src/main/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensor.java b/sonar-dotnet-tests-library/src/main/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensor.java index a14679cbbbc..d0b945ac7f6 100644 --- a/sonar-dotnet-tests-library/src/main/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensor.java +++ b/sonar-dotnet-tests-library/src/main/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensor.java @@ -82,12 +82,19 @@ public void execute(SensorContext context) { void analyze(SensorContext context, Coverage coverage) { coverageAggregator.aggregate(wildcardPatternFileProvider, coverage); + boolean hasAnyMainFileCovered = false; for (String filePath : coverage.files()) { FilePredicates p = context.fileSystem().predicates(); - InputFile inputFile = context.fileSystem().inputFile(p.and(p.hasType(Type.MAIN), p.hasAbsolutePath(filePath))); + InputFile inputFile = context.fileSystem().inputFile(p.hasAbsolutePath(filePath)); if (inputFile == null) { - LOG.debug("Code coverage will not be imported for the following file outside of SonarQube: " + filePath); + LOG.debug("The file '" + filePath +"' is either excluded or outside of your solution folder therefore Code " + + "Coverage will not be imported."); + continue; + } + + if (inputFile.type().equals(Type.TEST)) { + // Do not log for test files to avoid pointless noise continue; } @@ -95,8 +102,8 @@ void analyze(SensorContext context, Coverage coverage) { continue; } - NewCoverage newCoverage = context.newCoverage() - .onFile(inputFile); + hasAnyMainFileCovered = true; + NewCoverage newCoverage = context.newCoverage().onFile(inputFile); for (Map.Entry entry : coverage.hits(filePath).entrySet()) { newCoverage.lineHits(entry.getKey(), entry.getValue()); @@ -104,6 +111,11 @@ void analyze(SensorContext context, Coverage coverage) { newCoverage.save(); } + + if (!coverage.files().isEmpty() && !hasAnyMainFileCovered) { + LOG.warn("The Code Coverage report doesn't contain any coverage data for the included files. For " + + "troubleshooting hints, please refer to https://docs.sonarqube.org/x/CoBh"); + } } } diff --git a/sonar-dotnet-tests-library/src/test/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensorTest.java b/sonar-dotnet-tests-library/src/test/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensorTest.java index 8ef60777e0c..fc440a80a5a 100644 --- a/sonar-dotnet-tests-library/src/test/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensorTest.java +++ b/sonar-dotnet-tests-library/src/test/java/org/sonar/plugins/dotnet/tests/CoverageReportImportSensorTest.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap; import java.io.File; import java.io.IOException; +import java.util.Collections; import java.util.HashSet; import java.util.function.Predicate; import org.junit.Rule; @@ -30,6 +31,7 @@ import org.mockito.Mockito; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.config.Configuration; @@ -157,6 +159,50 @@ public void analyzeIntegrationTests() throws Exception { assertThat(context.lineHits("foo:Foo.cs", 4)).isEqualTo(0); } + @Test + public void execute_coverage_no_main_file() throws IOException { + File baseDir = temp.newFolder(); + + Coverage coverage = mock(Coverage.class); + String fooPath = new File(baseDir, "Foo.cs").getCanonicalPath(); + when(coverage.files()).thenReturn(new HashSet<>(Collections.singletonList(fooPath))); + + CoverageAggregator coverageAggregator = mock(CoverageAggregator.class); + + SensorContextTester context = SensorContextTester.create(baseDir); + context.fileSystem().add(new TestInputFileBuilder("foo", "Foo.cs").setLanguage("cs") + .setType(Type.TEST).build()); + + CoverageConfiguration coverageConf = new CoverageConfiguration("cs", "", "", "", ""); + + new CoverageReportImportSensor(coverageConf, coverageAggregator, "cs", "C#", false) + .analyze(context, coverage); + + assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("The Code Coverage report doesn't contain any coverage " + + "data for the included files. For troubleshooting hints, please refer to https://docs.sonarqube.org/x/CoBh"); + } + + @Test + public void execute_coverage_not_indexed_file() throws IOException { + File baseDir = temp.newFolder(); + + Coverage coverage = mock(Coverage.class); + String fooPath = new File(baseDir, "Foo.cs").getCanonicalPath(); + when(coverage.files()).thenReturn(new HashSet<>(Collections.singletonList(fooPath))); + + CoverageAggregator coverageAggregator = mock(CoverageAggregator.class); + + SensorContextTester context = SensorContextTester.create(baseDir); + + CoverageConfiguration coverageConf = new CoverageConfiguration("cs", "", "", "", ""); + + new CoverageReportImportSensor(coverageConf, coverageAggregator, "cs", "C#", false) + .analyze(context, coverage); + + assertThat(logTester.logs(LoggerLevel.DEBUG)).containsOnly("The file '" + fooPath + "' is either excluded or outside of " + + "your solution folder therefore Code Coverage will not be imported."); + } + private SensorContextTester computeCoverageMeasures(boolean isIntegrationTest) throws Exception { File baseDir = temp.newFolder();