]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8760 Define 'Cognitive Complexity' metric 1655/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 9 Feb 2017 15:37:56 +0000 (16:37 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 10 Feb 2017 09:19:53 +0000 (10:19 +0100)
14 files changed:
it/it-projects/shared/xoo-multi-modules-sample/module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo.measures
it/it-projects/shared/xoo-multi-modules-sample/module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo.measures
it/it-projects/shared/xoo-multi-modules-sample/module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo.measures
it/it-projects/shared/xoo-multi-modules-sample/module_b/module_b2/src/main/xoo/com/sonar/it/samples/modules/b2/HelloB2.xoo.measures
it/it-projects/shared/xoo-sample/src/main/xoo/sample/Sample.xoo.measures
it/it-tests/src/test/java/it/Category1Suite.java
it/it-tests/src/test/java/it/complexity/ComplexityMeasuresTest.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ComplexityMeasuresStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportComplexityMeasuresStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ViewsComplexityMeasuresStepTest.java
sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
sonar-core/src/main/resources/org/sonar/l10n/core.properties
sonar-core/src/test/java/org/sonar/core/metric/ScannerMetricsTest.java
sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java

index 641332a5013fcf0203ca4d358b95e113896d397a..06c9b6c2f389bba2b487dcd428af3dfe419d086e 100644 (file)
@@ -2,6 +2,7 @@ ncloc:13
 #Used by dashboard/widgets tests
 complexity:3
 complexity_in_classes:3
+cognitive_complexity:4
 classes:1
 comment_lines:3
 public_api:5
index 7190c2f5f9e288b15c4c8e695f3bb7f659180bfd..643b706757ea8217d526f7d71b930647e9f711b4 100644 (file)
@@ -26,6 +26,7 @@ import it.authorisation.IssuePermissionTest;
 import it.authorisation.PermissionSearchTest;
 import it.authorisation.ProvisioningPermissionTest;
 import it.authorisation.QualityProfileAdminPermissionTest;
+import it.complexity.ComplexityMeasuresTest;
 import it.customMeasure.CustomMeasuresTest;
 import it.i18n.I18nTest;
 import it.measure.MeasuresWsTest;
@@ -98,7 +99,9 @@ import static util.ItUtils.xooPlugin;
   // source code
   EncodingTest.class,
   HighlightingTest.class,
-  ProjectCodeTest.class
+  ProjectCodeTest.class,
+  // complexity
+  ComplexityMeasuresTest.class
 })
 public class Category1Suite {
 
diff --git a/it/it-tests/src/test/java/it/complexity/ComplexityMeasuresTest.java b/it/it-tests/src/test/java/it/complexity/ComplexityMeasuresTest.java
new file mode 100644 (file)
index 0000000..0396233
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package it.complexity;
+
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.build.SonarScanner;
+import it.Category1Suite;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Java6Assertions.entry;
+import static util.ItUtils.getMeasuresAsDoubleByMetricKey;
+import static util.ItUtils.projectDir;
+
+// TODO complete the test with other complexity metrics
+public class ComplexityMeasuresTest {
+
+  private static final String PROJECT = "com.sonarsource.it.samples:multi-modules-sample";
+  private static final String MODULE = "com.sonarsource.it.samples:multi-modules-sample:module_a";
+  private static final String SUB_MODULE = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1";
+  private static final String DIRECTORY = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1";
+  private static final String FILE = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo";
+
+  private static final String COMPLEXITY_METRIC = "complexity";
+  private static final String COGNITIVE_COMPLEXITY_METRIC = "cognitive_complexity";
+
+  @ClassRule
+  public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;
+
+  @BeforeClass
+  public static void inspectProject() {
+    orchestrator.resetData();
+    orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample")));
+  }
+
+  @Test
+  public void compute_complexity_metrics_on_file() {
+    assertThat(getMeasuresAsDoubleByMetricKey(orchestrator, FILE, COMPLEXITY_METRIC, COGNITIVE_COMPLEXITY_METRIC)).containsOnly(
+      entry(COMPLEXITY_METRIC, 3d),
+      entry(COGNITIVE_COMPLEXITY_METRIC, 4d));
+  }
+
+  @Test
+  public void compute_complexity_metrics_on_directory() {
+    assertThat(getMeasuresAsDoubleByMetricKey(orchestrator, DIRECTORY, COMPLEXITY_METRIC, COGNITIVE_COMPLEXITY_METRIC)).containsOnly(
+      entry(COMPLEXITY_METRIC, 3d),
+      entry(COGNITIVE_COMPLEXITY_METRIC, 4d));
+  }
+
+  @Test
+  public void compute_complexity_metrics_on_sub_module() {
+    assertThat(getMeasuresAsDoubleByMetricKey(orchestrator, SUB_MODULE, COMPLEXITY_METRIC, COGNITIVE_COMPLEXITY_METRIC)).containsOnly(
+      entry(COMPLEXITY_METRIC, 3d),
+      entry(COGNITIVE_COMPLEXITY_METRIC, 4d));
+  }
+
+  @Test
+  public void compute_complexity_metrics_on_module() {
+    assertThat(getMeasuresAsDoubleByMetricKey(orchestrator, MODULE, COMPLEXITY_METRIC, COGNITIVE_COMPLEXITY_METRIC)).containsOnly(
+      entry(COMPLEXITY_METRIC, 7d),
+      entry(COGNITIVE_COMPLEXITY_METRIC, 9d));
+  }
+
+  @Test
+  public void compute_complexity_metrics_on_project() {
+    assertThat(getMeasuresAsDoubleByMetricKey(orchestrator, PROJECT, COMPLEXITY_METRIC, COGNITIVE_COMPLEXITY_METRIC)).containsOnly(
+      entry(COMPLEXITY_METRIC, 13d),
+      entry(COGNITIVE_COMPLEXITY_METRIC, 17d));
+  }
+
+}
index f710ad9105167f9df44196099078ae25beaca477..2cc7ea7f57812b4046279cbec87d901a0b61a896 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.server.computation.task.step.ComputationStep;
 import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY;
 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.COGNITIVE_COMPLEXITY_KEY;
 import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES_KEY;
 import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY;
 import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_KEY;
@@ -53,6 +54,7 @@ public class ComplexityMeasuresStep implements ComputationStep {
     createIntSumFormula(COMPLEXITY_KEY),
     createIntSumFormula(COMPLEXITY_IN_CLASSES_KEY),
     createIntSumFormula(COMPLEXITY_IN_FUNCTIONS_KEY),
+    createIntSumFormula(COGNITIVE_COMPLEXITY_KEY),
     new DistributionFormula(FUNCTION_COMPLEXITY_DISTRIBUTION_KEY),
     new DistributionFormula(FILE_COMPLEXITY_DISTRIBUTION_KEY),
     new DistributionFormula(CLASS_COMPLEXITY_DISTRIBUTION_KEY),
index 67d4bc666fba4a1a97a6df70c8c680835e975866..fff37cc9a0373b1ceee8222b1195de7603f0cdb6 100644 (file)
@@ -35,6 +35,8 @@ 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.COGNITIVE_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.COGNITIVE_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;
@@ -102,7 +104,9 @@ public class ReportComplexityMeasuresStepTest {
     .add(CLASS_COMPLEXITY)
     .add(CLASSES)
     .add(FUNCTION_COMPLEXITY)
-    .add(FUNCTIONS);
+    .add(FUNCTIONS)
+    .add(COGNITIVE_COMPLEXITY);
+
   @Rule
   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
 
@@ -123,6 +127,11 @@ public class ReportComplexityMeasuresStepTest {
     verify_sum_aggregation(COMPLEXITY_IN_FUNCTIONS_KEY);
   }
 
+  @Test
+  public void aggregate_cognitive_complexity() throws Exception {
+    verify_sum_aggregation(COGNITIVE_COMPLEXITY_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));
index 9a1ee04a03b033c90c3c70a90fa57b96d904238c..1cb49d6cff21f804588aa175a677837f926e8c2f 100644 (file)
@@ -35,6 +35,8 @@ 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.COGNITIVE_COMPLEXITY;
+import static org.sonar.api.measures.CoreMetrics.COGNITIVE_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;
@@ -101,7 +103,9 @@ public class ViewsComplexityMeasuresStepTest {
     .add(CLASS_COMPLEXITY)
     .add(CLASSES)
     .add(FUNCTION_COMPLEXITY)
-    .add(FUNCTIONS);
+    .add(FUNCTIONS)
+    .add(COGNITIVE_COMPLEXITY);
+
   @Rule
   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
 
@@ -122,6 +126,11 @@ public class ViewsComplexityMeasuresStepTest {
     verify_sum_aggregation(COMPLEXITY_IN_FUNCTIONS_KEY);
   }
 
+  @Test
+  public void aggregate_cognitive_complexity_in_functions() throws Exception {
+    verify_sum_aggregation(COGNITIVE_COMPLEXITY_KEY);
+  }
+
   private void verify_sum_aggregation(String metricKey) {
     addRawMeasureValue(PROJECT_VIEW_1_REF, metricKey, 10);
     addRawMeasureValue(PROJECT_VIEW_2_REF, metricKey, 40);
index 295cd8416d9e2a3290eab2807d66bb3a292b57dc..9d9596cd57f103150a86d08247f4242169064ca1 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.api.measures.Metrics;
 
 import static org.sonar.api.measures.CoreMetrics.ACCESSORS;
 import static org.sonar.api.measures.CoreMetrics.CLASSES;
+import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY;
 import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES;
 import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DATA;
 import static org.sonar.api.measures.CoreMetrics.COMPLEXITY;
@@ -95,6 +96,7 @@ public class ScannerMetrics {
     COMPLEXITY,
     COMPLEXITY_IN_CLASSES,
     COMPLEXITY_IN_FUNCTIONS,
+    COGNITIVE_COMPLEXITY,
     FILE_COMPLEXITY_DISTRIBUTION,
     FUNCTION_COMPLEXITY_DISTRIBUTION,
 
index 317f5048d526499265d1cf7e342c63bd26cf6cc4..2d59b3c72cfb4a60a1d1e05e29f582a534d51160 100644 (file)
@@ -1930,6 +1930,8 @@ metric.class_complexity_distribution.description=Classes distribution /complexit
 metric.class_complexity_distribution.name=Class Distribution / Complexity
 metric.code_smells.description=Code Smells
 metric.code_smells.name=Code Smells
+metric.cognitive_complexity.description=Cognitive complexity
+metric.cognitive_complexity.name=Cognitive Complexity
 metric.commented_out_code_lines.description=Commented lines of code
 metric.commented_out_code_lines.name=Commented-Out LOC
 metric.comment_blank_lines.description=Comments that do not contain comments
index fc44410de8d05ea3c0b60668b7afbf1e12c3860c..80c9231b2c151d0095b71b38f5fbfd386228ac43 100644 (file)
@@ -36,7 +36,7 @@ public class ScannerMetricsTest {
 
   @Test
   public void check_number_of_allowed_core_metrics() throws Exception {
-    assertThat(SENSOR_METRICS_WITHOUT_METRIC_PLUGIN.getMetrics()).hasSize(33);
+    assertThat(SENSOR_METRICS_WITHOUT_METRIC_PLUGIN.getMetrics()).hasSize(34);
   }
 
   @Test
index dbcafc7e600ce7248e21b71cc2f0150840fd14ed..a2e7a526ed65be544ff449373c59ed5144ecffc2 100644 (file)
@@ -467,6 +467,16 @@ public final class CoreMetrics {
       .setDomain(DOMAIN_COMPLEXITY)
       .create();
 
+  public static final String COGNITIVE_COMPLEXITY_KEY = "cognitive_complexity";
+  public static final Metric<Integer> COGNITIVE_COMPLEXITY = new Metric.Builder(COGNITIVE_COMPLEXITY_KEY, "Cognitive Complexity", Metric.ValueType.INT)
+    .setDescription("Cognitive complexity")
+    .setDirection(Metric.DIRECTION_WORST)
+    .setQualitative(false)
+    .setDomain(DOMAIN_COMPLEXITY)
+    .setBestValue(0.0)
+    .setOptimizedBestValue(true)
+    .create();
+
   // --------------------------------------------------------------------------------------------------------------------
   //
   // UNIT TESTS