Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
package org.sonar.plugins.python.coverage;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.xml.stream.XMLStreamException;
import org.apache.commons.lang.StringUtils;
import org.codehaus.staxmate.in.SMInputCursor;
Expand All @@ -43,7 +48,8 @@ public void parseReport(File xmlFile, SensorContext context, final Map<InputFile
unresolvedFilenameCount = 0;

StaxParser parser = new StaxParser(rootCursor -> {
File baseDirectory = context.fileSystem().baseDir();
File defaultBaseDirectory = context.fileSystem().baseDir();
List<File> baseDirectories = Collections.singletonList(defaultBaseDirectory);
try {
rootCursor.advance();
} catch (com.ctc.wstx.exc.WstxEOFException eofExc) {
Expand All @@ -53,9 +59,9 @@ public void parseReport(File xmlFile, SensorContext context, final Map<InputFile
SMInputCursor cursor = rootCursor.childElementCursor();
while (cursor.getNext() != null) {
if ("sources".equals(cursor.getLocalName())) {
baseDirectory = extractBaseDirectory(cursor, baseDirectory);
baseDirectories = extractBaseDirectories(cursor, defaultBaseDirectory);
} else if ("packages".equals(cursor.getLocalName())) {
collectFileMeasures(cursor.descendantElementCursor("class"), context, coverageData, baseDirectory);
collectFileMeasures(cursor.descendantElementCursor("class"), context, coverageData, baseDirectories);
}
}
});
Expand All @@ -65,43 +71,65 @@ public void parseReport(File xmlFile, SensorContext context, final Map<InputFile
}
}

private static File extractBaseDirectory(SMInputCursor sources, File defaultBaseDirectory) throws XMLStreamException {
private static List<File> extractBaseDirectories(SMInputCursor sources, File defaultBaseDirectory) throws XMLStreamException {
List<File> baseDirectories = new ArrayList<>();
SMInputCursor source = sources.childElementCursor("source");
while (source.getNext() != null) {
String path = source.collectDescendantText();
if (!StringUtils.isBlank(path)) {
File baseDirectory = new File(path);
if (baseDirectory.isDirectory()) {
return baseDirectory;
baseDirectories.add(baseDirectory);
} else {
LOG.warn("Invalid directory path in 'source' element: {}", path);
}
}
}
return defaultBaseDirectory;
if (baseDirectories.isEmpty()) {
return Collections.singletonList(defaultBaseDirectory);
}
return baseDirectories;
}

private void collectFileMeasures(SMInputCursor classCursor, SensorContext context, Map<InputFile, NewCoverage> coverageData, File baseDirectory)
private void collectFileMeasures(SMInputCursor classCursor, SensorContext context, Map<InputFile, NewCoverage> coverageData, List<File> baseDirectories)
throws XMLStreamException {
while (classCursor.getNext() != null) {
File file = new File(classCursor.getAttrValue("filename"));
if (!file.isAbsolute()) {
file = new File(baseDirectory, file.getPath());
}
InputFile inputFile = context.fileSystem().inputFile(context.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath()));
String filename = classCursor.getAttrValue("filename");
InputFile inputFile = resolve(context, baseDirectories, filename);
if (inputFile != null) {
NewCoverage coverage = coverageData.computeIfAbsent(inputFile, f -> context.newCoverage().onFile(f));
collectFileData(classCursor, coverage);
} else {
classCursor.advance();
unresolvedFilenameCount++;
if (unresolvedFilenameCount == 1) {
LOG.error("Cannot find the file '{}' in the base directory '{}', ignoring coverage measures for this file", file.getPath(), baseDirectory.getPath());
}
}
}
}

@Nullable
private InputFile resolve(SensorContext context, List<File> baseDirectories, String filename) {
List<File> fileList = baseDirectories.stream()
.map(base -> new File(base, filename))
.filter(File::exists)
.collect(Collectors.toList());
if (fileList.isEmpty()) {
logUnresolvedFile("Cannot resolve the file path '{}' of the coverage report, the file does not exist in all <source>.", filename);
return null;
}
if (fileList.size()>1) {
logUnresolvedFile("Cannot resolve the file path '{}' of the coverage report, ambiguity, the file exists in several <source>.", filename);
return null;
}
String absolutePath = fileList.get(0).getAbsolutePath();
return context.fileSystem().inputFile(context.fileSystem().predicates().hasAbsolutePath(absolutePath));
}

private void logUnresolvedFile(String message, String filename) {
unresolvedFilenameCount++;
if (unresolvedFilenameCount == 1) {
LOG.error(message, filename);
}
}

private static void collectFileData(SMInputCursor classCursor, NewCoverage coverage) throws XMLStreamException {
SMInputCursor line = classCursor.childElementCursor("lines").advance().childElementCursor("line");
while (line.getNext() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public void init() {
inputFile("sources/file2.py", Type.MAIN);
inputFile("sources/file3.py", Type.MAIN);
inputFile("sources/file4.py", Type.MAIN);
inputFile("sources/folder1/file1.py", Type.MAIN);
inputFile("sources/folder1/file2.py", Type.MAIN);
inputFile("sources/folder2/file2.py", Type.MAIN);
}

private InputFile inputFile(String relativePath, Type type) {
Expand Down Expand Up @@ -146,6 +149,17 @@ public void test_coverage_4_4_2() {
assertThat(context.coveredConditions(FILE4_KEY, 10)).isEqualTo(1);
}

@Test
public void test_coverage_4_4_2_multi_source() {
settings.setProperty(PythonCoverageSensor.REPORT_PATH_KEY, "coverage.4.4.2-multi-sources.xml");
coverageSensor.execute(context);

assertThat(context.lineHits("moduleKey:sources/folder1/file1.py", 1)).isEqualTo(1);
// file2.py ambiguity
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_PATH_KEY, "*coverage.4.4.2*.xml");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" ?>
<coverage branch-rate="0.5" branches-covered="2" branches-valid="4" complexity="0" line-rate="0.75" lines-covered="6" lines-valid="8" timestamp="1515594208483" version="4.4.2">
<!-- Generated by coverage.py: https://coverage.readthedocs.io -->
<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
<sources>
<source>src/test/resources/org/sonar/plugins/python/coverage-reports/sources/folder2</source>
<source>src/test/resources/org/sonar/plugins/python/coverage-reports/sources/folder1</source>
</sources>
<packages>
<package name=".">
<classes>
<class filename="file1.py" name="file1.py">
<methods/>
<lines>
<line hits="1" number="1"/>
</lines>
</class>
</classes>
</package>
<package name=".">
<classes>
<class filename="file2.py" name="file2.py">
<methods/>
<lines>
<line hits="1" number="1"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo()