diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2016-02-19 10:39:17 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2016-02-22 10:57:26 +0100 |
commit | accc8fc25dbdddb7fc6fbc5fa171ce29929d01d9 (patch) | |
tree | 0b4daa853beea7ec734f8b52df0cf126f4e7efe8 /sonar-batch/src | |
parent | cef567021858b0e7239ac80d4512172ef7b70dbd (diff) | |
download | sonarqube-accc8fc25dbdddb7fc6fbc5fa171ce29929d01d9.tar.gz sonarqube-accc8fc25dbdddb7fc6fbc5fa171ce29929d01d9.zip |
SONAR-5772 New executable_lines_data metric
Diffstat (limited to 'sonar-batch/src')
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"); |