3 * Copyright (C) 2009-2016 SonarSource SA
4 * mailto:contact AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.computation.task.projectanalysis.formula;
22 import com.google.common.base.Optional;
23 import com.google.common.collect.ImmutableList;
24 import org.assertj.core.api.AbstractIterableAssert;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.measures.CoreMetrics;
28 import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler;
29 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
30 import org.sonar.server.computation.task.projectanalysis.component.ViewsComponent;
31 import org.sonar.server.computation.task.projectanalysis.formula.counter.IntVariationValue;
32 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
33 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry;
34 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
35 import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
36 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
37 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
38 import org.sonar.server.computation.task.projectanalysis.period.Period;
39 import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
41 import static org.assertj.core.api.Assertions.assertThat;
42 import static org.assertj.guava.api.Assertions.assertThat;
43 import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
44 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
45 import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
46 import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY;
47 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT_VIEW;
48 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.SUBVIEW;
49 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.VIEW;
50 import static org.sonar.server.computation.task.projectanalysis.component.ViewsComponent.builder;
51 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
52 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
53 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
55 public class ViewsFormulaExecutorComponentVisitorTest {
56 private static final int ROOT_REF = 1;
57 private static final int SUBVIEW_1_REF = 11;
58 private static final int SUB_SUBVIEW_REF = 111;
59 private static final int PROJECT_VIEW_1_REF = 1111;
60 private static final int PROJECT_VIEW_2_REF = 1113;
61 private static final int SUBVIEW_2_REF = 12;
62 private static final int PROJECT_VIEW_3_REF = 121;
63 private static final int PROJECT_VIEW_4_REF = 13;
65 private static final ViewsComponent BALANCED_COMPONENT_TREE = ViewsComponent.builder(VIEW, ROOT_REF)
67 ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
69 ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF)
71 builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build(),
72 builder(PROJECT_VIEW, PROJECT_VIEW_2_REF).build())
75 ViewsComponent.builder(SUBVIEW, SUBVIEW_2_REF)
77 builder(PROJECT_VIEW, PROJECT_VIEW_3_REF).build())
79 builder(PROJECT_VIEW, PROJECT_VIEW_4_REF).build())
83 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
85 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
86 .add(CoreMetrics.LINES)
87 .add(CoreMetrics.NCLOC)
88 .add(CoreMetrics.NEW_LINES_TO_COVER)
89 .add(CoreMetrics.NEW_COVERAGE);
91 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
93 public PeriodsHolderRule periodsHolder = new PeriodsHolderRule()
94 .setPeriods(new Period(2, "some mode", null, 95l, "u1"), new Period(5, "some other mode", null, 756L, "u2"));
97 public void verify_aggregation_on_value() throws Exception {
98 treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
99 addRawMeasure(PROJECT_VIEW_1_REF, 1, LINES_KEY);
100 addRawMeasure(PROJECT_VIEW_2_REF, 2, LINES_KEY);
101 addRawMeasure(PROJECT_VIEW_3_REF, 3, LINES_KEY);
102 addRawMeasure(PROJECT_VIEW_4_REF, 4, LINES_KEY);
104 new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
105 .visit(BALANCED_COMPONENT_TREE);
107 verifyProjectViewsHasNoAddedRawMeasures();
108 verifySingleMetricValue(SUB_SUBVIEW_REF, 3);
109 verifySingleMetricValue(SUBVIEW_1_REF, 3);
110 verifySingleMetricValue(SUBVIEW_2_REF, 3);
111 verifySingleMetricValue(ROOT_REF, 10);
114 private MeasureRepositoryRule addRawMeasure(int componentRef, int value, String metricKey) {
115 return measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
119 public void verify_multi_metric_formula_support_and_aggregation() throws Exception {
120 treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
121 addRawMeasure(PROJECT_VIEW_1_REF, 1, LINES_KEY);
122 addRawMeasure(PROJECT_VIEW_2_REF, 2, LINES_KEY);
123 addRawMeasure(PROJECT_VIEW_3_REF, 5, LINES_KEY);
124 addRawMeasure(PROJECT_VIEW_4_REF, 4, LINES_KEY);
126 new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeMultiMetricFormula()))
127 .visit(BALANCED_COMPONENT_TREE);
129 verifyProjectViewsHasNoAddedRawMeasures();
130 verifyMultiMetricValues(SUB_SUBVIEW_REF, 13, 103);
131 verifyMultiMetricValues(SUBVIEW_1_REF, 13, 103);
132 verifyMultiMetricValues(SUBVIEW_2_REF, 15, 105);
133 verifyMultiMetricValues(ROOT_REF, 22, 112);
137 public void verify_aggregation_on_variations() throws Exception {
138 treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
140 addRawMeasureWithVariation(PROJECT_VIEW_1_REF, NEW_LINES_TO_COVER_KEY, 10, 20);
141 addRawMeasureWithVariation(PROJECT_VIEW_2_REF, NEW_LINES_TO_COVER_KEY, 8, 16);
142 addRawMeasureWithVariation(PROJECT_VIEW_3_REF, NEW_LINES_TO_COVER_KEY, 2, 4);
143 addRawMeasureWithVariation(PROJECT_VIEW_4_REF, NEW_LINES_TO_COVER_KEY, 3, 7);
145 new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeVariationFormula()))
146 .visit(BALANCED_COMPONENT_TREE);
148 verifyProjectViewsHasNoAddedRawMeasures();
149 verifySingleMetricWithVariations(SUB_SUBVIEW_REF, 18, 36);
150 verifySingleMetricWithVariations(SUBVIEW_1_REF, 18, 36);
151 verifySingleMetricWithVariations(SUBVIEW_2_REF, 2, 4);
152 verifySingleMetricWithVariations(ROOT_REF, 23, 47);
155 private AbstractIterableAssert<?, ? extends Iterable<? extends MeasureRepoEntry>, MeasureRepoEntry> verifySingleMetricWithVariations(int componentRef, int variation2Value,
156 int variation5Value) {
157 return assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
158 .containsOnly(entryOf(NEW_COVERAGE_KEY, createMeasureWithVariation(variation2Value, variation5Value)));
161 private MeasureRepositoryRule addRawMeasureWithVariation(int componentRef, String metricKey, int variation2Value, int variation5Value) {
162 return measureRepository.addRawMeasure(componentRef, metricKey, createMeasureWithVariation(variation2Value, variation5Value));
165 private static Measure createMeasureWithVariation(double variation2Value, double variation5Value) {
166 return newMeasureBuilder().setVariations(new MeasureVariations(null, variation2Value, null, null, variation5Value)).createNoValue();
170 public void verify_no_measure_added_on_projectView() throws Exception {
171 ViewsComponent project = ViewsComponent.builder(VIEW, ROOT_REF)
173 ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
175 ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF)
177 builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build())
181 treeRootHolder.setRoot(project);
183 new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
186 assertNoAddedRawMeasure(PROJECT_VIEW_1_REF);
187 verifySingleMetricValue(SUB_SUBVIEW_REF, 0);
188 verifySingleMetricValue(SUBVIEW_1_REF, 0);
189 verifySingleMetricValue(ROOT_REF, 0);
193 public void add_measure_even_if_leaf_is_not_a_PROJECT_VIEW() throws Exception {
194 ViewsComponent project = ViewsComponent.builder(VIEW, ROOT_REF)
196 ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
198 ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF).build())
201 treeRootHolder.setRoot(project);
203 new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
206 verifySingleMetricValue(SUB_SUBVIEW_REF, 0);
207 verifySingleMetricValue(SUBVIEW_1_REF, 0);
208 verifySingleMetricValue(ROOT_REF, 0);
211 private class FakeFormula implements Formula<FakeCounter> {
214 public FakeCounter createNewCounter() {
215 return new FakeCounter();
219 public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
220 // verify the context which is passed to the method
221 assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
222 assertThat(context.getComponent()).isNotNull();
223 assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NCLOC_KEY));
225 return Optional.of(Measure.newMeasureBuilder().create(counter.value));
229 public String[] getOutputMetricKeys() {
230 return new String[] {NCLOC_KEY};
234 private class FakeMultiMetricFormula implements Formula<FakeCounter> {
237 public FakeCounter createNewCounter() {
238 return new FakeCounter();
242 public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
243 // verify the context which is passed to the method
244 assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
245 assertThat(context.getComponent()).isNotNull();
246 assertThat(context.getMetric())
247 .isIn(metricRepository.getByKey(NEW_LINES_TO_COVER_KEY), metricRepository.getByKey(NEW_COVERAGE_KEY));
249 return Optional.of(Measure.newMeasureBuilder().create(counter.value + metricOffset(context.getMetric())));
252 private int metricOffset(Metric metric) {
253 if (metric.getKey().equals(NEW_LINES_TO_COVER_KEY)) {
256 if (metric.getKey().equals(NEW_COVERAGE_KEY)) {
259 throw new IllegalArgumentException("Unsupported metric " + metric);
263 public String[] getOutputMetricKeys() {
264 return new String[] {NEW_LINES_TO_COVER_KEY, NEW_COVERAGE_KEY};
268 private class FakeCounter implements Counter<FakeCounter> {
269 private int value = 0;
272 public void aggregate(FakeCounter counter) {
273 this.value += counter.value;
277 public void initialize(CounterInitializationContext context) {
278 verifyLeafContext(context);
280 Optional<Measure> measureOptional = context.getMeasure(LINES_KEY);
281 if (measureOptional.isPresent()) {
282 value += measureOptional.get().getIntValue();
287 private class FakeVariationFormula implements Formula<FakeVariationCounter> {
290 public FakeVariationCounter createNewCounter() {
291 return new FakeVariationCounter();
295 public Optional<Measure> createMeasure(FakeVariationCounter counter, CreateMeasureContext context) {
296 // verify the context which is passed to the method
297 assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
298 assertThat(context.getComponent()).isNotNull();
299 assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NEW_COVERAGE_KEY));
301 Optional<MeasureVariations> measureVariations = counter.values.toMeasureVariations();
302 if (measureVariations.isPresent()) {
305 .setVariations(measureVariations.get())
308 return Optional.absent();
312 public String[] getOutputMetricKeys() {
313 return new String[] {NEW_COVERAGE_KEY};
317 private class FakeVariationCounter implements Counter<FakeVariationCounter> {
318 private final IntVariationValue.Array values = IntVariationValue.newArray();
321 public void aggregate(FakeVariationCounter counter) {
322 values.incrementAll(counter.values);
326 public void initialize(CounterInitializationContext context) {
327 verifyLeafContext(context);
329 Optional<Measure> measureOptional = context.getMeasure(NEW_LINES_TO_COVER_KEY);
330 if (!measureOptional.isPresent()) {
333 for (Period period : context.getPeriods()) {
334 this.values.increment(
336 (int) measureOptional.get().getVariations().getVariation(period.getIndex()));
341 private FormulaExecutorComponentVisitor formulaExecutorComponentVisitor(Formula formula) {
342 return FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository)
343 .withVariationSupport(periodsHolder)
344 .buildFor(ImmutableList.of(formula));
347 private void verifyProjectViewsHasNoAddedRawMeasures() {
348 assertNoAddedRawMeasure(PROJECT_VIEW_1_REF);
349 assertNoAddedRawMeasure(PROJECT_VIEW_2_REF);
350 assertNoAddedRawMeasure(PROJECT_VIEW_3_REF);
351 assertNoAddedRawMeasure(PROJECT_VIEW_4_REF);
354 private void assertNoAddedRawMeasure(int componentRef) {
355 assertThat(measureRepository.getAddedRawMeasures(componentRef)).isEmpty();
358 private void verifySingleMetricValue(int componentRef, int measureValue) {
359 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
360 .containsOnly(entryOf(NCLOC_KEY, newMeasureBuilder().create(measureValue)));
363 private void verifyMultiMetricValues(int componentRef, int valueLinesToCover, int valueItCoverage) {
364 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
366 entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(valueLinesToCover)),
367 entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(valueItCoverage)));
370 private void verifyLeafContext(CounterInitializationContext context) {
371 assertThat(context.getLeaf().getChildren()).isEmpty();
372 assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());