aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-07-01 18:33:52 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-07-02 13:46:26 +0200
commit00bd0332e9346fc49d9cd5205deb34929be2b22f (patch)
treec35d2ac1de1c33aa5b6ae6b4745f85ef57861801
parent4a199cc79ff17dfc24f8de685760bcbda0e48d09 (diff)
downloadsonarqube-00bd0332e9346fc49d9cd5205deb34929be2b22f.tar.gz
sonarqube-00bd0332e9346fc49d9cd5205deb34929be2b22f.zip
SONAR-6605 Create average formula
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java178
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaStepTest.java121
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java254
3 files changed, 553 insertions, 0 deletions
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
new file mode 100644
index 00000000000..8d9c3cb996c
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/AverageFormula.java
@@ -0,0 +1,178 @@
+/*
+ * 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.server.computation.formula;
+
+import com.google.common.base.Optional;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.measure.Measure;
+
+public class AverageFormula implements Formula<AverageFormula.AverageCounter> {
+
+ private final String outputMetricKey;
+
+ private final String mainMetric;
+ private final String byMetric;
+ @CheckForNull
+ private final String fallbackMetric;
+
+ private AverageFormula(Builder builder) {
+ this.outputMetricKey = builder.outputMetricKey;
+ this.mainMetric = builder.mainMetric;
+ this.byMetric = builder.byMetric;
+ this.fallbackMetric = builder.fallbackMetric;
+ }
+
+ @Override
+ public AverageCounter createNewCounter() {
+ return new AverageCounter();
+ }
+
+ @Override
+ public Optional<Measure> createMeasure(AverageCounter counter, Component.Type componentType) {
+ Optional<Double> mainValueOptional = counter.getMainValue();
+ Optional<Double> byValueOptional = counter.getByValue();
+ if (mainValueOptional.isPresent() && byValueOptional.isPresent()) {
+ double mainValue = mainValueOptional.get();
+ double byValue = byValueOptional.get();
+ if (byValue > 0d) {
+ return Optional.of(Measure.newMeasureBuilder().create(mainValue / byValue));
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public String getOutputMetricKey() {
+ return outputMetricKey;
+ }
+
+ public static class Builder {
+ private String outputMetricKey;
+ private String mainMetric;
+ private String byMetric;
+ @CheckForNull
+ private String fallbackMetric;
+
+ private Builder() {
+ // prevents instantiation outside static method
+ }
+
+ public static Builder newBuilder(){
+ return new Builder();
+ }
+
+ public Builder setOutputMetricKey(String m) {
+ this.outputMetricKey = m;
+ return this;
+ }
+
+ public Builder setMainMetricKey(String m) {
+ this.mainMetric = m;
+ return this;
+ }
+
+ public Builder setByMetricKey(String m) {
+ this.byMetric = m;
+ return this;
+ }
+
+ public Builder setFallbackMetricKey(@Nullable String m) {
+ this.fallbackMetric = m;
+ return this;
+ }
+
+ public AverageFormula build() {
+ Objects.requireNonNull(outputMetricKey, "Output metric key cannot be null");
+ Objects.requireNonNull(mainMetric, "Main metric Key cannot be null");
+ Objects.requireNonNull(byMetric, "By metric Key cannot be null");
+ return new AverageFormula(this);
+ }
+ }
+
+ class AverageCounter implements Counter<AverageCounter> {
+
+ private boolean initialized = false;
+
+ private double mainValue = 0d;
+ private double byValue = 0d;
+
+ @Override
+ public void aggregate(AverageCounter counter) {
+ addValuesIfPresent(counter.getMainValue(), counter.getByValue());
+ }
+
+ @Override
+ public void aggregate(CounterContext counterContext) {
+ Optional<Double> mainValueOptional = getDoubleValue(counterContext.getMeasure(mainMetric));
+ if (!mainValueOptional.isPresent() && fallbackMetric != null) {
+ mainValueOptional = getDoubleValue(counterContext.getMeasure(fallbackMetric));
+ }
+ Optional<Double> byValueOptional = getDoubleValue(counterContext.getMeasure(byMetric));
+ addValuesIfPresent(mainValueOptional, byValueOptional);
+ }
+
+ private void addValuesIfPresent(Optional<Double> counterMainValue, Optional<Double> counterByValue) {
+ if (counterMainValue.isPresent() && counterByValue.isPresent()) {
+ initialized = true;
+ mainValue += counterMainValue.get();
+ byValue += counterByValue.get();
+ }
+ }
+
+ public Optional<Double> getMainValue() {
+ return getValue(mainValue);
+ }
+
+ public Optional<Double> getByValue() {
+ return getValue(byValue);
+ }
+
+ private Optional<Double> getValue(double value) {
+ if (initialized) {
+ return Optional.of(value);
+ }
+ return Optional.absent();
+ }
+ }
+
+ private static Optional<Double> getDoubleValue(Optional<Measure> measureOptional) {
+ if (!measureOptional.isPresent()) {
+ return Optional.absent();
+ }
+ Measure measure = measureOptional.get();
+ switch (measure.getValueType()) {
+ case DOUBLE:
+ return Optional.of(measure.getDoubleValue());
+ case LONG:
+ return Optional.of((double) measure.getLongValue());
+ case INT:
+ return Optional.of((double) measure.getIntValue());
+ case NO_VALUE:
+ return Optional.absent();
+ default:
+ throw new IllegalArgumentException(String.format("Measure of type '%s' are not supported", measure.getValueType().name()));
+ }
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaStepTest.java
new file mode 100644
index 00000000000..683052e194e
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaStepTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.server.computation.formula;
+
+import com.google.common.collect.Lists;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
+import org.sonar.server.computation.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.metric.MetricRepositoryRule;
+import org.sonar.server.computation.step.ComputeFormulaMeasuresStep;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_KEY;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.DumbComponent.builder;
+import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+import static org.sonar.server.computation.measure.MeasureRepoEntry.entryOf;
+import static org.sonar.server.computation.measure.MeasureRepoEntry.toEntries;
+
+public class AverageFormulaStepTest {
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ @Rule
+ public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+ .add(CoreMetrics.FUNCTION_COMPLEXITY)
+ .add(CoreMetrics.COMPLEXITY_IN_FUNCTIONS)
+ .add(CoreMetrics.FUNCTIONS);
+
+ @Rule
+ public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+ ComputeFormulaMeasuresStep sut;
+
+ @Before
+ public void setUp() throws Exception {
+ FormulaRepository formulaRepository = mock(FormulaRepository.class);
+ when(formulaRepository.getFormulas()).thenReturn(Lists.<Formula>newArrayList(
+ AverageFormula.Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .build()));
+ sut = new ComputeFormulaMeasuresStep(treeRootHolder, measureRepository, metricRepository, formulaRepository);
+ }
+
+ @Test
+ public void add_measures() throws Exception {
+ DumbComponent project = builder(PROJECT, 1)
+ .addChildren(
+ builder(MODULE, 11)
+ .addChildren(
+ builder(DIRECTORY, 111)
+ .addChildren(
+ builder(Component.Type.FILE, 1111).build(),
+ builder(Component.Type.FILE, 1112).build()
+ ).build()
+ ).build(),
+ builder(MODULE, 12)
+ .addChildren(
+ builder(DIRECTORY, 121)
+ .addChildren(
+ builder(Component.Type.FILE, 1211).build()
+ ).build()
+ ).build()
+ ).build();
+
+ treeRootHolder.setRoot(project);
+
+ measureRepository.addRawMeasure(1111, COMPLEXITY_IN_FUNCTIONS_KEY, newMeasureBuilder().create(5));
+ measureRepository.addRawMeasure(1111, FUNCTIONS_KEY, newMeasureBuilder().create(2));
+
+ measureRepository.addRawMeasure(1112, COMPLEXITY_IN_FUNCTIONS_KEY, newMeasureBuilder().create(1));
+ measureRepository.addRawMeasure(1112, FUNCTIONS_KEY, newMeasureBuilder().create(1));
+
+ measureRepository.addRawMeasure(1211, COMPLEXITY_IN_FUNCTIONS_KEY, newMeasureBuilder().create(9));
+ measureRepository.addRawMeasure(1211, FUNCTIONS_KEY, newMeasureBuilder().create(2));
+
+ sut.execute();
+
+ assertThat(toEntries(measureRepository.getNewRawMeasures(1))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(3d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(11))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(1111))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(2.5d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(1112))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(1d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(12))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(121))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d)));
+ assertThat(toEntries(measureRepository.getNewRawMeasures(1211))).containsOnly(entryOf(FUNCTION_COMPLEXITY_KEY, newMeasureBuilder().create(4.5d)));
+ }
+
+}
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
new file mode 100644
index 00000000000..2a3c0d88a3d
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/formula/AverageFormulaTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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.server.computation.formula;
+
+import com.google.common.base.Optional;
+import org.assertj.guava.api.Assertions;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.measure.Measure;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_KEY;
+import static org.sonar.server.computation.formula.AverageFormula.Builder;
+
+public class AverageFormulaTest {
+
+ private static final AverageFormula BASIC_AVERAGE_FORMULA = Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .build();
+
+ CounterContext counterContext = mock(CounterContext.class);
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void fail_with_NPE_when_building_formula_without_output_metric() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Output metric key cannot be null");
+
+ Builder.newBuilder()
+ .setOutputMetricKey(null)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .build();
+ }
+
+ @Test
+ public void fail_with_NPE_when_building_formula_without_main_metric() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Main metric Key cannot be null");
+
+ Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(null)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .build();
+ }
+
+ @Test
+ public void fail_with_NPE_when_building_formula_without_by_metric() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("By metric Key cannot be null");
+
+ Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(null)
+ .build();
+ }
+
+ @Test
+ public void check_new_counter_class() throws Exception {
+ assertThat(BASIC_AVERAGE_FORMULA.createNewCounter().getClass()).isEqualTo(AverageFormula.AverageCounter.class);
+ }
+
+ @Test
+ public void check_output_metric_key_is_function_complexity_key() throws Exception {
+ assertThat(BASIC_AVERAGE_FORMULA.getOutputMetricKey()).isEqualTo(FUNCTION_COMPLEXITY_KEY);
+ }
+
+ @Test
+ public void create_measure_when_counter_is_aggregated_from_context() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10d);
+ addMeasure(FUNCTIONS_KEY, 2d);
+ counter.aggregate(counterContext);
+
+ assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5d);
+ }
+
+ @Test
+ public void create_measure_when_counter_is_aggregated_from_another_counter() throws Exception {
+ AverageFormula.AverageCounter anotherCounter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10d);
+ addMeasure(FUNCTIONS_KEY, 2d);
+ anotherCounter.aggregate(counterContext);
+
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ counter.aggregate(anotherCounter);
+
+ assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5d);
+ }
+
+ @Test
+ public void create_double_measure() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10d);
+ addMeasure(FUNCTIONS_KEY, 2d);
+ counter.aggregate(counterContext);
+
+ assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5d);
+ }
+
+ @Test
+ public void create_integer_measure() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10);
+ addMeasure(FUNCTIONS_KEY, 2);
+ counter.aggregate(counterContext);
+
+ assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5);
+ }
+
+ @Test
+ public void create_long_measure() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10L);
+ addMeasure(FUNCTIONS_KEY, 2L);
+ counter.aggregate(counterContext);
+
+ assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5L);
+ }
+
+ @Test
+ public void not_create_measure_when_aggregated_measure_has_no_value() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10L);
+ when(counterContext.getMeasure(FUNCTIONS_KEY)).thenReturn(Optional.of(Measure.newMeasureBuilder().createNoValue()));
+ counter.aggregate(counterContext);
+
+ Assertions.assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT)).isAbsent();
+ }
+
+ @Test
+ public void fail_with_IAE_when_aggregate_from_component_and_context_with_not_numeric_measures() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Measure of type 'STRING' are not supported");
+
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10L);
+ when(counterContext.getMeasure(FUNCTIONS_KEY)).thenReturn(Optional.of(Measure.newMeasureBuilder().create("data")));
+ counter.aggregate(counterContext);
+
+ BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT);
+ }
+
+ @Test
+ public void no_measure_created_when_counter_has_no_value() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ when(counterContext.getMeasure(anyString())).thenReturn(Optional.<Measure>absent());
+ counter.aggregate(counterContext);
+
+ Assertions.assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT)).isAbsent();
+ }
+
+ @Test
+ public void not_create_measure_when_only_one_measure() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10L);
+ when(counterContext.getMeasure(FUNCTIONS_KEY)).thenReturn(Optional.<Measure>absent());
+ counter.aggregate(counterContext);
+
+ Assertions.assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT)).isAbsent();
+ }
+
+ @Test
+ public void not_create_measure_when_by_value_is_zero() throws Exception {
+ AverageFormula.AverageCounter counter = BASIC_AVERAGE_FORMULA.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10d);
+ addMeasure(FUNCTIONS_KEY, 0d);
+ counter.aggregate(counterContext);
+
+ Assertions.assertThat(BASIC_AVERAGE_FORMULA.createMeasure(counter, Component.Type.PROJECT)).isAbsent();
+ }
+
+ @Test
+ public void create_measure_from_fall_back_measure() throws Exception {
+ AverageFormula sut = Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .setFallbackMetricKey(CoreMetrics.COMPLEXITY_KEY)
+ .build();
+
+ AverageFormula.AverageCounter counter = sut.createNewCounter();
+ when(counterContext.getMeasure(COMPLEXITY_IN_FUNCTIONS_KEY)).thenReturn(Optional.<Measure>absent());
+ addMeasure(COMPLEXITY_KEY, 10d);
+ addMeasure(FUNCTIONS_KEY, 2d);
+ counter.aggregate(counterContext);
+
+ assertThat(sut.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5d);
+ }
+
+ @Test
+ public void not_use_fallback_measure_if_main_measure_exists() throws Exception {
+ AverageFormula sut = Builder.newBuilder()
+ .setOutputMetricKey(FUNCTION_COMPLEXITY_KEY)
+ .setMainMetricKey(COMPLEXITY_IN_FUNCTIONS_KEY)
+ .setByMetricKey(FUNCTIONS_KEY)
+ .setFallbackMetricKey(CoreMetrics.COMPLEXITY_KEY)
+ .build();
+
+ AverageFormula.AverageCounter counter = sut.createNewCounter();
+ addMeasure(COMPLEXITY_IN_FUNCTIONS_KEY, 10d);
+ addMeasure(COMPLEXITY_KEY, 12d);
+ addMeasure(FUNCTIONS_KEY, 2d);
+ counter.aggregate(counterContext);
+
+ assertThat(sut.createMeasure(counter, Component.Type.PROJECT).get().getDoubleValue()).isEqualTo(5d);
+ }
+
+ private void addMeasure(String metricKey, double value) {
+ when(counterContext.getMeasure(metricKey)).thenReturn(Optional.of(Measure.newMeasureBuilder().create(value)));
+ }
+
+ private void addMeasure(String metricKey, int value) {
+ when(counterContext.getMeasure(metricKey)).thenReturn(Optional.of(Measure.newMeasureBuilder().create(value)));
+ }
+
+ private void addMeasure(String metricKey, long value) {
+ when(counterContext.getMeasure(metricKey)).thenReturn(Optional.of(Measure.newMeasureBuilder().create(value)));
+ }
+
+}