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.qualitymodel;
22 import java.util.Arrays;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.api.rules.RuleType;
27 import org.sonar.api.utils.Duration;
28 import org.sonar.core.issue.DefaultIssue;
29 import org.sonar.core.util.Uuids;
30 import org.sonar.server.computation.batch.TreeRootHolderRule;
31 import org.sonar.server.computation.component.Component;
32 import org.sonar.server.computation.component.FileAttributes;
33 import org.sonar.server.computation.component.ReportComponent;
34 import org.sonar.server.computation.component.VisitorsCrawler;
35 import org.sonar.server.computation.issue.ComponentIssuesRepositoryRule;
36 import org.sonar.server.computation.issue.FillComponentIssuesVisitorRule;
37 import org.sonar.server.computation.measure.Measure;
38 import org.sonar.server.computation.measure.MeasureRepositoryRule;
39 import org.sonar.server.computation.metric.MetricRepositoryRule;
40 import org.sonar.server.computation.qualitymodel.RatingGrid.Rating;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.when;
45 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
46 import static org.sonar.api.measures.CoreMetrics.DEVELOPMENT_COST;
47 import static org.sonar.api.measures.CoreMetrics.DEVELOPMENT_COST_KEY;
48 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A;
49 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY;
50 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_RELIABILITY_RATING_A;
51 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY;
52 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_SECURITY_RATING_A;
53 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_SECURITY_RATING_A_KEY;
54 import static org.sonar.api.measures.CoreMetrics.NCLOC;
55 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
56 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING;
57 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
58 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING;
59 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
60 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO;
61 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO_KEY;
62 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING;
63 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
64 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT;
65 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT_KEY;
66 import static org.sonar.api.rule.Severity.BLOCKER;
67 import static org.sonar.api.rule.Severity.CRITICAL;
68 import static org.sonar.api.rule.Severity.INFO;
69 import static org.sonar.api.rule.Severity.MAJOR;
70 import static org.sonar.api.rule.Severity.MINOR;
71 import static org.sonar.api.rules.RuleType.BUG;
72 import static org.sonar.api.rules.RuleType.CODE_SMELL;
73 import static org.sonar.api.rules.RuleType.VULNERABILITY;
74 import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
75 import static org.sonar.server.computation.component.Component.Type.FILE;
76 import static org.sonar.server.computation.component.Component.Type.MODULE;
77 import static org.sonar.server.computation.component.Component.Type.PROJECT;
78 import static org.sonar.server.computation.component.ReportComponent.builder;
79 import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
80 import static org.sonar.server.computation.measure.MeasureRepoEntry.entryOf;
81 import static org.sonar.server.computation.measure.MeasureRepoEntry.toEntries;
82 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.A;
83 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.B;
84 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.C;
85 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.D;
86 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.E;
88 public class QualityModelMeasuresVisitorForReportTest {
90 static final String LANGUAGE_KEY_1 = "lKey1";
91 static final String LANGUAGE_KEY_2 = "lKey2";
93 static final double[] RATING_GRID = new double[] {0.1, 0.2, 0.5, 1};
95 static final long DEV_COST_LANGUAGE_1 = 30;
96 static final long DEV_COST_LANGUAGE_2 = 42;
98 static final int PROJECT_REF = 1;
99 static final int MODULE_REF = 12;
100 static final int DIRECTORY_REF = 123;
101 static final int FILE_1_REF = 1231;
102 static final int FILE_2_REF = 1232;
104 static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
106 builder(MODULE, MODULE_REF).setKey("module")
108 builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
110 builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1)).setKey("file1").build(),
111 builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1)).setKey("file2").build()
117 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
120 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
122 .add(DEVELOPMENT_COST)
124 .add(SQALE_DEBT_RATIO)
126 .add(EFFORT_TO_REACH_MAINTAINABILITY_RATING_A)
127 .add(RELIABILITY_RATING)
128 .add(EFFORT_TO_REACH_RELIABILITY_RATING_A)
129 .add(SECURITY_RATING)
130 .add(EFFORT_TO_REACH_SECURITY_RATING_A);
133 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
136 public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
139 public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
141 private RatingSettings ratingSettings = mock(RatingSettings.class);
143 private VisitorsCrawler underTest;
146 public void setUp() {
147 // assumes rating configuration is consistent
148 when(ratingSettings.getRatingGrid()).thenReturn(new RatingGrid(RATING_GRID));
149 when(ratingSettings.getDevCost(LANGUAGE_KEY_1)).thenReturn(DEV_COST_LANGUAGE_1);
150 when(ratingSettings.getDevCost(LANGUAGE_KEY_2)).thenReturn(DEV_COST_LANGUAGE_2);
152 underTest = new VisitorsCrawler(Arrays.asList(
153 fillComponentIssuesVisitorRule,
154 new QualityModelMeasuresVisitor(metricRepository, measureRepository, ratingSettings, componentIssuesRepositoryRule)));
158 public void measures_created_for_project_are_all_zero_when_they_have_no_FILE_child() {
159 ReportComponent root = builder(PROJECT, 1).build();
160 treeRootHolder.setRoot(root);
162 underTest.visit(root);
164 assertThat(toEntries(measureRepository.getRawMeasures(root)))
166 entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")),
167 entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d, 1)),
168 entryOf(SQALE_RATING_KEY, createMaintainabilityRatingMeasure(A)),
169 entryOf(EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, newMeasureBuilder().create(0L)),
170 entryOf(RELIABILITY_RATING_KEY, createMaintainabilityRatingMeasure(A)),
171 entryOf(EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, newMeasureBuilder().create(0L)),
172 entryOf(SECURITY_RATING_KEY, createMaintainabilityRatingMeasure(A)),
173 entryOf(EFFORT_TO_REACH_SECURITY_RATING_A_KEY, newMeasureBuilder().create(0L))
178 public void compute_development_cost() {
179 ReportComponent root = builder(PROJECT, 1)
183 builder(DIRECTORY, 111)
185 createFileComponent(LANGUAGE_KEY_1, 1111),
186 createFileComponent(LANGUAGE_KEY_2, 1112),
187 builder(FILE, 1113).setFileAttributes(new FileAttributes(true, LANGUAGE_KEY_1)).build())
189 builder(DIRECTORY, 112)
191 createFileComponent(LANGUAGE_KEY_2, 1121))
196 builder(DIRECTORY, 121)
198 createFileComponent(LANGUAGE_KEY_1, 1211))
200 builder(DIRECTORY, 122).build())
202 builder(MODULE, 13).build())
205 treeRootHolder.setRoot(root);
208 addRawMeasure(NCLOC_KEY, 1111, ncloc1111);
211 addRawMeasure(NCLOC_KEY, 1112, ncloc1112);
213 int nclocValue1121 = 30;
214 addRawMeasure(NCLOC_KEY, 1121, nclocValue1121);
217 addRawMeasure(NCLOC_KEY, 1211, ncloc1211);
219 underTest.visit(root);
221 // verify measures on files
222 verifyAddedRawMeasure(1111, DEVELOPMENT_COST_KEY, Long.toString(ncloc1111 * DEV_COST_LANGUAGE_1));
223 verifyAddedRawMeasure(1112, DEVELOPMENT_COST_KEY, Long.toString(ncloc1111 * DEV_COST_LANGUAGE_2));
224 verifyNoAddedRawMeasure(1113);
225 verifyAddedRawMeasure(1121, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2));
226 verifyAddedRawMeasure(1211, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
228 // directory has no children => no file => 0 everywhere and A rating
229 verifyAddedRawMeasure(122, DEVELOPMENT_COST_KEY, "0");
231 // directory has children => dev cost is aggregated
232 verifyAddedRawMeasure(111, DEVELOPMENT_COST_KEY, Long.toString(
233 ncloc1111 * DEV_COST_LANGUAGE_1 +
234 ncloc1112 * DEV_COST_LANGUAGE_2
236 verifyAddedRawMeasure(112, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2));
237 verifyAddedRawMeasure(121, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
239 // just for fun, we didn't define any debt on module => they must all have rating A
240 verifyAddedRawMeasure(11, DEVELOPMENT_COST_KEY, Long.toString(
241 ncloc1111 * DEV_COST_LANGUAGE_1 +
242 ncloc1112 * DEV_COST_LANGUAGE_2 +
243 nclocValue1121 * DEV_COST_LANGUAGE_2
245 verifyAddedRawMeasure(12, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
246 verifyAddedRawMeasure(13, DEVELOPMENT_COST_KEY, "0");
247 verifyAddedRawMeasure(1, DEVELOPMENT_COST_KEY, Long.toString(
248 ncloc1111 * DEV_COST_LANGUAGE_1 +
249 ncloc1112 * DEV_COST_LANGUAGE_2 +
250 nclocValue1121 * DEV_COST_LANGUAGE_2 +
251 ncloc1211 * DEV_COST_LANGUAGE_1
256 public void compute_maintainability_debt_ratio_measure() throws Exception {
257 treeRootHolder.setRoot(ROOT_PROJECT);
260 addRawMeasure(NCLOC_KEY, FILE_1_REF, file1Ncloc);
261 long file1MaintainabilityCost = 100L;
262 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, file1MaintainabilityCost);
265 addRawMeasure(NCLOC_KEY, FILE_2_REF, file2Ncloc);
266 long file2MaintainabilityCost = 1L;
267 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, file2MaintainabilityCost);
269 long directoryMaintainabilityCost = 100L;
270 addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, directoryMaintainabilityCost);
272 long moduleMaintainabilityCost = 100L;
273 addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, moduleMaintainabilityCost);
275 long projectMaintainabilityCost = 1000L;
276 addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, projectMaintainabilityCost);
278 underTest.visit(ROOT_PROJECT);
280 verifyAddedRawMeasure(FILE_1_REF, SQALE_DEBT_RATIO_KEY, file1MaintainabilityCost * 1d / (file1Ncloc * DEV_COST_LANGUAGE_1) * 100);
281 verifyAddedRawMeasure(FILE_2_REF, SQALE_DEBT_RATIO_KEY, file2MaintainabilityCost * 1d / (file2Ncloc * DEV_COST_LANGUAGE_1) * 100);
282 verifyAddedRawMeasure(DIRECTORY_REF, SQALE_DEBT_RATIO_KEY, directoryMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
283 verifyAddedRawMeasure(MODULE_REF, SQALE_DEBT_RATIO_KEY, moduleMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
284 verifyAddedRawMeasure(PROJECT_REF, SQALE_DEBT_RATIO_KEY, projectMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
288 public void compute_maintainability_rating_measure() throws Exception {
289 treeRootHolder.setRoot(ROOT_PROJECT);
291 addRawMeasure(NCLOC_KEY, FILE_1_REF, 10);
292 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 100L);
294 addRawMeasure(NCLOC_KEY, FILE_2_REF, 5);
295 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, 1L);
297 addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, 100L);
298 addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, 100L);
299 addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, 1000L);
301 underTest.visit(ROOT_PROJECT);
303 verifyAddedRawMeasure(FILE_1_REF, SQALE_RATING_KEY, C);
304 verifyAddedRawMeasure(FILE_2_REF, SQALE_RATING_KEY, A);
305 verifyAddedRawMeasure(DIRECTORY_REF, SQALE_RATING_KEY, C);
306 verifyAddedRawMeasure(MODULE_REF, SQALE_RATING_KEY, C);
307 verifyAddedRawMeasure(PROJECT_REF, SQALE_RATING_KEY, E);
311 public void compute_effort_to_maintainability_rating_A_measure() throws Exception {
312 treeRootHolder.setRoot(ROOT_PROJECT);
315 long file1Effort = 100L;
316 addRawMeasure(NCLOC_KEY, FILE_1_REF, file1Ncloc);
317 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, file1Effort);
320 long file2Effort = 20L;
321 addRawMeasure(NCLOC_KEY, FILE_2_REF, file2Ncloc);
322 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, file2Effort);
324 long dirEffort = 120L;
325 addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, dirEffort);
327 long moduleEffort = 120L;
328 addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, moduleEffort);
330 long projectEffort = 150L;
331 addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, projectEffort);
333 underTest.visit(ROOT_PROJECT);
335 verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
336 (long) (file1Effort - RATING_GRID[0] * file1Ncloc * DEV_COST_LANGUAGE_1));
337 verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
338 (long) (file2Effort - RATING_GRID[0] * file2Ncloc * DEV_COST_LANGUAGE_1));
339 verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
340 (long) (dirEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
341 verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
342 (long) (moduleEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
343 verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
344 (long) (projectEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
348 public void compute_0_effort_to_maintainability_rating_A_when_effort_is_lower_than_dev_cost() throws Exception {
349 treeRootHolder.setRoot(ROOT_PROJECT);
351 addRawMeasure(NCLOC_KEY, FILE_1_REF, 10);
352 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 2L);
354 underTest.visit(ROOT_PROJECT);
356 verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, 0L);
360 public void effort_to_maintainability_rating_A_is_same_as_effort_when_no_dev_cost() throws Exception {
361 treeRootHolder.setRoot(ROOT_PROJECT);
363 addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 100L);
365 underTest.visit(ROOT_PROJECT);
367 verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, 100);
371 public void compute_reliability_rating() throws Exception {
372 treeRootHolder.setRoot(ROOT_PROJECT);
373 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newBugIssue(1L, MAJOR),
374 // Should not be taken into account
375 newVulnerabilityIssue(5L, MINOR)
377 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newBugIssue(2L, CRITICAL), newBugIssue(3L, MINOR),
378 // Should not be taken into account
379 newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
382 underTest.visit(ROOT_PROJECT);
384 verifyAddedRawMeasure(FILE_1_REF, RELIABILITY_RATING_KEY, E);
385 verifyAddedRawMeasure(FILE_2_REF, RELIABILITY_RATING_KEY, D);
386 verifyAddedRawMeasure(DIRECTORY_REF, RELIABILITY_RATING_KEY, E);
387 verifyAddedRawMeasure(MODULE_REF, RELIABILITY_RATING_KEY, E);
388 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
392 public void compute_security_rating() throws Exception {
393 treeRootHolder.setRoot(ROOT_PROJECT);
394 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(10L, BLOCKER), newVulnerabilityIssue(1L, MAJOR),
395 // Should not be taken into account
396 newBugIssue(1L, MAJOR));
397 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newVulnerabilityIssue(2L, CRITICAL), newVulnerabilityIssue(3L, MINOR),
398 // Should not be taken into account
399 newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
402 underTest.visit(ROOT_PROJECT);
404 verifyAddedRawMeasure(FILE_1_REF, SECURITY_RATING_KEY, E);
405 verifyAddedRawMeasure(FILE_2_REF, SECURITY_RATING_KEY, D);
406 verifyAddedRawMeasure(DIRECTORY_REF, SECURITY_RATING_KEY, E);
407 verifyAddedRawMeasure(MODULE_REF, SECURITY_RATING_KEY, E);
408 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
412 public void compute_E_reliability_and_security_rating_on_blocker_issue() throws Exception {
413 treeRootHolder.setRoot(ROOT_PROJECT);
414 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newVulnerabilityIssue(1L, BLOCKER),
415 // Should not be taken into account
416 newBugIssue(1L, MAJOR));
418 underTest.visit(ROOT_PROJECT);
420 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
421 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
425 public void compute_D_reliability_and_security_rating_on_critical_issue() throws Exception {
426 treeRootHolder.setRoot(ROOT_PROJECT);
427 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, CRITICAL), newVulnerabilityIssue(15L, CRITICAL),
428 // Should not be taken into account
429 newCodeSmellIssue(1L, MAJOR));
431 underTest.visit(ROOT_PROJECT);
433 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, D);
434 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, D);
438 public void compute_C_reliability_and_security_rating_on_major_issue() throws Exception {
439 treeRootHolder.setRoot(ROOT_PROJECT);
440 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newVulnerabilityIssue(15L, MAJOR),
441 // Should not be taken into account
442 newCodeSmellIssue(1L, MAJOR));
444 underTest.visit(ROOT_PROJECT);
446 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, C);
447 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, C);
451 public void compute_B_reliability_and_security_rating_on_minor_issue() throws Exception {
452 treeRootHolder.setRoot(ROOT_PROJECT);
453 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MINOR), newVulnerabilityIssue(15L, MINOR),
454 // Should not be taken into account
455 newCodeSmellIssue(1L, MAJOR));
457 underTest.visit(ROOT_PROJECT);
459 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, B);
460 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, B);
464 public void compute_A_reliability_and_security_rating_on_info_issue() throws Exception {
465 treeRootHolder.setRoot(ROOT_PROJECT);
466 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, INFO), newVulnerabilityIssue(15L, INFO),
467 // Should not be taken into account
468 newCodeSmellIssue(1L, MAJOR));
470 underTest.visit(ROOT_PROJECT);
472 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, A);
473 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
477 public void compute_effort_to_reliability_rating_A_measure() throws Exception {
478 treeRootHolder.setRoot(ROOT_PROJECT);
480 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newBugIssue(1L, MAJOR),
481 // CODE SMELL should not be taken into account
482 newCodeSmellIssue(4L, MAJOR),
483 // Resolved issue should be ignored
484 newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
486 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newBugIssue(2L, CRITICAL), newBugIssue(3L, MINOR),
487 // INFO issue should not be taken into account
488 newBugIssue(5L, INFO),
489 // Issue without debt
490 newIssue(MAJOR, BUG));
492 underTest.visit(ROOT_PROJECT);
494 verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 10L + 1L);
495 verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 2L + 3L);
496 verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
497 verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
498 verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
502 public void compute_effort_to_security_rating_A_measure() throws Exception {
503 treeRootHolder.setRoot(ROOT_PROJECT);
505 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(8L, BLOCKER), newVulnerabilityIssue(6L, MAJOR),
506 // CODE SMELL should not be taken into account
507 newCodeSmellIssue(4L, MAJOR),
508 // Resolved issue should be ignored
509 newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
511 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newVulnerabilityIssue(2L, CRITICAL), newVulnerabilityIssue(1L, MINOR),
512 // INFO issue should not be taken into account
513 newVulnerabilityIssue(5L, INFO),
514 // Issue without debt
515 newIssue(MAJOR, VULNERABILITY));
517 underTest.visit(ROOT_PROJECT);
519 verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 8L + 6L);
520 verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 2L + 1L);
521 verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
522 verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
523 verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
526 private void addRawMeasure(String metricKey, int componentRef, long value) {
527 measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
530 private void addRawMeasure(String metricKey, int componentRef, int value) {
531 measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
534 private void verifyAddedRawMeasure(int componentRef, String metricKey, long value) {
535 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value)));
538 private void verifyAddedRawMeasure(int componentRef, String metricKey, double value) {
539 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value, 1)));
542 private void verifyAddedRawMeasure(int componentRef, String metricKey, Rating rating) {
543 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(rating.getIndex(), rating.name())));
546 private void verifyAddedRawMeasure(int componentRef, String metricKey, String value) {
547 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value)));
550 private void verifyNoAddedRawMeasure(int componentRef) {
551 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).isEmpty();
554 private static ReportComponent createFileComponent(String languageKey1, int fileRef) {
555 return builder(FILE, fileRef).setFileAttributes(new FileAttributes(false, languageKey1)).build();
558 private static Measure createMaintainabilityRatingMeasure(Rating rating) {
559 return newMeasureBuilder().create(rating.getIndex(), rating.name());
562 private static DefaultIssue newBugIssue(long effort, String severity) {
563 return newIssue(effort, severity, BUG);
566 private static DefaultIssue newVulnerabilityIssue(long effort, String severity) {
567 return newIssue(effort, severity, VULNERABILITY);
570 private static DefaultIssue newCodeSmellIssue(long effort, String severity) {
571 return newIssue(effort, severity, CODE_SMELL);
574 private static DefaultIssue newIssue(long effort, String severity, RuleType type) {
575 return newIssue(severity, type)
576 .setEffort(Duration.create(effort));
579 private static DefaultIssue newIssue(String severity, RuleType type) {
580 return new DefaultIssue()
581 .setKey(Uuids.create())
582 .setSeverity(severity)