From: Sébastien Lesaint Date: Wed, 19 Aug 2015 12:40:01 +0000 (+0200) Subject: add support for Views to SizeMeasuresStep and FormulaExecutorComponentVisitor X-Git-Tag: 5.2-RC1~648 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f8bd7b5db35532d226652da3dfe22dce5b45b874;p=sonarqube.git add support for Views to SizeMeasuresStep and FormulaExecutorComponentVisitor --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java index 52fdb6b98db..4f3abd84a22 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java @@ -27,7 +27,6 @@ import java.util.Map; import javax.annotation.CheckForNull; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.ComponentVisitor; -import org.sonar.server.computation.component.CrawlerDepthLimit; import org.sonar.server.computation.component.PathAwareVisitorAdapter; import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureRepository; @@ -37,6 +36,9 @@ import org.sonar.server.computation.period.Period; import org.sonar.server.computation.period.PeriodsHolder; import static java.util.Objects.requireNonNull; +import static org.sonar.server.computation.component.Component.Type.FILE; +import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW; +import static org.sonar.server.computation.component.CrawlerDepthLimit.reportMaxDepth; public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter { private static final SimpleStackElementFactory COUNTERS_FACTORY = new SimpleStackElementFactory() { @@ -48,7 +50,13 @@ public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter formulas; private FormulaExecutorComponentVisitor(Builder builder, List formulas) { - super(CrawlerDepthLimit.FILE, ComponentVisitor.Order.POST_ORDER, COUNTERS_FACTORY); + super(reportMaxDepth(FILE).withViewsMaxDepth(PROJECT_VIEW), ComponentVisitor.Order.POST_ORDER, COUNTERS_FACTORY); this.periodsHolder = builder.periodsHolder; this.measureRepository = builder.measureRepository; this.metricRepository = builder.metricRepository; @@ -113,7 +121,22 @@ public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter path) { - processFile(file, path); + processLeaf(file, path); + } + + @Override + public void visitView(Component view, Path path) { + processNotFile(view, path); + } + + @Override + public void visitSubView(Component subView, Path path) { + processNotFile(subView, path); + } + + @Override + public void visitProjectView(Component projectView, Path path) { + processLeaf(projectView, path); } private void processNotFile(Component component, Path path) { @@ -129,7 +152,7 @@ public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter path) { + private void processLeaf(Component file, Path path) { FileAggregateContext counterContext = new FileAggregateContextImpl(file); for (Formula formula : formulas) { Counter counter = formula.createNewCounter(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/SumFormula.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/SumFormula.java index cf513d8cf55..5ee84399ae9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/SumFormula.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/SumFormula.java @@ -21,12 +21,15 @@ package org.sonar.server.computation.formula; import com.google.common.base.Optional; -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; +import static org.sonar.server.computation.component.Component.Type.FILE; +import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW; public class SumFormula implements Formula { + private static final CrawlerDepthLimit LIMIT = CrawlerDepthLimit.reportMaxDepth(FILE).withViewsMaxDepth(PROJECT_VIEW); private final String metricKey; @@ -42,7 +45,7 @@ public class SumFormula implements Formula { @Override public Optional createMeasure(SumCounter counter, CreateMeasureContext context) { Optional valueOptional = counter.getValue(); - if (valueOptional.isPresent() && context.getComponent().getType().isHigherThan(Component.Type.FILE)) { + if (valueOptional.isPresent() && LIMIT.isDeeperThan(context.getComponent().getType())) { return Optional.of(Measure.newMeasureBuilder().create(valueOptional.get())); } return Optional.absent(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SizeMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SizeMeasuresStep.java index 005800a3bdb..2441c1cb62c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SizeMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SizeMeasuresStep.java @@ -19,16 +19,17 @@ */ package org.sonar.server.computation.step; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.sonar.api.measures.CoreMetrics; import org.sonar.server.computation.component.Component; -import org.sonar.server.computation.component.CrawlerDepthLimit; import org.sonar.server.computation.component.PathAwareCrawler; import org.sonar.server.computation.component.PathAwareVisitorAdapter; import org.sonar.server.computation.component.TreeRootHolder; 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.Metric; import org.sonar.server.computation.metric.MetricRepository; @@ -41,7 +42,10 @@ import static org.sonar.api.measures.CoreMetrics.GENERATED_NCLOC_KEY; import static org.sonar.api.measures.CoreMetrics.LINES_KEY; import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; import static org.sonar.api.measures.CoreMetrics.STATEMENTS_KEY; +import static org.sonar.server.computation.component.Component.Type.FILE; +import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW; import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; +import static org.sonar.server.computation.component.CrawlerDepthLimit.reportMaxDepth; import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; /** @@ -92,7 +96,7 @@ public class SizeMeasuresStep implements ComputationStep { private final Metric fileMetric; public FileAndDirectoryMeasureVisitor(Metric directoryMetric, Metric fileMetric) { - super(CrawlerDepthLimit.FILE, POST_ORDER, COUNTER_STACK_ELEMENT_FACTORY); + super(reportMaxDepth(FILE).withViewsMaxDepth(PROJECT_VIEW), POST_ORDER, COUNTER_STACK_ELEMENT_FACTORY); this.directoryMetric = directoryMetric; this.fileMetric = fileMetric; } @@ -135,6 +139,30 @@ public class SizeMeasuresStep implements ComputationStep { path.parent().files += 1; } + @Override + public void visitView(Component view, Path path) { + createMeasures(view, path.current().directories, path.current().files); + } + + @Override + public void visitSubView(Component subView, Path path) { + createMeasures(subView, path.current().directories, path.current().files); + + path.parent().directories += path.current().directories; + path.parent().files += path.current().files; + } + + @Override + public void visitProjectView(Component projectView, Path path) { + path.parent().directories += getIntValue(projectView, this.directoryMetric); + path.parent().files += getIntValue(projectView, this.fileMetric); + } + + private int getIntValue(Component component, Metric metric) { + Optional fileMeasure = measureRepository.getRawMeasure(component, metric); + return fileMeasure.isPresent() ? fileMeasure.get().getIntValue() : 0; + } + } private static class Counter { @@ -153,5 +181,10 @@ public class SizeMeasuresStep implements ComputationStep { public Counter createForFile(Component file) { return null; } + + @Override + public Counter createForProjectView(Component projectView) { + return null; + } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryRule.java index 97c51843b5f..a490b61a3b4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryRule.java @@ -48,6 +48,8 @@ import static com.google.common.collect.FluentIterable.from; import static com.google.common.collect.Maps.filterKeys; import static java.lang.String.format; import static java.util.Objects.requireNonNull; +import static org.sonar.server.computation.component.Component.Type.FILE; +import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW; /** * An implementation of MeasureRepository as a JUnit rule which provides add methods for raw measures and extra add @@ -103,7 +105,7 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe InternalKey internalKey = new InternalKey(component, metric); checkState(!baseMeasures.containsKey(internalKey), - format("Can not add a BaseMeasure twice for a Component (ref=%s) and Metric (key=%s)", component.getReportAttributes().getRef(), metric.getKey())); + format("Can not add a BaseMeasure twice for a Component (ref=%s) and Metric (key=%s)", getRef(component), metric.getKey())); baseMeasures.put(internalKey, measure); @@ -229,22 +231,24 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe @Override public void add(Component component, Metric metric, Measure measure) { - InternalKey internalKey = new InternalKey(component.getReportAttributes().getRef(), metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); + String ref = getRef(component); + InternalKey internalKey = new InternalKey(ref, metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); if (rawMeasures.containsKey(internalKey)) { throw new UnsupportedOperationException(format( "A measure can only be set once for Component (ref=%s), Metric (key=%s), ruleId=%s, characteristicId=%s", - component.getReportAttributes().getRef(), metric.getKey(), measure.getRuleId(), measure.getCharacteristicId())); + ref, metric.getKey(), measure.getRuleId(), measure.getCharacteristicId())); } rawMeasures.put(internalKey, measure); } @Override public void update(Component component, Metric metric, Measure measure) { - InternalKey internalKey = new InternalKey(component.getReportAttributes().getRef(), metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); + String componentRef = getRef(component); + InternalKey internalKey = new InternalKey(componentRef, metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); if (!rawMeasures.containsKey(internalKey)) { throw new UnsupportedOperationException(format( "A measure can only be updated if it has been added first for Component (ref=%s), Metric (key=%s), ruleId=%s, characteristicId=%s", - component.getReportAttributes().getRef(), metric.getKey(), measure.getRuleId(), measure.getCharacteristicId())); + componentRef, metric.getKey(), measure.getRuleId(), measure.getCharacteristicId())); } rawMeasures.put(internalKey, measure); } @@ -262,31 +266,31 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe private static final class InternalKey { private static final int DEFAULT_VALUE = -9876; - private final int componentRef; + private final String componentRef; private final String metricKey; private final int ruleId; private final int characteristicId; public InternalKey(Component component, Metric metric) { - this(component.getReportAttributes().getRef(), metric.getKey(), null, null); + this(getRef(component), metric.getKey(), null, null); } public InternalKey(Component component, Metric metric, @Nullable Integer ruleId, @Nullable Integer characteristicId) { - this(component.getReportAttributes().getRef(), metric.getKey(), ruleId, characteristicId); + this(getRef(component), metric.getKey(), ruleId, characteristicId); } - public InternalKey(int componentRef, String metricKey) { + public InternalKey(String componentRef, String metricKey) { this(componentRef, metricKey, null, null); } - public InternalKey(int componentRef, String metricKey, @Nullable Integer ruleId, @Nullable Integer characteristicId) { + public InternalKey(String componentRef, String metricKey, @Nullable Integer ruleId, @Nullable Integer characteristicId) { this.componentRef = componentRef; this.metricKey = metricKey; this.ruleId = ruleId == null ? DEFAULT_VALUE : ruleId; this.characteristicId = characteristicId == null ? DEFAULT_VALUE : characteristicId; } - public int getComponentRef() { + public String getComponentRef() { return componentRef; } @@ -335,15 +339,15 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe private static class HasComponentRefPredicate implements Predicate { - private final Component component; + private final String componentRef; public HasComponentRefPredicate(Component component) { - this.component = component; + this.componentRef = getRef(component); } @Override public boolean apply(@Nonnull InternalKey input) { - return input.getComponentRef() == component.getReportAttributes().getRef(); + return input.getComponentRef().equals(this.componentRef); } } @@ -386,16 +390,16 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe } private static final class TreeComponentProvider implements ComponentProvider { - private final Map componentsByRef = new HashMap<>(); + private final Map componentsByRef = new HashMap<>(); public TreeComponentProvider(Component root) { new DepthTraversalTypeAwareCrawler( - new TypeAwareVisitorAdapter(CrawlerDepthLimit.FILE, ComponentVisitor.Order.PRE_ORDER) { + new TypeAwareVisitorAdapter(CrawlerDepthLimit.reportMaxDepth(FILE).withViewsMaxDepth(PROJECT_VIEW), ComponentVisitor.Order.PRE_ORDER) { @Override public void visitAny(Component component) { - checkState(!componentsByRef.containsKey(component.getReportAttributes().getRef()), - "Tree contains more than one component with ref " + component.getReportAttributes().getRef()); - componentsByRef.put(component.getReportAttributes().getRef(), component); + String ref = getRef(component); + checkState(!componentsByRef.containsKey(ref), "Tree contains more than one component with ref " + ref); + componentsByRef.put(ref, component); } }).visit(root); } @@ -412,10 +416,14 @@ public class MeasureRepositoryRule extends ExternalResource implements MeasureRe @Override public Component getByRef(int componentRef) { - Component component = componentsByRef.get(componentRef); + Component component = componentsByRef.get(String.valueOf(componentRef)); checkState(component != null, "Can not find Component for ref " + componentRef); return component; } } + private static String getRef(Component component) { + return component.getType().isReportType() ? String.valueOf(component.getReportAttributes().getRef()) : component.getKey(); + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportSizeMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportSizeMeasuresStepTest.java new file mode 100644 index 00000000000..ca84cb94c2b --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportSizeMeasuresStepTest.java @@ -0,0 +1,222 @@ +/* + * 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 javax.annotation.Nullable; +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.FileAttributes; +import org.sonar.server.computation.measure.MeasureRepoEntry; +import org.sonar.server.computation.measure.MeasureRepositoryRule; +import org.sonar.server.computation.metric.MetricRepositoryRule; + +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.FluentIterable.from; +import static com.google.common.collect.Iterables.concat; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY; +import static org.sonar.api.measures.CoreMetrics.DIRECTORIES_KEY; +import static org.sonar.api.measures.CoreMetrics.FILES_KEY; +import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.GENERATED_LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; +import static org.sonar.api.measures.CoreMetrics.STATEMENTS_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 ReportSizeMeasuresStepTest { + + private static final String LANGUAGE_DOES_NOT_MATTER_HERE = null; + 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_1_REF = 1234; + private static final int DIRECTORY_2_REF = 1235; + private static final int DIRECTORY_3_REF = 1236; + private static final int FILE_1_REF = 12341; + private static final int FILE_2_REF = 12343; + private static final int FILE_3_REF = 12351; + private static final int UNIT_TEST_1_REF = 12352; + private static final int UNIT_TEST_2_REF = 12361; + private static final Integer NO_FILE_METRIC = null; + + @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_1_REF) + .addChildren( + builder(FILE, FILE_1_REF).build(), + builder(FILE, FILE_2_REF).build()) + .build(), + builder(DIRECTORY, DIRECTORY_2_REF) + .addChildren( + builder(FILE, FILE_3_REF).build(), + builder(FILE, UNIT_TEST_1_REF).setFileAttributes(new FileAttributes(true, LANGUAGE_DOES_NOT_MATTER_HERE)).build()) + .build(), + builder(DIRECTORY, DIRECTORY_3_REF) + .addChildren( + builder(FILE, UNIT_TEST_2_REF).setFileAttributes(new FileAttributes(true, LANGUAGE_DOES_NOT_MATTER_HERE)).build()) + .build()) + .build()) + .build()) + .build()); + @Rule + public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + .add(CoreMetrics.FILES) + .add(CoreMetrics.DIRECTORIES) + .add(CoreMetrics.LINES) + .add(CoreMetrics.GENERATED_LINES) + .add(CoreMetrics.NCLOC) + .add(CoreMetrics.GENERATED_NCLOC) + .add(CoreMetrics.FUNCTIONS) + .add(CoreMetrics.STATEMENTS) + .add(CoreMetrics.CLASSES) + .add(CoreMetrics.ACCESSORS); + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + private SizeMeasuresStep underTest = new SizeMeasuresStep(treeRootHolder, metricRepository, measureRepository); + + @Test + public void verify_FILE_and_DIRECTORY_computation_and_aggregation() { + underTest.execute(); + + verifyMeasuresOnFile(FILE_1_REF, 1); + verifyMeasuresOnFile(FILE_2_REF, 1); + verifyMeasuresOnFile(FILE_3_REF, 1); + verifyNoMeasure(UNIT_TEST_1_REF); + verifyNoMeasure(UNIT_TEST_2_REF); + verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1); + verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1); + verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); + verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3); + verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3); + verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3); + } + + @Test + public void verify_LINE_related_measures_aggregation() { + verifyTwoMeasureAggregation(LINES_KEY, GENERATED_LINES_KEY); + } + + private void verifyTwoMeasureAggregation(String metric1Key, String metric2Key) { + measureRepository.addRawMeasure(FILE_1_REF, metric1Key, newMeasureBuilder().create(1)); + measureRepository.addRawMeasure(FILE_1_REF, metric2Key, newMeasureBuilder().create(10)); + // FILE_2_REF has no metric2 measure + measureRepository.addRawMeasure(FILE_2_REF, metric1Key, newMeasureBuilder().create(6)); + // FILE_3_REF has no measure at all + // UNIT_TEST_1_REF has no metric1 + measureRepository.addRawMeasure(UNIT_TEST_1_REF, metric2Key, newMeasureBuilder().create(90)); + + underTest.execute(); + + verifyMeasuresOnFile(FILE_1_REF, 1); + verifyMeasuresOnFile(FILE_2_REF, 1); + verifyMeasuresOnFile(FILE_3_REF, 1); + verifyNoMeasure(UNIT_TEST_1_REF); + verifyNoMeasure(UNIT_TEST_2_REF); + verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1, + entryOf(metric1Key, newMeasureBuilder().create(7)), entryOf(metric2Key, newMeasureBuilder().create(10))); + verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1, + entryOf(metric2Key, newMeasureBuilder().create(90))); + MeasureRepoEntry[] subModuleAndAboveEntries = { + entryOf(metric1Key, newMeasureBuilder().create(7)), + entryOf(metric2Key, newMeasureBuilder().create(100)) + }; + verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); + verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3, subModuleAndAboveEntries); + verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3, subModuleAndAboveEntries); + verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3, subModuleAndAboveEntries); + } + + @Test + public void verify_NCLOC_measure_aggregation() { + verifyMetricAggregation(NCLOC_KEY); + } + + private void verifyMetricAggregation(String metricKey) { + measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create(6)); + measureRepository.addRawMeasure(UNIT_TEST_1_REF, metricKey, newMeasureBuilder().create(3)); + + underTest.execute(); + + verifyMeasuresOnFile(FILE_1_REF, 1); + verifyMeasuresOnFile(FILE_2_REF, 1); + verifyMeasuresOnFile(FILE_3_REF, 1); + verifyNoMeasure(UNIT_TEST_1_REF); + verifyNoMeasure(UNIT_TEST_2_REF); + verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1, entryOf(metricKey, newMeasureBuilder().create(16))); + verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1, entryOf(metricKey, newMeasureBuilder().create(3))); + verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); + verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); + verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); + verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); + } + + @Test + public void verify_FUNCTIONS_and_STATEMENT_measure_aggregation() { + verifyTwoMeasureAggregation(FUNCTIONS_KEY, STATEMENTS_KEY); + } + + @Test + public void verify_CLASSES_measure_aggregation() { + verifyMetricAggregation(CLASSES_KEY); + } + + private void verifyMeasuresOnFile(int componentRef, int fileCount) { + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))) + .containsOnly(entryOf(FILES_KEY, newMeasureBuilder().create(fileCount))); + } + + private void verifyMeasuresOnOtherComponent(int componentRef, @Nullable Integer fileCount, int directoryCount, MeasureRepoEntry... otherMeasures) { + MeasureRepoEntry[] measureRepoEntries = concatIntoArray( + otherMeasures, + fileCount == null ? null : entryOf(FILES_KEY, newMeasureBuilder().create(fileCount)), entryOf(DIRECTORIES_KEY, newMeasureBuilder().create(directoryCount))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))) + .containsOnly(measureRepoEntries); + } + + private static MeasureRepoEntry[] concatIntoArray(MeasureRepoEntry[] otherMeasures, MeasureRepoEntry... measureRepoEntries) { + return from(concat( + asList(otherMeasures), + from(asList(measureRepoEntries)).filter(notNull()))) + .toArray(MeasureRepoEntry.class); + } + + private void verifyNoMeasure(int componentRef) { + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).isEmpty(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SizeMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SizeMeasuresStepTest.java deleted file mode 100644 index 3cdb7341dc4..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SizeMeasuresStepTest.java +++ /dev/null @@ -1,222 +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 javax.annotation.Nullable; -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.FileAttributes; -import org.sonar.server.computation.measure.MeasureRepoEntry; -import org.sonar.server.computation.measure.MeasureRepositoryRule; -import org.sonar.server.computation.metric.MetricRepositoryRule; - -import static com.google.common.base.Predicates.notNull; -import static com.google.common.collect.FluentIterable.from; -import static com.google.common.collect.Iterables.concat; -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY; -import static org.sonar.api.measures.CoreMetrics.DIRECTORIES_KEY; -import static org.sonar.api.measures.CoreMetrics.FILES_KEY; -import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.GENERATED_LINES_KEY; -import static org.sonar.api.measures.CoreMetrics.LINES_KEY; -import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; -import static org.sonar.api.measures.CoreMetrics.STATEMENTS_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 SizeMeasuresStepTest { - - private static final String LANGUAGE_DOES_NOT_MATTER_HERE = null; - 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_1_REF = 1234; - private static final int DIRECTORY_2_REF = 1235; - private static final int DIRECTORY_3_REF = 1236; - private static final int FILE_1_REF = 12341; - private static final int FILE_2_REF = 12343; - private static final int FILE_3_REF = 12351; - private static final int UNIT_TEST_1_REF = 12352; - private static final int UNIT_TEST_2_REF = 12361; - private static final Integer NO_FILE_METRIC = null; - - @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_1_REF) - .addChildren( - builder(FILE, FILE_1_REF).build(), - builder(FILE, FILE_2_REF).build()) - .build(), - builder(DIRECTORY, DIRECTORY_2_REF) - .addChildren( - builder(FILE, FILE_3_REF).build(), - builder(FILE, UNIT_TEST_1_REF).setFileAttributes(new FileAttributes(true, LANGUAGE_DOES_NOT_MATTER_HERE)).build()) - .build(), - builder(DIRECTORY, DIRECTORY_3_REF) - .addChildren( - builder(FILE, UNIT_TEST_2_REF).setFileAttributes(new FileAttributes(true, LANGUAGE_DOES_NOT_MATTER_HERE)).build()) - .build()) - .build()) - .build()) - .build()); - @Rule - public MetricRepositoryRule metricRepository = new MetricRepositoryRule() - .add(CoreMetrics.FILES) - .add(CoreMetrics.DIRECTORIES) - .add(CoreMetrics.LINES) - .add(CoreMetrics.GENERATED_LINES) - .add(CoreMetrics.NCLOC) - .add(CoreMetrics.GENERATED_NCLOC) - .add(CoreMetrics.FUNCTIONS) - .add(CoreMetrics.STATEMENTS) - .add(CoreMetrics.CLASSES) - .add(CoreMetrics.ACCESSORS); - @Rule - public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); - - private SizeMeasuresStep underTest = new SizeMeasuresStep(treeRootHolder, metricRepository, measureRepository); - - @Test - public void verify_FILE_and_DIRECTORY_computation_and_aggregation() { - underTest.execute(); - - verifyMeasuresOnFile(FILE_1_REF, 1); - verifyMeasuresOnFile(FILE_2_REF, 1); - verifyMeasuresOnFile(FILE_3_REF, 1); - verifyNoMeasure(UNIT_TEST_1_REF); - verifyNoMeasure(UNIT_TEST_2_REF); - verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1); - verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1); - verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); - verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3); - verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3); - verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3); - } - - @Test - public void verify_LINE_related_measures_aggregation() { - verifyTwoMeasureAggregation(LINES_KEY, GENERATED_LINES_KEY); - } - - private void verifyTwoMeasureAggregation(String metric1Key, String metric2Key) { - measureRepository.addRawMeasure(FILE_1_REF, metric1Key, newMeasureBuilder().create(1)); - measureRepository.addRawMeasure(FILE_1_REF, metric2Key, newMeasureBuilder().create(10)); - // FILE_2_REF has no metric2 measure - measureRepository.addRawMeasure(FILE_2_REF, metric1Key, newMeasureBuilder().create(6)); - // FILE_3_REF has no measure at all - // UNIT_TEST_1_REF has no metric1 - measureRepository.addRawMeasure(UNIT_TEST_1_REF, metric2Key, newMeasureBuilder().create(90)); - - underTest.execute(); - - verifyMeasuresOnFile(FILE_1_REF, 1); - verifyMeasuresOnFile(FILE_2_REF, 1); - verifyMeasuresOnFile(FILE_3_REF, 1); - verifyNoMeasure(UNIT_TEST_1_REF); - verifyNoMeasure(UNIT_TEST_2_REF); - verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1, - entryOf(metric1Key, newMeasureBuilder().create(7)), entryOf(metric2Key, newMeasureBuilder().create(10))); - verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1, - entryOf(metric2Key, newMeasureBuilder().create(90))); - MeasureRepoEntry[] subModuleAndAboveEntries = { - entryOf(metric1Key, newMeasureBuilder().create(7)), - entryOf(metric2Key, newMeasureBuilder().create(100)) - }; - verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); - verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3, subModuleAndAboveEntries); - verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3, subModuleAndAboveEntries); - verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3, subModuleAndAboveEntries); - } - - @Test - public void verify_NCLOC_measure_aggregation() { - verifyMetricAggregation(NCLOC_KEY); - } - - private void verifyMetricAggregation(String metricKey) { - measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create(10)); - measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create(6)); - measureRepository.addRawMeasure(UNIT_TEST_1_REF, metricKey, newMeasureBuilder().create(3)); - - underTest.execute(); - - verifyMeasuresOnFile(FILE_1_REF, 1); - verifyMeasuresOnFile(FILE_2_REF, 1); - verifyMeasuresOnFile(FILE_3_REF, 1); - verifyNoMeasure(UNIT_TEST_1_REF); - verifyNoMeasure(UNIT_TEST_2_REF); - verifyMeasuresOnOtherComponent(DIRECTORY_1_REF, 2, 1, entryOf(metricKey, newMeasureBuilder().create(16))); - verifyMeasuresOnOtherComponent(DIRECTORY_2_REF, 1, 1, entryOf(metricKey, newMeasureBuilder().create(3))); - verifyMeasuresOnOtherComponent(DIRECTORY_3_REF, NO_FILE_METRIC, 1); - verifyMeasuresOnOtherComponent(SUB_MODULE_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); - verifyMeasuresOnOtherComponent(MODULE_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); - verifyMeasuresOnOtherComponent(ROOT_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(19))); - } - - @Test - public void verify_FUNCTIONS_and_STATEMENT_measure_aggregation() { - verifyTwoMeasureAggregation(FUNCTIONS_KEY, STATEMENTS_KEY); - } - - @Test - public void verify_CLASSES_measure_aggregation() { - verifyMetricAggregation(CLASSES_KEY); - } - - private void verifyMeasuresOnFile(int componentRef, int fileCount) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))) - .containsOnly(entryOf(FILES_KEY, newMeasureBuilder().create(fileCount))); - } - - private void verifyMeasuresOnOtherComponent(int componentRef, @Nullable Integer fileCount, int directoryCount, MeasureRepoEntry... otherMeasures) { - MeasureRepoEntry[] measureRepoEntries = concatIntoArray( - otherMeasures, - fileCount == null ? null : entryOf(FILES_KEY, newMeasureBuilder().create(fileCount)), entryOf(DIRECTORIES_KEY, newMeasureBuilder().create(directoryCount))); - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))) - .containsOnly(measureRepoEntries); - } - - private static MeasureRepoEntry[] concatIntoArray(MeasureRepoEntry[] otherMeasures, MeasureRepoEntry... measureRepoEntries) { - return from(concat( - asList(otherMeasures), - from(asList(measureRepoEntries)).filter(notNull()))) - .toArray(MeasureRepoEntry.class); - } - - private void verifyNoMeasure(int componentRef) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).isEmpty(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsSizeMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsSizeMeasuresStepTest.java new file mode 100644 index 00000000000..777ae998863 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsSizeMeasuresStepTest.java @@ -0,0 +1,228 @@ +/* + * 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 javax.annotation.Nullable; +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.measure.MeasureRepoEntry; +import org.sonar.server.computation.measure.MeasureRepositoryRule; +import org.sonar.server.computation.metric.MetricRepositoryRule; + +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.FluentIterable.from; +import static com.google.common.collect.Iterables.concat; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.measures.CoreMetrics.CLASSES_KEY; +import static org.sonar.api.measures.CoreMetrics.DIRECTORIES_KEY; +import static org.sonar.api.measures.CoreMetrics.FILES_KEY; +import static org.sonar.api.measures.CoreMetrics.FUNCTIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.GENERATED_LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.LINES_KEY; +import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; +import static org.sonar.api.measures.CoreMetrics.STATEMENTS_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 ViewsSizeMeasuresStepTest { + + private static final int ROOT_REF = 1; + private static final int SUBVIEW_1_REF = 12; + private static final int SUBVIEW_2_REF = 13; + private static final int SUB_SUBVIEW_1_REF = 121; + private static final int SUB_SUBVIEW_2_REF = 122; + private static final int SUB_SUBVIEW_3_REF = 123; + private static final int PROJECTVIEW_1_REF = 1231; + private static final int PROJECTVIEW_2_REF = 1232; + private static final int PROJECTVIEW_3_REF = 1241; + private static final int PROJECTVIEW_4_REF = 1251; + private static final int PROJECTVIEW_5_REF = 14; + private static final Integer NO_FILE_METRIC = null; + + @Rule + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot( + builder(VIEW, ROOT_REF) + .addChildren( + builder(SUBVIEW, SUBVIEW_1_REF) + .addChildren( + builder(SUBVIEW, SUB_SUBVIEW_1_REF) + .addChildren( + builder(PROJECT_VIEW, PROJECTVIEW_1_REF).build(), + builder(PROJECT_VIEW, PROJECTVIEW_2_REF).build()) + .build(), + builder(SUBVIEW, SUB_SUBVIEW_2_REF) + .addChildren( + builder(PROJECT_VIEW, PROJECTVIEW_3_REF).build()) + .build(), + builder(SUBVIEW, SUB_SUBVIEW_3_REF).addChildren( + builder(PROJECT_VIEW, PROJECTVIEW_4_REF).build()) + .build()) + .build(), + builder(SUBVIEW, SUBVIEW_2_REF).build(), + builder(PROJECT_VIEW, PROJECTVIEW_5_REF).build()) + .build()); + @Rule + public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + .add(CoreMetrics.FILES) + .add(CoreMetrics.DIRECTORIES) + .add(CoreMetrics.LINES) + .add(CoreMetrics.GENERATED_LINES) + .add(CoreMetrics.NCLOC) + .add(CoreMetrics.GENERATED_NCLOC) + .add(CoreMetrics.FUNCTIONS) + .add(CoreMetrics.STATEMENTS) + .add(CoreMetrics.CLASSES) + .add(CoreMetrics.ACCESSORS); + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository) + .addRawMeasure(PROJECTVIEW_1_REF, CoreMetrics.FILES_KEY, newMeasureBuilder().create(1)) + .addRawMeasure(PROJECTVIEW_2_REF, CoreMetrics.FILES_KEY, newMeasureBuilder().create(2)) + .addRawMeasure(PROJECTVIEW_3_REF, CoreMetrics.FILES_KEY, newMeasureBuilder().create(3)) + // PROJECTVIEW_4_REF has no file metric + .addRawMeasure(PROJECTVIEW_5_REF, CoreMetrics.FILES_KEY, newMeasureBuilder().create(5)) + .addRawMeasure(PROJECTVIEW_1_REF, CoreMetrics.DIRECTORIES_KEY, newMeasureBuilder().create(1)) + .addRawMeasure(PROJECTVIEW_2_REF, CoreMetrics.DIRECTORIES_KEY, newMeasureBuilder().create(2)) + // PROJECTVIEW_3_REF has no directory metric + .addRawMeasure(PROJECTVIEW_4_REF, CoreMetrics.DIRECTORIES_KEY, newMeasureBuilder().create(4)) + .addRawMeasure(PROJECTVIEW_5_REF, CoreMetrics.DIRECTORIES_KEY, newMeasureBuilder().create(5)); + + private SizeMeasuresStep underTest = new SizeMeasuresStep(treeRootHolder, metricRepository, measureRepository); + + @Test + public void verify_FILE_and_DIRECTORY_computation_and_aggregation() { + underTest.execute(); + + verifyNoMeasure(PROJECTVIEW_1_REF); + verifyNoMeasure(PROJECTVIEW_2_REF); + verifyNoMeasure(PROJECTVIEW_3_REF); + verifyNoMeasure(PROJECTVIEW_4_REF); + verifyNoMeasure(PROJECTVIEW_5_REF); + verifyMeasures(SUB_SUBVIEW_1_REF, 3, 3); + verifyMeasures(SUB_SUBVIEW_2_REF, 3, 0); + verifyMeasures(SUB_SUBVIEW_3_REF, NO_FILE_METRIC, 4); + verifyMeasures(SUBVIEW_1_REF, 6, 7); + verifyMeasures(SUBVIEW_2_REF, NO_FILE_METRIC, 0); + verifyMeasures(ROOT_REF, 11, 12); + } + + @Test + public void verify_LINE_related_measures_aggregation() { + verifyTwoMeasureAggregation(LINES_KEY, GENERATED_LINES_KEY); + } + + private void verifyTwoMeasureAggregation(String metric1Key, String metric2Key) { + measureRepository.addRawMeasure(PROJECTVIEW_1_REF, metric1Key, newMeasureBuilder().create(1)); + measureRepository.addRawMeasure(PROJECTVIEW_1_REF, metric2Key, newMeasureBuilder().create(10)); + // PROJECTVIEW_2_REF has no metric2 measure + measureRepository.addRawMeasure(PROJECTVIEW_2_REF, metric1Key, newMeasureBuilder().create(6)); + // PROJECTVIEW_3_REF has no measure at all + // PROJECTVIEW_4_REF has no metric1 + measureRepository.addRawMeasure(PROJECTVIEW_4_REF, metric2Key, newMeasureBuilder().create(90)); + measureRepository.addRawMeasure(PROJECTVIEW_5_REF, metric1Key, newMeasureBuilder().create(3)); + measureRepository.addRawMeasure(PROJECTVIEW_5_REF, metric2Key, newMeasureBuilder().create(7)); + + underTest.execute(); + + verifyNoMeasure(PROJECTVIEW_1_REF); + verifyNoMeasure(PROJECTVIEW_2_REF); + verifyNoMeasure(PROJECTVIEW_3_REF); + verifyNoMeasure(PROJECTVIEW_4_REF); + verifyNoMeasure(PROJECTVIEW_5_REF); + verifyNoMeasure(PROJECTVIEW_4_REF); + verifyMeasures(SUB_SUBVIEW_1_REF, 3, 3, + entryOf(metric1Key, newMeasureBuilder().create(7)), entryOf(metric2Key, newMeasureBuilder().create(10))); + verifyMeasures(SUB_SUBVIEW_2_REF, 3, 0); + verifyMeasures(SUB_SUBVIEW_3_REF, NO_FILE_METRIC, 4, + entryOf(metric2Key, newMeasureBuilder().create(90))); + verifyMeasures(SUBVIEW_1_REF, 6, 7, + entryOf(metric1Key, newMeasureBuilder().create(7)), entryOf(metric2Key, newMeasureBuilder().create(100))); + verifyMeasures(SUBVIEW_2_REF, NO_FILE_METRIC, 0); + verifyMeasures(ROOT_REF, 11, 12, + entryOf(metric1Key, newMeasureBuilder().create(10)), entryOf(metric2Key, newMeasureBuilder().create(107))); + } + + @Test + public void verify_NCLOC_measure_aggregation() { + verifyMetricAggregation(NCLOC_KEY); + } + + private void verifyMetricAggregation(String metricKey) { + measureRepository.addRawMeasure(PROJECTVIEW_1_REF, metricKey, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(PROJECTVIEW_2_REF, metricKey, newMeasureBuilder().create(6)); + measureRepository.addRawMeasure(PROJECTVIEW_4_REF, metricKey, newMeasureBuilder().create(3)); + measureRepository.addRawMeasure(PROJECTVIEW_5_REF, metricKey, newMeasureBuilder().create(7)); + + underTest.execute(); + + verifyNoMeasure(PROJECTVIEW_1_REF); + verifyNoMeasure(PROJECTVIEW_2_REF); + verifyNoMeasure(PROJECTVIEW_3_REF); + verifyNoMeasure(PROJECTVIEW_4_REF); + verifyNoMeasure(PROJECTVIEW_5_REF); + verifyMeasures(SUB_SUBVIEW_1_REF, 3, 3, entryOf(metricKey, newMeasureBuilder().create(16))); + verifyMeasures(SUB_SUBVIEW_2_REF, 3, 0); + verifyMeasures(SUB_SUBVIEW_3_REF, NO_FILE_METRIC, 4, entryOf(metricKey, newMeasureBuilder().create(3))); + verifyMeasures(SUBVIEW_1_REF, 6, 7, entryOf(metricKey, newMeasureBuilder().create(19))); + verifyMeasures(SUBVIEW_2_REF, NO_FILE_METRIC, 0); + verifyMeasures(ROOT_REF, 11, 12, entryOf(metricKey, newMeasureBuilder().create(26))); + } + + @Test + public void verify_FUNCTIONS_and_STATEMENT_measure_aggregation() { + verifyTwoMeasureAggregation(FUNCTIONS_KEY, STATEMENTS_KEY); + } + + @Test + public void verify_CLASSES_measure_aggregation() { + verifyMetricAggregation(CLASSES_KEY); + } + + private void verifyMeasures(int componentRef, @Nullable Integer fileCount, int directoryCount, MeasureRepoEntry... otherMeasures) { + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))) + .containsOnly( + concatIntoArray(otherMeasures, createFileAndDirectoryEntries(fileCount, directoryCount))); + } + + private static MeasureRepoEntry[] createFileAndDirectoryEntries(@Nullable Integer fileCount, int directoryCount) { + return new MeasureRepoEntry[] { + fileCount == null ? null : entryOf(FILES_KEY, newMeasureBuilder().create(fileCount)), + entryOf(DIRECTORIES_KEY, newMeasureBuilder().create(directoryCount)) + }; + } + + private static MeasureRepoEntry[] concatIntoArray(MeasureRepoEntry[] otherMeasures, MeasureRepoEntry... measureRepoEntries) { + return from(concat( + asList(otherMeasures), + from(asList(measureRepoEntries)).filter(notNull()))) + .toArray(MeasureRepoEntry.class); + } + + private void verifyNoMeasure(int componentRef) { + assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).isEmpty(); + } +}