PythonCoverageSensor implements Sensor { @Override public void execute(SensorContext context) { String baseDir = context.fileSystem().baseDir().getPath(); Configuration config = context.config(); warnDeprecatedPropertyUsage(config); HashSet<InputFile> filesCovered = new HashSet<>(); List<File> reports = getCoverageReports(baseDir, config); if (!reports.isEmpty()) { LOG.info("Python test coverage"); for (File report : uniqueAbsolutePaths(reports)) { Map<InputFile, NewCoverage> coverageMeasures = parseReport(report, context); saveMeasures(coverageMeasures, filesCovered); } } } PythonCoverageSensor(AnalysisWarningsWrapper analysisWarnings); @Override void describe(SensorDescriptor descriptor); @Override void execute(SensorContext context); static final String REPORT_PATHS_KEY; static final String DEFAULT_REPORT_PATH; static final String REPORT_PATH_KEY; }
@Test public void report_not_found() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "/fake/path/report.xml"); coverageSensor.execute(context); assertThat(context.lineHits(FILE1_KEY, 1)).isNull(); }
@Test public void absolute_path() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, new File(moduleBaseDir, "coverage.xml").getAbsolutePath()); coverageSensor.execute(context); assertThat(context.lineHits(FILE1_KEY, 1)).isEqualTo(1); }
@Test public void test_coverage() { coverageSensor.execute(context); Integer[] file1Expected = {1, null, null, 0, null, 0}; Integer[] file2Expected = {1, 3, 1, 0, 1, 1}; for (int line = 1; line <= 6; line++) { assertThat(context.lineHits(FILE1_KEY, line)).isEqualTo(file1Expected[line - 1]); assertThat(context.lineHits(FILE2_KEY, line)).isEqualTo(file2Expected[line - 1]); assertThat(context.lineHits(FILE3_KEY, line)).isNull(); assertThat(context.lineHits(FILE4_KEY, line)).isNull(); } assertThat(context.conditions(FILE2_KEY, 2)).isNull(); assertThat(context.conditions(FILE2_KEY, 3)).isEqualTo(2); assertThat(context.coveredConditions(FILE2_KEY, 3)).isEqualTo(1); }
@Test public void test_coverage_4_4_2() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "coverage.4.4.2.xml"); coverageSensor.execute(context); List<Integer> actual = IntStream.range(1, 18).mapToObj(line -> context.lineHits(FILE4_KEY, line)).collect(Collectors.toList()); assertThat(actual).isEqualTo(Arrays.asList( null, null, null, null, null, 1, 1, 1, 0, 1, 1, null, 0, null, 1, null, null)); assertThat(context.conditions(FILE4_KEY, 7)).isNull(); assertThat(context.conditions(FILE4_KEY, 8)).isEqualTo(2); assertThat(context.coveredConditions(FILE4_KEY, 8)).isEqualTo(1); assertThat(context.conditions(FILE4_KEY, 10)).isEqualTo(2); assertThat(context.coveredConditions(FILE4_KEY, 10)).isEqualTo(1); }
@Test public void test_coverage_4_4_2_multi_source() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "coverage.4.4.2-multi-sources.xml"); coverageSensor.execute(context); assertThat(context.lineHits("moduleKey:sources/folder1/file1.py", 1)).isEqualTo(1); assertThat(context.lineHits("moduleKey:sources/folder1/file2.py", 1)).isNull(); assertThat(context.lineHits("moduleKey:sources/folder2/file2.py", 1)).isNull(); }
@Test public void test_unique_report() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "*coverage.4.4.2*.xml"); settings.setProperty(PythonCoverageSensor.REPORT_PATH_KEY, "*coverage.4.4.2*.xml"); coverageSensor.execute(context); List<Integer> actual = IntStream.range(1, 18).mapToObj(line -> context.lineHits(FILE4_KEY, line)).collect(Collectors.toList()); Integer coverageAtLine6 = actual.get(5); assertThat(coverageAtLine6).isEqualTo(1); verify(analysisWarnings, times(1)).addWarning(eq("Property 'sonar.python.coverage.reportPath' has been removed. Please use 'sonar.python.coverage.reportPaths' instead.")); }
@Test public void test_report_with_absolute_path() throws Exception { String reportPath = createReportWithAbsolutePaths(); settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, reportPath); coverageSensor.execute(context); assertThat(context.lineHits(FILE1_KEY, 1)).isEqualTo(1); assertThat(context.lineHits(FILE1_KEY, 2)).isEqualTo(3); assertThat(context.lineHits(FILE1_KEY, 3)).isEqualTo(1); assertThat(context.lineHits(FILE1_KEY, 4)).isEqualTo(0); assertThat(context.lineHits(FILE1_KEY, 5)).isEqualTo(1); assertThat(context.lineHits(FILE1_KEY, 6)).isEqualTo(1); }
@Test public void test_unresolved_path() { logTester.clear(); settings.setProperty(PythonCoverageSensor.REPORT_PATH_KEY, "coverage_with_unresolved_path.xml"); settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, ""); coverageSensor.execute(context); String currentFileSeparator = File.separator; assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); assertThat(logTester.logs(LoggerLevel.WARN)) .contains("Property 'sonar.python.coverage.reportPath' has been removed. Please use 'sonar.python.coverage.reportPaths' instead."); assertThat(context.lineHits(FILE1_KEY, 1)).isNull(); logTester.clear(); settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "coverage_with_unresolved_absolute_path.xml"); coverageSensor.execute(context); String expectedLogMessage = String.format( "Cannot resolve the file path '%sabsolute%ssources%snot_exist.py' of the coverage report, the file does not exist in all <source>.", currentFileSeparator, currentFileSeparator, currentFileSeparator); assertThat(logTester.logs(LoggerLevel.ERROR)).containsExactly( expectedLogMessage, "Cannot resolve 2 file paths, ignoring coverage measures for those files"); }
@Test public void test_comma_separated_paths() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "coverage.xml,coverage.4.4.2*.xml"); coverageSensor.execute(context); assertThat(context.conditions(FILE2_KEY, 2)).isNull(); assertThat(context.conditions(FILE2_KEY, 3)).isEqualTo(2); assertThat(context.coveredConditions(FILE2_KEY, 3)).isEqualTo(1); assertThat(context.conditions(FILE4_KEY, 7)).isNull(); assertThat(context.conditions(FILE4_KEY, 8)).isEqualTo(2); assertThat(context.coveredConditions(FILE4_KEY, 8)).isEqualTo(1); assertThat(context.conditions(FILE4_KEY, 10)).isEqualTo(2); assertThat(context.coveredConditions(FILE4_KEY, 10)).isEqualTo(1); }
@Test public void test_comma_separated_paths_with_deprecated_property() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, ""); settings.setProperty(PythonCoverageSensor.REPORT_PATH_KEY, "coverage.xml,coverage.4.4.2*.xml"); coverageSensor.execute(context); assertThat(context.conditions(FILE2_KEY, 2)).isNull(); assertThat(context.conditions(FILE2_KEY, 3)).isNull(); assertThat(context.coveredConditions(FILE2_KEY, 3)).isNull(); assertThat(context.conditions(FILE4_KEY, 7)).isNull(); assertThat(context.conditions(FILE4_KEY, 8)).isNull(); assertThat(context.coveredConditions(FILE4_KEY, 8)).isNull(); assertThat(context.conditions(FILE4_KEY, 10)).isNull(); assertThat(context.coveredConditions(FILE4_KEY, 10)).isNull(); }
@Test(expected = IllegalStateException.class) public void should_fail_on_invalid_report() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "invalid-coverage-result.xml"); coverageSensor.execute(context); }
@Test(expected = IllegalStateException.class) public void should_fail_on_unexpected_eof() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "coverage_with_eof_error.xml"); coverageSensor.execute(context); }
@Test public void should_do_nothing_on_empty_report() { settings.setProperty(PythonCoverageSensor.REPORT_PATHS_KEY, "empty-coverage-result.xml"); coverageSensor.execute(context); assertThat(context.lineHits(FILE1_KEY, 1)).isNull(); }
@Test public void no_default_report_log() { settings.clear(); PythonCoverageSensor sensor = new PythonCoverageSensor(analysisWarnings); sensor.execute(context); assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("No report was found for sonar.python.coverage.reportPaths using default pattern coverage-reports/*coverage-*.xml"); }