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.server.measure.live;
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.HashSet;
26 import java.util.Optional;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.rules.ExpectedException;
31 import org.sonar.api.issue.Issue;
32 import org.sonar.api.measures.CoreMetrics;
33 import org.sonar.api.measures.Metric;
34 import org.sonar.api.rule.Severity;
35 import org.sonar.api.rules.RuleType;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.db.issue.IssueGroupDto;
38 import org.sonar.server.measure.DebtRatingGrid;
39 import org.sonar.server.measure.Rating;
41 import static java.util.Arrays.asList;
42 import static org.assertj.core.api.Assertions.assertThat;
44 public class IssueMetricFormulaFactoryImplTest {
46 public ExpectedException expectedException = ExpectedException.none();
48 private IssueMetricFormulaFactoryImpl underTest = new IssueMetricFormulaFactoryImpl();
51 public void getFormulaMetrics_include_the_dependent_metrics() {
52 for (IssueMetricFormula formula : underTest.getFormulas()) {
53 assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
54 for (Metric dependentMetric : formula.getDependentMetrics()) {
55 assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
61 public void test_violations() {
62 withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
63 with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
66 IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
67 with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
69 // include issues on leak
70 IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
71 with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
75 public void test_bugs() {
76 withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
78 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
79 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
81 newResolvedGroup(RuleType.BUG).setCount(7),
83 newGroup(RuleType.CODE_SMELL).setCount(11))
84 .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
88 public void test_code_smells() {
89 withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
91 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
92 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
94 newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
96 newGroup(RuleType.BUG).setCount(11))
97 .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
101 public void test_vulnerabilities() {
102 withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
104 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
105 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
107 newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
108 // not vulnerabilities
109 newGroup(RuleType.BUG).setCount(11))
110 .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
114 public void test_security_hotspots() {
115 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
117 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
118 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
120 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
122 newGroup(RuleType.BUG).setCount(11))
123 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
127 public void count_unresolved_by_severity() {
129 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
130 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
131 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
132 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
133 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
136 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
137 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
138 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
139 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
140 // exclude security hotspot
141 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
143 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
145 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
146 newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
147 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
148 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
149 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
150 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
151 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
152 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
156 public void count_resolved() {
158 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
159 .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 0);
162 newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
163 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
164 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
165 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
166 newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
167 // exclude security hotspot
168 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
169 // exclude unresolved
170 newGroup(RuleType.VULNERABILITY).setCount(17),
171 newGroup(RuleType.BUG).setCount(19))
172 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
173 .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 7 + 11);
177 public void count_by_status() {
179 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
180 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
181 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
184 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
185 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
186 newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
187 newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
188 newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
189 // exclude security hotspot
190 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
191 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
192 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
193 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
194 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
198 public void test_technical_debt() {
199 withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
202 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
203 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
204 // exclude security hotspot
205 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
206 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
208 newGroup(RuleType.BUG).setEffort(7.0),
210 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
211 .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
215 public void test_reliability_remediation_effort() {
216 withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
219 newGroup(RuleType.BUG).setEffort(3.0),
220 newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
222 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
224 newResolvedGroup(RuleType.BUG).setEffort(17.0))
225 .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
229 public void test_security_remediation_effort() {
230 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
233 newGroup(RuleType.VULNERABILITY).setEffort(3.0),
234 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
236 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
238 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
239 .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
243 public void test_sqale_debt_ratio_and_sqale_rating() {
245 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
246 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
248 // technical_debt not computed
249 with(CoreMetrics.DEVELOPMENT_COST, 0)
250 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
251 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
252 with(CoreMetrics.DEVELOPMENT_COST, 20)
253 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
254 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
256 // development_cost not computed
257 with(CoreMetrics.TECHNICAL_DEBT, 0)
258 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
259 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
260 with(CoreMetrics.TECHNICAL_DEBT, 20)
261 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
262 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
264 // input measures are available
265 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
266 .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
267 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
268 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
270 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
271 .and(CoreMetrics.DEVELOPMENT_COST, 160.0)
272 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 12.5)
273 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.C);
275 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
276 .and(CoreMetrics.DEVELOPMENT_COST, 10.0)
277 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 200.0)
278 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.E);
280 // A is 5% --> min debt is exactly 200*0.05=10
281 with(CoreMetrics.DEVELOPMENT_COST, 200.0)
282 .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
283 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 5.0)
284 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
286 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
287 .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
288 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
289 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
291 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
292 .and(CoreMetrics.DEVELOPMENT_COST, 80.0)
293 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0);
295 with(CoreMetrics.TECHNICAL_DEBT, -20.0)
296 .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
297 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
298 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
300 // bug, debt can't be negative
301 with(CoreMetrics.TECHNICAL_DEBT, -20.0)
302 .and(CoreMetrics.DEVELOPMENT_COST, 80.0)
303 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
304 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
306 // bug, cost can't be negative
307 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
308 .and(CoreMetrics.DEVELOPMENT_COST, -80.0)
309 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
310 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
314 public void test_effort_to_reach_maintainability_rating_A() {
316 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
318 // technical_debt not computed
319 with(CoreMetrics.DEVELOPMENT_COST, 0.0)
320 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
321 with(CoreMetrics.DEVELOPMENT_COST, 20.0)
322 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
324 // development_cost not computed
325 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
326 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
327 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
328 // development cost is considered as zero, so the effort is to reach... zero
329 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 20.0);
332 with(CoreMetrics.DEVELOPMENT_COST, 200.0)
333 .and(CoreMetrics.TECHNICAL_DEBT, 40.0)
334 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
335 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 40.0 - (200.0 * 0.05));
338 with(CoreMetrics.DEVELOPMENT_COST, 200.0)
339 .and(CoreMetrics.TECHNICAL_DEBT, 180.0)
340 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
341 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 180.0 - (200.0 * 0.05));
344 with(CoreMetrics.DEVELOPMENT_COST, 200.0)
345 .and(CoreMetrics.TECHNICAL_DEBT, 8.0)
346 // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
347 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
349 // exactly lower range of B
350 with(CoreMetrics.DEVELOPMENT_COST, 200.0)
351 .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
352 // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
353 // FIXME need zero to reach A but effective rating is B !
354 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
358 public void test_reliability_rating() {
360 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
363 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
364 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
365 // excluded, not a bug
366 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
367 // highest severity of bugs is CRITICAL --> D
368 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
371 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
372 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
374 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
378 public void test_security_rating() {
380 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
383 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
384 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
385 // excluded, not a vulnerability
386 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
387 // highest severity of vulnerabilities is CRITICAL --> D
388 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
391 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
392 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
393 // no vulnerabilities --> A
394 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
398 public void test_new_bugs() {
399 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
402 newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
403 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
404 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
406 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
407 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
408 .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
412 public void test_new_code_smells() {
413 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
416 newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
417 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
418 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
420 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
421 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
422 .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
426 public void test_new_vulnerabilities() {
427 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
430 newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
431 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
432 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
433 // not vulnerabilities
434 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
435 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
436 .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
440 public void test_new_security_hotspots() {
441 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0.0);
444 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
445 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
446 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
448 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
449 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
450 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
454 public void test_new_violations() {
455 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
458 newGroup(RuleType.BUG).setInLeak(true).setCount(5),
459 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
460 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
462 newGroup(RuleType.BUG).setInLeak(false).setCount(11),
463 newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
464 newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
465 .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
469 public void test_new_blocker_violations() {
471 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
474 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
475 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
476 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
478 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
480 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
481 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
482 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
486 public void test_new_critical_violations() {
488 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
491 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
492 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
493 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
495 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
497 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
498 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
499 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
503 public void test_new_major_violations() {
505 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
508 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
509 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
510 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
512 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
514 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
515 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
516 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
520 public void test_new_minor_violations() {
522 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
525 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
526 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
527 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
529 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
531 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
532 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
533 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
537 public void test_new_info_violations() {
539 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
542 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
543 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
544 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
546 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
548 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
549 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
550 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
554 public void test_new_technical_debt() {
555 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
558 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
560 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
562 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
563 newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
565 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
566 .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
570 public void test_new_reliability_remediation_effort() {
571 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
574 newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
576 newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
578 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
580 newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
581 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
585 public void test_new_security_remediation_effort() {
586 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
589 newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
591 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
593 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
595 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
596 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
600 public void test_new_reliability_rating() {
601 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
604 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
605 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
607 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
609 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
611 newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
612 // highest severity of bugs on leak period is minor -> B
613 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
617 public void test_new_security_rating() {
618 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
621 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
622 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
624 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
626 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
628 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
629 // highest severity of bugs on leak period is minor -> B
630 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
634 public void test_new_sqale_debt_ratio_and_new_maintainability_rating() {
636 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
637 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
639 // technical_debt not computed
640 withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
641 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
642 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
643 withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
644 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
645 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
647 // development_cost not computed
648 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0)
649 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
650 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
651 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20)
652 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
653 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
655 // input measures are available
656 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
657 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
658 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
659 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
661 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
662 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
663 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 12.5)
664 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.C);
666 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
667 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0)
668 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 200.0)
669 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.E);
671 // A is 5% --> min debt is exactly 200*0.05=10
672 withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
673 .andLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 10.0)
674 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 5.0)
675 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
677 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
678 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
679 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
680 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
682 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
683 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
684 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0);
686 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
687 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
688 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
689 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
691 // bug, debt can't be negative
692 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
693 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
694 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
695 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
697 // bug, cost can't be negative
698 withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
699 .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
700 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
701 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
704 private Verifier with(IssueGroupDto... groups) {
705 return new Verifier(groups);
708 private Verifier withNoIssues() {
709 return new Verifier(new IssueGroupDto[0]);
712 private Verifier with(Metric metric, double value) {
713 return new Verifier(new IssueGroupDto[0]).and(metric, value);
716 private Verifier withLeak(Metric metric, double leakValue) {
717 return new Verifier(new IssueGroupDto[0]).andLeak(metric, leakValue);
720 private class Verifier {
721 private final IssueGroupDto[] groups;
722 private final Map<Metric, Double> values = new HashMap<>();
723 private final Map<Metric, Double> leakValues = new HashMap<>();
725 private Verifier(IssueGroupDto[] groups) {
726 this.groups = groups;
729 Verifier and(Metric metric, double value) {
730 this.values.put(metric, value);
734 Verifier andLeak(Metric metric, double value) {
735 this.leakValues.put(metric, value);
739 Verifier assertThatValueIs(Metric metric, double expectedValue) {
740 TestContext context = run(metric, false);
741 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
745 Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
746 TestContext context = run(metric, true);
747 assertThat(context.doubleLeakValue).isNotNull().isEqualTo(expectedValue);
751 Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
752 TestContext context = run(metric, true);
753 assertThat(context.ratingLeakValue).isNotNull().isEqualTo(expectedRating);
757 Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
758 TestContext context = run(metric, false);
759 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
763 private TestContext run(Metric metric, boolean expectLeakFormula) {
764 IssueMetricFormula formula = underTest.getFormulas().stream()
765 .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
768 assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
769 TestContext context = new TestContext(formula.getDependentMetrics(), values, leakValues);
770 formula.compute(context, newIssueCounter(groups));
775 private static IssueCounter newIssueCounter(IssueGroupDto... issues) {
776 return new IssueCounter(asList(issues));
779 private static IssueGroupDto newGroup() {
780 return newGroup(RuleType.CODE_SMELL);
783 private static IssueGroupDto newGroup(RuleType ruleType) {
784 IssueGroupDto dto = new IssueGroupDto();
785 // set non-null fields
786 dto.setRuleType(ruleType.getDbConstant());
789 dto.setSeverity(Severity.INFO);
790 dto.setStatus(Issue.STATUS_OPEN);
791 dto.setInLeak(false);
795 private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
796 return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
799 private static IssueGroupDto newResolvedGroup(String resolution, String status) {
800 return newGroup().setResolution(resolution).setStatus(status);
803 private static class TestContext implements IssueMetricFormula.Context {
804 private final Set<Metric> dependentMetrics;
805 private Double doubleValue;
806 private Rating ratingValue;
807 private Double doubleLeakValue;
808 private Rating ratingLeakValue;
809 private final Map<Metric, Double> values;
810 private final Map<Metric, Double> leakValues;
812 private TestContext(Collection<Metric> dependentMetrics, Map<Metric, Double> values, Map<Metric, Double> leakValues) {
813 this.dependentMetrics = new HashSet<>(dependentMetrics);
814 this.values = values;
815 this.leakValues = leakValues;
819 public ComponentDto getComponent() {
820 throw new UnsupportedOperationException();
824 public DebtRatingGrid getDebtRatingGrid() {
825 return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5});
829 public Optional<Double> getValue(Metric metric) {
830 if (!dependentMetrics.contains(metric)) {
831 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
833 if (values.containsKey(metric)) {
834 return Optional.of(values.get(metric));
836 return Optional.empty();
840 public Optional<Double> getLeakValue(Metric metric) {
841 if (!dependentMetrics.contains(metric)) {
842 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
844 if (leakValues.containsKey(metric)) {
845 return Optional.of(leakValues.get(metric));
847 return Optional.empty();
851 public void setValue(double value) {
852 this.doubleValue = value;
856 public void setValue(Rating value) {
857 this.ratingValue = value;
861 public void setLeakValue(double value) {
862 this.doubleLeakValue = value;
866 public void setLeakValue(Rating value) {
867 this.ratingLeakValue = value;