From: Julien Lancelot Date: Wed, 15 Jul 2015 08:52:26 +0000 (+0200) Subject: SONAR-6682 Add computation of comment density measures in Compute Engine X-Git-Tag: 5.2-RC1~1117 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F416%2Fhead;p=sonarqube.git SONAR-6682 Add computation of comment density measures in Compute Engine --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/CoreFormulaRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/CoreFormulaRepositoryImpl.java index 32a94674937..f8d2ef969ab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/CoreFormulaRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/CoreFormulaRepositoryImpl.java @@ -52,9 +52,6 @@ public class CoreFormulaRepositoryImpl implements CoreFormulaRepository { new SumFormula(CLASSES_KEY), new SumFormula(FUNCTIONS_KEY), new SumFormula(STATEMENTS_KEY), - // new SumFormula(PUBLIC_API_KEY), - // new SumFormula(COMMENT_LINES_KEY), - // new SumFormula(PUBLIC_UNDOCUMENTED_API_KEY), new SumFormula(COMPLEXITY_KEY), new SumFormula(COMPLEXITY_IN_CLASSES_KEY), // TODO this formula seems to be useless as this measure seems only required on files 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 new file mode 100644 index 00000000000..1d1934a7b09 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/CommentMeasuresStep.java @@ -0,0 +1,97 @@ +/* + * 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 com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import org.sonar.server.computation.component.TreeRootHolder; +import org.sonar.server.computation.formula.BiSumCounter; +import org.sonar.server.computation.formula.CreateMeasureContext; +import org.sonar.server.computation.formula.Formula; +import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor; +import org.sonar.server.computation.measure.Measure; +import org.sonar.server.computation.measure.MeasureRepository; +import org.sonar.server.computation.metric.MetricRepository; + +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DENSITY_KEY; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; + +/** + * Computes comments measures on files and then aggregates them on higher components. + */ +public class CommentMeasuresStep implements ComputationStep { + + private static final ImmutableList FORMULAS = ImmutableList.of( + // TODO add this formula when {@link CoreMetrics.DUPLICATED_LINES_DENSITY} will be computed in CE + // new SumFormula(CoreMetrics.COMMENT_LINES_KEY), + new CommentDensityFormula() + ); + + private final TreeRootHolder treeRootHolder; + private final MetricRepository metricRepository; + private final MeasureRepository measureRepository; + + public CommentMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { + this.treeRootHolder = treeRootHolder; + this.metricRepository = metricRepository; + this.measureRepository = measureRepository; + } + + @Override + public void execute() { + FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) + .buildFor(FORMULAS) + .visit(treeRootHolder.getRoot()); + } + + private static class CommentDensityFormula implements Formula { + + @Override + public BiSumCounter createNewCounter() { + return new BiSumCounter(NCLOC_KEY, COMMENT_LINES_KEY); + } + + @Override + public Optional createMeasure(BiSumCounter counter, CreateMeasureContext context) { + if (counter.getValue1().isPresent() && counter.getValue2().isPresent()) { + double nclocs = counter.getValue1().get(); + double comments = counter.getValue2().get(); + double divisor = nclocs + comments; + if (divisor > 0d) { + double value = 100d * (comments / divisor); + return Optional.of(Measure.newMeasureBuilder().create(value)); + } + } + return Optional.absent(); + } + + @Override + public String[] getOutputMetricKeys() { + return new String[] {COMMENT_LINES_DENSITY_KEY}; + } + } + + @Override + public String getDescription() { + return "Aggregation of comment measures"; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java index 7f8600f5016..7850702900d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java @@ -54,6 +54,8 @@ public class ComputationSteps { IntegrateIssuesStep.class, CoreMetricFormulaExecutorStep.class, CustomMeasuresCopyStep.class, + CommentMeasuresStep.class, + DocumentationMeasuresStep.class, // SQALE measures depend on issues SqaleMeasuresStep.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/DocumentationMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DocumentationMeasuresStep.java new file mode 100644 index 00000000000..159dde255b0 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/DocumentationMeasuresStep.java @@ -0,0 +1,98 @@ +/* + * 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 com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import org.sonar.server.computation.component.TreeRootHolder; +import org.sonar.server.computation.formula.BiSumCounter; +import org.sonar.server.computation.formula.CreateMeasureContext; +import org.sonar.server.computation.formula.Formula; +import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor; +import org.sonar.server.computation.formula.SumFormula; +import org.sonar.server.computation.measure.Measure; +import org.sonar.server.computation.measure.MeasureRepository; +import org.sonar.server.computation.metric.MetricRepository; + +import static org.sonar.api.measures.CoreMetrics.PUBLIC_API_KEY; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_DOCUMENTED_API_DENSITY_KEY; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_UNDOCUMENTED_API_KEY; + +/** + * Computes documentation measures on files and then aggregates them on higher components. + */ +public class DocumentationMeasuresStep implements ComputationStep { + + private static final ImmutableList FORMULAS = ImmutableList.of( + new SumFormula(PUBLIC_API_KEY), + new SumFormula(PUBLIC_UNDOCUMENTED_API_KEY), + new PublicApiDensityFormula() + ); + + private final TreeRootHolder treeRootHolder; + private final MetricRepository metricRepository; + private final MeasureRepository measureRepository; + + public DocumentationMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { + this.treeRootHolder = treeRootHolder; + this.metricRepository = metricRepository; + this.measureRepository = measureRepository; + } + + @Override + public void execute() { + FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) + .buildFor(FORMULAS) + .visit(treeRootHolder.getRoot()); + } + + private static class PublicApiDensityFormula implements Formula { + + @Override + public BiSumCounter createNewCounter() { + return new BiSumCounter(PUBLIC_API_KEY, PUBLIC_UNDOCUMENTED_API_KEY); + } + + @Override + public Optional createMeasure(BiSumCounter counter, CreateMeasureContext context) { + if (counter.getValue1().isPresent() && counter.getValue2().isPresent()) { + double publicApis = counter.getValue1().get(); + double publicUndocumentedApis = counter.getValue2().get(); + if (publicApis > 0d) { + double documentedAPI = publicApis - publicUndocumentedApis; + double value = 100d * (documentedAPI / publicApis); + return Optional.of(Measure.newMeasureBuilder().create(value)); + } + } + return Optional.absent(); + } + + @Override + public String[] getOutputMetricKeys() { + return new String[] {PUBLIC_DOCUMENTED_API_DENSITY_KEY}; + } + } + + @Override + public String getDescription() { + return "Aggregation of documentation measures"; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/CommentMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CommentMeasuresStepTest.java new file mode 100644 index 00000000000..2ec41254925 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/CommentMeasuresStepTest.java @@ -0,0 +1,190 @@ +/* + * 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.assertj.guava.api.Assertions; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +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.sonar.api.measures.CoreMetrics.COMMENT_LINES; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DENSITY; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DENSITY_KEY; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.NCLOC; +import static org.sonar.api.measures.CoreMetrics.NCLOC_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.DumbComponent.builder; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; + +public class CommentMeasuresStepTest { + + private static final int ROOT_REF = 1; + private static final int MODULE_REF = 12; + private static final int SUB_MODULE_REF = 123; + private static final int DIRECTORY_REF = 1234; + private static final int FILE_1_REF = 12341; + private static final int FILE_2_REF = 12342; + + @Rule + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + + @Rule + public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + .add(NCLOC) + .add(COMMENT_LINES) + .add(COMMENT_LINES_DENSITY); + + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + ComputationStep sut = new CommentMeasuresStep(treeRootHolder, metricRepository, measureRepository); + + @Before + public void setUp() throws Exception { + treeRootHolder.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()); + } + + @Test + @Ignore("Could be reactivated when formula will be added") + public void aggregate_comment_lines() { + measureRepository.addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(400)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(COMMENT_LINES_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(COMMENT_LINES_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(COMMENT_LINES_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(COMMENT_LINES_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(COMMENT_LINES_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(COMMENT_LINES_KEY)).containsOnly(newMeasureBuilder().create(500)); + } + + @Test + public void compute_comment_density() { + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(150)); + + measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(200)); + measureRepository.addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(50)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(60d)); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(20d)); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(40d)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(40d)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(40d)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(40d)); + } + + @Test + public void compute_zero_comment_density_when_zero_comment() { + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(0)); + + measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(200)); + measureRepository.addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(0)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(COMMENT_LINES_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(0d)); + } + + @Test + public void not_compute_comment_density_when_zero_ncloc_and_zero_comment() { + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(0)); + measureRepository.addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(0)); + + measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(0)); + measureRepository.addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(0)); + + sut.execute(); + assertNoNewMeasures(COMMENT_LINES_DENSITY_KEY); + } + + @Test + public void not_compute_comment_density_when_no_ncloc() { + measureRepository.addRawMeasure(FILE_1_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(150)); + measureRepository.addRawMeasure(FILE_2_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(50)); + + sut.execute(); + assertNoNewMeasures(COMMENT_LINES_DENSITY_KEY); + } + + @Test + public void not_compute_comment_density_when_no_comment() { + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(100)); + + sut.execute(); + assertNoNewMeasures(COMMENT_LINES_DENSITY_KEY); + } + + @Test + public void compute_nothing_when_no_data() { + sut.execute(); + + Assertions.assertThat(measureRepository.getNewRawMeasures(FILE_1_REF)).isEmpty(); + Assertions.assertThat(measureRepository.getNewRawMeasures(FILE_2_REF)).isEmpty(); + Assertions.assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF)).isEmpty(); + Assertions.assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF)).isEmpty(); + Assertions.assertThat(measureRepository.getNewRawMeasures(MODULE_REF)).isEmpty(); + Assertions.assertThat(measureRepository.getNewRawMeasures(ROOT_REF)).isEmpty(); + } + + private void assertNoNewMeasures(String metric) { + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(metric)).isEmpty(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/DocumentationMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/DocumentationMeasuresStepTest.java new file mode 100644 index 00000000000..851f5db6861 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/DocumentationMeasuresStepTest.java @@ -0,0 +1,203 @@ +/* + * 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.Before; +import org.junit.Rule; +import org.junit.Test; +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.PUBLIC_API; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_API_KEY; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_DOCUMENTED_API_DENSITY; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_DOCUMENTED_API_DENSITY_KEY; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_UNDOCUMENTED_API; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_UNDOCUMENTED_API_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.DumbComponent.builder; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; + +public class DocumentationMeasuresStepTest { + + private static final int ROOT_REF = 1; + private static final int MODULE_REF = 12; + private static final int SUB_MODULE_REF = 123; + private static final int DIRECTORY_REF = 1234; + private static final int FILE_1_REF = 12341; + private static final int FILE_2_REF = 12342; + + @Rule + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + + @Rule + public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + .add(PUBLIC_API) + .add(PUBLIC_UNDOCUMENTED_API) + .add(PUBLIC_DOCUMENTED_API_DENSITY); + + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + ComputationStep sut = new DocumentationMeasuresStep(treeRootHolder, metricRepository, measureRepository); + + @Before + public void setUp() throws Exception { + treeRootHolder.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()); + } + + @Test + public void aggregate_public_api() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_API_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_API_KEY, newMeasureBuilder().create(400)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(PUBLIC_API_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(PUBLIC_API_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(PUBLIC_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(PUBLIC_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(PUBLIC_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(PUBLIC_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + } + + @Test + public void aggregate_public_undocumented_api() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(400)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(PUBLIC_UNDOCUMENTED_API_KEY)).containsOnly(newMeasureBuilder().create(500)); + } + + @Test + public void compute_public_documented_api_density() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_API_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(50)); + + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_API_KEY, newMeasureBuilder().create(400)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(100)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(50d)); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(75d)); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(70d)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(70d)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(70d)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(70d)); + } + + @Test + public void not_compute_public_documented_api_density_when_no_public_api() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(50)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(100)); + + sut.execute(); + assertNoNewMeasures(PUBLIC_DOCUMENTED_API_DENSITY_KEY); + } + + @Test + public void not_compute_public_documented_api_density_when_no_public_undocumented_api() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_API_KEY, newMeasureBuilder().create(50)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_API_KEY, newMeasureBuilder().create(100)); + + sut.execute(); + assertNoNewMeasures(PUBLIC_DOCUMENTED_API_DENSITY_KEY); + } + + @Test + public void not_compute_public_documented_api_density_when_public_api_is_zero() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_API_KEY, newMeasureBuilder().create(0)); + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(50)); + + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_API_KEY, newMeasureBuilder().create(0)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(100)); + + sut.execute(); + assertNoNewMeasures(PUBLIC_DOCUMENTED_API_DENSITY_KEY); + } + + @Test + public void compute_100_percent_public_documented_api_density_when_public_undocumented_api_is_zero() { + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_API_KEY, newMeasureBuilder().create(100)); + measureRepository.addRawMeasure(FILE_1_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(0)); + + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_API_KEY, newMeasureBuilder().create(400)); + measureRepository.addRawMeasure(FILE_2_REF, PUBLIC_UNDOCUMENTED_API_KEY, newMeasureBuilder().create(0)); + + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(PUBLIC_DOCUMENTED_API_DENSITY_KEY)).containsOnly(newMeasureBuilder().create(100d)); + } + + @Test + public void compute_nothing_when_no_data() { + sut.execute(); + + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF)).isEmpty(); + } + + private void assertNoNewMeasures(String metric) { + assertThat(measureRepository.getNewRawMeasures(FILE_1_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(FILE_2_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(DIRECTORY_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(SUB_MODULE_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(MODULE_REF).get(metric)).isEmpty(); + assertThat(measureRepository.getNewRawMeasures(ROOT_REF).get(metric)).isEmpty(); + } +}