diff --git a/its/plugin/projects/lcov-wildcard/bar/bar.js b/its/plugin/projects/lcov-wildcard/bar/bar.js
new file mode 100644
index 00000000000..4bad53da13b
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/bar/bar.js
@@ -0,0 +1,12 @@
+function isArrayLike (obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+}
+
+function size (obj) {
+ if (obj == null) {
+ return 0;
+ }
+ return isArrayLike(obj) ? obj.length : Object.keys(obj).length;
+}
+
+module.exports = size;
diff --git a/its/plugin/projects/lcov-wildcard/bar/bar.lcov b/its/plugin/projects/lcov-wildcard/bar/bar.lcov
new file mode 100644
index 00000000000..8d13373be45
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/bar/bar.lcov
@@ -0,0 +1,24 @@
+TN:
+SF:./bar.js
+FN:1,isArrayLike
+FN:5,size
+FNF:2
+FNH:2
+FNDA:2,isArrayLike
+FNDA:2,size
+DA:1,1
+DA:2,2
+DA:5,1
+DA:6,2
+DA:7,0
+DA:9,2
+DA:12,1
+LF:7
+LH:6
+BRDA:6,1,0,0
+BRDA:6,1,1,2
+BRDA:9,2,0,1
+BRDA:9,2,1,1
+BRF:4
+BRH:3
+end_of_record
diff --git a/its/plugin/projects/lcov-wildcard/baz/baz.js b/its/plugin/projects/lcov-wildcard/baz/baz.js
new file mode 100644
index 00000000000..4bad53da13b
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/baz/baz.js
@@ -0,0 +1,12 @@
+function isArrayLike (obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+}
+
+function size (obj) {
+ if (obj == null) {
+ return 0;
+ }
+ return isArrayLike(obj) ? obj.length : Object.keys(obj).length;
+}
+
+module.exports = size;
diff --git a/its/plugin/projects/lcov-wildcard/baz/baz.lcov b/its/plugin/projects/lcov-wildcard/baz/baz.lcov
new file mode 100644
index 00000000000..87bd27d861c
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/baz/baz.lcov
@@ -0,0 +1,24 @@
+TN:
+SF:./baz.js
+FN:1,isArrayLike
+FN:5,size
+FNF:2
+FNH:2
+FNDA:2,isArrayLike
+FNDA:2,size
+DA:1,1
+DA:2,2
+DA:5,1
+DA:6,2
+DA:7,0
+DA:9,2
+DA:12,1
+LF:7
+LH:6
+BRDA:6,1,0,0
+BRDA:6,1,1,2
+BRDA:9,2,0,1
+BRDA:9,2,1,1
+BRF:4
+BRH:3
+end_of_record
diff --git a/its/plugin/projects/lcov-wildcard/baz/qux/qux.js b/its/plugin/projects/lcov-wildcard/baz/qux/qux.js
new file mode 100644
index 00000000000..4bad53da13b
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/baz/qux/qux.js
@@ -0,0 +1,12 @@
+function isArrayLike (obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+}
+
+function size (obj) {
+ if (obj == null) {
+ return 0;
+ }
+ return isArrayLike(obj) ? obj.length : Object.keys(obj).length;
+}
+
+module.exports = size;
diff --git a/its/plugin/projects/lcov-wildcard/baz/qux/qux.lcov b/its/plugin/projects/lcov-wildcard/baz/qux/qux.lcov
new file mode 100644
index 00000000000..234a6029812
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/baz/qux/qux.lcov
@@ -0,0 +1,24 @@
+TN:
+SF:./qux.js
+FN:1,isArrayLike
+FN:5,size
+FNF:2
+FNH:2
+FNDA:2,isArrayLike
+FNDA:2,size
+DA:1,1
+DA:2,2
+DA:5,1
+DA:6,2
+DA:7,0
+DA:9,2
+DA:12,1
+LF:7
+LH:6
+BRDA:6,1,0,0
+BRDA:6,1,1,2
+BRDA:9,2,0,1
+BRDA:9,2,1,1
+BRF:4
+BRH:3
+end_of_record
diff --git a/its/plugin/projects/lcov-wildcard/foo.js b/its/plugin/projects/lcov-wildcard/foo.js
new file mode 100644
index 00000000000..4bad53da13b
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/foo.js
@@ -0,0 +1,12 @@
+function isArrayLike (obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+}
+
+function size (obj) {
+ if (obj == null) {
+ return 0;
+ }
+ return isArrayLike(obj) ? obj.length : Object.keys(obj).length;
+}
+
+module.exports = size;
diff --git a/its/plugin/projects/lcov-wildcard/foo.lcov b/its/plugin/projects/lcov-wildcard/foo.lcov
new file mode 100644
index 00000000000..b362930e291
--- /dev/null
+++ b/its/plugin/projects/lcov-wildcard/foo.lcov
@@ -0,0 +1,24 @@
+TN:
+SF:./foo.js
+FN:1,isArrayLike
+FN:5,size
+FNF:2
+FNH:2
+FNDA:2,isArrayLike
+FNDA:2,size
+DA:1,1
+DA:2,2
+DA:5,1
+DA:6,2
+DA:7,0
+DA:9,2
+DA:12,1
+LF:7
+LH:6
+BRDA:6,1,0,0
+BRDA:6,1,1,2
+BRDA:9,2,0,1
+BRDA:9,2,1,1
+BRF:4
+BRH:3
+end_of_record
diff --git a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CoverageTest.java b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CoverageTest.java
index 0e39791effe..06437b5eefc 100644
--- a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CoverageTest.java
+++ b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/CoverageTest.java
@@ -218,4 +218,23 @@ public void conditions_on_non_executable_lines() {
assertThat(getMeasureAsInt(projectKey, "conditions_to_cover")).isEqualTo(2);
assertThat(getMeasureAsInt(projectKey, "uncovered_conditions")).isEqualTo(1);
}
+
+ @Test
+ public void wildcard_LCOV_report_paths() {
+ final String projectKey = "LcovWildcardReportPaths";
+ SonarScanner build = Tests.createScanner()
+ .setProjectDir(TestUtils.projectDir("lcov-wildcard"))
+ .setProjectKey(projectKey)
+ .setProjectName(projectKey)
+ .setProjectVersion("1.0")
+ .setSourceDirs(".")
+ .setProperty("sonar.javascript.lcov.reportPaths", "foo.lcov,bar/*.lcov,**/qux/*.lcov");
+ Tests.setEmptyProfile(projectKey);
+ orchestrator.executeBuild(build);
+
+ assertThat(getMeasureAsInt(projectKey + ":foo.js", "uncovered_lines")).isEqualTo(1);
+ assertThat(getMeasureAsInt(projectKey + ":bar/bar.js", "uncovered_lines")).isEqualTo(1);
+ assertThat(getMeasureAsInt(projectKey + ":baz/baz.js", "uncovered_lines")).isEqualTo(5);
+ assertThat(getMeasureAsInt(projectKey + ":baz/qux/qux.js", "uncovered_lines")).isEqualTo(1);
+ }
}
diff --git a/pom.xml b/pom.xml
index 676b0005cca..9bcd6a29b07 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
3.35.0.2707
4.3.1.2486
2.8.6
- 1.14.1.690
+ 1.16.0.719
${project.groupId}:sonar-javascript-plugin:jar
true
diff --git a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/lcov/CoverageSensor.java b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/lcov/CoverageSensor.java
index a05229caae6..0cff7ce0b6e 100644
--- a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/lcov/CoverageSensor.java
+++ b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/lcov/CoverageSensor.java
@@ -20,14 +20,12 @@
package org.sonar.plugins.javascript.lcov;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
@@ -41,6 +39,7 @@
import org.sonar.plugins.javascript.JavaScriptLanguage;
import org.sonar.plugins.javascript.JavaScriptPlugin;
import org.sonar.plugins.javascript.TypeScriptLanguage;
+import org.sonarsource.analyzer.commons.FileProvider;
public class CoverageSensor implements Sensor {
private static final Logger LOG = Loggers.get(CoverageSensor.class);
@@ -64,11 +63,7 @@ public void execute(SensorContext context) {
reports.addAll(Arrays.asList(context.config().getStringArray(JavaScriptPlugin.TS_LCOV_REPORT_PATHS)));
}
- List lcovFiles = reports.stream()
- .map(report -> getIOFile(context.fileSystem().baseDir(), report))
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
-
+ List lcovFiles = getLcovFiles(context.fileSystem().baseDir(), reports);
if (lcovFiles.isEmpty()) {
LOG.warn("No coverage information will be saved because all LCOV files cannot be found.");
return;
@@ -76,6 +71,25 @@ public void execute(SensorContext context) {
saveCoverageFromLcovFiles(context, lcovFiles);
}
+ private static List getLcovFiles(File baseDir, Set reportPaths) {
+ List lcovFiles = new ArrayList<>();
+ for (String reportPath : reportPaths) {
+ LOG.debug("Using '{}' to resolve LCOV files", reportPath);
+ FileProvider fileProvider = new FileProvider(baseDir, reportPath);
+ List matchingFiles = fileProvider.getMatchingFiles();
+ if (matchingFiles.isEmpty()) {
+ File file = new File(reportPath);
+ if (!file.exists()) {
+ LOG.info("No LCOV files were found using {}", reportPath);
+ } else {
+ matchingFiles.add(file);
+ }
+ }
+ lcovFiles.addAll(matchingFiles);
+ }
+ return lcovFiles;
+ }
+
private static void saveCoverageFromLcovFiles(SensorContext context, List lcovFiles) {
LOG.info("Analysing {}", lcovFiles);
@@ -111,22 +125,4 @@ private static void saveCoverageFromLcovFiles(SensorContext context, List
LOG.warn("Found {} inconsistencies in coverage report. Re-run analyse in debug mode to see details.", inconsistenciesNumber);
}
}
-
- /**
- * Returns a java.io.File for the given path.
- * If path is not absolute, returns a File with module base directory as parent path.
- */
- @CheckForNull
- private static File getIOFile(File baseDir, String path) {
- File file = new File(path);
- if (!file.isAbsolute()) {
- file = new File(baseDir, path);
- }
- if (!file.isFile()) {
- LOG.warn("No coverage information will be saved because LCOV file cannot be found.");
- LOG.warn("Provided LCOV file path: {}. Seek file with path: {}", path, file.getAbsolutePath());
- return null;
- }
- return file;
- }
}
diff --git a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/lcov/CoverageSensorTest.java b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/lcov/CoverageSensorTest.java
index 4022d4ab13a..e41c8bb6d04 100644
--- a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/lcov/CoverageSensorTest.java
+++ b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/lcov/CoverageSensorTest.java
@@ -173,7 +173,7 @@ public void test_unresolved_path() {
.contains("Could not resolve 2 file paths in [" + moduleBaseDir.getAbsolutePath() + fileName + "]")
.contains("First unresolved path: unresolved/file1.js (Run in DEBUG mode to get full list of unresolved paths)");
assertThat(logTester.logs(LoggerLevel.DEBUG))
- .isEmpty();
+ .contains("Using 'reports/report_with_unresolved_path.lcov' to resolve LCOV files");
}
@Test
@@ -202,7 +202,7 @@ public void should_log_warning_when_wrong_data() throws Exception {
assertThat(context.coveredConditions("moduleKey:file1.js", 2)).isEqualTo(2);
assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Problem during processing LCOV report: can't save DA data for line 3 of coverage report file (java.lang.NumberFormatException: For input string: \"1.\").");
- String stringIndexOutOfBoundLogMessage = logTester.logs(LoggerLevel.DEBUG).get(1);
+ String stringIndexOutOfBoundLogMessage = logTester.logs(LoggerLevel.DEBUG).get(2);
assertThat(stringIndexOutOfBoundLogMessage).startsWith("Problem during processing LCOV report: can't save DA data for line 4 of coverage report file (java.lang.StringIndexOutOfBoundsException:");
assertThat(logTester.logs(LoggerLevel.DEBUG).get(logTester.logs(LoggerLevel.DEBUG).size() - 1)).startsWith("Problem during processing LCOV report: can't save BRDA data for line 6 of coverage report file (java.lang.ArrayIndexOutOfBoundsException: ");
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Found 3 inconsistencies in coverage report. Re-run analyse in debug mode to see details.");
@@ -285,6 +285,24 @@ public void should_resolve_absolute_path() throws Exception {
assertThat(context.lineHits(file2Key, 2)).isEqualTo(5);
}
+ @Test
+ public void should_resolve_wildcard_report_paths() throws Exception {
+ settings.setProperty(JavaScriptPlugin.LCOV_REPORT_PATHS, "**/wildcard/**/*.lcov");
+ inputFile("file1.js", Type.MAIN);
+ inputFile("file2.js", Type.MAIN); // not referenced in any '**/wildcard/**/*.lcov' files
+ inputFile("tests/file1.js", Type.MAIN);
+ coverageSensor.execute(context);
+
+ String file1Key = "moduleKey:file1.js";
+ assertThat(context.lineHits(file1Key, 2)).isEqualTo(1);
+
+ String file2Key = "moduleKey:file2.js";
+ assertThat(context.lineHits(file2Key, 2)).isNull();
+
+ String nestedFileKey = "moduleKey:tests/file1.js";
+ assertThat(context.lineHits(nestedFileKey, 2)).isEqualTo(1);
+ }
+
@Test
public void should_import_coverage_for_ts() throws Exception {
DefaultInputFile inputFile = new TestInputFileBuilder("moduleKey", "src/file1.ts")
diff --git a/sonar-javascript-plugin/src/test/resources/coverage/wildcard/nested/report.lcov b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/nested/report.lcov
new file mode 100644
index 00000000000..9784ef69022
--- /dev/null
+++ b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/nested/report.lcov
@@ -0,0 +1,4 @@
+TN:
+SF:tests/file1.js
+DA:2,1
+end_of_record
diff --git a/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.info b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.info
new file mode 100644
index 00000000000..a012d395a3e
--- /dev/null
+++ b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.info
@@ -0,0 +1,4 @@
+TN:
+SF:file2.js
+DA:2,1
+end_of_record
diff --git a/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.lcov b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.lcov
new file mode 100644
index 00000000000..dc9b48a2bca
--- /dev/null
+++ b/sonar-javascript-plugin/src/test/resources/coverage/wildcard/report.lcov
@@ -0,0 +1,4 @@
+TN:
+SF:file1.js
+DA:2,1
+end_of_record