aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2016-02-19 10:39:17 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2016-02-22 10:57:26 +0100
commitaccc8fc25dbdddb7fc6fbc5fa171ce29929d01d9 (patch)
tree0b4daa853beea7ec734f8b52df0cf126f4e7efe8 /sonar-batch/src
parentcef567021858b0e7239ac80d4512172ef7b70dbd (diff)
downloadsonarqube-accc8fc25dbdddb7fc6fbc5fa171ce29929d01d9.tar.gz
sonarqube-accc8fc25dbdddb7fc6fbc5fa171ce29929d01d9.zip
SONAR-5772 New executable_lines_data metric
Diffstat (limited to 'sonar-batch/src')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java190
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/source/ZeroCoverageSensor.java112
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java55
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java28
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java16
10 files changed, 302 insertions, 129 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
index 319b8292ba3..4b7c4b61f57 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
@@ -35,6 +35,7 @@ import org.sonar.batch.scm.ScmConfiguration;
import org.sonar.batch.scm.ScmSensor;
import org.sonar.batch.source.CodeColorizerSensor;
import org.sonar.batch.source.LinesSensor;
+import org.sonar.batch.source.ZeroCoverageSensor;
import org.sonar.batch.task.ListTask;
import org.sonar.batch.task.ScanTask;
import org.sonar.batch.task.Tasks;
@@ -55,6 +56,7 @@ public class BatchComponents {
ScmSensor.class,
LinesSensor.class,
+ ZeroCoverageSensor.class,
CodeColorizerSensor.class,
// Issues tracking
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java
index dbfe3b4d03b..921c37f5a83 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/CoveragePublisher.java
@@ -54,49 +54,49 @@ public class CoveragePublisher implements ReportPublisherStep {
}
Map<Integer, Coverage.Builder> coveragePerLine = new LinkedHashMap<>();
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine,
+ int lineCount = ((InputFile) resource.inputComponent()).lines();
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setUtHits(Integer.parseInt(value) > 0);
}
});
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.CONDITIONS_BY_LINE_KEY, coveragePerLine,
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.CONDITIONS_BY_LINE_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setConditions(Integer.parseInt(value));
}
});
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setUtCoveredConditions(Integer.parseInt(value));
}
});
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.IT_COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine,
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.IT_COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setItHits(Integer.parseInt(value) > 0);
}
});
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setItCoveredConditions(Integer.parseInt(value));
}
});
- applyLineMeasure(resource.key(), ((InputFile) resource.inputComponent()).lines(), CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
+ applyLineMeasure(resource.key(), lineCount, CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
new MeasureOperation() {
@Override
public void apply(String value, Coverage.Builder builder) {
builder.setOverallCoveredConditions(Integer.parseInt(value));
}
});
-
writer.writeComponentCoverage(resource.batchId(), Iterables.transform(coveragePerLine.values(), BuildCoverage.INSTANCE));
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
index 9f7ed5657af..5561f456043 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
@@ -20,9 +20,11 @@
package org.sonar.batch.report;
import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
+import com.google.common.base.Predicate;
import java.io.Serializable;
+import java.util.Set;
import javax.annotation.Nonnull;
+import org.sonar.api.batch.measure.Metric;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric.ValueType;
import org.sonar.batch.index.BatchComponent;
@@ -31,97 +33,135 @@ import org.sonar.batch.protocol.Constants.MeasureValueType;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.measure.MeasureCache;
+import org.sonar.core.metric.BatchMetrics;
+
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.newHashSet;
public class MeasuresPublisher implements ReportPublisherStep {
- private final BatchComponentCache resourceCache;
- private final MeasureCache measureCache;
+ private static final class MeasureToReportMeasure implements Function<Measure, BatchReport.Measure> {
+ private final BatchComponent resource;
+ private final BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder();
- public MeasuresPublisher(BatchComponentCache resourceCache, MeasureCache measureCache) {
- this.resourceCache = resourceCache;
- this.measureCache = measureCache;
- }
+ private MeasureToReportMeasure(BatchComponent resource) {
+ this.resource = resource;
+ }
- @Override
- public void publish(BatchReportWriter writer) {
- for (final BatchComponent resource : resourceCache.all()) {
- Iterable<Measure> batchMeasures = measureCache.byResource(resource.resource());
- Iterable<org.sonar.batch.protocol.output.BatchReport.Measure> reportMeasures = Iterables.transform(batchMeasures, new Function<Measure, BatchReport.Measure>() {
- private final BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder();
-
- @Override
- public BatchReport.Measure apply(@Nonnull Measure input) {
- validateMeasure(input, resource.key());
- return toReportMeasure(builder, input);
- }
- });
- writer.writeComponentMeasures(resource.batchId(), reportMeasures);
+ @Override
+ public BatchReport.Measure apply(@Nonnull Measure input) {
+ validateMeasure(input, resource.key());
+ return toReportMeasure(builder, input);
+ }
+
+ private static void validateMeasure(Measure measure, String componentKey) {
+ if (measure.getValue() == null && measure.getData() == null) {
+ throw new IllegalArgumentException(String.format("Measure on metric '%s' and component '%s' has no value, but it's not allowed", measure.getMetricKey(), componentKey));
+ }
+ }
+
+ private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Measure measure) {
+ builder.clear();
+
+ builder.setValueType(getMeasureValueType(measure.getMetric().getType()));
+ setValueAccordingToType(builder, measure);
+ // Because some numeric measures also have a data (like Sqale rating)
+ String data = measure.getData();
+ if (data != null) {
+ builder.setStringValue(data);
+ }
+ builder.setMetricKey(measure.getMetricKey());
+ return builder.build();
}
- }
- private static void validateMeasure(Measure measure, String componentKey) {
- if (measure.getValue() == null && measure.getData() == null) {
- throw new IllegalArgumentException(String.format("Measure on metric '%s' and component '%s' has no value, but it's not allowed", measure.getMetricKey(), componentKey));
+ private void setValueAccordingToType(BatchReport.Measure.Builder builder, Measure measure) {
+ Serializable value = measure.value();
+ switch (builder.getValueType()) {
+ case BOOLEAN:
+ builder.setBooleanValue((Boolean) value);
+ break;
+ case DOUBLE:
+ builder.setDoubleValue(((Number) value).doubleValue());
+ break;
+ case INT:
+ builder.setIntValue(((Number) value).intValue());
+ break;
+ case LONG:
+ builder.setLongValue(((Number) value).longValue());
+ break;
+ case STRING:
+ builder.setStringValue((String) value);
+ break;
+ default:
+ throw new IllegalStateException("Unknown value type: " + builder.getValueType());
+ }
}
+
+ private MeasureValueType getMeasureValueType(ValueType type) {
+ switch (type) {
+ case INT:
+ case RATING:
+ return MeasureValueType.INT;
+ case FLOAT:
+ case PERCENT:
+ return MeasureValueType.DOUBLE;
+ case BOOL:
+ return MeasureValueType.BOOLEAN;
+ case STRING:
+ case DATA:
+ case LEVEL:
+ case DISTRIB:
+ return MeasureValueType.STRING;
+ case WORK_DUR:
+ case MILLISEC:
+ return MeasureValueType.LONG;
+ default:
+ throw new IllegalStateException("Unknown value type: " + type);
+ }
+ }
+
}
- private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Measure measure) {
- builder.clear();
+ private static final class IsMetricAllowed implements Predicate<Measure> {
+ private final Set<String> allowedMetricKeys;
+
+ private IsMetricAllowed(Set<String> allowedMetricKeys) {
+ this.allowedMetricKeys = allowedMetricKeys;
+ }
- builder.setValueType(getMeasureValueType(measure.getMetric().getType()));
- setValueAccordingToType(builder, measure);
- // Because some numeric measures also have a data (like Sqale rating)
- String data = measure.getData();
- if (data != null) {
- builder.setStringValue(data);
+ @Override
+ public boolean apply(Measure input) {
+ return allowedMetricKeys.contains(input.getMetricKey());
}
- builder.setMetricKey(measure.getMetricKey());
- return builder.build();
}
- private void setValueAccordingToType(BatchReport.Measure.Builder builder, Measure measure) {
- Serializable value = measure.value();
- switch (builder.getValueType()) {
- case BOOLEAN:
- builder.setBooleanValue((Boolean) value);
- break;
- case DOUBLE:
- builder.setDoubleValue(((Number) value).doubleValue());
- break;
- case INT:
- builder.setIntValue(((Number) value).intValue());
- break;
- case LONG:
- builder.setLongValue(((Number) value).longValue());
- break;
- case STRING:
- builder.setStringValue((String) value);
- break;
- default:
- throw new IllegalStateException("Unknown value type: " + builder.getValueType());
+ private static final class MetricToKey implements Function<Metric, String> {
+ @Override
+ public String apply(Metric input) {
+ return input.key();
}
}
- private MeasureValueType getMeasureValueType(ValueType type) {
- switch (type) {
- case INT:
- case RATING:
- return MeasureValueType.INT;
- case FLOAT:
- case PERCENT:
- return MeasureValueType.DOUBLE;
- case BOOL:
- return MeasureValueType.BOOLEAN;
- case STRING:
- case DATA:
- case LEVEL:
- case DISTRIB:
- return MeasureValueType.STRING;
- case WORK_DUR:
- case MILLISEC:
- return MeasureValueType.LONG;
- default:
- throw new IllegalStateException("Unknown value type: " + type);
+ private final BatchComponentCache resourceCache;
+ private final MeasureCache measureCache;
+ private final BatchMetrics batchMetrics;
+
+ public MeasuresPublisher(BatchComponentCache resourceCache, MeasureCache measureCache, BatchMetrics batchMetrics) {
+ this.resourceCache = resourceCache;
+ this.measureCache = measureCache;
+ this.batchMetrics = batchMetrics;
+ }
+
+ @Override
+ public void publish(BatchReportWriter writer) {
+ final Set<String> allowedMetricKeys = newHashSet(transform(batchMetrics.getMetrics(), new MetricToKey()));
+ for (final BatchComponent resource : resourceCache.all()) {
+ Iterable<Measure> batchMeasures = measureCache.byResource(resource.resource());
+ Iterable<org.sonar.batch.protocol.output.BatchReport.Measure> reportMeasures = transform(
+ filter(batchMeasures, new IsMetricAllowed(allowedMetricKeys)),
+ new MeasureToReportMeasure(resource));
+ writer.writeComponentMeasures(resource.batchId(), reportMeasures);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index a567cd2e48b..2e265e2640d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -92,6 +92,7 @@ import org.sonar.batch.source.CodeColorizers;
import org.sonar.batch.test.TestPlanBuilder;
import org.sonar.batch.test.TestableBuilder;
import org.sonar.core.issue.workflow.FunctionExecutor;
+import org.sonar.core.metric.BatchMetrics;
import org.sonar.core.platform.ComponentContainer;
public class ProjectScanContainer extends ComponentContainer {
@@ -197,6 +198,7 @@ public class ProjectScanContainer extends ComponentContainer {
ProjectSettings.class,
// Report
+ BatchMetrics.class,
ReportPublisher.class,
AnalysisContextReportPublisher.class,
MetadataPublisher.class,
@@ -206,7 +208,7 @@ public class ProjectScanContainer extends ComponentContainer {
CoveragePublisher.class,
SourcePublisher.class,
TestExecutionAndCoveragePublisher.class,
-
+
// Cpd
CpdExecutor.class,
SonarDuplicationsIndex.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java
index c0adb26f4b6..963f7e14b91 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureCache.java
@@ -51,7 +51,11 @@ public class MeasureCache {
}
public Iterable<Measure> byResource(Resource r) {
- return cache.values(r.getEffectiveKey());
+ return byComponentKey(r.getEffectiveKey());
+ }
+
+ public Iterable<Measure> byComponentKey(String effectiveKey) {
+ return cache.values(effectiveKey);
}
@CheckForNull
diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
index 1d7221b8d96..09604877532 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
@@ -67,10 +67,6 @@ public class DefaultSensorStorage implements SensorStorage {
private static final Logger LOG = LoggerFactory.getLogger(DefaultSensorStorage.class);
private static final List<Metric> INTERNAL_METRICS = Arrays.<Metric>asList(
- // Computed by CpdSensor
- CoreMetrics.DUPLICATED_FILES,
- CoreMetrics.DUPLICATED_LINES,
- CoreMetrics.DUPLICATED_BLOCKS,
// Computed by LinesSensor
CoreMetrics.LINES);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/ZeroCoverageSensor.java b/sonar-batch/src/main/java/org/sonar/batch/source/ZeroCoverageSensor.java
new file mode 100644
index 00000000000..f211050dabc
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/source/ZeroCoverageSensor.java
@@ -0,0 +1,112 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.source;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Sets;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.Phase;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.coverage.CoverageType;
+import org.sonar.api.batch.sensor.coverage.NewCoverage;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.scan.measure.MeasureCache;
+
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.newHashSet;
+
+@Phase(name = Phase.Name.POST)
+public final class ZeroCoverageSensor implements Sensor {
+
+ private static final class MeasureToMetricKey implements Function<Measure, String> {
+ @Override
+ public String apply(Measure input) {
+ return input.getMetricKey();
+ }
+ }
+
+ private static final class MetricToKey implements Function<Metric, String> {
+ @Override
+ public String apply(Metric input) {
+ return input.key();
+ }
+ }
+
+ private final MeasureCache measureCache;
+
+ public ZeroCoverageSensor(MeasureCache measureCache) {
+ this.measureCache = measureCache;
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.name("Zero Coverage Sensor");
+ }
+
+ @Override
+ public void execute(final SensorContext context) {
+ FileSystem fs = context.fileSystem();
+ for (InputFile f : fs.inputFiles(fs.predicates().hasType(Type.MAIN))) {
+ if (!isCoverageMeasuresAlreadyDefined(f)) {
+ Measure execLines = measureCache.byMetric(f.key(), CoreMetrics.EXECUTABLE_LINES_DATA_KEY);
+ if (execLines != null) {
+ storeZeroCoverageForEachExecutableLine(context, f, execLines);
+ }
+
+ }
+ }
+ }
+
+ private static void storeZeroCoverageForEachExecutableLine(final SensorContext context, InputFile f, Measure execLines) {
+ NewCoverage newCoverage = context.newCoverage().ofType(CoverageType.UNIT).onFile(f);
+ Map<Integer, String> lineMeasures = KeyValueFormat.parseIntString((String) execLines.value());
+ for (Map.Entry<Integer, String> lineMeasure : lineMeasures.entrySet()) {
+ int lineIdx = lineMeasure.getKey();
+ if (lineIdx <= f.lines()) {
+ String value = lineMeasure.getValue();
+ if (StringUtils.isNotEmpty(value) && Integer.parseInt(value) > 0) {
+ newCoverage.lineHits(lineIdx, 0);
+ }
+ }
+ }
+ newCoverage.save();
+ }
+
+ private boolean isCoverageMeasuresAlreadyDefined(InputFile f) {
+ Set<String> metricKeys = newHashSet(transform(measureCache.byComponentKey(f.key()), new MeasureToMetricKey()));
+ Function<Metric, String> metricToKey = new MetricToKey();
+ Set<String> allCoverageMetricKeys = newHashSet(concat(transform(CoverageType.UNIT.allMetrics(), metricToKey),
+ transform(CoverageType.IT.allMetrics(), metricToKey),
+ transform(CoverageType.OVERALL.allMetrics(), metricToKey)));
+ return !Sets.intersection(metricKeys, allCoverageMetricKeys).isEmpty();
+ }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
index 9c9fa85b624..d693527df47 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/coverage/CoverageMediumTest.java
@@ -91,11 +91,11 @@ public class CoverageMediumTest {
assertThat(result.coverageFor(file, 2).getOverallCoveredConditions()).isEqualTo(0);
Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
- assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue", "stringValue")
- .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2, ""),
- tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0, ""),
- tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2, ""),
- tuple(CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, 0, "2=1"));
+ assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue")
+ .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2),
+ tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0),
+ tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2),
+ tuple(CoreMetrics.UNCOVERED_CONDITIONS_KEY, 1));
}
@Test
@@ -132,4 +132,49 @@ public class CoverageMediumTest {
CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY);
}
+ @Test
+ public void fallbackOnExecutableLines() throws IOException {
+
+ File baseDir = temp.getRoot();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File measuresFile = new File(srcDir, "sample.xoo.measures");
+ FileUtils.write(xooFile, "function foo() {\n if (a && b) {\nalert('hello');\n}\n}");
+ FileUtils.write(measuresFile, "executable_lines_data:2=1;3=1;4=0");
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ InputFile file = result.inputFile("src/sample.xoo");
+ assertThat(result.coverageFor(file, 1)).isNull();
+
+ assertThat(result.coverageFor(file, 2).getUtHits()).isFalse();
+ assertThat(result.coverageFor(file, 2).getItHits()).isFalse();
+ assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(0);
+ assertThat(result.coverageFor(file, 2).getUtCoveredConditions()).isEqualTo(0);
+ assertThat(result.coverageFor(file, 2).getItCoveredConditions()).isEqualTo(0);
+ assertThat(result.coverageFor(file, 2).getOverallCoveredConditions()).isEqualTo(0);
+
+ assertThat(result.coverageFor(file, 3).getUtHits()).isFalse();
+ assertThat(result.coverageFor(file, 4)).isNull();
+
+ Map<String, List<org.sonar.batch.protocol.output.BatchReport.Measure>> allMeasures = result.allMeasures();
+ assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue")
+ .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2),
+ tuple(CoreMetrics.UNCOVERED_LINES_KEY, 2));
+
+ assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey").doesNotContain(CoreMetrics.CONDITIONS_TO_COVER_KEY, CoreMetrics.UNCOVERED_CONDITIONS_KEY);
+ }
+
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
index 3399ab52604..51830c30d1e 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
@@ -30,8 +30,6 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.Metric.ValueType;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.batch.index.BatchComponentCache;
@@ -39,6 +37,7 @@ import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.measure.MeasureCache;
+import org.sonar.core.metric.BatchMetrics;
import org.sonar.core.util.CloseableIterator;
import static java.util.Arrays.asList;
@@ -70,28 +69,17 @@ public class MeasuresPublisherTest {
resourceCache.add(sampleFile, null);
measureCache = mock(MeasureCache.class);
when(measureCache.byResource(any(Resource.class))).thenReturn(Collections.<Measure>emptyList());
- publisher = new MeasuresPublisher(resourceCache, measureCache);
+ publisher = new MeasuresPublisher(resourceCache, measureCache, new BatchMetrics());
}
@Test
public void publishMeasures() throws Exception {
- Measure measure = new Measure<>(CoreMetrics.COVERAGE)
- .setValue(2.0)
- .setPersonId(2);
- // Manual measure
- Measure manual = new Measure<>(new Metric<>("manual_metric", ValueType.BOOL))
- .setValue(1.0);
- // Sqale rating have both a value and a data
- Measure rating = new Measure<>(CoreMetrics.SQALE_RATING)
- .setValue(2.0)
- .setData("A");
- // Long measure
- Measure longMeasure = new Measure<>(CoreMetrics.TECHNICAL_DEBT)
- .setValue(1.0);
+ Measure measure = new Measure<>(CoreMetrics.LINES_TO_COVER)
+ .setValue(2.0);
// String value
Measure stringMeasure = new Measure<>(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION)
.setData("foo bar");
- when(measureCache.byResource(sampleFile)).thenReturn(asList(measure, manual, rating, longMeasure, stringMeasure));
+ when(measureCache.byResource(sampleFile)).thenReturn(asList(measure, stringMeasure));
File outputDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(outputDir);
@@ -102,13 +90,13 @@ public class MeasuresPublisherTest {
assertThat(reader.readComponentMeasures(1)).hasSize(0);
try (CloseableIterator<BatchReport.Measure> componentMeasures = reader.readComponentMeasures(2)) {
- assertThat(componentMeasures).hasSize(5);
+ assertThat(componentMeasures).hasSize(2);
}
}
@Test
public void fail_with_IAE_when_measure_has_no_value() throws Exception {
- Measure measure = new Measure<>(CoreMetrics.COVERAGE);
+ Measure measure = new Measure<>(CoreMetrics.LINES_TO_COVER);
when(measureCache.byResource(sampleFile)).thenReturn(Collections.singletonList(measure));
File outputDir = temp.newFolder();
@@ -118,7 +106,7 @@ public class MeasuresPublisherTest {
publisher.publish(writer);
fail();
} catch (RuntimeException e) {
- assertThat(ExceptionUtils.getFullStackTrace(e)).contains("Measure on metric 'coverage' and component 'foo:src/Foo.php' has no value, but it's not allowed");
+ assertThat(ExceptionUtils.getFullStackTrace(e)).contains("Measure on metric 'lines_to_cover' and component 'foo:src/Foo.php' has no value, but it's not allowed");
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java
index 043ae5eb107..61f21529547 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/measure/MeasureCacheTest.java
@@ -166,22 +166,6 @@ public class MeasureCacheTest extends AbstractCachesTest {
}
@Test
- public void should_add_measure_with_same_metric() {
- Project p = new Project("struts");
-
- assertThat(measureCache.entries()).hasSize(0);
- assertThat(measureCache.byResource(p)).hasSize(0);
-
- Measure m1 = new Measure(CoreMetrics.NCLOC, 1.0);
- Measure m2 = new Measure(CoreMetrics.NCLOC, 1.0).setPersonId(2);
- measureCache.put(p, m1);
- measureCache.put(p, m2);
-
- assertThat(measureCache.entries()).hasSize(2);
- assertThat(measureCache.byResource(p)).hasSize(2);
- }
-
- @Test
public void should_get_measures() {
Project p = new Project("struts");
Resource dir = Directory.create("foo/bar").setEffectiveKey("struts:foo/bar");