3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info 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.ce.task.projectanalysis.step;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Optional;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.sonar.api.measures.CoreMetrics;
30 import org.sonar.ce.task.projectanalysis.component.Component;
31 import org.sonar.ce.task.projectanalysis.component.FileAttributes;
32 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
33 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
34 import org.sonar.ce.task.projectanalysis.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys;
35 import org.sonar.ce.task.projectanalysis.measure.Measure;
36 import org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry;
37 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
38 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
39 import org.sonar.ce.task.projectanalysis.source.NewLinesRepository;
40 import org.sonar.ce.task.step.TestComputationStepContext;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.assertj.guava.api.Assertions.assertThat;
44 import static org.mockito.Mockito.mock;
45 import static org.mockito.Mockito.when;
46 import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE_KEY;
47 import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY;
48 import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY;
49 import static org.sonar.api.measures.CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY;
50 import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY;
51 import static org.sonar.api.measures.CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY;
52 import static org.sonar.api.measures.CoreMetrics.NEW_UNCOVERED_LINES_KEY;
53 import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
54 import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
55 import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT;
56 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
57 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
58 import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
59 import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
61 public class ReportNewCoverageMeasuresStepTest {
63 private static final int ROOT_REF = 1;
64 private static final int DIRECTORY_1_REF = 1111;
65 private static final int FILE_1_REF = 11111;
66 private static final int DIRECTORY_2_REF = 1112;
67 private static final int FILE_2_REF = 11121;
68 private static final int FILE_3_REF = 11122;
69 private static final Component FILE_1 = builder(FILE, FILE_1_REF).build();
70 private static final Component FILE_2 = builder(FILE, FILE_2_REF).build();
71 private static final Component FILE_3 = builder(FILE, FILE_3_REF).build();
73 private static final ReportComponent MULTIPLE_FILES_TREE = builder(PROJECT, ROOT_REF)
75 builder(DIRECTORY, DIRECTORY_1_REF)
78 builder(DIRECTORY, DIRECTORY_2_REF)
79 .addChildren(FILE_2, FILE_3)
84 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
86 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
87 .add(CoreMetrics.COVERAGE_LINE_HITS_DATA)
88 .add(CoreMetrics.CONDITIONS_BY_LINE)
89 .add(CoreMetrics.COVERED_CONDITIONS_BY_LINE)
90 .add(CoreMetrics.NEW_LINES_TO_COVER)
91 .add(CoreMetrics.NEW_UNCOVERED_LINES)
92 .add(CoreMetrics.NEW_CONDITIONS_TO_COVER)
93 .add(CoreMetrics.NEW_UNCOVERED_CONDITIONS)
94 .add(CoreMetrics.NEW_COVERAGE)
95 .add(CoreMetrics.NEW_BRANCH_COVERAGE)
96 .add(CoreMetrics.NEW_LINE_COVERAGE);
99 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
100 private NewLinesRepository newLinesRepository = mock(NewLinesRepository.class);
101 private NewCoverageMeasuresStep underTest = new NewCoverageMeasuresStep(treeRootHolder, measureRepository, metricRepository, newLinesRepository);
102 public static final ReportComponent FILE_COMPONENT = ReportComponent.builder(Component.Type.FILE, FILE_1_REF)
103 .setFileAttributes(new FileAttributes(false, null, 1)).build();
106 public void no_measure_for_PROJECT_component() {
107 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, ROOT_REF).build());
109 underTest.execute(new TestComputationStepContext());
111 assertThat(measureRepository.isEmpty()).isTrue();
115 public void no_measure_for_DIRECTORY_component() {
116 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.DIRECTORY, DIRECTORY_1_REF).build());
118 underTest.execute(new TestComputationStepContext());
120 assertThat(measureRepository.isEmpty()).isTrue();
124 public void no_measure_for_unit_test_FILE_component() {
125 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.FILE, FILE_1_REF).setFileAttributes(new FileAttributes(true, null, 1)).build());
127 underTest.execute(new TestComputationStepContext());
129 assertThat(measureRepository.isEmpty()).isTrue();
133 public void no_measures_for_FILE_component_without_code() {
134 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, null, 1)).build());
136 underTest.execute(new TestComputationStepContext());
138 assertThat(measureRepository.isEmpty()).isTrue();
142 public void zero_measures_when_nothing_has_changed() {
143 treeRootHolder.setRoot(FILE_COMPONENT);
144 when(newLinesRepository.newLinesAvailable()).thenReturn(true);
145 when(newLinesRepository.getNewLines(FILE_COMPONENT)).thenReturn(Optional.of(Collections.emptySet()));
146 measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), COVERAGE_LINE_HITS_DATA_KEY, newMeasureBuilder().create("2=1;3=1"));
147 measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), CONDITIONS_BY_LINE_KEY, newMeasureBuilder().create("2=1"));
148 measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), COVERED_CONDITIONS_BY_LINE_KEY, newMeasureBuilder().create("2=1"));
150 underTest.execute(new TestComputationStepContext());
152 verify_only_zero_measures_on_new_lines_and_conditions_measures(FILE_COMPONENT);
156 public void zero_measures_for_FILE_component_without_CoverageData() {
157 treeRootHolder.setRoot(FILE_1);
160 underTest.execute(new TestComputationStepContext());
162 verify_only_zero_measures_on_new_lines_and_conditions_measures(FILE_1);
166 public void verify_computation_of_measures_for_new_lines_for_FILE() {
167 when(newLinesRepository.newLinesAvailable()).thenReturn(true);
169 String coverageLineHitsData = COVERAGE_LINE_HITS_DATA_KEY;
170 String newLinesToCover = NEW_LINES_TO_COVER_KEY;
171 String newUncoveredLines = NEW_UNCOVERED_LINES_KEY;
172 String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY;
173 String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY;
175 verify_computation_of_measures_for_new_lines(coverageLineHitsData,
176 newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions);
179 private void verify_computation_of_measures_for_new_lines(String coverageLineHitsData,
180 String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) {
181 treeRootHolder.setRoot(FILE_COMPONENT);
182 setNewLines(FILE_1, 1, 2, 4);
184 measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), coverageLineHitsData, newMeasureBuilder().create("2=0;3=2;4=3"));
186 underTest.execute(new TestComputationStepContext());
188 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_COMPONENT.getReportAttributes().getRef()))).contains(
189 entryOf(newLinesToCover, createMeasure(2d)),
190 entryOf(newUncoveredLines, createMeasure(1d)),
191 entryOf(newConditionsToCover, createMeasure(0d)),
192 entryOf(newUncoveredConditions, createMeasure(0d)));
196 public void verify_computation_of_measures_for_new_conditions_for_FILE() {
197 when(newLinesRepository.newLinesAvailable()).thenReturn(true);
199 String coverageLineHitsData = COVERAGE_LINE_HITS_DATA_KEY;
200 String conditionsByLine = CONDITIONS_BY_LINE_KEY;
201 String coveredConditionsByLine = COVERED_CONDITIONS_BY_LINE_KEY;
202 String newLinesToCover = NEW_LINES_TO_COVER_KEY;
203 String newUncoveredLines = NEW_UNCOVERED_LINES_KEY;
204 String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY;
205 String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY;
207 verify_computation_of_measures_for_new_conditions(new MetricKeys(coverageLineHitsData, conditionsByLine, coveredConditionsByLine,
208 newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions));
212 public void verify_aggregation_of_measures_for_new_conditions() {
213 when(newLinesRepository.newLinesAvailable()).thenReturn(true);
215 String coverageLineHitsData = CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY;
216 String conditionsByLine = CoreMetrics.CONDITIONS_BY_LINE_KEY;
217 String coveredConditionsByLine = CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY;
218 String newLinesToCover = NEW_LINES_TO_COVER_KEY;
219 String newUncoveredLines = NEW_UNCOVERED_LINES_KEY;
220 String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY;
221 String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY;
223 MetricKeys metricKeys = new MetricKeys(coverageLineHitsData, conditionsByLine, coveredConditionsByLine,
224 newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions);
226 treeRootHolder.setRoot(MULTIPLE_FILES_TREE);
227 defineNewLinesAndMeasures(FILE_1, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(0, 3, 2));
228 defineNewLinesAndMeasures(FILE_2, metricKeys, new MeasureValues(0, 14, 6), new MeasureValues(0, 13, 7));
229 defineNewLinesAndMeasures(FILE_3, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(1, 13, 7));
231 underTest.execute(new TestComputationStepContext());
234 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains(
235 entryOf(metricKeys.newLinesToCover, createMeasure(5d)),
236 entryOf(metricKeys.newUncoveredLines, createMeasure(3d)),
237 entryOf(metricKeys.newConditionsToCover, createMeasure(7d)),
238 entryOf(metricKeys.newUncoveredConditions, createMeasure(4d)));
239 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains(
240 entryOf(metricKeys.newLinesToCover, createMeasure(5d)),
241 entryOf(metricKeys.newUncoveredLines, createMeasure(4d)),
242 entryOf(metricKeys.newConditionsToCover, createMeasure(27d)),
243 entryOf(metricKeys.newUncoveredConditions, createMeasure(14d)));
244 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_3_REF))).contains(
245 entryOf(metricKeys.newLinesToCover, createMeasure(5d)),
246 entryOf(metricKeys.newUncoveredLines, createMeasure(2d)),
247 entryOf(metricKeys.newConditionsToCover, createMeasure(17d)),
248 entryOf(metricKeys.newUncoveredConditions, createMeasure(9d)));
250 assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_1_REF))).contains(
251 entryOf(metricKeys.newLinesToCover, createMeasure(5d)),
252 entryOf(metricKeys.newUncoveredLines, createMeasure(3d)),
253 entryOf(metricKeys.newConditionsToCover, createMeasure(7d)),
254 entryOf(metricKeys.newUncoveredConditions, createMeasure(4d)));
255 assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_2_REF))).contains(
256 entryOf(metricKeys.newLinesToCover, createMeasure(10d)),
257 entryOf(metricKeys.newUncoveredLines, createMeasure(6d)),
258 entryOf(metricKeys.newConditionsToCover, createMeasure(44d)),
259 entryOf(metricKeys.newUncoveredConditions, createMeasure(23d)));
261 MeasureRepoEntry[] repoEntriesFromProject = {entryOf(metricKeys.newLinesToCover, createMeasure(15d)),
262 entryOf(metricKeys.newUncoveredLines, createMeasure(9d)),
263 entryOf(metricKeys.newConditionsToCover, createMeasure(51d)),
264 entryOf(metricKeys.newUncoveredConditions, createMeasure(27d))};
266 assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(repoEntriesFromProject);
270 public void verify_aggregates_variations_for_new_code_line_and_branch_Coverage() {
271 LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys(
272 CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY,
273 CoreMetrics.NEW_UNCOVERED_LINES_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY);
274 String codeCoverageKey = CoreMetrics.NEW_COVERAGE_KEY;
275 String lineCoverageKey = CoreMetrics.NEW_LINE_COVERAGE_KEY;
276 String branchCoverageKey = CoreMetrics.NEW_BRANCH_COVERAGE_KEY;
278 verify_aggregates_variations(metricKeys, codeCoverageKey, lineCoverageKey, branchCoverageKey);
281 private void verify_aggregates_variations(LinesAndConditionsWithUncoveredMetricKeys metricKeys, String codeCoverageKey, String lineCoverageKey, String branchCoverageKey) {
282 treeRootHolder.setRoot(MULTIPLE_FILES_TREE);
284 .addRawMeasure(FILE_1_REF, metricKeys.getLines(), createMeasure(3000d))
285 .addRawMeasure(FILE_1_REF, metricKeys.getConditions(), createMeasure(300d))
286 .addRawMeasure(FILE_1_REF, metricKeys.getUncoveredLines(), createMeasure(30d))
287 .addRawMeasure(FILE_1_REF, metricKeys.getUncoveredConditions(), createMeasure(9d))
289 .addRawMeasure(FILE_2_REF, metricKeys.getLines(), createMeasure(2000d))
290 .addRawMeasure(FILE_2_REF, metricKeys.getConditions(), createMeasure(400d))
291 .addRawMeasure(FILE_2_REF, metricKeys.getUncoveredLines(), createMeasure(200d))
292 .addRawMeasure(FILE_2_REF, metricKeys.getUncoveredConditions(), createMeasure(16d));
294 underTest.execute(new TestComputationStepContext());
296 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).containsOnly(
297 entryOf(codeCoverageKey, createMeasure(98.8d)),
298 entryOf(lineCoverageKey, createMeasure(99d)),
299 entryOf(branchCoverageKey, createMeasure(97d)));
300 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).containsOnly(
301 entryOf(codeCoverageKey, createMeasure(91d)),
302 entryOf(lineCoverageKey, createMeasure(90d)),
303 entryOf(branchCoverageKey, createMeasure(96d)));
304 assertThat(measureRepository.getAddedRawMeasures(FILE_3_REF)).isEmpty();
306 assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_1_REF))).containsOnly(
307 entryOf(codeCoverageKey, createMeasure(98.8d)),
308 entryOf(lineCoverageKey, createMeasure(99d)),
309 entryOf(branchCoverageKey, createMeasure(97d)));
311 assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_2_REF))).containsOnly(
312 entryOf(codeCoverageKey, createMeasure(91d)),
313 entryOf(lineCoverageKey, createMeasure(90d)),
314 entryOf(branchCoverageKey, createMeasure(96d)));
316 MeasureRepoEntry[] modulesAndProjectEntries = {
317 entryOf(codeCoverageKey, createMeasure(95.5d)),
318 entryOf(lineCoverageKey, createMeasure(95.4d)),
319 entryOf(branchCoverageKey, createMeasure(96.4d))
322 assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).containsOnly(modulesAndProjectEntries);
325 private void verify_only_zero_measures_on_new_lines_and_conditions_measures(Component component) {
326 assertThat(toEntries(measureRepository.getAddedRawMeasures(component.getReportAttributes().getRef()))).containsOnly(
327 entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(0d)),
328 entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(0d)),
329 entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(0d)),
330 entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(0d)));
333 private void defineNewLinesAndMeasures(Component c, MetricKeys metricKeys, MeasureValues line4, MeasureValues line6) {
334 setNewLines(c, 1, 2, 4, 5, 6, 7);
335 measureRepository.addRawMeasure(c.getReportAttributes().getRef(), metricKeys.coverageLineHitsData,
336 newMeasureBuilder().create("2=0;3=2;4=" + line4.lineHits + ";5=1;6=" + line6.lineHits + ";7=0"));
338 .addRawMeasure(c.getReportAttributes().getRef(), metricKeys.conditionsByLine, newMeasureBuilder().create("4=" + line4.coveredConditions + ";6=" + line6.coveredConditions));
339 measureRepository.addRawMeasure(c.getReportAttributes().getRef(), metricKeys.coveredConditionsByLine,
340 newMeasureBuilder().create("4=" + line4.uncoveredConditions + ";6=" + line6.uncoveredConditions));
343 private static final class MetricKeys {
344 private final String coverageLineHitsData;
345 private final String conditionsByLine;
346 private final String coveredConditionsByLine;
347 private final String newLinesToCover;
348 private final String newUncoveredLines;
349 private final String newConditionsToCover;
350 private final String newUncoveredConditions;
352 public MetricKeys(String coverageLineHitsData, String conditionsByLine, String coveredConditionsByLine,
353 String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) {
354 this.coverageLineHitsData = coverageLineHitsData;
355 this.conditionsByLine = conditionsByLine;
356 this.coveredConditionsByLine = coveredConditionsByLine;
357 this.newLinesToCover = newLinesToCover;
358 this.newUncoveredLines = newUncoveredLines;
359 this.newConditionsToCover = newConditionsToCover;
360 this.newUncoveredConditions = newUncoveredConditions;
364 private static final class MeasureValues {
365 private final int lineHits;
366 private final int coveredConditions;
367 private final int uncoveredConditions;
369 public MeasureValues(int lineHits, int coveredConditions, int uncoveredConditions) {
370 this.lineHits = lineHits;
371 this.coveredConditions = coveredConditions;
372 this.uncoveredConditions = uncoveredConditions;
376 private void verify_computation_of_measures_for_new_conditions(MetricKeys metricKeys) {
377 treeRootHolder.setRoot(FILE_COMPONENT);
378 defineNewLinesAndMeasures(FILE_COMPONENT, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(0, 3, 2));
380 underTest.execute(new TestComputationStepContext());
382 assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_COMPONENT.getReportAttributes().getRef()))).contains(
383 entryOf(metricKeys.newLinesToCover, createMeasure(5d)),
384 entryOf(metricKeys.newUncoveredLines, createMeasure(3d)),
385 entryOf(metricKeys.newConditionsToCover, createMeasure(7d)),
386 entryOf(metricKeys.newUncoveredConditions, createMeasure(4d)));
389 private static Measure createMeasure(Double expectedVariation) {
390 return newMeasureBuilder()
391 .setVariation(expectedVariation)
395 private void setNewLines(Component c, Integer... lines) {
396 when(newLinesRepository.newLinesAvailable()).thenReturn(true);
397 Set<Integer> newLines = new HashSet<>(Arrays.asList(lines));
398 when(newLinesRepository.getNewLines(c)).thenReturn(Optional.of(newLines));