]> source.dussan.org Git - sonarqube.git/commitdiff
add support for Views Component tree to ComplexityMeasuresStep
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 25 Aug 2015 11:47:11 +0000 (13:47 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Sat, 29 Aug 2015 13:58:41 +0000 (15:58 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/formula/DistributionFormula.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComplexityMeasuresStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ComplexityMeasuresStepTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportComplexityMeasuresStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsComplexityMeasuresStepTest.java [new file with mode: 0644]

index 27c6229e0b08ac2908617ede4528f64169334e5e..cdeca70332635595cf385cc1d8f27fd1f0bc0c08 100644 (file)
 package org.sonar.server.computation.formula;
 
 import com.google.common.base.Optional;
-import java.util.Objects;
 import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.CrawlerDepthLimit;
 import org.sonar.server.computation.measure.Measure;
 
+import static java.util.Objects.requireNonNull;
+
 public class DistributionFormula implements Formula<DistributionFormula.DistributionCounter> {
 
   private final String metricKey;
 
   public DistributionFormula(String metricKey) {
-    this.metricKey = Objects.requireNonNull(metricKey, "Metric key cannot be null");
+    this.metricKey = requireNonNull(metricKey, "Metric key cannot be null");
   }
 
   @Override
@@ -42,7 +44,7 @@ public class DistributionFormula implements Formula<DistributionFormula.Distribu
   public Optional<Measure> createMeasure(DistributionCounter counter, CreateMeasureContext context) {
     Component.Type componentType = context.getComponent().getType();
     Optional<String> value = counter.getValue();
-    if (value.isPresent() && componentType.isHigherThan(Component.Type.FILE)) {
+    if (value.isPresent() && CrawlerDepthLimit.LEAVES.isDeeperThan(componentType)) {
       return Optional.of(Measure.newMeasureBuilder().create(value.get()));
     }
     return Optional.absent();
index d6474a99a2f4851c14003a1e6670d56be5b04b7f..bd42ec28534b66cba84d08409d65f04944b0dcee 100644 (file)
@@ -53,15 +53,13 @@ public class ComplexityMeasuresStep implements ComputationStep {
     createIntSumFormula(COMPLEXITY_KEY),
     createIntSumFormula(COMPLEXITY_IN_CLASSES_KEY),
     createIntSumFormula(COMPLEXITY_IN_FUNCTIONS_KEY),
-
-  new DistributionFormula(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY),
+    new DistributionFormula(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY),
     new DistributionFormula(FILE_COMPLEXITY_DISTRIBUTION_KEY),
     new DistributionFormula(CLASS_COMPLEXITY_DISTRIBUTION_KEY),
-
-  AverageFormula.Builder.newBuilder().setOutputMetricKey(FILE_COMPLEXITY_KEY)
-    .setMainMetricKey(COMPLEXITY_KEY)
-    .setByMetricKey(FILES_KEY)
-    .build(),
+    AverageFormula.Builder.newBuilder().setOutputMetricKey(FILE_COMPLEXITY_KEY)
+      .setMainMetricKey(COMPLEXITY_KEY)
+      .setByMetricKey(FILES_KEY)
+      .build(),
     AverageFormula.Builder.newBuilder().setOutputMetricKey(CLASS_COMPLEXITY_KEY)
       .setMainMetricKey(COMPLEXITY_IN_CLASSES_KEY)
       .setByMetricKey(CLASSES_KEY)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ComplexityMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ComplexityMeasuresStepTest.java
deleted file mode 100644 (file)
index 449a7a2..0000000
+++ /dev/null
@@ -1,224 +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.server.computation.step;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.batch.TreeRootHolderRule;
-import org.sonar.server.computation.component.ReportComponent;
-import org.sonar.server.computation.measure.MeasureRepositoryRule;
-import org.sonar.server.computation.metric.MetricRepositoryRule;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.guava.api.Assertions.assertThat;
-import static org.sonar.api.measures.CoreMetrics.CLASSES;
-import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY;
-import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY;
-import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION;
-import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY;
-import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_KEY;
-import static org.sonar.api.measures.CoreMetrics.COMPLEXITY;
-import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES;
-import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES_KEY;
-import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS;
-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.FILES;
-import static org.sonar.api.measures.CoreMetrics.FILES_KEY;
-import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY;
-import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION;
-import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY;
-import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_KEY;
-import static org.sonar.api.measures.CoreMetrics.FUNCTIONS;
-import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY;
-import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY;
-import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION;
-import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_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.FILE;
-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.ReportComponent.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 ComplexityMeasuresStepTest {
-
-  private static final int ROOT_REF = 1;
-  private static final int MODULE_REF = 11;
-  private static final int SUB_MODULE_REF = 111;
-  private static final int DIRECTORY_REF = 1111;
-  private static final int FILE_1_REF = 11111;
-  private static final int FILE_2_REF = 11121;
-
-  private static final ReportComponent MULTIPLE_FILES_TREE = builder(PROJECT, ROOT_REF)
-    .addChildren(
-      builder(MODULE, MODULE_REF)
-        .addChildren(
-          builder(MODULE, SUB_MODULE_REF)
-            .addChildren(
-              builder(DIRECTORY, DIRECTORY_REF)
-                .addChildren(
-                  builder(FILE, FILE_1_REF).build(),
-                  builder(FILE, FILE_2_REF).build()
-                ).build()
-            )
-            .build()
-        ).build()
-    ).build();
-
-  @Rule
-  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
-  @Rule
-  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(MULTIPLE_FILES_TREE);
-
-  @Rule
-  public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
-    .add(COMPLEXITY)
-    .add(COMPLEXITY_IN_CLASSES)
-    .add(COMPLEXITY_IN_FUNCTIONS)
-    .add(FUNCTION_COMPLEXITY_DISTRIBUTION)
-    .add(FILE_COMPLEXITY_DISTRIBUTION)
-    .add(CLASS_COMPLEXITY_DISTRIBUTION)
-    .add(FILE_COMPLEXITY)
-    .add(FILES)
-    .add(CLASS_COMPLEXITY)
-    .add(CLASSES)
-    .add(FUNCTION_COMPLEXITY)
-    .add(FUNCTIONS)
-    ;
-
-  @Rule
-  public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
-  private ComputationStep underTest = new ComplexityMeasuresStep(treeRootHolder, metricRepository, measureRepository);
-
-  @Test
-  public void aggregate_complexity() throws Exception {
-    verify_sum_aggregation(COMPLEXITY_KEY);
-  }
-
-  @Test
-  public void aggregate_complexity_in_classes() throws Exception {
-    verify_sum_aggregation(COMPLEXITY_IN_CLASSES_KEY);
-  }
-
-  @Test
-  public void aggregate_complexity_in_functions() throws Exception {
-    verify_sum_aggregation(COMPLEXITY_IN_FUNCTIONS_KEY);
-  }
-
-  private void verify_sum_aggregation(String metricKey){
-    measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create(10));
-    measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create(40));
-
-    underTest.execute();
-
-    assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, metricKey)).isAbsent();
-    assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, metricKey)).isAbsent();
-
-    int expectedNonFileValue = 50;
-    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)));
-  }
-
-  @Test
-  public void aggregate_function_complexity_distribution() throws Exception {
-    verify_distribution_aggregation(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY);
-  }
-
-  @Test
-  public void aggregate_file_complexity_distribution() throws Exception {
-    verify_distribution_aggregation(FILE_COMPLEXITY_DISTRIBUTION_KEY);
-  }
-
-  @Test
-  public void aggregate_class_complexity_distribution() throws Exception {
-    verify_distribution_aggregation(CLASS_COMPLEXITY_DISTRIBUTION_KEY);
-  }
-
-  private void verify_distribution_aggregation(String metricKey){
-    measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create("0.5=3;3.5=5;6.5=9"));
-    measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create("0.5=0;3.5=2;6.5=1"));
-
-    underTest.execute();
-
-    assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, metricKey)).isAbsent();
-    assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, metricKey)).isAbsent();
-
-    String expectedNonFileValue = "0.5=3;3.5=7;6.5=10";
-    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)));
-  }
-
-  @Test
-  public void compute_and_aggregate_file_complexity() throws Exception {
-    verify_average_compute_and_aggregation(FILE_COMPLEXITY_KEY, COMPLEXITY_KEY, FILES_KEY);
-  }
-
-  @Test
-  public void compute_and_aggregate_class_complexity() throws Exception {
-    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_IN_CLASSES_KEY, CLASSES_KEY);
-  }
-
-  @Test
-  public void compute_and_aggregate_class_complexity_with_fallback_metric() throws Exception {
-    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_KEY, CLASSES_KEY);
-  }
-
-  @Test
-  public void compute_and_aggregate_function_complexity() throws Exception {
-    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_IN_FUNCTIONS_KEY, FUNCTIONS_KEY);
-  }
-
-  @Test
-  public void compute_and_aggregate_function_complexity_with_fallback_metric() throws Exception {
-    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_KEY, FUNCTIONS_KEY);
-  }
-
-  private void verify_average_compute_and_aggregation(String metricKey, String mainMetric, String byMetric){
-    measureRepository.addRawMeasure(FILE_1_REF, mainMetric, newMeasureBuilder().create(5));
-    measureRepository.addRawMeasure(FILE_1_REF, byMetric, newMeasureBuilder().create(2));
-
-    measureRepository.addRawMeasure(FILE_2_REF, mainMetric, newMeasureBuilder().create(1));
-    measureRepository.addRawMeasure(FILE_2_REF, byMetric, newMeasureBuilder().create(1));
-
-    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)));
-
-    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)));
-  }
-
-}
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
new file mode 100644 (file)
index 0000000..7f6b092
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * 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.step;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.server.computation.batch.BatchReportReaderRule;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.metric.MetricRepositoryRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.CLASSES;
+import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES_KEY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS;
+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.FILES;
+import static org.sonar.api.measures.CoreMetrics.FILES_KEY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_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.FILE;
+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.ReportComponent.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 ReportComplexityMeasuresStepTest {
+
+  private static final int ROOT_REF = 1;
+  private static final int MODULE_REF = 11;
+  private static final int SUB_MODULE_REF = 111;
+  private static final int DIRECTORY_REF = 1111;
+  private static final int FILE_1_REF = 11111;
+  private static final int FILE_2_REF = 11121;
+
+  @Rule
+  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
+    .setRoot(builder(PROJECT, ROOT_REF)
+      .addChildren(
+        builder(MODULE, MODULE_REF)
+          .addChildren(
+            builder(MODULE, SUB_MODULE_REF)
+              .addChildren(
+                builder(DIRECTORY, DIRECTORY_REF)
+                  .addChildren(
+                    builder(FILE, FILE_1_REF).build(),
+                    builder(FILE, FILE_2_REF).build())
+                  .build())
+              .build())
+          .build())
+      .build());
+  @Rule
+  public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+    .add(COMPLEXITY)
+    .add(COMPLEXITY_IN_CLASSES)
+    .add(COMPLEXITY_IN_FUNCTIONS)
+    .add(FUNCTION_COMPLEXITY_DISTRIBUTION)
+    .add(FILE_COMPLEXITY_DISTRIBUTION)
+    .add(CLASS_COMPLEXITY_DISTRIBUTION)
+    .add(FILE_COMPLEXITY)
+    .add(FILES)
+    .add(CLASS_COMPLEXITY)
+    .add(CLASSES)
+    .add(FUNCTION_COMPLEXITY)
+    .add(FUNCTIONS);
+  @Rule
+  public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+  private ComputationStep underTest = new ComplexityMeasuresStep(treeRootHolder, metricRepository, measureRepository);
+
+  @Test
+  public void aggregate_complexity() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_KEY);
+  }
+
+  @Test
+  public void aggregate_complexity_in_classes() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_IN_CLASSES_KEY);
+  }
+
+  @Test
+  public void aggregate_complexity_in_functions() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_IN_FUNCTIONS_KEY);
+  }
+
+  private void verify_sum_aggregation(String metricKey) {
+    measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create(10));
+    measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create(40));
+
+    underTest.execute();
+
+    assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, metricKey)).isAbsent();
+    assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, metricKey)).isAbsent();
+
+    int expectedNonFileValue = 50;
+    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)));
+  }
+
+  @Test
+  public void aggregate_function_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  @Test
+  public void aggregate_file_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(FILE_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  @Test
+  public void aggregate_class_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(CLASS_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  private void verify_distribution_aggregation(String metricKey) {
+    measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create("0.5=3;3.5=5;6.5=9"));
+    measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create("0.5=0;3.5=2;6.5=1"));
+
+    underTest.execute();
+
+    assertThat(measureRepository.getAddedRawMeasure(FILE_1_REF, metricKey)).isAbsent();
+    assertThat(measureRepository.getAddedRawMeasure(FILE_2_REF, metricKey)).isAbsent();
+
+    String expectedNonFileValue = "0.5=3;3.5=7;6.5=10";
+    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)));
+  }
+
+  @Test
+  public void compute_and_aggregate_file_complexity() throws Exception {
+    verify_average_compute_and_aggregation(FILE_COMPLEXITY_KEY, COMPLEXITY_KEY, FILES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_class_complexity() throws Exception {
+    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_IN_CLASSES_KEY, CLASSES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_class_complexity_with_fallback_metric() throws Exception {
+    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_KEY, CLASSES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_function_complexity() throws Exception {
+    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_IN_FUNCTIONS_KEY, FUNCTIONS_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_function_complexity_with_fallback_metric() throws Exception {
+    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_KEY, FUNCTIONS_KEY);
+  }
+
+  private void verify_average_compute_and_aggregation(String metricKey, String mainMetric, String byMetric) {
+    measureRepository.addRawMeasure(FILE_1_REF, mainMetric, newMeasureBuilder().create(5));
+    measureRepository.addRawMeasure(FILE_1_REF, byMetric, newMeasureBuilder().create(2));
+
+    measureRepository.addRawMeasure(FILE_2_REF, mainMetric, newMeasureBuilder().create(1));
+    measureRepository.addRawMeasure(FILE_2_REF, byMetric, newMeasureBuilder().create(1));
+
+    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)));
+
+    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)));
+  }
+
+}
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
new file mode 100644 (file)
index 0000000..dcad4dc
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * 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.step;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.server.computation.batch.BatchReportReaderRule;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.metric.MetricRepositoryRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.CLASSES;
+import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES_KEY;
+import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS;
+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.FILES;
+import static org.sonar.api.measures.CoreMetrics.FILES_KEY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS;
+import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_KEY;
+import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW;
+import static org.sonar.server.computation.component.Component.Type.SUBVIEW;
+import static org.sonar.server.computation.component.Component.Type.VIEW;
+import static org.sonar.server.computation.component.ViewsComponent.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 ViewsComplexityMeasuresStepTest {
+
+  private static final int ROOT_REF = 1;
+  private static final int SUBVIEW_REF = 11;
+  private static final int SUB_SUBVIEW_1_REF = 111;
+  private static final int PROJECT_VIEW_1_REF = 11111;
+  private static final int PROJECT_VIEW_2_REF = 11121;
+  private static final int SUB_SUBVIEW_2_REF = 112;
+  private static final int PROJECT_VIEW_3_REF = 12;
+
+  @Rule
+  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
+    .setRoot(builder(VIEW, ROOT_REF)
+      .addChildren(
+        builder(SUBVIEW, SUBVIEW_REF)
+          .addChildren(
+            builder(SUBVIEW, SUB_SUBVIEW_1_REF)
+              .addChildren(
+                builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build(),
+                builder(PROJECT_VIEW, PROJECT_VIEW_2_REF).build())
+              .build(),
+            builder(SUBVIEW, SUB_SUBVIEW_2_REF).build())
+          .build(),
+        builder(PROJECT_VIEW, PROJECT_VIEW_3_REF).build())
+      .build());
+  @Rule
+  public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+    .add(COMPLEXITY)
+    .add(COMPLEXITY_IN_CLASSES)
+    .add(COMPLEXITY_IN_FUNCTIONS)
+    .add(FUNCTION_COMPLEXITY_DISTRIBUTION)
+    .add(FILE_COMPLEXITY_DISTRIBUTION)
+    .add(CLASS_COMPLEXITY_DISTRIBUTION)
+    .add(FILE_COMPLEXITY)
+    .add(FILES)
+    .add(CLASS_COMPLEXITY)
+    .add(CLASSES)
+    .add(FUNCTION_COMPLEXITY)
+    .add(FUNCTIONS);
+  @Rule
+  public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+  private ComputationStep underTest = new ComplexityMeasuresStep(treeRootHolder, metricRepository, measureRepository);
+
+  @Test
+  public void aggregate_complexity() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_KEY);
+  }
+
+  @Test
+  public void aggregate_complexity_in_classes() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_IN_CLASSES_KEY);
+  }
+
+  @Test
+  public void aggregate_complexity_in_functions() throws Exception {
+    verify_sum_aggregation(COMPLEXITY_IN_FUNCTIONS_KEY);
+  }
+
+  private void verify_sum_aggregation(String metricKey) {
+    addRawMeasureValue(PROJECT_VIEW_1_REF, metricKey, 10);
+    addRawMeasureValue(PROJECT_VIEW_2_REF, metricKey, 40);
+    addRawMeasureValue(PROJECT_VIEW_3_REF, metricKey, 20);
+
+    underTest.execute();
+
+    assertNoAddedRawMeasureOnProjectViews();
+    assertAddedRawMeasures(SUB_SUBVIEW_1_REF, metricKey, 50);
+    assertNoAddedRawMeasure(SUB_SUBVIEW_2_REF);
+    assertAddedRawMeasures(SUBVIEW_REF, metricKey, 50);
+    assertAddedRawMeasures(ROOT_REF, metricKey, 70);
+  }
+
+  @Test
+  public void aggregate_function_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  @Test
+  public void aggregate_file_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(FILE_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  @Test
+  public void aggregate_class_complexity_distribution() throws Exception {
+    verify_distribution_aggregation(CLASS_COMPLEXITY_DISTRIBUTION_KEY);
+  }
+
+  private void verify_distribution_aggregation(String metricKey) {
+    addRawMeasure(PROJECT_VIEW_1_REF, metricKey, "0.5=3;3.5=5;6.5=9");
+    addRawMeasure(PROJECT_VIEW_2_REF, metricKey, "0.5=0;3.5=2;6.5=1");
+    addRawMeasure(PROJECT_VIEW_3_REF, metricKey, "0.5=1;3.5=1;6.5=0");
+
+    underTest.execute();
+
+    assertNoAddedRawMeasureOnProjectViews();
+    assertAddedRawMeasures(SUB_SUBVIEW_1_REF, metricKey, "0.5=3;3.5=7;6.5=10");
+    assertNoAddedRawMeasure(SUB_SUBVIEW_2_REF);
+    assertAddedRawMeasures(SUBVIEW_REF, metricKey, "0.5=3;3.5=7;6.5=10");
+    assertAddedRawMeasures(ROOT_REF, metricKey, "0.5=4;3.5=8;6.5=10");
+  }
+
+  @Test
+  public void compute_and_aggregate_file_complexity() throws Exception {
+    verify_average_compute_and_aggregation(FILE_COMPLEXITY_KEY, COMPLEXITY_KEY, FILES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_class_complexity() throws Exception {
+    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_IN_CLASSES_KEY, CLASSES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_class_complexity_with_fallback_metric() throws Exception {
+    verify_average_compute_and_aggregation(CLASS_COMPLEXITY_KEY, COMPLEXITY_KEY, CLASSES_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_function_complexity() throws Exception {
+    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_IN_FUNCTIONS_KEY, FUNCTIONS_KEY);
+  }
+
+  @Test
+  public void compute_and_aggregate_function_complexity_with_fallback_metric() throws Exception {
+    verify_average_compute_and_aggregation(FUNCTION_COMPLEXITY_KEY, COMPLEXITY_KEY, FUNCTIONS_KEY);
+  }
+
+  private void verify_average_compute_and_aggregation(String metricKey, String mainMetric, String byMetric) {
+    addRawMeasureValue(PROJECT_VIEW_1_REF, mainMetric, 5);
+    addRawMeasureValue(PROJECT_VIEW_1_REF, byMetric, 2);
+
+    addRawMeasureValue(PROJECT_VIEW_2_REF, mainMetric, 1);
+    addRawMeasureValue(PROJECT_VIEW_2_REF, byMetric, 1);
+
+    addRawMeasureValue(PROJECT_VIEW_3_REF, mainMetric, 6);
+    addRawMeasureValue(PROJECT_VIEW_3_REF, byMetric, 8);
+
+    underTest.execute();
+
+    assertNoAddedRawMeasureOnProjectViews();
+    assertAddedRawMeasures(SUB_SUBVIEW_1_REF, metricKey, 2d);
+    assertNoAddedRawMeasure(SUB_SUBVIEW_2_REF);
+    assertAddedRawMeasures(SUBVIEW_REF, metricKey, 2d);
+    assertAddedRawMeasures(ROOT_REF, metricKey, 1.1d);
+  }
+
+  private void addRawMeasure(int componentRef, String metricKey, String value) {
+    measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
+  }
+
+  private void assertNoAddedRawMeasureOnProjectViews() {
+    assertNoAddedRawMeasure(PROJECT_VIEW_1_REF);
+    assertNoAddedRawMeasure(PROJECT_VIEW_2_REF);
+    assertNoAddedRawMeasure(PROJECT_VIEW_3_REF);
+  }
+
+  private void assertNoAddedRawMeasure(int componentRef) {
+    assertThat(measureRepository.getAddedRawMeasures(componentRef)).isEmpty();
+  }
+
+  private void assertAddedRawMeasures(int componentRef, String metricKey, String expected) {
+    assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(expected)));
+  }
+
+  private void assertAddedRawMeasures(int componentRef, String metricKey, int expected) {
+    assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(expected)));
+  }
+
+  private void assertAddedRawMeasures(int componentRef, String metricKey, double expected) {
+    assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(expected)));
+  }
+
+  private void addRawMeasureValue(int componentRef, String metricKey, int value) {
+    measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
+  }
+
+}