]> source.dussan.org Git - sonarqube.git/blob
781639920f3deebedd15d5bb410fc18484e736f6
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2016 SonarSource SA
4  * mailto:contact AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.computation.task.projectanalysis.qualitymodel;
21
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Ordering;
25 import java.util.Arrays;
26 import java.util.Set;
27 import org.assertj.core.data.Offset;
28 import org.junit.Before;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.sonar.api.utils.KeyValueFormat;
32 import org.sonar.server.computation.task.projectanalysis.component.Component;
33 import org.sonar.server.computation.task.projectanalysis.component.FileAttributes;
34 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
35 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
36 import org.sonar.server.computation.task.projectanalysis.component.VisitorsCrawler;
37 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
38 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
39 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
40 import org.sonar.server.computation.task.projectanalysis.period.Period;
41 import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
42 import org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating;
43 import org.sonar.server.computation.task.projectanalysis.scm.Changeset;
44 import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepositoryRule;
45
46 import static com.google.common.base.Preconditions.checkArgument;
47 import static org.mockito.Mockito.mock;
48 import static org.mockito.Mockito.when;
49 import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA;
50 import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA_KEY;
51 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING;
52 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
53 import static org.sonar.api.measures.CoreMetrics.NEW_SQALE_DEBT_RATIO;
54 import static org.sonar.api.measures.CoreMetrics.NEW_SQALE_DEBT_RATIO_KEY;
55 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT;
56 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT_KEY;
57 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY;
58 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.FILE;
59 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE;
60 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT;
61 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
62 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureAssert.assertThat;
63 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.A;
64 import static org.sonar.server.computation.task.projectanalysis.qualitymodel.RatingGrid.Rating.D;
65
66 public class NewMaintainabilityMeasuresVisitorTest {
67
68   private static final double[] RATING_GRID = new double[] {0.1, 0.2, 0.5, 1};
69
70   private static final String LANGUAGE_1_KEY = "language 1 key";
71   private static final long LANGUAGE_1_DEV_COST = 30l;
72   private static final long PERIOD_SNAPSHOT_DATE = 12323l;
73   private static final String SOME_ANALYSIS_UUID = "9993l";
74   private static final String SOME_PERIOD_MODE = "some mode";
75   private static final int ROOT_REF = 1;
76   private static final int LANGUAGE_1_FILE_REF = 11111;
77   private static final Offset<Double> VARIATION_COMPARISON_OFFSET = Offset.offset(0.01);
78
79   @Rule
80   public ScmInfoRepositoryRule scmInfoRepository = new ScmInfoRepositoryRule();
81   @Rule
82   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
83   @Rule
84   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
85     .add(NEW_TECHNICAL_DEBT)
86     .add(NCLOC_DATA)
87     .add(NEW_SQALE_DEBT_RATIO)
88     .add(NEW_MAINTAINABILITY_RATING);
89   @Rule
90   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
91   @Rule
92   public PeriodsHolderRule periodsHolder = new PeriodsHolderRule();
93
94   private RatingSettings ratingSettings = mock(RatingSettings.class);
95
96   private VisitorsCrawler underTest;
97
98   @Before
99   public void setUp() throws Exception {
100     when(ratingSettings.getRatingGrid()).thenReturn(new RatingGrid(RATING_GRID));
101     underTest = new VisitorsCrawler(Arrays.asList(new NewMaintainabilityMeasuresVisitor(metricRepository, measureRepository, scmInfoRepository,
102       periodsHolder, ratingSettings)));
103   }
104
105   @Test
106   public void project_has_new_measures_for_each_defined_period() {
107     setPeriod();
108     treeRootHolder.setRoot(builder(PROJECT, ROOT_REF).build());
109
110     underTest.visit(treeRootHolder.getRoot());
111
112     assertNewDebtRatioValues(ROOT_REF, 0);
113     assertNewMaintainability(ROOT_REF, A);
114   }
115
116   @Test
117   public void project_has_no_measure_if_there_is_no_period() {
118     periodsHolder.setPeriod(null);
119     treeRootHolder.setRoot(builder(PROJECT, ROOT_REF).build());
120
121     underTest.visit(treeRootHolder.getRoot());
122
123     assertNoNewDebtRatioMeasure(ROOT_REF);
124     assertNoNewMaintainability(ROOT_REF);
125   }
126
127   @Test
128   public void file_has_no_new_debt_ratio_variation_if_there_is_no_period() {
129     periodsHolder.setPeriod(null);
130     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
131     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
132     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
133
134     underTest.visit(treeRootHolder.getRoot());
135
136     assertNoNewDebtRatioMeasure(LANGUAGE_1_FILE_REF);
137     assertNoNewDebtRatioMeasure(ROOT_REF);
138   }
139
140   @Test
141   public void file_has_0_new_debt_ratio_if_all_scm_dates_are_before_snapshot_dates() {
142     setPeriod();
143     treeRootHolder.setRoot(
144       builder(PROJECT, ROOT_REF)
145         .addChildren(
146           builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build())
147         .build());
148     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
149     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NCLOC_DATA_KEY, createNclocDataMeasure(2, 3, 4));
150     scmInfoRepository.setScmInfo(LANGUAGE_1_FILE_REF, createChangesets(PERIOD_SNAPSHOT_DATE - 100, 4));
151
152     underTest.visit(treeRootHolder.getRoot());
153
154     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
155     assertNewDebtRatioValues(ROOT_REF, 0);
156   }
157
158   @Test
159   public void file_has_new_debt_ratio_if_some_scm_dates_are_after_snapshot_dates() {
160     setPeriod();
161     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
162     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
163     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
164
165     underTest.visit(treeRootHolder.getRoot());
166
167     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 83.33);
168     assertNewDebtRatioValues(ROOT_REF, 83.33);
169   }
170
171   @Test
172   public void new_debt_ratio_changes_with_language_cost() {
173     setPeriod();
174     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST * 10);
175     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
176     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
177
178     underTest.visit(treeRootHolder.getRoot());
179
180     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 8.33);
181     assertNewDebtRatioValues(ROOT_REF, 8.33);
182   }
183
184   @Test
185   public void new_debt_ratio_changes_with_new_technical_debt() {
186     setPeriod();
187     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
188     setupOneFileAloneInAProject(500, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
189     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(500));
190
191     underTest.visit(treeRootHolder.getRoot());
192
193     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 833.33);
194     assertNewDebtRatioValues(ROOT_REF, 833.33);
195   }
196
197   @Test
198   public void new_debt_ratio_on_non_file_level_is_based_on_new_technical_debt_of_that_level() {
199     setPeriod();
200     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
201     setupOneFileAloneInAProject(500, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
202     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(1200));
203
204     underTest.visit(treeRootHolder.getRoot());
205
206     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 833.33);
207     assertNewDebtRatioValues(ROOT_REF, 833.33);
208   }
209
210   @Test
211   public void new_debt_ratio_when_file_is_unit_test() {
212     setPeriod();
213     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
214     setupOneFileAloneInAProject(500, Flag.UT_FILE, Flag.WITH_NCLOC, Flag.WITH_CHANGESET);
215     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(1200));
216
217     underTest.visit(treeRootHolder.getRoot());
218
219     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 833.33);
220     assertNewDebtRatioValues(ROOT_REF, 833.33);
221   }
222
223   @Test
224   public void new_debt_ratio_is_0_when_file_has_no_changesets() {
225     setPeriod();
226     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
227     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.NO_CHANGESET);
228     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
229
230     underTest.visit(treeRootHolder.getRoot());
231
232     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
233     assertNewDebtRatioValues(ROOT_REF, 0);
234   }
235
236   @Test
237   public void new_debt_ratio_is_0_on_non_file_level_when_no_file_has_changesets() {
238     setPeriod();
239     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
240     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.WITH_NCLOC, Flag.NO_CHANGESET);
241     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200));
242
243     underTest.visit(treeRootHolder.getRoot());
244
245     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
246     assertNewDebtRatioValues(ROOT_REF, 0);
247   }
248
249   @Test
250   public void new_debt_ratio_is_0_when_there_is_no_ncloc_in_file() {
251     setPeriod();
252     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
253     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.NO_NCLOC, Flag.WITH_CHANGESET);
254     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
255
256     underTest.visit(treeRootHolder.getRoot());
257
258     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
259     assertNewDebtRatioValues(ROOT_REF, 0);
260   }
261
262   @Test
263   public void new_debt_ratio_is_0_on_non_file_level_when_one_file_has_zero_new_debt_because_of_no_changeset() {
264     setPeriod();
265     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
266     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.NO_NCLOC, Flag.WITH_CHANGESET);
267     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200));
268
269     underTest.visit(treeRootHolder.getRoot());
270
271     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
272     assertNewDebtRatioValues(ROOT_REF, 0);
273   }
274
275   @Test
276   public void new_debt_ratio_is_0_when_ncloc_measure_is_missing() {
277     setPeriod();
278     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
279     setupOneFileAloneInAProject(50, Flag.SRC_FILE, Flag.MISSING_MEASURE_NCLOC, Flag.WITH_CHANGESET);
280     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(50));
281
282     underTest.visit(treeRootHolder.getRoot());
283
284     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 0);
285     assertNewDebtRatioValues(ROOT_REF, 0);
286   }
287
288   @Test
289   public void leaf_components_always_have_a_measure_when_at_least_one_period_exist_and_ratio_is_computed_from_current_level_new_debt() {
290     setPeriod();
291     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
292     treeRootHolder.setRoot(
293       builder(PROJECT, ROOT_REF)
294         .addChildren(
295           builder(MODULE, 11)
296             .addChildren(
297               builder(DIRECTORY, 111)
298                 .addChildren(
299                   builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build())
300                 .build())
301             .build())
302         .build());
303
304     Measure newDebtMeasure = createNewDebtMeasure(50);
305     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NEW_TECHNICAL_DEBT_KEY, newDebtMeasure);
306     measureRepository.addRawMeasure(111, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(150));
307     measureRepository.addRawMeasure(11, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200));
308     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(250));
309     // 4 lines file, only first one is not ncloc
310     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NCLOC_DATA_KEY, createNclocDataMeasure(2, 3, 4));
311     // first 2 lines are before all snapshots, 2 last lines are after PERIOD 2's snapshot date
312     scmInfoRepository.setScmInfo(LANGUAGE_1_FILE_REF, createChangesets(PERIOD_SNAPSHOT_DATE - 100, 2, PERIOD_SNAPSHOT_DATE + 100, 2));
313
314     underTest.visit(treeRootHolder.getRoot());
315
316     assertNewDebtRatioValues(LANGUAGE_1_FILE_REF, 83.33);
317     assertNewDebtRatioValues(111, 83.33);
318     assertNewDebtRatioValues(11, 83.33);
319     assertNewDebtRatioValues(ROOT_REF, 83.33);
320   }
321
322   @Test
323   public void compute_new_maintainability_rating() throws Exception {
324     setPeriod();
325     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
326     treeRootHolder.setRoot(
327       builder(PROJECT, ROOT_REF)
328         .addChildren(
329           builder(MODULE, 11)
330             .addChildren(
331               builder(DIRECTORY, 111)
332                 .addChildren(
333                   builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build())
334                 .build())
335             .build())
336         .build());
337
338     Measure newDebtMeasure = createNewDebtMeasure(50);
339     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NEW_TECHNICAL_DEBT_KEY, newDebtMeasure);
340     measureRepository.addRawMeasure(111, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(150));
341     measureRepository.addRawMeasure(11, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(200));
342     measureRepository.addRawMeasure(ROOT_REF, NEW_TECHNICAL_DEBT_KEY, createNewDebtMeasure(250));
343     // 4 lines file, only first one is not ncloc
344     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NCLOC_DATA_KEY, createNclocDataMeasure(2, 3, 4));
345     // first 2 lines are before all snapshots, 2 last lines are after PERIOD 2's snapshot date
346     scmInfoRepository.setScmInfo(LANGUAGE_1_FILE_REF, createChangesets(PERIOD_SNAPSHOT_DATE - 100, 2, PERIOD_SNAPSHOT_DATE + 100, 2));
347
348     underTest.visit(treeRootHolder.getRoot());
349
350     assertNewMaintainability(LANGUAGE_1_FILE_REF, D);
351     assertNewMaintainability(111, D);
352     assertNewMaintainability(11, D);
353     assertNewMaintainability(ROOT_REF, D);
354   }
355
356   @Test
357   public void compute_new_maintainability_rating_to_A_when_no_debt() throws Exception {
358     setPeriod();
359     when(ratingSettings.getDevCost(LANGUAGE_1_KEY)).thenReturn(LANGUAGE_1_DEV_COST);
360     treeRootHolder.setRoot(
361       builder(PROJECT, ROOT_REF)
362         .addChildren(
363           builder(MODULE, 11)
364             .addChildren(
365               builder(DIRECTORY, 111)
366                 .addChildren(
367                   builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_1_KEY, 1)).build())
368                 .build())
369             .build())
370         .build());
371
372     underTest.visit(treeRootHolder.getRoot());
373
374     assertNewMaintainability(LANGUAGE_1_FILE_REF, A);
375     assertNewMaintainability(111, A);
376     assertNewMaintainability(11, A);
377     assertNewMaintainability(ROOT_REF, A);
378   }
379
380   private void setupOneFileAloneInAProject(int newDebt, Flag isUnitTest, Flag withNclocLines, Flag withChangeSets) {
381     checkArgument(isUnitTest == Flag.UT_FILE || isUnitTest == Flag.SRC_FILE);
382     checkArgument(withNclocLines == Flag.WITH_NCLOC || withNclocLines == Flag.NO_NCLOC || withNclocLines == Flag.MISSING_MEASURE_NCLOC);
383     checkArgument(withChangeSets == Flag.WITH_CHANGESET || withChangeSets == Flag.NO_CHANGESET);
384
385     treeRootHolder.setRoot(
386       builder(PROJECT, ROOT_REF)
387         .addChildren(
388           builder(FILE, LANGUAGE_1_FILE_REF).setFileAttributes(new FileAttributes(isUnitTest == Flag.UT_FILE, LANGUAGE_1_KEY, 1)).build())
389         .build());
390
391     Measure newDebtMeasure = createNewDebtMeasure(newDebt);
392     measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NEW_TECHNICAL_DEBT_KEY, newDebtMeasure);
393     if (withNclocLines == Flag.WITH_NCLOC) {
394       // 4 lines file, only first one is not ncloc
395       measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NCLOC_DATA_KEY, createNclocDataMeasure(2, 3, 4));
396     } else if (withNclocLines == Flag.NO_NCLOC) {
397       // 4 lines file, none of which is ncloc
398       measureRepository.addRawMeasure(LANGUAGE_1_FILE_REF, NCLOC_DATA_KEY, createNoNclocDataMeasure(4));
399     }
400     if (withChangeSets == Flag.WITH_CHANGESET) {
401       // first 2 lines are before all snapshots, 2 last lines are after PERIOD 2's snapshot date
402       scmInfoRepository.setScmInfo(LANGUAGE_1_FILE_REF, createChangesets(PERIOD_SNAPSHOT_DATE - 100, 2, PERIOD_SNAPSHOT_DATE + 100, 2));
403     }
404   }
405
406   private enum Flag {
407     UT_FILE, SRC_FILE, NO_CHANGESET, WITH_CHANGESET, WITH_NCLOC, NO_NCLOC, MISSING_MEASURE_NCLOC
408   }
409
410   public static ReportComponent.Builder builder(Component.Type type, int ref) {
411     return ReportComponent.builder(type, ref).setKey(String.valueOf(ref));
412   }
413
414   private Measure createNewDebtMeasure(double variation) {
415     return newMeasureBuilder().setVariation(variation).createNoValue();
416   }
417
418   private static Measure createNclocDataMeasure(Integer... nclocLines) {
419     Set<Integer> nclocLinesSet = ImmutableSet.copyOf(nclocLines);
420     int max = Ordering.<Integer>natural().max(nclocLinesSet);
421     ImmutableMap.Builder<Integer, Integer> builder = ImmutableMap.builder();
422     for (int i = 1; i <= max; i++) {
423       builder.put(i, nclocLinesSet.contains(i) ? 1 : 0);
424     }
425     return newMeasureBuilder().create(KeyValueFormat.format(builder.build(), KeyValueFormat.newIntegerConverter(), KeyValueFormat.newIntegerConverter()));
426   }
427
428   private static Measure createNoNclocDataMeasure(int lineCount) {
429     ImmutableMap.Builder<Integer, Integer> builder = ImmutableMap.builder();
430     for (int i = 1; i <= lineCount; i++) {
431       builder.put(i, 0);
432     }
433     return newMeasureBuilder().create(KeyValueFormat.format(builder.build(), KeyValueFormat.newIntegerConverter(), KeyValueFormat.newIntegerConverter()));
434   }
435
436   /**
437    * Creates changesets of {@code lines} lines which all have the same date {@code scmDate}.
438    */
439   private static Changeset[] createChangesets(long scmDate, int lines) {
440     Changeset changetset = Changeset.newChangesetBuilder().setDate(scmDate).setRevision("rev-1").build();
441     Changeset[] changesets = new Changeset[lines];
442     for (int i = 0; i < lines; i++) {
443       changesets[i] = changetset;
444     }
445     return changesets;
446   }
447
448   /**
449    * Creates a changeset of {@code lineCount} lines which have the date {@code scmDate} and {@code otherLineCount} lines which
450    * have the date {@code otherScmDate}.
451    */
452   private static Changeset[] createChangesets(long scmDate, int lineCount, long otherScmDate, int otherLineCount) {
453     Changeset[] changesets = new Changeset[lineCount + otherLineCount];
454     Changeset changetset1 = Changeset.newChangesetBuilder().setDate(scmDate).setRevision("rev-1").build();
455     for (int i = 0; i < lineCount; i++) {
456       changesets[i] = changetset1;
457     }
458     Changeset changetset2 = Changeset.newChangesetBuilder().setDate(otherScmDate).setRevision("rev-2").build();
459     for (int i = lineCount; i < lineCount + otherLineCount; i++) {
460       changesets[i] = changetset2;
461     }
462     return changesets;
463   }
464
465   private void assertNoNewDebtRatioMeasure(int componentRef) {
466     assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SQALE_DEBT_RATIO_KEY))
467       .isAbsent();
468   }
469
470   private void assertNewDebtRatioValues(int componentRef, double expectedVariation) {
471     assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SQALE_DEBT_RATIO_KEY)).hasVariation(expectedVariation, VARIATION_COMPARISON_OFFSET);
472   }
473
474   private void assertNewMaintainability(int componentRef, Rating expectedVariation) {
475     assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_MAINTAINABILITY_RATING_KEY)).hasVariation(expectedVariation.getIndex());
476   }
477
478   private void assertNoNewMaintainability(int componentRef) {
479     assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_MAINTAINABILITY_RATING_KEY))
480       .isAbsent();
481   }
482
483   private void setPeriod() {
484     periodsHolder.setPeriod(new Period(SOME_PERIOD_MODE, null, PERIOD_SNAPSHOT_DATE, SOME_ANALYSIS_UUID));
485   }
486 }