diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-12-04 11:41:15 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-12-07 17:26:43 +0100 |
commit | 6cf62f0adc9677404df3ff457135591c17ad89a5 (patch) | |
tree | 08b31db10e52e92575a6343768f93e46b13266b7 | |
parent | 541c15654fc024534c45710b30b9cfc8ec551d96 (diff) | |
download | sonarqube-6cf62f0adc9677404df3ff457135591c17ad89a5.tar.gz sonarqube-6cf62f0adc9677404df3ff457135591c17ad89a5.zip |
SONAR-6939 ability for plugins to override the decimal scale of float
measures
92 files changed, 685 insertions, 1034 deletions
diff --git a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/BatchPlugin.java b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/BatchPlugin.java index 7c4c479c64b..f26975594f9 100644 --- a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/BatchPlugin.java +++ b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/BatchPlugin.java @@ -1,5 +1,9 @@ package com.sonarsource; +import com.sonarsource.decimal_scale_of_measures.DecimalScaleMeasureComputer; +import com.sonarsource.decimal_scale_of_measures.DecimalScaleMetric; +import com.sonarsource.decimal_scale_of_measures.DecimalScaleProperty; +import com.sonarsource.decimal_scale_of_measures.DecimalScaleSensor; import java.util.Arrays; import java.util.List; import org.sonar.api.SonarPlugin; @@ -8,6 +12,12 @@ public class BatchPlugin extends SonarPlugin { public List getExtensions() { return Arrays.asList( + // SONAR-6939 decimal_scale_of_measures + DecimalScaleMeasureComputer.class, + DecimalScaleMetric.class, + DecimalScaleSensor.class, + DecimalScaleProperty.definition(), + DumpSettingsInitializer.class, RaiseMessageException.class, TempFolderExtension.class, diff --git a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMeasureComputer.java b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMeasureComputer.java new file mode 100644 index 00000000000..f3dc985c7e8 --- /dev/null +++ b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMeasureComputer.java @@ -0,0 +1,34 @@ +package com.sonarsource.decimal_scale_of_measures; + +import org.sonar.api.ce.measure.Measure; +import org.sonar.api.ce.measure.MeasureComputer; + +public class DecimalScaleMeasureComputer implements MeasureComputer { + + @Override + public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) { + return defContext.newDefinitionBuilder() + // Output metrics must contains at least one metric + .setOutputMetrics(DecimalScaleMetric.KEY) + + .build(); + } + + @Override + public void compute(MeasureComputerContext context) { + if (context.getMeasure(DecimalScaleMetric.KEY) == null) { + Iterable<Measure> childMeasures = context.getChildrenMeasures(DecimalScaleMetric.KEY); + int count = 0; + double total = 0.0; + for (Measure childMeasure : childMeasures) { + count++; + total += childMeasure.getDoubleValue(); + } + double value = 0.0; + if (count > 0) { + value = total / count; + } + context.addMeasure(DecimalScaleMetric.KEY, value); + } + } +} diff --git a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMetric.java b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMetric.java new file mode 100644 index 00000000000..ef12e051fb1 --- /dev/null +++ b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleMetric.java @@ -0,0 +1,25 @@ +package com.sonarsource.decimal_scale_of_measures; + +import java.util.Collections; +import java.util.List; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.Metrics; + +public class DecimalScaleMetric implements Metrics { + + public static final String KEY = "decimal_scale"; + + private static final Metric METRIC = new Metric.Builder(KEY, "Decimal Scale", Metric.ValueType.FLOAT) + .setDescription("Numeric metric with overridden decimal scale") + .setDecimalScale(4) + .create(); + + @Override + public List getMetrics() { + return Collections.singletonList(definition()); + } + + public static Metric definition() { + return METRIC; + } +} diff --git a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleProperty.java b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleProperty.java new file mode 100644 index 00000000000..5fa85e71e59 --- /dev/null +++ b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleProperty.java @@ -0,0 +1,13 @@ +package com.sonarsource.decimal_scale_of_measures; + +import org.sonar.api.PropertyType; +import org.sonar.api.config.PropertyDefinition; + +public class DecimalScaleProperty { + + public static final String KEY = "sonar.scanner.feedDecimalScaleMetric"; + + public static PropertyDefinition definition() { + return PropertyDefinition.builder(KEY).name("Enable test decimal_scale_of_measures").type(PropertyType.BOOLEAN).defaultValue(String.valueOf(false)).build(); + } +} diff --git a/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleSensor.java b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleSensor.java new file mode 100644 index 00000000000..c6fe8c6ea03 --- /dev/null +++ b/it/it-plugins/batch-plugin/src/main/java/com/sonarsource/decimal_scale_of_measures/DecimalScaleSensor.java @@ -0,0 +1,36 @@ +package com.sonarsource.decimal_scale_of_measures; + +import org.sonar.api.batch.Sensor; +import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.fs.FilePredicate; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.resources.Project; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +public class DecimalScaleSensor implements Sensor { + private static final Logger LOG = Loggers.get(DecimalScaleSensor.class); + + @Override + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + @Override + public void analyse(Project module, SensorContext context) { + if (context.settings().getBoolean(DecimalScaleProperty.KEY)) { + FilePredicate all = context.fileSystem().predicates().all(); + Iterable<InputFile> files = context.fileSystem().inputFiles(all); + double value = 0.0001; + for (InputFile file : files) { + LOG.info("Value for {}: {}", file.relativePath(), value); + context.newMeasure() + .on(file) + .forMetric(DecimalScaleMetric.definition()) + .withValue(value) + .save(); + value += 0.0001; + } + } + } +} diff --git a/it/it-tests/src/test/java/it/Category3Suite.java b/it/it-tests/src/test/java/it/Category3Suite.java index 61bfc18575a..cd1f4974f5c 100644 --- a/it/it-tests/src/test/java/it/Category3Suite.java +++ b/it/it-tests/src/test/java/it/Category3Suite.java @@ -7,6 +7,7 @@ package it; import com.sonar.orchestrator.Orchestrator; import it.analysis.*; +import it.measure.DecimalScaleMetricTest; import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -29,7 +30,9 @@ import static util.ItUtils.xooPlugin; BatchTest.class, IssuesModeTest.class, SettingsEncryptionTest.class, - ReportDumpTest.class + ReportDumpTest.class, + // measures + DecimalScaleMetricTest.class }) public class Category3Suite { @@ -45,7 +48,7 @@ public class Category3Suite { // Used by IssuesModeTest .addPlugin(pluginArtifact("access-secured-props-plugin")) - // used by TempFolderTest + // used by TempFolderTest and DecimalScaleMetricTest .addPlugin(pluginArtifact("batch-plugin")) // used by ExtensionLifecycleTest diff --git a/it/it-tests/src/test/java/it/measure/DecimalScaleMetricTest.java b/it/it-tests/src/test/java/it/measure/DecimalScaleMetricTest.java new file mode 100644 index 00000000000..63c716051cf --- /dev/null +++ b/it/it-tests/src/test/java/it/measure/DecimalScaleMetricTest.java @@ -0,0 +1,39 @@ +package it.measure; + +import com.sonar.orchestrator.Orchestrator; +import it.Category3Suite; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.wsclient.services.Resource; +import org.sonar.wsclient.services.ResourceQuery; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * SONAR-6939 + */ +public class DecimalScaleMetricTest { + + /** + * Requires the plugin "batch-plugin" + */ + @ClassRule + public static Orchestrator orchestrator = Category3Suite.ORCHESTRATOR; + + @Test + public void override_decimal_scale_of_numeric_metric() { + String projectKey = "DecimalScaleMetricTest.override_decimal_scale_of_numeric_metric"; + // see DecimalScaleMetric + String metricKey = "decimal_scale"; + ItUtils.runProjectAnalysis(orchestrator, "shared/xoo-sample", + "sonar.projectKey", projectKey, + "sonar.scanner.feedDecimalScaleMetric", String.valueOf(true)); + + Resource resource = orchestrator.getServer().getWsClient() + .find(ResourceQuery.createForMetrics(projectKey, metricKey)); + // Ability to define decimal scale of metrics was introduced in v5.3. By default it is 1. + assertThat(resource.getMeasureValue(metricKey)).isEqualTo(0.0001); + assertThat(resource.getMeasureFormattedValue(metricKey, null)).isEqualTo("0.0001"); + } +} diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java index a2cb7066e0a..598be59d3dc 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java @@ -32,8 +32,6 @@ import org.sonar.xoo.lang.SymbolReferencesSensor; import org.sonar.xoo.lang.SyntaxHighlightingSensor; import org.sonar.xoo.lang.XooCpdMapping; import org.sonar.xoo.lang.XooTokenizer; -import org.sonar.xoo.measures.ConstantFloatMeasureSensor; -import org.sonar.xoo.measures.XooMetrics; import org.sonar.xoo.rule.ChecksSensor; import org.sonar.xoo.rule.CreateIssueByInternalKeySensor; import org.sonar.xoo.rule.DeprecatedResourceApiSensor; @@ -115,10 +113,6 @@ public class XooPlugin extends SonarPlugin { TestExecutionSensor.class, CoveragePerTestSensor.class, - // Measures - XooMetrics.class, - ConstantFloatMeasureSensor.class, - // Other XooProjectBuilder.class, XooPostJob.class); diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/ConstantFloatMeasureSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/ConstantFloatMeasureSensor.java deleted file mode 100644 index 416efe2bc39..00000000000 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/ConstantFloatMeasureSensor.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.xoo.measures; - -import org.sonar.api.batch.Sensor; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.config.Settings; -import org.sonar.api.measures.Measure; -import org.sonar.api.resources.Project; -import org.sonar.xoo.Xoo; - -/** - * Save a constant float measure on each XOO source file - */ -public class ConstantFloatMeasureSensor implements Sensor { - - public static final String SONAR_XOO_ENABLE_FLOAT_SENSOR = "sonar.xoo.enableFloatSensor"; - public static final String SONAR_XOO_FLOAT_PRECISION = "sonar.xoo.floatPrecision"; - - public static final double CONSTANT_VALUE = 1.2345678910111213d; - - private final FileSystem fs; - private final Settings settings; - - public ConstantFloatMeasureSensor(FileSystem fs, Settings settings) { - this.fs = fs; - this.settings = settings; - } - - @Override - public boolean shouldExecuteOnProject(Project project) { - return fs.hasFiles(fs.predicates().hasLanguage(Xoo.KEY)) && settings.getBoolean( - SONAR_XOO_ENABLE_FLOAT_SENSOR); - } - - @Override - public void analyse(Project project, SensorContext context) { - Measure<?> floatMeasure = settings.hasKey(SONAR_XOO_FLOAT_PRECISION) - ? new Measure<>(XooMetrics.CONSTANT_FLOAT_MEASURE, CONSTANT_VALUE, settings.getInt(SONAR_XOO_FLOAT_PRECISION)) - : new Measure<>(XooMetrics.CONSTANT_FLOAT_MEASURE, CONSTANT_VALUE); - for (InputFile inputFile : getSourceFiles()) { - context.saveMeasure(inputFile, floatMeasure); - } - } - - private Iterable<InputFile> getSourceFiles() { - return fs.inputFiles(fs.predicates().and(fs.predicates().hasLanguage(Xoo.KEY), fs.predicates().hasType(InputFile.Type.MAIN))); - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } -} diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/XooMetrics.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/XooMetrics.java deleted file mode 100644 index 511baf2761c..00000000000 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/XooMetrics.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.xoo.measures; - -import com.google.common.collect.Lists; -import java.util.List; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.measures.Metrics; - -public final class XooMetrics implements Metrics { - - public static final String CONSTANT_FLOAT_MEASURE_KEY = "xoo_constant_float_measure"; - - public static final Metric<Float> CONSTANT_FLOAT_MEASURE = new Metric.Builder(CONSTANT_FLOAT_MEASURE_KEY, "Constant float measure", Metric.ValueType.FLOAT) - .setDescription("Return always the same float measure for every components") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create(); - - @Override - public List<Metric> getMetrics() { - return Lists.<Metric>newArrayList(CONSTANT_FLOAT_MEASURE); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java index 1506751c82e..f2456fb68a3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java @@ -56,7 +56,7 @@ public class AverageFormula implements Formula<AverageFormula.AverageCounter> { double mainValue = mainValueOptional.get(); double byValue = byValueOptional.get(); if (byValue > 0d) { - return Optional.of(Measure.newMeasureBuilder().create(mainValue / byValue)); + return Optional.of(Measure.newMeasureBuilder().create(mainValue / byValue, context.getMetric().getDecimalScale())); } } return Optional.absent(); @@ -78,7 +78,7 @@ public class AverageFormula implements Formula<AverageFormula.AverageCounter> { // prevents instantiation outside static method } - public static Builder newBuilder(){ + public static Builder newBuilder() { return new Builder(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageFormula.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageFormula.java index 1521df8f9d0..6f44d2fbc2f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageFormula.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageFormula.java @@ -39,7 +39,7 @@ public abstract class CoverageFormula<T extends ElementsAndCoveredElementsCounte long elements = counter.elements; long coveredElements = counter.coveredElements; if (elements > 0L) { - return Optional.of(newMeasureBuilder().create(calculateCoverage(coveredElements, elements))); + return Optional.of(newMeasureBuilder().create(calculateCoverage(coveredElements, elements), context.getMetric().getDecimalScale())); } return Optional.absent(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java index a7931c61116..9c10dfde023 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/BatchMeasureToMeasure.java @@ -75,7 +75,10 @@ public class BatchMeasureToMeasure { if (!batchMeasure.hasDoubleValue()) { return toNoValueMeasure(builder, batchMeasure); } - return of(builder.create(batchMeasure.getDoubleValue(), data)); + return of(builder.create(batchMeasure.getDoubleValue(), + // Decimals are not truncated in scanner report, so an arbitrary decimal scale is applied when reading values from report + org.sonar.api.measures.Metric.MAX_DECIMAL_SCALE, + data)); } private static Optional<Measure> toBooleanMeasure(Measure.NewMeasureBuilder builder, BatchReport.Measure batchMeasure, @Nullable String data) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java index 0891ca0e137..ffb4ead0809 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/Measure.java @@ -34,11 +34,6 @@ import static java.util.Objects.requireNonNull; public final class Measure { - /** - * Default precision when saving a double value type - */ - private static final int DEFAULT_PRECISION = 1; - public enum ValueType { NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL } @@ -94,12 +89,11 @@ public final class Measure { private Measure(ValueType valueType, @Nullable Integer ruleId, @Nullable Integer characteristicId, @Nullable Developer developer, @Nullable Double value, @Nullable String data, @Nullable Level dataLevel, @Nullable String description, @Nullable QualityGateStatus qualityGateStatus, @Nullable MeasureVariations variations) { - checkArgument(value == null || !Double.isNaN(value), "Nan is not allowed as a Measure value"); this.valueType = valueType; this.ruleId = ruleId; this.characteristicId = characteristicId; this.developer = developer; - this.value = scale(value); + this.value = value; this.data = data; this.dataLevel = dataLevel; this.description = description; @@ -107,15 +101,6 @@ public final class Measure { this.variations = variations; } - @CheckForNull - private static Double scale(@Nullable Double value) { - if (value == null) { - return null; - } - BigDecimal bd = BigDecimal.valueOf(value); - return bd.setScale(DEFAULT_PRECISION, RoundingMode.HALF_UP).doubleValue(); - } - public static NewMeasureBuilder newMeasureBuilder() { return new NewMeasureBuilder(); } @@ -217,12 +202,14 @@ public final class Measure { return create(value, null); } - public Measure create(double value, @Nullable String data) { - return new Measure(ValueType.DOUBLE, ruleId, characteristicId, developer, value, data, null, description, qualityGateStatus, variations); + public Measure create(double value, int decimalScale, @Nullable String data) { + checkArgument(!Double.isNaN(value), "NaN is not allowed as a Measure value"); + double scaledValue = scale(value, decimalScale); + return new Measure(ValueType.DOUBLE, ruleId, characteristicId, developer, scaledValue, data, null, description, qualityGateStatus, variations); } - public Measure create(double value) { - return create(value, null); + public Measure create(double value, int decimalScale) { + return create(value, decimalScale, null); } public Measure create(String value) { @@ -468,4 +455,9 @@ public final class Measure { .add("description", description) .toString(); } + + private static double scale(double value, int decimalScale) { + BigDecimal bd = BigDecimal.valueOf(value); + return bd.setScale(decimalScale, RoundingMode.HALF_UP).doubleValue(); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java index 68a598d4d2a..b029e98ba53 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureDtoToMeasure.java @@ -75,7 +75,9 @@ public class MeasureDtoToMeasure { if (value == null) { return toNoValueMeasure(measureDto); } - return of(setCommonProperties(Measure.newMeasureBuilder(), measureDto).create(value.doubleValue(), data)); + + return of(setCommonProperties(Measure.newMeasureBuilder(), measureDto) + .create(value.doubleValue(), org.sonar.api.measures.Metric.MAX_DECIMAL_SCALE, data)); } private static Optional<Measure> toBooleanMeasure(MeasureDto measureDto, @Nullable Double value, String data) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java index 13d3a9a4578..3449aad39ff 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java @@ -151,7 +151,7 @@ public class MeasureComputerContextImpl implements MeasureComputerContext { public void addMeasure(String metricKey, double value) { Metric metric = metricRepository.getByKey(metricKey); validateAddMeasure(metric); - measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value)); + measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value, metric.getDecimalScale())); } @Override diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java index ee6771b6cfe..3c096d69609 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/Metric.java @@ -49,6 +49,12 @@ public interface Metric { @CheckForNull Double getBestValue(); + /** + * The decimal scale of float measures. Returned value is greater than or equal zero. + * @throws IllegalStateException if the value type is not decimal (see {@link org.sonar.server.computation.measure.Measure.ValueType} + */ + int getDecimalScale(); + enum MetricType { INT(Measure.ValueType.INT), MILLISEC(Measure.ValueType.LONG), diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java index cfce85a4047..eed9a958399 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java @@ -22,15 +22,27 @@ package org.sonar.server.computation.metric; import com.google.common.base.Function; import javax.annotation.Nonnull; import org.sonar.db.metric.MetricDto; +import org.sonar.server.computation.measure.Measure; + +import static com.google.common.base.Objects.firstNonNull; enum MetricDtoToMetric implements Function<MetricDto, Metric> { INSTANCE; + private static final int DEFAULT_DECIMAL_SCALE = 1; + @Override @Nonnull public Metric apply(@Nonnull MetricDto metricDto) { + Metric.MetricType metricType = Metric.MetricType.valueOf(metricDto.getValueType()); + Integer decimalScale = null; + if (metricType.getValueType() == Measure.ValueType.DOUBLE) { + decimalScale = firstNonNull(metricDto.getDecimalScale(), DEFAULT_DECIMAL_SCALE); + } + return new MetricImpl( - metricDto.getId(), metricDto.getKey(), metricDto.getShortName(), Metric.MetricType.valueOf(metricDto.getValueType()), + metricDto.getId(), metricDto.getKey(), metricDto.getShortName(), metricType, + decimalScale, metricDto.getBestValue(), metricDto.isOptimizedBestValue()); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java index 0e8980d53ea..df411912075 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricImpl.java @@ -19,13 +19,15 @@ */ package org.sonar.server.computation.metric; -import java.util.Objects; +import com.google.common.base.Objects; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import org.sonar.server.computation.measure.Measure; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; @Immutable public final class MetricImpl implements Metric { @@ -34,20 +36,26 @@ public final class MetricImpl implements Metric { private final String key; private final String name; private final MetricType type; + private final Integer decimalScale; private final Double bestValue; private final boolean bestValueOptimized; public MetricImpl(int id, String key, String name, MetricType type) { - this(id, key, name, type, null, false); + this(id, key, name, type, null, null, false); } - public MetricImpl(int id, String key, String name, MetricType type, + public MetricImpl(int id, String key, String name, MetricType type, @Nullable Integer decimalScale, @Nullable Double bestValue, boolean bestValueOptimized) { checkArgument(!bestValueOptimized || bestValue != null, "A BestValue must be specified if Metric is bestValueOptimized"); this.id = id; - this.key = requireNonNull(key); - this.name = requireNonNull(name); - this.type = requireNonNull(type); + this.key = checkNotNull(key); + this.name = checkNotNull(name); + this.type = checkNotNull(type); + if (type.getValueType() == Measure.ValueType.DOUBLE) { + this.decimalScale = Objects.firstNonNull(decimalScale, org.sonar.api.measures.Metric.DEFAULT_DECIMAL_SCALE); + } else { + this.decimalScale = decimalScale; + } this.bestValueOptimized = bestValueOptimized; this.bestValue = bestValue; } @@ -73,6 +81,12 @@ public final class MetricImpl implements Metric { } @Override + public int getDecimalScale() { + checkState(decimalScale != null, "Decimal scale is not defined on metric %s", key); + return decimalScale; + } + + @Override @CheckForNull public Double getBestValue() { return bestValue; @@ -92,7 +106,7 @@ public final class MetricImpl implements Metric { return false; } MetricImpl metric = (MetricImpl) o; - return Objects.equals(key, metric.key); + return Objects.equal(key, metric.key); } @Override diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/sqale/SqaleMeasuresVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/sqale/SqaleMeasuresVisitor.java index 7ebcf4ea813..cc2cb24ad3f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/sqale/SqaleMeasuresVisitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/sqale/SqaleMeasuresVisitor.java @@ -129,7 +129,7 @@ public class SqaleMeasuresVisitor extends PathAwareVisitorAdapter<SqaleMeasuresV } private void saveDebtRatioMeasure(Component component, double density) { - measureRepository.add(component, debtRatioMetric, newMeasureBuilder().create(100.0 * density)); + measureRepository.add(component, debtRatioMetric, newMeasureBuilder().create(100.0 * density, debtRatioMetric.getDecimalScale())); } private void saveSqaleRatingMeasure(Component component, double density) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CommentMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CommentMeasuresStep.java index 883960d4aa9..1ca58fd3a1f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CommentMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CommentMeasuresStep.java @@ -112,7 +112,7 @@ public class CommentMeasuresStep implements ComputationStep { double divisor = nclocs + comments; if (divisor > 0d) { double value = 100d * (comments / divisor); - return Optional.of(Measure.newMeasureBuilder().create(value)); + return Optional.of(Measure.newMeasureBuilder().create(value, context.getMetric().getDecimalScale())); } } } @@ -155,7 +155,7 @@ public class CommentMeasuresStep implements ComputationStep { if (publicApis > 0d) { double documentedAPI = publicApis - publicUndocumentedApis; double value = 100d * (documentedAPI / publicApis); - return Optional.of(Measure.newMeasureBuilder().create(value)); + return Optional.of(Measure.newMeasureBuilder().create(value, context.getMetric().getDecimalScale())); } } return Optional.absent(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CustomMeasuresCopyStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CustomMeasuresCopyStep.java index 2cf7e865d0f..60eff65c489 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/CustomMeasuresCopyStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CustomMeasuresCopyStep.java @@ -92,7 +92,7 @@ public class CustomMeasuresCopyStep implements ComputationStep { return Measure.newMeasureBuilder().create((long) dto.getValue()); case FLOAT: case PERCENT: - return Measure.newMeasureBuilder().create(dto.getValue()); + return Measure.newMeasureBuilder().create(dto.getValue(), metric.getDecimalScale()); case BOOL: return Measure.newMeasureBuilder().create(NumberUtils.compare(dto.getValue(), 1.0) == 0); case LEVEL: diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java index 2d60d64a37b..897d7f231b7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DuplicationMeasuresStep.java @@ -209,7 +209,7 @@ public class DuplicationMeasuresStep implements ComputationStep { Optional<Integer> nbLines = getNbLinesFromLocOrNcloc(context); if (nbLines.isPresent() && nbLines.get() > 0) { double density = Math.min(100d, 100d * duplicatedLines / nbLines.get()); - return Optional.of(Measure.newMeasureBuilder().create(density)); + return Optional.of(Measure.newMeasureBuilder().create(density, context.getMetric().getDecimalScale())); } return Optional.absent(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/UnitTestMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/UnitTestMeasuresStep.java index 61a87ac1283..47d67790df3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/UnitTestMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/UnitTestMeasuresStep.java @@ -92,7 +92,7 @@ public class UnitTestMeasuresStep implements ComputationStep { case TEST_FAILURES_KEY: return createMeasure(context.getComponent().getType(), counter.testsFailuresCounter.getValue()); case TEST_SUCCESS_DENSITY_KEY: - return createDensityMeasure(counter); + return createDensityMeasure(counter, context.getMetric().getDecimalScale()); default: throw new IllegalStateException(String.format("Metric '%s' is not supported", metricKey)); } @@ -105,7 +105,7 @@ public class UnitTestMeasuresStep implements ComputationStep { return Optional.absent(); } - private static Optional<Measure> createDensityMeasure(UnitTestsCounter counter) { + private static Optional<Measure> createDensityMeasure(UnitTestsCounter counter, int decimalScale) { if (isPositive(counter.testsCounter.getValue(), true) && isPositive(counter.testsErrorsCounter.getValue(), false) && isPositive(counter.testsFailuresCounter.getValue(), false)) { @@ -113,7 +113,7 @@ public class UnitTestMeasuresStep implements ComputationStep { int errors = counter.testsErrorsCounter.getValue().get(); int failures = counter.testsFailuresCounter.getValue().get(); double density = (errors + failures) * 100d / tests; - return Optional.of(Measure.newMeasureBuilder().create(100d - density)); + return Optional.of(Measure.newMeasureBuilder().create(100d - density, decimalScale)); } return Optional.absent(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricJsonWriter.java index fc9ad5b2596..ceb6b9357bc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricJsonWriter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricJsonWriter.java @@ -40,7 +40,9 @@ public class MetricJsonWriter { public static final String FIELD_QUALITATIVE = "qualitative"; public static final String FIELD_HIDDEN = "hidden"; public static final String FIELD_CUSTOM = "custom"; - public static final Set<String> OPTIONAL_FIELDS = ImmutableSet.of(FIELD_NAME, FIELD_DESCRIPTION, FIELD_DOMAIN, FIELD_DIRECTION, FIELD_QUALITATIVE, FIELD_HIDDEN, FIELD_CUSTOM); + public static final String FIELD_DECIMAL_SCALE = "decimalScale"; + public static final Set<String> OPTIONAL_FIELDS = ImmutableSet.of(FIELD_NAME, FIELD_DESCRIPTION, FIELD_DOMAIN, + FIELD_DIRECTION, FIELD_QUALITATIVE, FIELD_HIDDEN, FIELD_CUSTOM, FIELD_DECIMAL_SCALE); public static final Set<String> MANDATORY_FIELDS = ImmutableSet.of(FIELD_ID, FIELD_KEY, FIELD_NAME, FIELD_DOMAIN, FIELD_TYPE); public static final Set<String> ALL_FIELDS = ImmutableSet.copyOf(Sets.union(MANDATORY_FIELDS, OPTIONAL_FIELDS)); @@ -69,6 +71,7 @@ public class MetricJsonWriter { writeIfNeeded(json, metric.isQualitative(), FIELD_QUALITATIVE, fieldsToReturn); writeIfNeeded(json, metric.isHidden(), FIELD_HIDDEN, fieldsToReturn); writeIfNeeded(json, metric.isUserManaged(), FIELD_CUSTOM, fieldsToReturn); + writeIfNeeded(json, metric.getDecimalScale(), FIELD_DECIMAL_SCALE, fieldsToReturn); json.endObject(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/SearchAction.java index 118230d5fa1..03aa5e668b7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/SearchAction.java @@ -52,8 +52,6 @@ public class SearchAction implements MetricsWsAction { public static final String PARAM_IS_CUSTOM = "isCustom"; - private static final Set<String> OPTIONAL_FIELDS = newHashSet(FIELD_NAME, FIELD_DESCRIPTION, FIELD_DOMAIN, FIELD_TYPE, FIELD_DIRECTION, FIELD_QUALITATIVE, FIELD_HIDDEN, - FIELD_CUSTOM); private final Set<String> allPossibleFields; private final DbClient dbClient; @@ -61,7 +59,7 @@ public class SearchAction implements MetricsWsAction { public SearchAction(DbClient dbClient) { this.dbClient = dbClient; Set<String> possibleFields = newHashSet(FIELD_ID, FIELD_KEY); - possibleFields.addAll(OPTIONAL_FIELDS); + possibleFields.addAll(MetricJsonWriter.OPTIONAL_FIELDS); allPossibleFields = possibleFields; } @@ -72,7 +70,7 @@ public class SearchAction implements MetricsWsAction { .setDescription("Search for metrics") .setResponseExample(getClass().getResource("example-search.json")) .addPagingParams(100) - .addFieldsParam(OPTIONAL_FIELDS) + .addFieldsParam(MetricJsonWriter.OPTIONAL_FIELDS) .setHandler(this); action.createParam(PARAM_IS_CUSTOM) diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java b/server/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java index 9f3746bf464..34a7138a473 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java +++ b/server/sonar-server/src/main/java/org/sonar/server/startup/RegisterMetrics.java @@ -156,6 +156,7 @@ public class RegisterMetrics { dto.setUserManaged(metric.getUserManaged()); dto.setWorstValue(metric.getWorstValue()); dto.setDeleteHistoricalData(metric.getDeleteHistoricalData()); + dto.setDecimalScale(metric.getDecimalScale()); return dto; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaExecutionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaExecutionTest.java index abf260cde66..f34cca2d52d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaExecutionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaExecutionTest.java @@ -107,14 +107,14 @@ public class AverageFormulaExecutionTest { new PathAwareCrawler<>(underTest).visit(project); - assertThat(toEntries(measureRepository.getAddedRawMeasures(1))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(3d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(11))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(1111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2.5d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(1112))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(1d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(12))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(121))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(1211))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(1))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(3d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(11))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(1111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2.5d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(1112))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(1d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(12))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(121))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(1211))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d, 1))); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java index 32ad48aac48..5e34ba93146 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java @@ -245,7 +245,7 @@ public class AverageFormulaTest { } private void addMeasure(String metricKey, double value) { - when(counterInitializationContext.getMeasure(metricKey)).thenReturn(Optional.of(Measure.newMeasureBuilder().create(value))); + when(counterInitializationContext.getMeasure(metricKey)).thenReturn(Optional.of(Measure.newMeasureBuilder().create(value, 1))); } private void addMeasure(String metricKey, int value) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/coverage/CoverageUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/coverage/CoverageUtilsTest.java index 9be8edbbae1..6269d2af2ff 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/coverage/CoverageUtilsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/coverage/CoverageUtilsTest.java @@ -87,7 +87,7 @@ public class CoverageUtilsTest { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("value can not be converted to long because current value type is a DOUBLE"); - fileAggregateContext.put(SOME_METRIC_KEY, newMeasureBuilder().create(152d)); + fileAggregateContext.put(SOME_METRIC_KEY, newMeasureBuilder().create(152d, 1)); getLongMeasureValue(fileAggregateContext, SOME_METRIC_KEY); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java index ac9c83e0451..6ec84888939 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java @@ -72,7 +72,7 @@ public class CommentDensityRuleTest { @Test public void no_issues_if_enough_comments() { activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0, 1)); DefaultIssue issue = underTest.processFile(FILE, "java"); @@ -82,7 +82,7 @@ public class CommentDensityRuleTest { @Test public void issue_if_not_enough_comments() { activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(10.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(10.0, 1)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(40)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(360)); @@ -99,7 +99,7 @@ public class CommentDensityRuleTest { @Test public void issue_if_not_enough_comments__test_ceil() { activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0, 1)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1)); @@ -121,7 +121,7 @@ public class CommentDensityRuleTest { thrown.expectMessage("Minimum density of rule [common-java:InsufficientCommentDensity] is incorrect. Got [100] but must be strictly less than 100."); activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "100"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0, 1)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java index 68d6c59e9db..be3e3850d18 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java @@ -86,7 +86,7 @@ public abstract class CoverageRuleTest { @Test public void no_issue_if_enough_coverage() { activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0, 1)); DefaultIssue issue = underTest.processFile(FILE, "java"); @@ -96,7 +96,7 @@ public abstract class CoverageRuleTest { @Test public void issue_if_coverage_is_too_low() { activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"))); - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getUncoveredMetricKey(), Measure.newMeasureBuilder().create(40)); measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getToCoverMetricKey(), Measure.newMeasureBuilder().create(50)); @@ -123,7 +123,7 @@ public abstract class CoverageRuleTest { @Test public void ignored_if_rule_is_deactivated() { // coverage is too low, but rule is not activated - measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0)); + measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1)); DefaultIssue issue = underTest.processFile(FILE, "java"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java index ff5b90b606d..08cc3c6b9cf 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BatchMeasureToMeasureTest.java @@ -203,7 +203,7 @@ public class BatchMeasureToMeasureTest { assertThat(measure.isPresent()).isTrue(); assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.DOUBLE); - assertThat(measure.get().getDoubleValue()).isEqualTo(10.6d); + assertThat(measure.get().getDoubleValue()).isEqualTo(10.6395d); assertThat(measure.get().getData()).isEqualTo(SOME_DATA); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BestValueOptimizationTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BestValueOptimizationTest.java index 90491dd2cc0..9e3e2117e57 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BestValueOptimizationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/BestValueOptimizationTest.java @@ -145,9 +145,9 @@ public class BestValueOptimizationTest { public void verify_value_comparison_for_double_metric() { Predicate<Measure> underTest = BestValueOptimization.from(createMetric(Metric.MetricType.FLOAT, 36.5d), FILE_COMPONENT); - assertThat(underTest.apply(newMeasureBuilder().create(36.5d))).isTrue(); - assertThat(underTest.apply(newMeasureBuilder().setVariations(SOME_EMPTY_VARIATIONS).create(36.5d))).isTrue(); - assertThat(underTest.apply(newMeasureBuilder().create(36.6d))).isFalse(); + assertThat(underTest.apply(newMeasureBuilder().create(36.5d, 1))).isTrue(); + assertThat(underTest.apply(newMeasureBuilder().setVariations(SOME_EMPTY_VARIATIONS).create(36.5d, 1))).isTrue(); + assertThat(underTest.apply(newMeasureBuilder().create(36.6d, 1))).isFalse(); } @Test @@ -165,6 +165,6 @@ public class BestValueOptimizationTest { } private static MetricImpl createMetric(Metric.MetricType metricType, double bestValue) { - return new MetricImpl(metricType.hashCode() + (int) bestValue, "key" + metricType + bestValue, "name" + metricType + bestValue, metricType, bestValue, true); + return new MetricImpl(metricType.hashCode() + (int) bestValue, "key" + metricType + bestValue, "name" + metricType + bestValue, metricType, null, bestValue, true); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java index f30cc3a0e6e..5354fc51f66 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java @@ -156,7 +156,7 @@ public class MapBasedRawMeasureRepositoryTest { private static final List<Measure> MEASURES = ImmutableList.of( Measure.newMeasureBuilder().create(1), Measure.newMeasureBuilder().create(1l), - Measure.newMeasureBuilder().create(1d), + Measure.newMeasureBuilder().create(1d, 1), Measure.newMeasureBuilder().create(true), Measure.newMeasureBuilder().create(false), Measure.newMeasureBuilder().create("sds"), diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java index f5acb7726de..dbd60e52b24 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureDtoToMeasureTest.java @@ -23,6 +23,7 @@ import com.google.common.base.Optional; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import org.assertj.core.data.Offset; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -239,7 +240,7 @@ public class MeasureDtoToMeasureTest { assertThat(measure.isPresent()).isTrue(); assertThat(measure.get().getValueType()).isEqualTo(Measure.ValueType.DOUBLE); - assertThat(measure.get().getDoubleValue()).isEqualTo(10.6d); + assertThat(measure.get().getDoubleValue()).isEqualTo(10.6395d); assertThat(measure.get().getData()).isEqualTo(SOME_DATA); assertThat(measure.get().getQualityGateStatus().getStatus()).isEqualTo(Level.OK); assertThat(measure.get().getQualityGateStatus().getText()).isEqualTo(SOME_ALERT_TEXT); @@ -340,4 +341,15 @@ public class MeasureDtoToMeasureTest { assertThat(measure.get().getVariations().hasVariation4()).isFalse(); assertThat(measure.get().getVariations().getVariation5()).isEqualTo(5); } + + @Test + public void toMeasure_should_not_loose_decimals_of_float_values() { + MetricImpl metric = new MetricImpl(42, "double", "name", Metric.MetricType.FLOAT, 5, null, false); + MeasureDto measureDto = new MeasureDto() + .setValue(0.12345); + + Optional<Measure> measure = underTest.toMeasure(measureDto, metric); + + assertThat(measure.get().getDoubleValue()).isEqualTo(0.12345, Offset.offset(0.000001)); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java index d75b8a93496..456e79ef79d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java @@ -233,7 +233,7 @@ public class MeasureRepositoryImplTest { private static final List<Measure> MEASURES = ImmutableList.of( Measure.newMeasureBuilder().create(1), Measure.newMeasureBuilder().create(1l), - Measure.newMeasureBuilder().create(1d), + Measure.newMeasureBuilder().create(1d, 1), Measure.newMeasureBuilder().create(true), Measure.newMeasureBuilder().create(false), Measure.newMeasureBuilder().create("sds"), diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureTest.java index f95d131e427..4c93db5619d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureTest.java @@ -44,7 +44,7 @@ public class MeasureTest { private static final Measure INT_MEASURE = newMeasureBuilder().create((int) 1); private static final Measure LONG_MEASURE = newMeasureBuilder().create(1l); - private static final Measure DOUBLE_MEASURE = newMeasureBuilder().create(1d); + private static final Measure DOUBLE_MEASURE = newMeasureBuilder().create(1d, 1); private static final Measure STRING_MEASURE = newMeasureBuilder().create("some_sT ring"); private static final Measure TRUE_MEASURE = newMeasureBuilder().create(true); private static final Measure FALSE_MEASURE = newMeasureBuilder().create(false); @@ -296,7 +296,7 @@ public class MeasureTest { assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create(false, null).getQualityGateStatus()).isEqualTo(someStatus); assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create((int) 1, null).getQualityGateStatus()).isEqualTo(someStatus); assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create((long) 1, null).getQualityGateStatus()).isEqualTo(someStatus); - assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create((double) 1, null).getQualityGateStatus()).isEqualTo(someStatus); + assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create((double) 1, 1, null).getQualityGateStatus()).isEqualTo(someStatus); assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create("str").getQualityGateStatus()).isEqualTo(someStatus); assertThat(newMeasureBuilder().setQualityGateStatus(someStatus).create(Measure.Level.OK).getQualityGateStatus()).isEqualTo(someStatus); } @@ -361,7 +361,7 @@ public class MeasureTest { assertThat(newMeasureBuilder().create(false, someData).getData()).isEqualTo(someData); assertThat(newMeasureBuilder().create((int) 1, someData).getData()).isEqualTo(someData); assertThat(newMeasureBuilder().create((long) 1, someData).getData()).isEqualTo(someData); - assertThat(newMeasureBuilder().create((double) 1, someData).getData()).isEqualTo(someData); + assertThat(newMeasureBuilder().create((double) 1, 1, someData).getData()).isEqualTo(someData); } @Test @@ -371,26 +371,26 @@ public class MeasureTest { @Test public void double_values_are_scaled_to_1_digit_and_round() { - assertThat(newMeasureBuilder().create(30.27777d).getDoubleValue()).isEqualTo(30.3d); - assertThat(newMeasureBuilder().create(30d).getDoubleValue()).isEqualTo(30d); - assertThat(newMeasureBuilder().create(30.01d).getDoubleValue()).isEqualTo(30d); - assertThat(newMeasureBuilder().create(30.1d).getDoubleValue()).isEqualTo(30.1d); + assertThat(newMeasureBuilder().create(30.27777d, 1).getDoubleValue()).isEqualTo(30.3d); + assertThat(newMeasureBuilder().create(30d, 1).getDoubleValue()).isEqualTo(30d); + assertThat(newMeasureBuilder().create(30.01d, 1).getDoubleValue()).isEqualTo(30d); + assertThat(newMeasureBuilder().create(30.1d, 1).getDoubleValue()).isEqualTo(30.1d); } @Test public void create_with_double_value_throws_IAE_if_value_is_NaN() { expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Nan is not allowed as a Measure value"); + expectedException.expectMessage("NaN is not allowed as a Measure value"); - newMeasureBuilder().create(Double.NaN); + newMeasureBuilder().create(Double.NaN, 1); } @Test public void create_with_double_value_data_throws_IAE_if_value_is_NaN() { expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Nan is not allowed as a Measure value"); + expectedException.expectMessage("NaN is not allowed as a Measure value"); - newMeasureBuilder().create(Double.NaN, "some data"); + newMeasureBuilder().create(Double.NaN, 1, "some data"); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureToMeasureDtoTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureToMeasureDtoTest.java index 409673b7a05..7245fce8da6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureToMeasureDtoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureToMeasureDtoTest.java @@ -81,7 +81,7 @@ public class MeasureToMeasureDtoTest { { Measure.newMeasureBuilder().create(true, SOME_DATA), SOME_BOOLEAN_METRIC}, { Measure.newMeasureBuilder().create(1, SOME_DATA), SOME_INT_METRIC}, { Measure.newMeasureBuilder().create((long) 1, SOME_DATA), SOME_LONG_METRIC}, - { Measure.newMeasureBuilder().create((double) 2, SOME_DATA), SOME_DOUBLE_METRIC}, + { Measure.newMeasureBuilder().create((double) 2, 1, SOME_DATA), SOME_DOUBLE_METRIC}, { Measure.newMeasureBuilder().create(SOME_STRING), SOME_STRING_METRIC}, { Measure.newMeasureBuilder().create(Measure.Level.OK), SOME_LEVEL_METRIC} }; @@ -210,7 +210,7 @@ public class MeasureToMeasureDtoTest { @Test public void toMeasureDto_maps_value_and_data_from_data_field_for_DOUBLE_metric() { - MeasureDto trueMeasureDto = underTest.toMeasureDto(Measure.newMeasureBuilder().create((double) 789, SOME_DATA), SOME_DOUBLE_METRIC, SOME_COMPONENT); + MeasureDto trueMeasureDto = underTest.toMeasureDto(Measure.newMeasureBuilder().create((double) 789, 1, SOME_DATA), SOME_DOUBLE_METRIC, SOME_COMPONENT); assertThat(trueMeasureDto.getValue()).isEqualTo(789); assertThat(trueMeasureDto.getData()).isEqualTo(SOME_DATA); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureImplTest.java index c6b11e3fdbd..2f9714ce981 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureImplTest.java @@ -43,13 +43,13 @@ public class MeasureImplTest { thrown.expect(IllegalStateException.class); thrown.expectMessage("Value can not be converted to int because current value type is a DOUBLE"); - MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d)); + MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d, 1)); measure.getIntValue(); } @Test public void get_double_value() throws Exception { - MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d)); + MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d, 1)); assertThat(measure.getDoubleValue()).isEqualTo(1d); } @@ -103,7 +103,7 @@ public class MeasureImplTest { thrown.expect(IllegalStateException.class); thrown.expectMessage("Value can not be converted to boolean because current value type is a DOUBLE"); - MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d)); + MeasureImpl measure = new MeasureImpl(Measure.newMeasureBuilder().create(1d, 1)); measure.getBooleanValue(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java index 3b6cac89f36..839f6692f3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricImplTest.java @@ -53,7 +53,7 @@ public class MetricImplTest { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("A BestValue must be specified if Metric is bestValueOptimized"); - new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.INT, null, true); + new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.INT, 1, null, true); } @Test @@ -72,8 +72,8 @@ public class MetricImplTest { assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT)).isEqualTo(expected); assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.STRING)).isEqualTo(expected); - assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.STRING, 0d, true)).isEqualTo(expected); - assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.STRING, null, false)).isEqualTo(expected); + assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.STRING, null, 0d, true)).isEqualTo(expected); + assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.STRING, null, null, false)).isEqualTo(expected); assertThat(new MetricImpl(SOME_ID, "some other key", SOME_NAME, Metric.MetricType.FLOAT)).isNotEqualTo(expected); } @@ -87,7 +87,7 @@ public class MetricImplTest { @Test public void all_fields_are_displayed_in_toString() { - assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT, 951d, true).toString()) + assertThat(new MetricImpl(SOME_ID, SOME_KEY, SOME_NAME, Metric.MetricType.FLOAT, 1, 951d, true).toString()) .isEqualTo("MetricImpl{id=42, key=key, name=name, type=FLOAT, bestValue=951.0, bestValueOptimized=true}"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryRule.java index 8d77c4c7eb5..2b51faf2c01 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryRule.java @@ -62,6 +62,7 @@ public class MetricRepositoryRule extends ExternalResource implements MetricRepo return new MetricImpl( id, coreMetric.getKey(), coreMetric.getName(), convert(coreMetric.getType()), + coreMetric.getDecimalScale(), coreMetric.getBestValue(), coreMetric.isOptimizedBestValue()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionEvaluatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionEvaluatorTest.java index 246aa59975e..03fc4c87bd3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionEvaluatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/qualitygate/ConditionEvaluatorTest.java @@ -54,7 +54,7 @@ public class ConditionEvaluatorTest { public void testInputNumbers() { try { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); underTest.evaluate(createErrorCondition(metric, LESS_THAN, "20"), measure); } catch (NumberFormatException ex) { fail(); @@ -70,7 +70,7 @@ public class ConditionEvaluatorTest { try { Metric metric = createMetric(MetricType.PERCENT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); underTest.evaluate(createErrorCondition(metric, LESS_THAN, "20.1"), measure); } catch (NumberFormatException ex) { fail(); @@ -88,7 +88,7 @@ public class ConditionEvaluatorTest { @Test public void testEquals_for_double() { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.2"), measure)).hasLevel(ERROR).hasValue(10.2d); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.1"), measure)).hasLevel(OK).hasValue(10.2d); @@ -106,7 +106,7 @@ public class ConditionEvaluatorTest { @Test public void testNotEquals_for_double() { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, NOT_EQUALS, "10.2"), measure)).hasLevel(OK).hasValue(10.2d); assertThat(underTest.evaluate(createErrorCondition(metric, NOT_EQUALS, "10.1"), measure)).hasLevel(ERROR).hasValue(10.2d); @@ -124,7 +124,7 @@ public class ConditionEvaluatorTest { @Test public void testGreater() { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, GREATER_THAN, "10.1"), measure)).hasLevel(ERROR).hasValue(10.2d); assertThat(underTest.evaluate(createErrorCondition(metric, GREATER_THAN, "10.2"), measure)).hasLevel(OK).hasValue(10.2d); @@ -134,7 +134,7 @@ public class ConditionEvaluatorTest { @Test public void testSmaller() { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, LESS_THAN, "10.1"), measure)).hasLevel(OK).hasValue(10.2d); assertThat(underTest.evaluate(createErrorCondition(metric, LESS_THAN, "10.2"), measure)).hasLevel(OK).hasValue(10.2d); @@ -144,7 +144,7 @@ public class ConditionEvaluatorTest { @Test public void testEquals_Percent() { Metric metric = createMetric(MetricType.PERCENT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.2"), measure)).hasLevel(ERROR).hasValue(10.2d); } @@ -152,7 +152,7 @@ public class ConditionEvaluatorTest { @Test public void testEquals_Float() { Metric metric = createMetric(MetricType.PERCENT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.2"), measure)).hasLevel(ERROR).hasValue(10.2d); } @@ -235,7 +235,7 @@ public class ConditionEvaluatorTest { @Test public void testErrorAndWarningLevel() { Metric metric = createMetric(MetricType.FLOAT); - Measure measure = newMeasureBuilder().create(10.2d, null); + Measure measure = newMeasureBuilder().create(10.2d, 1, null); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.2"), measure)).hasLevel(ERROR); assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.1"), measure)).hasLevel(OK); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ReportSqaleMeasuresVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ReportSqaleMeasuresVisitorTest.java index b06cbc2f621..777658b202a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ReportSqaleMeasuresVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ReportSqaleMeasuresVisitorTest.java @@ -95,7 +95,7 @@ public class ReportSqaleMeasuresVisitorTest { assertThat(toEntries(measureRepository.getRawMeasures(root))) .containsOnly( entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d)), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d, 1)), entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(A))); } @@ -238,7 +238,7 @@ public class ReportSqaleMeasuresVisitorTest { private void verifyComponentMeasures(int componentRef, long expectedDevCost, double expectedDebtRatio, SqaleRatingGrid.SqaleRating expectedRating) { assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly( entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(Long.toString(expectedDevCost))), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(expectedDebtRatio * 100.0)), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(expectedDebtRatio * 100.0, 1)), entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(expectedRating))); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java index cdb5ed97f59..ed74622a39c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java @@ -111,7 +111,7 @@ public class ViewsSqaleMeasuresVisitorTest { assertThat(toEntries(measureRepository.getRawMeasures(root))) .containsOnly( entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d)), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d, 1)), entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(A))); } @@ -152,7 +152,7 @@ public class ViewsSqaleMeasuresVisitorTest { private void assertNewRawMeasures(int componentRef, long debt, long devCost, SqaleRatingGrid.SqaleRating sqaleRating) { assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly( entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(String.valueOf(devCost))), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(debt / (double) devCost * 100.0)), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(debt / (double) devCost * 100.0, 1)), entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(sqaleRating))); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/CustomMeasuresCopyStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CustomMeasuresCopyStepTest.java index e37f49682d5..741d477ca20 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/CustomMeasuresCopyStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CustomMeasuresCopyStepTest.java @@ -220,7 +220,7 @@ public class CustomMeasuresCopyStepTest { } private void assertRawMeasureValue(int componentRef, String metricKey, double value) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly(entryOf(metricKey, newMeasureBuilder().create(value))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly(entryOf(metricKey, newMeasureBuilder().create(value, 1))); } private void assertRawMeasureValue(int componentRef, String metricKey, String value) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java index cd2a159dce9..55c27353139 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java @@ -190,7 +190,7 @@ public class PersistMeasuresStepTest extends BaseStepTest { measureRepository.addRawMeasure(ROOT_REF, STRING_METRIC_KEY, newMeasureBuilder().create("measure-data")); measureRepository.addRawMeasure(INTERMEDIATE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(12)); measureRepository.addRawMeasure(INTERMEDIATE_2_REF, LONG_METRIC_KEY, newMeasureBuilder().create(9635L)); - measureRepository.addRawMeasure(LEAF_REF, DOUBLE_METRIC_KEY, newMeasureBuilder().create(123.123d)); + measureRepository.addRawMeasure(LEAF_REF, DOUBLE_METRIC_KEY, newMeasureBuilder().create(123.123d, 1)); underTest.execute(); @@ -271,7 +271,7 @@ public class PersistMeasuresStepTest extends BaseStepTest { .setVariation(createPeriod(4), 4.4d) .setVariation(createPeriod(5), 5.5d) .build()) - .create(10d)); + .create(10d, 1)); underTest.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComplexityMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComplexityMeasuresStepTest.java index 7f6b0921a69..878e4f521ff 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComplexityMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComplexityMeasuresStepTest.java @@ -204,14 +204,14 @@ public class ReportComplexityMeasuresStepTest { underTest.execute(); - assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(2.5))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(1d))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(2.5, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(1d, 1))); double expectedNonFileValue = 2d; - assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_MODULE_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_MODULE_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(entryOf(metricKey, newMeasureBuilder().create(expectedNonFileValue, 1))); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComputeMeasureVariationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComputeMeasureVariationsStepTest.java index 07f848adc1f..784a6103501 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComputeMeasureVariationsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComputeMeasureVariationsStepTest.java @@ -211,7 +211,7 @@ public class ReportComputeMeasureVariationsStepTest { addRawMeasure(PROJECT, ISSUES_METRIC, newMeasureBuilder().create(80, null)); addRawMeasure(PROJECT, DEBT_METRIC, newMeasureBuilder().create(5L, null)); - addRawMeasure(PROJECT, FILE_COMPLEXITY_METRIC, newMeasureBuilder().create(3d, null)); + addRawMeasure(PROJECT, FILE_COMPLEXITY_METRIC, newMeasureBuilder().create(3d, 1, null)); addRawMeasure(PROJECT, BUILD_BREAKER_METRIC, newMeasureBuilder().create(false, null)); underTest.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportCoverageMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportCoverageMeasuresStepTest.java index 220773de571..736c808e9fc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportCoverageMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportCoverageMeasuresStepTest.java @@ -204,19 +204,19 @@ public class ReportCoverageMeasuresStepTest { underTest.execute(); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains( - entryOf(codeCoverageKey, newMeasureBuilder().create(98.8d)), - entryOf(lineCoverageKey, newMeasureBuilder().create(99d)), - entryOf(branchCoverageKey, newMeasureBuilder().create(97d))); + entryOf(codeCoverageKey, newMeasureBuilder().create(98.8d, 1)), + entryOf(lineCoverageKey, newMeasureBuilder().create(99d, 1)), + entryOf(branchCoverageKey, newMeasureBuilder().create(97d, 1))); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains( - entryOf(codeCoverageKey, newMeasureBuilder().create(91d)), - entryOf(lineCoverageKey, newMeasureBuilder().create(90d)), - entryOf(branchCoverageKey, newMeasureBuilder().create(96d))); + entryOf(codeCoverageKey, newMeasureBuilder().create(91d, 1)), + entryOf(lineCoverageKey, newMeasureBuilder().create(90d, 1)), + entryOf(branchCoverageKey, newMeasureBuilder().create(96d, 1))); assertThat(toEntries(measureRepository.getAddedRawMeasures(UNIT_TEST_FILE_REF))).isEmpty(); MeasureRepoEntry[] nonFileRepoEntries = { - entryOf(codeCoverageKey, newMeasureBuilder().create(95.5d)), - entryOf(lineCoverageKey, newMeasureBuilder().create(95.4d)), - entryOf(branchCoverageKey, newMeasureBuilder().create(96.4d)) + entryOf(codeCoverageKey, newMeasureBuilder().create(95.5d, 1)), + entryOf(lineCoverageKey, newMeasureBuilder().create(95.4d, 1)), + entryOf(branchCoverageKey, newMeasureBuilder().create(96.4d, 1)) }; assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(nonFileRepoEntries); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportUnitTestMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportUnitTestMeasuresStepTest.java index 9da9e10ec1e..ba9c3ab4d7a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportUnitTestMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportUnitTestMeasuresStepTest.java @@ -130,12 +130,12 @@ public class ReportUnitTestMeasuresStepTest { underTest.execute(); - assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(40d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(70d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_MODULE_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(40d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(70d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_MODULE_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(60d, 1))); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComplexityMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComplexityMeasuresStepTest.java index dcad4dca23b..726f12a1c77 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComplexityMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComplexityMeasuresStepTest.java @@ -232,7 +232,7 @@ public class ViewsComplexityMeasuresStepTest { } private void assertAddedRawMeasures(int componentRef, String metricKey, double expected) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(expected))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(expected, 1))); } private void addRawMeasureValue(int componentRef, String metricKey, int value) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComputeMeasureVariationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComputeMeasureVariationsStepTest.java index f498a21c092..e005dceee43 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComputeMeasureVariationsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComputeMeasureVariationsStepTest.java @@ -214,7 +214,7 @@ public class ViewsComputeMeasureVariationsStepTest { addRawMeasure(VIEW, ISSUES_METRIC, Measure.newMeasureBuilder().create(80, null)); addRawMeasure(VIEW, DEBT_METRIC, Measure.newMeasureBuilder().create(5L, null)); - addRawMeasure(VIEW, FILE_COMPLEXITY_METRIC, Measure.newMeasureBuilder().create(3d, null)); + addRawMeasure(VIEW, FILE_COMPLEXITY_METRIC, Measure.newMeasureBuilder().create(3d, 1)); addRawMeasure(VIEW, BUILD_BREAKER_METRIC, Measure.newMeasureBuilder().create(false, null)); underTest.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsCoverageMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsCoverageMeasuresStepTest.java index 9d454dec179..27f6b72affa 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsCoverageMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsCoverageMeasuresStepTest.java @@ -215,17 +215,17 @@ public class ViewsCoverageMeasuresStepTest { assertThat(toEntries(measureRepository.getAddedRawMeasures(PROJECTVIEW_3_REF))).isEmpty(); MeasureRepoEntry[] subViewRepoEntries = { - entryOf(codeCoverageKey, newMeasureBuilder().create(95.5d)), - entryOf(lineCoverageKey, newMeasureBuilder().create(95.4d)), - entryOf(branchCoverageKey, newMeasureBuilder().create(96.4d)) + entryOf(codeCoverageKey, newMeasureBuilder().create(95.5d, 1)), + entryOf(lineCoverageKey, newMeasureBuilder().create(95.4d, 1)), + entryOf(branchCoverageKey, newMeasureBuilder().create(96.4d, 1)) }; assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_SUBVIEW_REF))).contains(subViewRepoEntries); assertThat(toEntries(measureRepository.getAddedRawMeasures(SUBVIEW_REF))).contains(subViewRepoEntries); assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains( - entryOf(codeCoverageKey, newMeasureBuilder().create(92d)), - entryOf(lineCoverageKey, newMeasureBuilder().create(91.2d)), - entryOf(branchCoverageKey, newMeasureBuilder().create(96.3d))); + entryOf(codeCoverageKey, newMeasureBuilder().create(92d, 1)), + entryOf(lineCoverageKey, newMeasureBuilder().create(91.2d, 1)), + entryOf(branchCoverageKey, newMeasureBuilder().create(96.3d, 1))); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsUnitTestMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsUnitTestMeasuresStepTest.java index 0035d6a9ece..522d835dc29 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsUnitTestMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsUnitTestMeasuresStepTest.java @@ -276,7 +276,7 @@ public class ViewsUnitTestMeasuresStepTest { private void assertAddedRawMeasureValue(int componentRef, String metricKey, double value) { assertThat(entryOf(metricKey, measureRepository.getAddedRawMeasure(componentRef, metricKey).get())) - .isEqualTo(entryOf(metricKey, newMeasureBuilder().create(value))); + .isEqualTo(entryOf(metricKey, newMeasureBuilder().create(value, 1))); } private void assertAddedRawMeasureValue(int componentRef, String metricKey, long value) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterMetricsTest.java b/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterMetricsTest.java index 6f6a63bfa85..f0d8dee6316 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterMetricsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/startup/RegisterMetricsTest.java @@ -81,6 +81,7 @@ public class RegisterMetricsTest { .setQualitative(true) .setDomain("new domain") .setUserManaged(false) + .setDecimalScale(3) .setHidden(true) .create(); Metric custom = new Metric.Builder("custom", "New custom", Metric.ValueType.FLOAT) diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics-result.xml index dbedde99411..fef184f9319 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics-result.xml @@ -3,6 +3,6 @@ <!-- disabled --> <metrics delete_historical_data="[false]" id="1" name="m1" val_type="FLOAT" description="desc1" domain="domain1" short_name="One" qualitative="[true]" user_managed="[false]" enabled="[false]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]" decimal_scale="[null]"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics.xml index b48ad61cd33..4ebaa508ddb 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/disable_undefined_metrics.xml @@ -4,6 +4,6 @@ short_name="One" qualitative="[true]" user_managed="[false]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]" decimal_scale="[null]"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric-result.xml index 1f4be94dde4..91722603b13 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric-result.xml @@ -4,6 +4,6 @@ short_name="New name" qualitative="[true]" user_managed="[false]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="-1" hidden="[true]"/> + optimized_best_value="[false]" best_value="[null]" direction="-1" hidden="[true]" decimal_scale="1"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric.xml index ad7f1e33933..3935b7ab168 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/enable_disabled_metric.xml @@ -4,6 +4,6 @@ short_name="One" qualitative="[true]" user_managed="[false]" enabled="[false]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]" decimal_scale="[null]"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/insert_new_metrics-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/insert_new_metrics-result.xml index 1bb5088d8e0..a525424ca47 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/insert_new_metrics-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/insert_new_metrics-result.xml @@ -2,10 +2,10 @@ <metrics delete_historical_data="[false]" id="1" name="m1" val_type="FLOAT" description="desc1" domain="domain1" short_name="One" qualitative="[true]" user_managed="[false]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]" decimal_scale="1"/> <metrics delete_historical_data="[false]" id="2" name="custom" val_type="FLOAT" description="This is a custom metric" domain="[null]" short_name="Custom" qualitative="[false]" user_managed="[true]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]" decimal_scale="1"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics-result.xml index 886e1d2d8f4..0cb384843c2 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics-result.xml @@ -4,12 +4,12 @@ <metrics delete_historical_data="[false]" id="1" name="m1" val_type="FLOAT" description="new description" domain="new domain" short_name="New name" qualitative="[true]" user_managed="[false]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="-1" hidden="[true]"/> + optimized_best_value="[false]" best_value="[null]" direction="-1" hidden="[true]" decimal_scale="3"/> <!-- custom metric is unchanged --> <metrics delete_historical_data="[false]" id="2" name="custom" val_type="FLOAT" description="This is a custom metric" domain="[null]" short_name="Custom" qualitative="[false]" user_managed="[true]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]" decimal_scale="1"/> </dataset> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics.xml b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics.xml index 483a9cb43c6..8f52db2d6f5 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/startup/RegisterMetricsTest/update_non_custom_metrics.xml @@ -3,10 +3,10 @@ <metrics delete_historical_data="[false]" id="1" name="m1" val_type="INT" description="old description" domain="old domain" short_name="old short name" qualitative="[false]" user_managed="[false]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="1" hidden="[false]" decimal_scale="[null]"/> <metrics delete_historical_data="[false]" id="2" name="custom" val_type="FLOAT" description="This is a custom metric" domain="[null]" short_name="Custom" qualitative="[false]" user_managed="[true]" enabled="[true]" worst_value="[null]" - optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]"/> + optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]" decimal_scale="1"/> </dataset> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/project_measure.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/project_measure.rb index e3195f67456..4b42ca50ded 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/project_measure.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/models/project_measure.rb @@ -79,7 +79,7 @@ class ProjectMeasure < ActiveRecord::Base when Metric::VALUE_TYPE_INT number_with_precision(value(), :precision => 0) when Metric::VALUE_TYPE_FLOAT - number_with_precision(value(), :precision => 1) + number_with_precision(value(), :precision => (metric().decimal_scale||1)) when Metric::VALUE_TYPE_PERCENT number_to_percentage(value(), {:precision => 1}) when Metric::VALUE_TYPE_MILLISEC @@ -108,12 +108,12 @@ class ProjectMeasure < ActiveRecord::Base when Metric::VALUE_TYPE_INT number_with_precision(val, :precision => 0) when Metric::VALUE_TYPE_FLOAT - number_with_precision(val, :precision => 1) + number_with_precision(val, :precision => (metric().decimal_scale||1)) when Metric::VALUE_TYPE_PERCENT if (options[:variation]==true) - number_with_precision(val, :precision => 1) + number_with_precision(val, :precision => (metric().decimal_scale||1)) else - number_to_percentage(val, {:precision => 1}) + number_to_percentage(val, {:precision => (metric().decimal_scale||1)}) end when Metric::VALUE_TYPE_MILLISEC millisecs_formatted_value(val) diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1005_add_decimal_scale_to_metrics.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1005_add_decimal_scale_to_metrics.rb new file mode 100644 index 00000000000..48d0bd5a1e2 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1005_add_decimal_scale_to_metrics.rb @@ -0,0 +1,33 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# + +# +# SonarQube 5.3 +# SONAR-6939 +# +class AddDecimalScaleToMetrics < ActiveRecord::Migration + + def self.up + add_column 'metrics', 'decimal_scale', :integer, :null => true + end + +end + + diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java index b78239bac82..9212cc46512 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java @@ -35,8 +35,6 @@ import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.output.BatchReport.Measure; import org.sonar.xoo.XooPlugin; -import org.sonar.xoo.measures.ConstantFloatMeasureSensor; -import org.sonar.xoo.measures.XooMetrics; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -52,7 +50,6 @@ public class MeasuresMediumTest { public BatchMediumTester tester = BatchMediumTester.builder() .registerPlugin("xoo", new XooPlugin()) .addDefaultQProfile("xoo", "Sonar Way") - .registerMetric(XooMetrics.CONSTANT_FLOAT_MEASURE) .build(); @Before @@ -103,71 +100,6 @@ public class MeasuresMediumTest { } @Test - public void floatMeasuresTruncatedTo1ByDefault() throws IOException { - File xooFile = new File(srcDir, "sample.xoo"); - File xooMeasureFile = new File(srcDir, "sample.xoo.measures"); - FileUtils.write(xooFile, "Sample xoo\ncontent"); - FileUtils.write(xooMeasureFile, "lines:20"); - - 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") - .put("sonar.cpd.xoo.skip", "true") - .put(ConstantFloatMeasureSensor.SONAR_XOO_ENABLE_FLOAT_SENSOR, "true") - .build()) - .start(); - - Map<String, List<Measure>> allMeasures = result.allMeasures(); - - assertThat(allMeasures.get("com.foo.project")).extracting("metricKey", "intValue", "doubleValue", "stringValue").containsOnly( - Tuple.tuple(CoreMetrics.QUALITY_PROFILES_KEY, 0, 0.0, - "[{\"key\":\"Sonar Way\",\"language\":\"xoo\",\"name\":\"Sonar Way\",\"rulesUpdatedAt\":\"2009-02-13T23:31:31+0000\"}]")); - - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue", "doubleValue").containsOnly( - Tuple.tuple(CoreMetrics.LINES_KEY, 2, 0.0), - Tuple.tuple(XooMetrics.CONSTANT_FLOAT_MEASURE_KEY, 0, 1.2)); - } - - @Test - public void floatMeasuresCustomPrecision() throws IOException { - File xooFile = new File(srcDir, "sample.xoo"); - File xooMeasureFile = new File(srcDir, "sample.xoo.measures"); - FileUtils.write(xooFile, "Sample xoo\ncontent"); - FileUtils.write(xooMeasureFile, "lines:20"); - - 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") - .put("sonar.cpd.xoo.skip", "true") - .put(ConstantFloatMeasureSensor.SONAR_XOO_ENABLE_FLOAT_SENSOR, "true") - .put(ConstantFloatMeasureSensor.SONAR_XOO_FLOAT_PRECISION, "5") - .build()) - .start(); - - Map<String, List<Measure>> allMeasures = result.allMeasures(); - - assertThat(allMeasures.get("com.foo.project")).extracting("metricKey", "intValue", "doubleValue", "stringValue").containsOnly( - Tuple.tuple(CoreMetrics.QUALITY_PROFILES_KEY, 0, 0.0, - "[{\"key\":\"Sonar Way\",\"language\":\"xoo\",\"name\":\"Sonar Way\",\"rulesUpdatedAt\":\"2009-02-13T23:31:31+0000\"}]")); - - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue", "doubleValue").containsOnly( - Tuple.tuple(CoreMetrics.LINES_KEY, 2, 0.0), - Tuple.tuple(XooMetrics.CONSTANT_FLOAT_MEASURE_KEY, 0, 1.23457)); - } - - @Test public void computeLinesOnAllFiles() throws IOException { File xooFile = new File(srcDir, "sample.xoo"); FileUtils.write(xooFile, "Sample xoo\n\ncontent"); diff --git a/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java b/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java index 9822dabaa84..c5bace1c447 100644 --- a/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java +++ b/sonar-db/src/main/java/org/sonar/db/metric/MetricDto.java @@ -55,6 +55,8 @@ public class MetricDto { private boolean enabled; + private Integer decimalScale; + public Integer getId() { return id; } @@ -196,4 +198,13 @@ public class MetricDto { return this; } + @CheckForNull + public Integer getDecimalScale() { + return decimalScale; + } + + public MetricDto setDecimalScale(@Nullable Integer i) { + this.decimalScale = i; + return this; + } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java index a9180d4e9c8..7bc2b344ce2 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java +++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java @@ -29,7 +29,7 @@ import org.sonar.db.MyBatis; public class DatabaseVersion { - public static final int LAST_VERSION = 1003; + public static final int LAST_VERSION = 1005; /** * The minimum supported version which can be upgraded. Lower diff --git a/sonar-db/src/main/resources/org/sonar/db/metric/MetricMapper.xml b/sonar-db/src/main/resources/org/sonar/db/metric/MetricMapper.xml index adf0d7544cb..58518e16eb7 100644 --- a/sonar-db/src/main/resources/org/sonar/db/metric/MetricMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/metric/MetricMapper.xml @@ -18,7 +18,8 @@ m.best_value as bestValue, m.optimized_best_value as optimizedBestValue, m.hidden, - m.delete_historical_data as deleteHistoricalData + m.delete_historical_data as deleteHistoricalData, + m.decimal_scale as decimalScale </sql> <select id="selectByKey" parameterType="map" resultType="org.sonar.db.metric.MetricDto"> @@ -86,13 +87,14 @@ keyProperty="id"> INSERT INTO metrics ( name, description, direction, domain, short_name, qualitative, val_type, user_managed, enabled, worst_value, - best_value, optimized_best_value, hidden, delete_historical_data) + best_value, optimized_best_value, hidden, delete_historical_data, decimal_scale) VALUES ( #{kee, jdbcType=VARCHAR}, #{description, jdbcType=VARCHAR}, #{direction, jdbcType=INTEGER}, #{domain, jdbcType=VARCHAR}, #{shortName, jdbcType=VARCHAR}, #{qualitative, jdbcType=BOOLEAN}, #{valueType, jdbcType=VARCHAR}, #{userManaged, jdbcType=BOOLEAN}, #{enabled, jdbcType=BOOLEAN}, #{worstValue, jdbcType=DOUBLE}, #{bestValue, jdbcType=DOUBLE}, - #{optimizedBestValue, jdbcType=BOOLEAN}, #{hidden, jdbcType=BOOLEAN}, #{deleteHistoricalData, jdbcType=BOOLEAN} + #{optimizedBestValue, jdbcType=BOOLEAN}, #{hidden, jdbcType=BOOLEAN}, #{deleteHistoricalData, jdbcType=BOOLEAN}, + #{decimalScale, jdbcType=INTEGER} ) </insert> @@ -107,7 +109,8 @@ description=#{description, jdbcType=VARCHAR}, direction=#{direction, jdbcType=INTEGER}, hidden=#{hidden, jdbcType=BOOLEAN}, - qualitative=#{qualitative, jdbcType=BOOLEAN} + qualitative=#{qualitative, jdbcType=BOOLEAN}, + decimal_scale=#{decimalScale, jdbcType=INTEGER} where id=#{id} </update> diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql index 0b770f42727..1e3e3a14b43 100644 --- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql +++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql @@ -364,6 +364,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1000'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1001'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1002'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1003'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1005'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl index d71d0d7399d..bda06b21a81 100644 --- a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -351,7 +351,8 @@ CREATE TABLE "METRICS" ( "BEST_VALUE" DOUBLE, "OPTIMIZED_BEST_VALUE" BOOLEAN, "HIDDEN" BOOLEAN, - "DELETE_HISTORICAL_DATA" BOOLEAN + "DELETE_HISTORICAL_DATA" BOOLEAN, + "DECIMAL_SCALE" INTEGER ); CREATE TABLE "LOADED_TEMPLATES" ( diff --git a/sonar-db/src/test/java/org/sonar/db/metric/MetricDaoTest.java b/sonar-db/src/test/java/org/sonar/db/metric/MetricDaoTest.java index eb3940fa9ae..473e83889b5 100644 --- a/sonar-db/src/test/java/org/sonar/db/metric/MetricDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/metric/MetricDaoTest.java @@ -82,6 +82,7 @@ public class MetricDaoTest { assertThat(result.isDeleteHistoricalData()).isFalse(); assertThat(result.isHidden()).isFalse(); assertThat(result.isEnabled()).isTrue(); + assertThat(result.getDecimalScale()).isEqualTo(3); // Disabled metrics are returned result = underTest.selectByKey(session, "disabled"); diff --git a/sonar-db/src/test/resources/org/sonar/db/metric/MetricDaoTest/shared.xml b/sonar-db/src/test/resources/org/sonar/db/metric/MetricDaoTest/shared.xml index dda5d3bbb88..1a43f8ed39e 100644 --- a/sonar-db/src/test/resources/org/sonar/db/metric/MetricDaoTest/shared.xml +++ b/sonar-db/src/test/resources/org/sonar/db/metric/MetricDaoTest/shared.xml @@ -2,14 +2,14 @@ <metrics id="1" name="ncloc" val_type="INT" description="Non Commenting Lines of Code" domain="Size" short_name="Lines of code" qualitative="[false]" enabled="[true]" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="-1" hidden="[false]" - delete_historical_data="[false]" user_managed="[false]"/> + delete_historical_data="[false]" user_managed="[false]" decimal_scale="[null]"/> <metrics id="2" name="coverage" val_type="PERCENT" description="Coverage by unit tests" domain="Tests" short_name="Coverage" qualitative="[true]" enabled="[true]" worst_value="0" optimized_best_value="[false]" best_value="100" direction="1" hidden="[false]" - delete_historical_data="[false]" user_managed="[false]"/> + delete_historical_data="[false]" user_managed="[false]" decimal_scale="3"/> <metrics id="3" name="disabled" val_type="INT" description="[null]" domain="[null]" short_name="disabled" qualitative="[false]" enabled="[false]" worst_value="0" optimized_best_value="[true]" best_value="100" direction="1" hidden="[false]" - delete_historical_data="[false]" user_managed="[false]"/> + delete_historical_data="[false]" user_managed="[false]" decimal_scale="[null]"/> </dataset> diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaContext.java index 766652028ed..50b1f151b7d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaContext.java @@ -19,37 +19,42 @@ */ package org.sonar.api.batch; +import org.sonar.api.measures.Formula; import org.sonar.api.measures.FormulaContext; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Resource; /** * @since 1.11 + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ +@Deprecated public class DefaultFormulaContext implements FormulaContext { - private Metric metric; - private DecoratorContext decoratorContext; - public DefaultFormulaContext(Metric metric) { - this.metric = metric; } @Override public Metric getTargetMetric() { - return metric; + throw fail(); } @Override public Resource getResource() { - return decoratorContext.getResource(); + throw fail(); } public void setMetric(Metric metric) { - this.metric = metric; + throw fail(); } public void setDecoratorContext(DecoratorContext decoratorContext) { - this.decoratorContext = decoratorContext; + throw fail(); + } + + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaData.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaData.java index 1aa4bc24193..8e218a00c9c 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaData.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DefaultFormulaData.java @@ -19,52 +19,51 @@ */ package org.sonar.api.batch; +import java.util.Collection; +import org.sonar.api.measures.Formula; import org.sonar.api.measures.FormulaData; import org.sonar.api.measures.Measure; import org.sonar.api.measures.MeasuresFilter; import org.sonar.api.measures.Metric; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * @since 1.11 + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ +@Deprecated public class DefaultFormulaData implements FormulaData { - private DecoratorContext decoratorContext; - - public DefaultFormulaData(DecoratorContext decoratorContext) { - this.decoratorContext = decoratorContext; + public DefaultFormulaData(DecoratorContext unused) { } @Override public Measure getMeasure(Metric metric) { - return decoratorContext.getMeasure(metric); + throw fail(); } @Override public <M> M getMeasures(MeasuresFilter<M> filter) { - return decoratorContext.getMeasures(filter); + throw fail(); } @Override public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) { - return decoratorContext.getChildrenMeasures(filter); + throw fail(); } @Override public Collection<Measure> getChildrenMeasures(Metric metric) { - return decoratorContext.getChildrenMeasures(metric); + throw fail(); } @Override public Collection<FormulaData> getChildren() { - List<FormulaData> result = new ArrayList<>(); - for (DecoratorContext childContext : decoratorContext.getChildren()) { - result.add(new DefaultFormulaData(childContext)); - } - return result; + throw fail(); + } + + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java index f029f438918..2c3af7f5b95 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java @@ -21,33 +21,15 @@ package org.sonar.api.measures; import java.util.List; -import org.sonar.api.resources.ResourceUtils; - -import static com.google.common.collect.Lists.newArrayList; /** - * Formula used to compute an average for a given metric A, which is the result of the sum of measures of this metric (A) divided by another metric (B). - * <p/> - * For example: to compute the metric "complexity by file", the main metric (A) is "complexity" and the other metric (B) is "file". - * * @since 3.0 - * @deprecated since 5.2 decorators are no more executed on batch side + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ @Deprecated public class AverageFormula implements Formula { - private Metric mainMetric; - private Metric byMetric; - private Metric fallbackMetric; - - /** - * This method should be private but it kep package-protected because of AverageComplexityFormula. - */ - AverageFormula(Metric mainMetric, Metric byMetric) { - this.mainMetric = mainMetric; - this.byMetric = byMetric; - } - /** * Creates a new {@link AverageFormula} class. * @@ -55,7 +37,7 @@ public class AverageFormula implements Formula { * @param by The metric used to divide the main metric to compute average (ex.: "file" for "complexity by file") */ public static AverageFormula create(Metric main, Metric by) { - return new AverageFormula(main, by); + return new AverageFormula(); } /** @@ -65,8 +47,7 @@ public class AverageFormula implements Formula { * @since 3.6 */ public AverageFormula setFallbackForMainMetric(Metric fallbackMetric) { - this.fallbackMetric = fallbackMetric; - return this; + throw fail(); } /** @@ -74,7 +55,7 @@ public class AverageFormula implements Formula { */ @Override public List<Metric> dependsUponMetrics() { - return fallbackMetric != null ? newArrayList(mainMetric, fallbackMetric, byMetric) : newArrayList(mainMetric, byMetric); + throw fail(); } /** @@ -82,56 +63,11 @@ public class AverageFormula implements Formula { */ @Override public Measure calculate(FormulaData data, FormulaContext context) { - if (!shouldDecorateResource(data, context)) { - return null; - } - - Measure result; - if (ResourceUtils.isFile(context.getResource())) { - result = calculateForFile(data, context); - } else { - result = calculateOnChildren(data, context); - } - return result; - } - - private Measure calculateOnChildren(FormulaData data, FormulaContext context) { - Measure result = null; - - double totalByMeasure = 0; - double totalMainMeasure = 0; - boolean hasApplicableChildren = false; - - for (FormulaData childrenData : data.getChildren()) { - Double fallbackMeasure = fallbackMetric != null ? MeasureUtils.getValue(childrenData.getMeasure(fallbackMetric), null) : null; - Double childrenByMeasure = MeasureUtils.getValue(childrenData.getMeasure(byMetric), null); - Double childrenMainMeasure = MeasureUtils.getValue(childrenData.getMeasure(mainMetric), fallbackMeasure); - if (childrenMainMeasure != null && childrenByMeasure != null && childrenByMeasure > 0.0) { - totalByMeasure += childrenByMeasure; - totalMainMeasure += childrenMainMeasure; - hasApplicableChildren = true; - } - } - if (hasApplicableChildren) { - result = new Measure(context.getTargetMetric(), totalMainMeasure / totalByMeasure); - } - return result; - } - - private Measure calculateForFile(FormulaData data, FormulaContext context) { - Measure result = null; - - Double fallbackMeasure = fallbackMetric != null ? MeasureUtils.getValue(data.getMeasure(fallbackMetric), null) : null; - Double byMeasure = MeasureUtils.getValue(data.getMeasure(byMetric), null); - Double mainMeasure = MeasureUtils.getValue(data.getMeasure(mainMetric), fallbackMeasure); - if (mainMeasure != null && byMeasure != null && byMeasure > 0.0) { - result = new Measure(context.getTargetMetric(), mainMeasure / byMeasure); - } - - return result; + throw fail(); } - private static boolean shouldDecorateResource(FormulaData data, FormulaContext context) { - return !MeasureUtils.hasValue(data.getMeasure(context.getTargetMetric())); + private static RuntimeException fail() { + throw new UnsupportedOperationException("Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. " + + "Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaContext.java index b3c2fcb524b..2011af669f9 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaContext.java @@ -23,7 +23,10 @@ import org.sonar.api.resources.Resource; /** * @since 1.11 + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ +@Deprecated public interface FormulaContext { Metric getTargetMetric(); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaData.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaData.java index 8cf5bb54307..459aec61695 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaData.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/FormulaData.java @@ -23,7 +23,10 @@ import java.util.Collection; /** * @since 1.11 + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ +@Deprecated public interface FormulaData { Measure getMeasure(Metric metric); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeanAggregationFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeanAggregationFormula.java index f66bf51009d..22647cca1d5 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeanAggregationFormula.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/MeanAggregationFormula.java @@ -19,21 +19,17 @@ */ package org.sonar.api.measures; -import java.util.Collection; -import java.util.Collections; import java.util.List; /** * @since 2.0 - * @deprecated since 5.2 decorators are no more executed on batch side + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ @Deprecated public class MeanAggregationFormula implements Formula { - private boolean forceZeroIfMissingData=false; - - public MeanAggregationFormula(boolean forceZeroIfMissingData) { - this.forceZeroIfMissingData = forceZeroIfMissingData; + public MeanAggregationFormula(boolean unused) { } public MeanAggregationFormula() { @@ -42,26 +38,16 @@ public class MeanAggregationFormula implements Formula { @Override public List<Metric> dependsUponMetrics() { - return Collections.emptyList(); + throw fail(); } @Override public Measure calculate(FormulaData data, FormulaContext context) { - double sum=0.0; - int count=0; - boolean hasValue=false; - Collection<Measure> measures = data.getChildrenMeasures(context.getTargetMetric()); - for (Measure measure : measures) { - if (MeasureUtils.hasValue(measure)) { - sum+=measure.getValue(); - count++; - hasValue=true; - } - } + throw fail(); + } - if (!hasValue && !forceZeroIfMissingData) { - return null; - } - return new Measure(context.getTargetMetric(), (count==0) ? 0.0 : (sum/count)); + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java index 4f2bef50a9f..adeae251213 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Measure.java @@ -21,8 +21,6 @@ package org.sonar.api.measures; import com.google.common.annotations.Beta; import java.io.Serializable; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.Date; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -43,7 +41,9 @@ public class Measure<G extends Serializable> implements Serializable { /** * Default precision when saving a float type metric + * @deprecated in 5.3. Decimal scale is provided by metric, not by measure. */ + @Deprecated public static final int DEFAULT_PRECISION = 1; protected String metricKey; @@ -322,27 +322,22 @@ public class Measure<G extends Serializable> implements Serializable { /** * Sets the measure value with a given precision * - * @param v the measure value - * @param precision the measure value precision - * @return the measure object instance + * @return {@code this} + * @deprecated in 5.3. The decimal scale is given by the metric, not by the measure. Anyway this parameter was enforced to 1 before version 5.3. */ - public Measure<G> setValue(@Nullable Double v, int precision) { + @Deprecated + public Measure<G> setValue(@Nullable Double v, int decimalScale) { if (v != null) { if (Double.isNaN(v)) { throw new IllegalArgumentException("Measure value can not be NaN"); } - this.value = scaleValue(v, precision); + this.value = v; } else { this.value = null; } return this; } - private static double scaleValue(double value, int scale) { - BigDecimal bd = BigDecimal.valueOf(value); - return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue(); - } - /** * @return the data field of the measure */ diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java index 949e0ab603c..8fdb94f44a6 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java @@ -27,19 +27,33 @@ import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.sonar.api.batch.BatchSide; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.server.ServerSide; +import static com.google.common.base.Objects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang.StringUtils.isNotBlank; + @BatchSide @InstantiationStrategy(InstantiationStrategy.PER_BATCH) @ServerSide public class Metric<G extends Serializable> implements Serializable, org.sonar.api.batch.measure.Metric<G> { /** + * @since 5.3 + */ + public static final int DEFAULT_DECIMAL_SCALE = 1; + + /** + * The maximum supported value of scale for decimal metrics + * @since 5.3 + */ + public static final int MAX_DECIMAL_SCALE = 20; + + /** * A metric bigger value means a degradation */ public static final int DIRECTION_WORST = -1; @@ -126,6 +140,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a private Boolean optimizedBestValue; private Boolean hidden = Boolean.FALSE; private Boolean deleteHistoricalData; + private Integer decimalScale; private Metric(Builder builder) { this.key = builder.key; @@ -143,6 +158,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a this.formula = builder.formula; this.userManaged = builder.userManaged; this.deleteHistoricalData = builder.deleteHistoricalData; + this.decimalScale = builder.decimalScale; } /** @@ -208,9 +224,12 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a this.name = name; this.qualitative = qualitative; this.userManaged = userManaged; - if (ValueType.PERCENT.equals(this.type)) { + if (ValueType.PERCENT == this.type) { this.bestValue = (direction == DIRECTION_BETTER) ? 100.0 : 0.0; this.worstValue = (direction == DIRECTION_BETTER) ? 0.0 : 100.0; + this.decimalScale = DEFAULT_DECIMAL_SCALE; + } else if (ValueType.FLOAT == this.type) { + this.decimalScale = DEFAULT_DECIMAL_SCALE; } } @@ -492,6 +511,15 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a return deleteHistoricalData; } + /** + * Return the number scale if metric type is {@link ValueType#FLOAT}, else {@code null} + * @since 5.3 + */ + @CheckForNull + public Integer getDecimalScale() { + return decimalScale; + } + @Override public int hashCode() { return key.hashCode(); @@ -557,6 +585,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a private boolean hidden = false; private boolean userManaged = false; private boolean deleteHistoricalData = false; + private Integer decimalScale = null; /** * Creates a new {@link Builder} object. @@ -566,15 +595,9 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a * @param type the metric type */ public Builder(String key, String name, ValueType type) { - if (StringUtils.isBlank(key)) { - throw new IllegalArgumentException("Metric key can not be blank"); - } - if (StringUtils.isBlank(name)) { - throw new IllegalArgumentException("Metric name can not be blank"); - } - if (type == null) { - throw new IllegalArgumentException("Metric type can not be null"); - } + checkArgument(isNotBlank(key), "Metric key can not be blank"); + checkArgument(isNotBlank(name), "Name of metric %s must be set", key); + checkArgument(type != null, "Type of metric %s must be set", key); this.key = key; this.name = name; this.type = type; @@ -647,11 +670,6 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a * When a formula is set, sensors/decorators just need to store measures at a specific level and let Sonar run the formula to store * measures on the remaining levels. * - * @see SumChildDistributionFormula - * @see SumChildValuesFormula - * @see MeanAggregationFormula - * @see WeightedMeanAggregationFormula - * * @param f the formula * @return the builder * @@ -741,14 +759,30 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a } /** + * Scale to be used if the metric has decimal type ({@link ValueType#FLOAT} or {@link ValueType#PERCENT}). + * Default is 1. It is not set (({@code null}) on non-decimal metrics. + * @since 5.3 + */ + public Builder setDecimalScale(int scale) { + checkArgument(scale >= 0, "Scale of decimal metric %s must be positive: %d", key, scale); + checkArgument(scale <= MAX_DECIMAL_SCALE, "Scale of decimal metric [%s] must be less than or equal %s: %s", key, MAX_DECIMAL_SCALE, scale); + this.decimalScale = scale; + return this; + } + + /** * Creates a new metric definition based on the properties set on this metric builder. * * @return a new {@link Metric} object */ public <G extends Serializable> Metric<G> create() { - if (ValueType.PERCENT.equals(this.type)) { + if (ValueType.PERCENT == this.type) { this.bestValue = (direction == DIRECTION_BETTER) ? 100.0 : 0.0; this.worstValue = (direction == DIRECTION_BETTER) ? 0.0 : 100.0; + this.decimalScale = firstNonNull(decimalScale, DEFAULT_DECIMAL_SCALE); + + } else if (ValueType.FLOAT == this.type) { + this.decimalScale = firstNonNull(decimalScale, DEFAULT_DECIMAL_SCALE); } return new Metric<>(this); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java index e75a2f3c119..616eb2cbff7 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildDistributionFormula.java @@ -19,50 +19,38 @@ */ package org.sonar.api.measures; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import org.sonar.api.resources.Scopes; /** * @since 2.0 * * Used to consolidate a distribution measure throughout the resource tree - * @deprecated since 5.2 decorators are no more executed on batch side + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ @Deprecated public class SumChildDistributionFormula implements Formula { - private String minimumScopeToPersist= Scopes.FILE; - @Override public List<Metric> dependsUponMetrics() { - return Collections.emptyList(); + throw fail(); } public String getMinimumScopeToPersist() { - return minimumScopeToPersist; + throw fail(); } public SumChildDistributionFormula setMinimumScopeToPersist(String s) { - this.minimumScopeToPersist = s; - return this; + throw fail(); } @Override public Measure calculate(FormulaData data, FormulaContext context) { - Collection<Measure> measures = data.getChildrenMeasures(context.getTargetMetric()); - if (measures == null || measures.isEmpty()) { - return null; - } - RangeDistributionBuilder distribution = new RangeDistributionBuilder(context.getTargetMetric()); - for (Measure measure : measures) { - distribution.add(measure); - } - Measure measure = distribution.build(); - if (!Scopes.isHigherThanOrEquals(context.getResource().getScope(), minimumScopeToPersist)) { - measure.setPersistenceMode(PersistenceMode.MEMORY); - } - return measure; + throw fail(); + } + + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildValuesFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildValuesFormula.java index 37e7abf6a25..450befdee5a 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildValuesFormula.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/SumChildValuesFormula.java @@ -19,33 +19,31 @@ */ package org.sonar.api.measures; -import java.util.Collections; import java.util.List; /** * @since 1.11 - * @deprecated since 5.2 decorators are no more executed on batch side + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ @Deprecated public class SumChildValuesFormula implements Formula { - private boolean saveZeroIfNoChildValues; - - public SumChildValuesFormula(boolean saveZeroIfNoChildValues) { - this.saveZeroIfNoChildValues = saveZeroIfNoChildValues; + public SumChildValuesFormula(boolean unused) { } @Override public List<Metric> dependsUponMetrics() { - return Collections.emptyList(); + throw fail(); } @Override public Measure calculate(FormulaData data, FormulaContext context) { - Double sum = MeasureUtils.sum(saveZeroIfNoChildValues, data.getChildrenMeasures(context.getTargetMetric())); - if (sum != null) { - return new Measure(context.getTargetMetric(), sum); - } - return null; + throw fail(); + } + + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/WeightedMeanAggregationFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/WeightedMeanAggregationFormula.java index 7be604edaf6..360eb01ea9e 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/WeightedMeanAggregationFormula.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/WeightedMeanAggregationFormula.java @@ -19,54 +19,31 @@ */ package org.sonar.api.measures; -import java.util.Collections; import java.util.List; /** * @since 2.0 - * @deprecated since 5.2 decorators are no more executed on batch side + * @deprecated since 5.2. Aggregation of measures is provided by {@link org.sonar.api.ce.measure.MeasureComputer}. {@link org.sonar.api.batch.Decorator} + * and {@link Formula} are no more supported. */ @Deprecated public class WeightedMeanAggregationFormula implements Formula { - private Metric weightingMetric; - private boolean zeroIfNoValues=false; - public WeightedMeanAggregationFormula(Metric weightingMetric, boolean zeroIfNoValues) { - this.weightingMetric = weightingMetric; - if (weightingMetric==null) { - throw new IllegalArgumentException("Metric can not be null"); - } - this.zeroIfNoValues = zeroIfNoValues; } @Override public List<Metric> dependsUponMetrics() { - return Collections.emptyList(); + throw fail(); } @Override public Measure calculate(FormulaData data, FormulaContext context) { - double sum=0.0; - double count=0.0; - boolean hasValue=false; - - for (FormulaData child : data.getChildren()) { - Measure measure = child.getMeasure(context.getTargetMetric()); - Measure weightingMeasure = child.getMeasure(weightingMetric); - if (MeasureUtils.haveValues(measure, weightingMeasure)) { - sum += measure.getValue() * weightingMeasure.getValue(); - count += weightingMeasure.getValue(); - hasValue=true; - } - } - - if (!hasValue && !zeroIfNoValues) { - return null; - } + throw fail(); + } - double result = (Double.doubleToRawLongBits(count)==0L) ? 0.0 : (sum/count); - return new Measure(context.getTargetMetric(), result); + private static RuntimeException fail() { + throw new UnsupportedOperationException( + "Unsupported since version 5.2. Decorators and formulas are not used anymore for aggregation measures. Please use org.sonar.api.ce.measure.MeasureComputer."); } } - diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/DefaultFormulaDataTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/DefaultFormulaDataTest.java index 5139aa75edb..03f6188eea6 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/DefaultFormulaDataTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/DefaultFormulaDataTest.java @@ -23,42 +23,22 @@ import org.junit.Test; import org.sonar.api.measures.MeasuresFilter; import org.sonar.api.measures.Metric; -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class DefaultFormulaDataTest { - @Test - public void isDecoratorContextProxy() { - DecoratorContext context = mock(DecoratorContext.class); - DefaultFormulaData data = new DefaultFormulaData(context); - - data.getChildrenMeasures(any(MeasuresFilter.class)); - verify(context).getChildrenMeasures(any(MeasuresFilter.class)); + DefaultFormulaData underTest = new DefaultFormulaData(null); - data.getChildrenMeasures(any(Metric.class)); - verify(context).getChildrenMeasures(any(Metric.class)); - - data.getMeasures(any(MeasuresFilter.class)); - verify(context).getMeasures(any(MeasuresFilter.class)); - - data.getMeasure(any(Metric.class)); - verify(context).getMeasure(any(Metric.class)); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_1() { + underTest.getChildren(); } - @Test - public void getChildren() { - DecoratorContext context = mock(DecoratorContext.class); - DecoratorContext child1 = mock(DecoratorContext.class); - DecoratorContext child2 = mock(DecoratorContext.class); - when(context.getChildren()).thenReturn(Arrays.asList(child1, child2)); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_2() { + underTest.getChildrenMeasures((MeasuresFilter) null); + } - DefaultFormulaData data = new DefaultFormulaData(context); - assertThat(data.getChildren()).hasSize(2); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_3() { + underTest.getChildrenMeasures((Metric) null); } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageFormulaTest.java index e4a9c96f57c..cc05ee44bbf 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageFormulaTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/AverageFormulaTest.java @@ -19,174 +19,24 @@ */ package org.sonar.api.measures; -import org.junit.Before; import org.junit.Test; -import org.sonar.api.resources.File; - -import java.util.List; - -import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class AverageFormulaTest { - private FormulaContext context; - private FormulaData data; + AverageFormula underTest = new AverageFormula(); - @Before - public void before() { - context = mock(FormulaContext.class); - when(context.getTargetMetric()).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY); - data = mock(FormulaData.class); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_1() { + underTest.calculate(null, null); } - @Test - public void test_depends_upon_metrics() throws Exception { - AverageFormula formula = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS); - assertThat(formula.dependsUponMetrics()).containsOnly(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_2() { + underTest.dependsUponMetrics(); } - @Test - public void test_depends_upon_fallback_metric() throws Exception { - AverageFormula formula = AverageFormula.create(CoreMetrics.COMPLEXITY_IN_FUNCTIONS, CoreMetrics.FUNCTIONS).setFallbackForMainMetric(CoreMetrics.COMPLEXITY); - assertThat(formula.dependsUponMetrics()).containsOnly(CoreMetrics.COMPLEXITY_IN_FUNCTIONS, CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_3() { + underTest.setFallbackForMainMetric(null); } - - @Test - public void test_average_calculation() { - List<FormulaData> childrenData = newArrayList(); - FormulaData data1 = mock(FormulaData.class); - childrenData.add(data1); - when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); - when(data1.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 107.0)); - - FormulaData data2 = mock(FormulaData.class); - childrenData.add(data2); - when(data2.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 127.0)); - when(data2.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 233.0)); - - when(data.getChildren()).thenReturn(childrenData); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - - assertThat(measure.getValue()).isEqualTo(2.0); - } - - @Test - public void should_not_compute_if_not_target_metric() { - when(data.getMeasure(CoreMetrics.FUNCTION_COMPLEXITY)).thenReturn(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, 2.0)); - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - assertThat(measure).isNull(); - } - - @Test - public void test_when_no_children_measures() { - List<FormulaData> childrenData = newArrayList(); - when(data.getChildren()).thenReturn(childrenData); - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - assertThat(measure).isNull(); - } - - @Test - public void test_when_no_complexity_measures() { - List<FormulaData> childrenData = newArrayList(); - FormulaData data1 = mock(FormulaData.class); - childrenData.add(data1); - when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); - - when(data.getChildren()).thenReturn(childrenData); - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - - assertThat(measure).isNull(); - } - - @Test - public void test_when_no_by_metric_measures() { - List<FormulaData> childrenData = newArrayList(); - FormulaData data1 = mock(FormulaData.class); - childrenData.add(data1); - when(data1.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 43.0)); - - when(data.getChildren()).thenReturn(childrenData); - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - - assertThat(measure).isNull(); - } - - @Test - public void test_when_mixed_metrics() { - List<FormulaData> childrenData = newArrayList(); - FormulaData data1 = mock(FormulaData.class); - childrenData.add(data1); - when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); - when(data1.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 107.0)); - - FormulaData data2 = mock(FormulaData.class); - childrenData.add(data2); - when(data2.getMeasure(CoreMetrics.STATEMENTS)).thenReturn(new Measure(CoreMetrics.STATEMENTS, 127.0)); - when(data2.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 233.0)); - - when(data.getChildren()).thenReturn(childrenData); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - - assertThat(measure.getValue()).isEqualTo(2.5); - } - - @Test - public void test_calculation_for_file() { - when(data.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 60.0)); - when(data.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 20.0)); - when(context.getResource()).thenReturn(File.create("foo")); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY, CoreMetrics.FUNCTIONS).calculate(data, context); - assertThat(measure.getValue()).isEqualTo(3.0); - } - - @Test - public void should_use_fallback_metric_when_no_data_on_main_metric_for_file() { - when(data.getMeasure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS)).thenReturn(null); - when(data.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 60.0)); - when(data.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 20.0)); - when(context.getResource()).thenReturn(File.create("foo")); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY_IN_FUNCTIONS, CoreMetrics.FUNCTIONS) - .setFallbackForMainMetric(CoreMetrics.COMPLEXITY) - .calculate(data, context); - assertThat(measure.getValue()).isEqualTo(3.0); - } - - @Test - public void should_use_main_metric_even_if_fallback_metric_provided() { - when(data.getMeasure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 60.0)); - when(data.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 42.0)); - when(data.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 20.0)); - when(context.getResource()).thenReturn(File.create("foo")); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY_IN_FUNCTIONS, CoreMetrics.FUNCTIONS) - .setFallbackForMainMetric(CoreMetrics.COMPLEXITY) - .calculate(data, context); - assertThat(measure.getValue()).isEqualTo(3.0); - } - - @Test - public void should_use_fallback_metric_when_no_data_on_main_metric_for_children() { - List<FormulaData> childrenData = newArrayList(); - FormulaData data1 = mock(FormulaData.class); - childrenData.add(data1); - when(data1.getMeasure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS)).thenReturn(null); - when(data1.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(new Measure(CoreMetrics.COMPLEXITY, 107.0)); - when(data1.getMeasure(CoreMetrics.FUNCTIONS)).thenReturn(new Measure(CoreMetrics.FUNCTIONS, 43.0)); - - when(data.getChildren()).thenReturn(childrenData); - - Measure measure = AverageFormula.create(CoreMetrics.COMPLEXITY_IN_FUNCTIONS, CoreMetrics.FUNCTIONS) - .setFallbackForMainMetric(CoreMetrics.COMPLEXITY) - .calculate(data, context); - - assertThat(measure.getValue()).isEqualTo(2.5); - } - } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeanAggregationFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeanAggregationFormulaTest.java index c1443832c7b..2beec78cdd1 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeanAggregationFormulaTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeanAggregationFormulaTest.java @@ -19,57 +19,19 @@ */ package org.sonar.api.measures; -import org.junit.Before; import org.junit.Test; -import java.util.Arrays; -import java.util.Collections; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class MeanAggregationFormulaTest { - private FormulaContext context; - private FormulaData data; - - @Before - public void before() { - context = mock(FormulaContext.class); - data = mock(FormulaData.class); - } - - @Test - public void calculateChildrenMean() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.COVERAGE); - when(data.getChildrenMeasures(CoreMetrics.COVERAGE)).thenReturn(Arrays.<Measure>asList(newCoverage(100.0), newCoverage(50.0), newCoverage(30.0))); - - Measure measure = new MeanAggregationFormula().calculate(data, context); - assertThat(measure.getValue(), is(60.0)); - } - - @Test - public void doNotForceZero() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.COVERAGE); - when(data.getChildrenMeasures(CoreMetrics.COVERAGE)).thenReturn(Collections.<Measure>emptyList()); - - Measure measure = new MeanAggregationFormula(false).calculate(data, context); - assertNull(measure); - } - - @Test - public void forceZero() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.COVERAGE); - when(data.getChildrenMeasures(CoreMetrics.COVERAGE)).thenReturn(Collections.<Measure>emptyList()); + MeanAggregationFormula underTest = new MeanAggregationFormula(); - Measure measure = new MeanAggregationFormula(true).calculate(data, context); - assertThat(measure.getValue(), is(0.0)); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_1() { + underTest.calculate(null, null); } - private Measure newCoverage(double val) { - return new Measure(CoreMetrics.COVERAGE, val); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_2() { + underTest.dependsUponMetrics(); } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java index 9a33b01caab..b671a63e9c7 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MeasureTest.java @@ -46,12 +46,6 @@ public class MeasureTest { } @Test - public void scaleValue() { - assertThat(new Measure(CoreMetrics.COVERAGE, 80.666666).getValue()).isEqualTo(80.7); - assertThat(new Measure(CoreMetrics.COVERAGE, 80.666666, 2).getValue()).isEqualTo(80.67); - } - - @Test public void defaultPersistenceModeIsFull() { assertThat(new Measure(CoreMetrics.LINES, 32.0).getPersistenceMode()).isEqualTo(PersistenceMode.FULL); } @@ -81,15 +75,6 @@ public class MeasureTest { assertThat(new Measure(CoreMetrics.LINES).setValue(3.6).getIntValue()).isEqualTo(3); } - @Test - public void valuesAreRoundUp() { - assertThat(new Measure(CoreMetrics.COVERAGE, 5.22222222).getValue()).isEqualTo(5.2); - assertThat(new Measure(CoreMetrics.COVERAGE, 5.7777777).getValue()).isEqualTo(5.8); - - assertThat(new Measure(CoreMetrics.COVERAGE, 5.22222222, 3).getValue()).isEqualTo(5.222); - assertThat(new Measure(CoreMetrics.COVERAGE, 5.7777777, 3).getValue()).isEqualTo(5.778); - } - /** * Proper definition of equality for measures is important, because used to store them. */ diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java index 24ae4b69be7..0a088f53d3a 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/MetricTest.java @@ -19,55 +19,97 @@ */ package org.sonar.api.measures; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class MetricTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Test public void shouldCreateMetric() { Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.INT) - .setDomain("my domain") - .create(); + .setDomain("my domain") + .create(); - assertThat(metric.getKey(), is("foo")); - assertThat(metric.getName(), is("Foo")); - assertThat(metric.getDomain(), is("my domain")); + assertThat(metric.getKey()).isEqualTo("foo"); + assertThat(metric.getName()).isEqualTo("Foo"); + assertThat(metric.getDomain()).isEqualTo("my domain"); } @Test public void shouldCreateMetricWithDefaultValues() { Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.INT) - .create(); - - assertThat(metric.getBestValue(), nullValue()); - assertThat(metric.getDescription(), nullValue()); - assertThat(metric.getWorstValue(), nullValue()); - assertThat(metric.getDirection(), is(Metric.DIRECTION_NONE)); - assertThat(metric.getEnabled(), is(true)); - assertThat(metric.getFormula(), nullValue()); - assertThat(metric.getId(), nullValue()); - assertThat(metric.getUserManaged(), is(false)); - assertThat(metric.isHidden(), is(false)); - assertThat(metric.isOptimizedBestValue(), is(false)); + .create(); + + assertThat(metric.getBestValue()).isNull(); + assertThat(metric.getDescription()).isNull(); + assertThat(metric.getWorstValue()).isNull(); + assertThat(metric.getDirection()).isEqualTo(Metric.DIRECTION_NONE); + assertThat(metric.getEnabled()).isTrue(); + assertThat(metric.getFormula()).isNull(); + assertThat(metric.getId()).isNull(); + assertThat(metric.getUserManaged()).isFalse(); + assertThat(metric.isHidden()).isFalse(); + assertThat(metric.isOptimizedBestValue()).isFalse(); } @Test public void shouldCreatePercentMetricWithDefaultValues() { Metric better = new Metric.Builder("foo", "Foo", Metric.ValueType.PERCENT) - .setDirection(Metric.DIRECTION_BETTER) - .create(); + .setDirection(Metric.DIRECTION_BETTER) + .create(); Metric worst = new Metric.Builder("foo", "Foo", Metric.ValueType.PERCENT) - .setDirection(Metric.DIRECTION_WORST) - .create(); + .setDirection(Metric.DIRECTION_WORST) + .create(); + + assertThat(better.getBestValue()).isEqualTo(100.0); + assertThat(better.getWorstValue()).isEqualTo(0.0); + assertThat(worst.getBestValue()).isEqualTo(0.0); + assertThat(worst.getWorstValue()).isEqualTo(100.0); + } + + @Test + public void override_decimal_scale_of_float_metric() { + Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.FLOAT) + .setDecimalScale(3) + .create(); + assertThat(metric.getDecimalScale()).isEqualTo(3); + } + + @Test + public void fail_if_decimal_scale_is_greater_than_max_supported_value() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Scale of decimal metric [foo] must be less than or equal 20: 21"); - assertThat(better.getBestValue(), is(100.0)); - assertThat(better.getWorstValue(), is(0.0)); - assertThat(worst.getBestValue(), is(0.0)); - assertThat(worst.getWorstValue(), is(100.0)); + new Metric.Builder("foo", "Foo", Metric.ValueType.FLOAT) + .setDecimalScale(Metric.MAX_DECIMAL_SCALE + 1) + .create(); } + @Test + public void override_decimal_scale_of_percent_metric() { + Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.PERCENT) + .setDecimalScale(3) + .create(); + assertThat(metric.getDecimalScale()).isEqualTo(3); + } + + @Test + public void default_decimal_scale_is_1() { + Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.FLOAT) + .create(); + assertThat(metric.getDecimalScale()).isEqualTo(1); + } + + @Test + public void non_decimal_metric_has_no_scale() { + Metric metric = new Metric.Builder("foo", "Foo", Metric.ValueType.INT) + .create(); + assertThat(metric.getDecimalScale()).isNull(); + } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java index b4d64fd8551..e712da3f312 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildDistributionFormulaTest.java @@ -19,122 +19,29 @@ */ package org.sonar.api.measures; -import com.google.common.collect.Lists; -import org.junit.Before; import org.junit.Test; -import org.sonar.api.resources.Directory; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Scopes; - -import java.util.Collections; -import java.util.List; - -import static junit.framework.Assert.assertNull; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class SumChildDistributionFormulaTest { - SumChildDistributionFormula formula; - FormulaContext context; - FormulaData data; - - @Before - public void init() { - formula = new SumChildDistributionFormula(); - context = mock(FormulaContext.class); - when(context.getResource()).thenReturn(File.create("foo")); - data = mock(FormulaData.class); - } - - @Test - public void testWhenGetChildrenReturnsNull() { - when(context.getTargetMetric()).thenReturn(new Metric("foo")); - when(data.getChildrenMeasures(new Metric("foo"))).thenReturn(null); - assertNull(formula.calculate(data, context)); - } - - @Test - public void testWhenGetChildrenReturnsEmpty() { - when(context.getTargetMetric()).thenReturn(new Metric("foo")); - when(data.getChildrenMeasures(new Metric("foo"))).thenReturn(Collections.<Measure>emptyList()); - assertNull(formula.calculate(data, context)); - } - - @Test - public void shouldNotSumDifferentRanges() { - Metric m = new Metric("foo", Metric.ValueType.DATA); - when(context.getTargetMetric()).thenReturn(m); - - List<Measure> list = Lists.newArrayList( - new Measure(m, "1=0;2=2;5=0;10=10;20=2"), - new Measure(m, "1=0;2=2;5=0;10=10;30=3") - ); - when(data.getChildrenMeasures(new Metric("foo"))).thenReturn(list); - assertThat(formula.calculate(data, context), nullValue()); - } - @Test - public void shouldSumSameIntRanges() { - Metric m = new Metric("foo", Metric.ValueType.DATA); - when(context.getTargetMetric()).thenReturn(m); + SumChildDistributionFormula underTest = new SumChildDistributionFormula(); - List<Measure> list = Lists.newArrayList( - new Measure(m, "1=0;2=2;5=0;10=10;20=2"), - new Measure(m, "1=3;2=2;5=3;10=12;20=0") - ); - when(data.getChildrenMeasures(new Metric("foo"))).thenReturn(list); - assertThat(formula.calculate(data, context).getData(), is("1=3;2=4;5=3;10=22;20=2")); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_1() { + underTest.calculate(null, null); } - @Test - public void shouldSumSameDoubleRanges() { - initContextWithChildren(); - assertThat(formula.calculate(data, context).getData(), is("0.5=3;2.5=6")); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_2() { + underTest.dependsUponMetrics(); } - @Test - public void shouldNotPersistWhenScopeLowerThanMinimun() { - when(context.getResource()).thenReturn(File.create("org/Foo.java")); - - initContextWithChildren(); - formula.setMinimumScopeToPersist(Scopes.DIRECTORY); - - Measure distribution = formula.calculate(data, context); - assertThat(distribution.getPersistenceMode().useDatabase(), is(false)); - } - - @Test - public void shouldPersistWhenScopeEqualsMinimun() { - when(context.getResource()).thenReturn(File.create("org/Foo.java")); - - initContextWithChildren(); - formula.setMinimumScopeToPersist(Scopes.FILE); - - Measure distribution = formula.calculate(data, context); - assertThat(distribution.getPersistenceMode().useDatabase(), is(true)); - } - - @Test - public void shouldPersistWhenScopeHigherThanMinimun() { - when(context.getResource()).thenReturn(Directory.create("org/foo")); - - initContextWithChildren(); - formula.setMinimumScopeToPersist(Scopes.FILE); - - Measure distribution = formula.calculate(data, context); - assertThat(distribution.getPersistenceMode().useDatabase(), is(true)); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_3() { + underTest.getMinimumScopeToPersist(); } - private void initContextWithChildren() { - Metric m = new Metric("foo", Metric.ValueType.DATA); - when(context.getTargetMetric()).thenReturn(m); - List<Measure> list = Lists.newArrayList( - new Measure(m, "0.5=0;2.5=2"), - new Measure(m, "0.5=3;2.5=4") - ); - when(data.getChildrenMeasures(new Metric("foo"))).thenReturn(list); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_4() { + underTest.setMinimumScopeToPersist(null); } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildValuesFormulaTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildValuesFormulaTest.java deleted file mode 100644 index 5bc69ab6684..00000000000 --- a/sonar-plugin-api/src/test/java/org/sonar/api/measures/SumChildValuesFormulaTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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.api.measures; - -import org.junit.Before; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SumChildValuesFormulaTest { - private FormulaContext context; - private FormulaData data; - - @Before - public void before() { - context = mock(FormulaContext.class); - data = mock(FormulaData.class); - } - - @Test - public void sumChildValues() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.NCLOC); - when(data.getChildrenMeasures(CoreMetrics.NCLOC)).thenReturn( - Arrays.<Measure>asList(new Measure(CoreMetrics.NCLOC, 100.0), new Measure(CoreMetrics.NCLOC, 50.0))); - - Measure measure = new SumChildValuesFormula(true).calculate(data, context); - - assertThat(measure.getMetric()).isEqualTo(CoreMetrics.NCLOC); - assertThat(measure.getValue()).isEqualTo(150.0); - } - - @Test - public void doNotInsertZero() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.NCLOC); - when(data.getChildrenMeasures(CoreMetrics.NCLOC)).thenReturn(Collections.<Measure>emptyList()); - - Measure measure = new SumChildValuesFormula(false).calculate(data, context); - - assertThat(measure).isNull(); - } - - @Test - public void doInsertZero() { - when(context.getTargetMetric()).thenReturn(CoreMetrics.NCLOC); - when(data.getChildrenMeasures(CoreMetrics.NCLOC)).thenReturn(Collections.<Measure>emptyList()); - - Measure measure = new SumChildValuesFormula(true).calculate(data, context); - - assertThat(measure.getMetric()).isEqualTo(CoreMetrics.NCLOC); - assertThat(measure.getValue()).isEqualTo(0.0); - } -} diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/package-info.java b/sonar-plugin-api/src/test/java/org/sonar/api/measures/WeightedMeanAggregationFormulaTest.java index 53dbecc35dc..3aa8d6d50af 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/measures/package-info.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/measures/WeightedMeanAggregationFormulaTest.java @@ -17,9 +17,20 @@ * 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.api.measures; -@ParametersAreNonnullByDefault -package org.sonar.xoo.measures; +import org.junit.Test; -import javax.annotation.ParametersAreNonnullByDefault; +public class WeightedMeanAggregationFormulaTest { + WeightedMeanAggregationFormula underTest = new WeightedMeanAggregationFormula(null, false); + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_1() { + underTest.calculate(null, null); + } + + @Test(expected = UnsupportedOperationException.class) + public void fail_if_used_2() { + underTest.dependsUponMetrics(); + } +} |