3 * Copyright (C) 2009-2024 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 com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedList;
29 import java.util.List;
31 import java.util.Optional;
33 import javax.annotation.Nullable;
34 import org.junit.Test;
35 import org.sonar.api.issue.Issue;
36 import org.sonar.api.issue.impact.SoftwareQuality;
37 import org.sonar.api.measures.CoreMetrics;
38 import org.sonar.api.measures.Metric;
39 import org.sonar.api.rule.Severity;
40 import org.sonar.api.rules.RuleType;
41 import org.sonar.db.component.ComponentDto;
42 import org.sonar.db.issue.IssueGroupDto;
43 import org.sonar.db.issue.IssueImpactGroupDto;
44 import org.sonar.server.measure.DebtRatingGrid;
45 import org.sonar.server.measure.Rating;
47 import static java.util.Arrays.asList;
48 import static org.assertj.core.api.Assertions.assertThat;
49 import static org.sonar.api.issue.impact.Severity.HIGH;
50 import static org.sonar.api.issue.impact.Severity.LOW;
51 import static org.sonar.api.issue.impact.Severity.MEDIUM;
52 import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
53 import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
54 import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
55 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
56 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS;
57 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
58 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING;
59 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
60 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
61 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
62 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
63 import static org.sonar.test.JsonAssert.assertJson;
65 public class MeasureUpdateFormulaFactoryImplTest {
67 public static final Gson GSON = new GsonBuilder().create();
68 private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl();
71 public void getFormulaMetrics_include_the_dependent_metrics() {
72 for (MeasureUpdateFormula formula : underTest.getFormulas()) {
73 assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
74 for (Metric<?> dependentMetric : formula.getDependentMetrics()) {
75 assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
81 public void hierarchy_adding_numbers() {
82 new HierarchyTester(CoreMetrics.VIOLATIONS)
84 .withChildrenValues(2d, 3d)
87 new HierarchyTester(CoreMetrics.BUGS)
89 .withChildrenValues(2d, 3d)
92 new HierarchyTester(CoreMetrics.NEW_BUGS)
98 public void hierarchy_highest_rating() {
99 new HierarchyTester(CoreMetrics.RELIABILITY_RATING)
101 .withChildrenValues(2d, 3d)
102 .expectedRating(Rating.C);
104 // if no children, no need to set a value
105 new HierarchyTester(CoreMetrics.SECURITY_RATING)
107 .expectedResult(null);
109 new HierarchyTester(CoreMetrics.NEW_RELIABILITY_RATING)
111 .withChildrenValues(2d, 3d)
112 .expectedRating(Rating.E);
116 public void hierarchy_combining_other_metrics() {
117 new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
118 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
119 .withChildrenHotspotsCounts(10, 10, 2, 10)
122 new HierarchyTester(SECURITY_HOTSPOTS_REVIEWED_STATUS)
123 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
124 .withChildrenHotspotsCounts(2, 10, 10, 10)
127 new HierarchyTester(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
128 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
129 .withChildrenHotspotsCounts(10, 10, 10, 2)
132 new HierarchyTester(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
133 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
134 .withChildrenHotspotsCounts(10, 2, 10, 10)
137 new HierarchyTester(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED)
138 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
139 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
140 .expectedResult(50d);
141 new HierarchyTester(CoreMetrics.SECURITY_REVIEW_RATING)
142 .withValue(SECURITY_HOTSPOTS_REVIEWED, 100d)
143 .expectedRating(Rating.A);
145 new HierarchyTester(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED)
146 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
147 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
148 .expectedResult(50d);
149 new HierarchyTester(CoreMetrics.NEW_SECURITY_REVIEW_RATING)
150 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
151 .expectedRating(Rating.E);
155 public void test_violations() {
156 withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
157 with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
160 IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
161 with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
163 // include issues on leak
164 IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
165 with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
169 public void test_bugs() {
170 withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
172 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
173 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
175 newResolvedGroup(RuleType.BUG).setCount(7),
177 newGroup(RuleType.CODE_SMELL).setCount(11))
178 .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
182 public void test_code_smells() {
183 withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
185 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
186 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
188 newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
190 newGroup(RuleType.BUG).setCount(11))
191 .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
195 public void test_vulnerabilities() {
196 withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
198 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
199 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
201 newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
202 // not vulnerabilities
203 newGroup(RuleType.BUG).setCount(11))
204 .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
208 public void test_security_hotspots() {
209 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
211 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
212 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
214 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
216 newGroup(RuleType.BUG).setCount(11))
217 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
221 public void test_security_review_rating() {
223 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
224 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
225 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B);
228 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A);
232 public void test_security_hotspots_reviewed() {
234 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
235 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
236 .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
239 .assertNoValue(SECURITY_HOTSPOTS_REVIEWED);
243 public void test_security_hotspots_reviewed_status() {
245 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
246 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
247 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
250 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
254 public void test_security_hotspots_to_review_status() {
256 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
257 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
258 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
261 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
265 public void count_unresolved_by_severity() {
267 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
268 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
269 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
270 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
271 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
274 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
275 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
276 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
277 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
278 // exclude security hotspot
279 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
281 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
283 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
284 newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
285 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
286 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
287 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
288 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
289 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
290 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
294 public void count_resolved() {
296 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
297 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0);
300 newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
301 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
302 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
303 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
304 newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
305 // exclude security hotspot
306 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
307 // exclude unresolved
308 newGroup(RuleType.VULNERABILITY).setCount(17),
309 newGroup(RuleType.BUG).setCount(19))
310 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
311 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
315 public void count_by_status() {
317 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
318 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
319 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
322 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
323 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
324 newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
325 newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
326 newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
327 // exclude security hotspot
328 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
329 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
330 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
331 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
332 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
336 public void test_technical_debt() {
337 withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
340 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
341 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
342 // exclude security hotspot
343 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
344 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
346 newGroup(RuleType.BUG).setEffort(7.0),
348 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
349 .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
353 public void test_reliability_remediation_effort() {
354 withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
357 newGroup(RuleType.BUG).setEffort(3.0),
358 newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
360 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
362 newResolvedGroup(RuleType.BUG).setEffort(17.0))
363 .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
367 public void test_security_remediation_effort() {
368 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
371 newGroup(RuleType.VULNERABILITY).setEffort(3.0),
372 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
374 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
376 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
377 .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
381 public void test_sqale_debt_ratio_and_sqale_rating() {
383 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
384 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
386 // technical_debt not computed
387 with(CoreMetrics.DEVELOPMENT_COST, "0")
388 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
389 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
390 with(CoreMetrics.DEVELOPMENT_COST, "20")
391 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
392 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
394 // development_cost not computed
395 with(CoreMetrics.TECHNICAL_DEBT, 0)
396 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
397 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
398 with(CoreMetrics.TECHNICAL_DEBT, 20)
399 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
400 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
402 // input measures are available
403 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
404 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
405 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
406 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
408 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
409 .andText(CoreMetrics.DEVELOPMENT_COST, "160")
410 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 12.5)
411 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.C);
413 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
414 .andText(CoreMetrics.DEVELOPMENT_COST, "10")
415 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 200.0)
416 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.E);
418 // A is 5% --> min debt is exactly 200*0.05=10
419 with(CoreMetrics.DEVELOPMENT_COST, "200")
420 .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
421 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 5.0)
422 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
424 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
425 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
426 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
427 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
429 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
430 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
431 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0);
433 with(CoreMetrics.TECHNICAL_DEBT, -20.0)
434 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
435 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
436 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
438 // bug, debt can't be negative
439 with(CoreMetrics.TECHNICAL_DEBT, -20.0)
440 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
441 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
442 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
444 // bug, cost can't be negative
445 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
446 .andText(CoreMetrics.DEVELOPMENT_COST, "-80")
447 .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
448 .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
452 public void test_effort_to_reach_maintainability_rating_A() {
454 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
456 // technical_debt not computed
457 with(CoreMetrics.DEVELOPMENT_COST, 0.0)
458 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
459 with(CoreMetrics.DEVELOPMENT_COST, 20.0)
460 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
462 // development_cost not computed
463 with(CoreMetrics.TECHNICAL_DEBT, 0.0)
464 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
465 with(CoreMetrics.TECHNICAL_DEBT, 20.0)
466 // development cost is considered as zero, so the effort is to reach... zero
467 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 20.0);
470 with(CoreMetrics.DEVELOPMENT_COST, "200")
471 .and(CoreMetrics.TECHNICAL_DEBT, 40.0)
472 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
473 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 40.0 - (200.0 * 0.05));
476 with(CoreMetrics.DEVELOPMENT_COST, "200")
477 .and(CoreMetrics.TECHNICAL_DEBT, 180.0)
478 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
479 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 180.0 - (200.0 * 0.05));
482 with(CoreMetrics.DEVELOPMENT_COST, "200")
483 .and(CoreMetrics.TECHNICAL_DEBT, 8.0)
484 // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
485 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
487 // exactly lower range of B
488 with(CoreMetrics.DEVELOPMENT_COST, "200")
489 .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
490 // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
491 // FIXME need zero to reach A but effective rating is B !
492 .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
496 public void test_reliability_rating() {
498 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
501 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
502 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
503 // excluded, not a bug
504 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
505 // highest severity of bugs is CRITICAL --> D
506 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
509 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
510 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
512 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
516 public void test_security_rating() {
518 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
521 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
522 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
523 // excluded, not a vulnerability
524 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
525 // highest severity of vulnerabilities is CRITICAL --> D
526 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
529 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
530 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
531 // no vulnerabilities --> A
532 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
536 public void test_new_bugs() {
537 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
540 newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
541 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
542 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
544 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
545 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
546 .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
551 public void test_new_code_smells() {
552 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
555 newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
556 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
557 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
559 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
560 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
561 .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
565 public void test_new_vulnerabilities() {
566 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
569 newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
570 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
571 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
572 // not vulnerabilities
573 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
574 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
575 .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
579 public void test_new_security_hotspots() {
580 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0);
583 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
584 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
585 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
587 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
588 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
589 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
593 public void test_new_violations() {
594 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
597 newGroup(RuleType.BUG).setInLeak(true).setCount(5),
598 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
599 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
601 newGroup(RuleType.BUG).setInLeak(false).setCount(11),
602 newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
603 newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
604 .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
608 public void test_new_blocker_violations() {
610 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
613 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
614 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
615 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
617 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
619 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
620 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
621 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
625 public void test_new_critical_violations() {
627 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
630 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
631 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
632 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
634 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
636 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
637 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
638 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
642 public void test_new_major_violations() {
644 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
647 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
648 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
649 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
651 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
653 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
654 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
655 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
659 public void test_new_minor_violations() {
661 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
664 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
665 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
666 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
668 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
670 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
671 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
672 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
676 public void test_new_info_violations() {
678 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
681 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
682 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
683 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
685 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
687 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
688 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
689 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
693 public void test_new_accepted_issues() {
695 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0);
698 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(3),
699 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(4),
700 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(30),
701 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(40),
703 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(5),
704 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(50))
705 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
709 public void test_new_technical_debt() {
710 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
713 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
715 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
717 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
718 newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
720 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
721 .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
725 public void test_new_reliability_remediation_effort() {
726 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
729 newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
731 newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
733 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
735 newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
736 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
740 public void test_new_security_remediation_effort() {
741 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
744 newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
746 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
748 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
750 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
751 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
755 public void test_new_reliability_rating() {
756 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
759 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
760 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
762 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
764 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
766 newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
767 // highest severity of bugs on leak period is minor -> B
768 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
772 public void test_new_security_rating() {
773 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
776 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
777 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
779 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
781 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
783 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
784 // highest severity of bugs on leak period is minor -> B
785 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
789 public void test_new_security_review_rating() {
791 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
792 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
794 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
795 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B);
798 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A);
802 public void test_new_security_hotspots_reviewed() {
804 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
805 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
807 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
808 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
811 .assertNoLeakValue(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED);
815 public void test_new_security_hotspots_reviewed_status() {
817 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
818 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
820 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
821 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
824 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
828 public void test_new_security_hotspots_to_review_status() {
830 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
831 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
833 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
834 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
837 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
841 public void test_new_sqale_debt_ratio_and_new_maintainability_rating() {
843 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
844 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
846 // technical_debt not computed
847 with(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
848 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
849 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
850 with(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
851 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
852 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
854 // development_cost not computed
855 with(CoreMetrics.NEW_TECHNICAL_DEBT, 0)
856 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
857 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
858 with(CoreMetrics.NEW_TECHNICAL_DEBT, 20)
859 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
860 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
862 // input measures are available
863 with(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
864 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
865 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
866 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
868 with(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
869 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
870 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 12.5)
871 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.C);
873 with(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
874 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0D)
875 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 200.0)
876 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.E);
878 // A is 5% --> min debt is exactly 200*0.05=10
879 with(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
880 .and(CoreMetrics.NEW_TECHNICAL_DEBT, 10.0)
881 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 5.0)
882 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
884 with(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
885 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
886 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
887 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
889 with(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
890 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
891 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0);
893 with(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
894 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
895 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
896 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
898 // bug, debt can't be negative
899 with(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
900 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
901 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
902 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
904 // bug, cost can't be negative
905 with(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
906 .and(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
907 .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
908 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
912 public void compute_shouldComputeHighImpactAcceptedIssues() {
914 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
917 newImpactGroup(RELIABILITY, HIGH, 3),
918 newImpactGroup(RELIABILITY, MEDIUM, 4),
919 newImpactGroup(RELIABILITY, LOW, 1),
920 newImpactGroup(SECURITY, HIGH, 3),
921 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4),
922 newImpactGroup(SECURITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 5),
923 newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
924 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
925 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8))
926 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
930 public void computeHierarchy_shouldComputeImpactMeasures() {
931 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
932 .withValue(impactMeasureToJson(6, 1, 2, 3))
933 .withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2))
934 .expectedJsonResult(impactMeasureToJson(22, 7, 7, 8));
936 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
937 .withValue(impactMeasureToJson(6, 1, 2, 3))
938 .expectedJsonResult(impactMeasureToJson(6, 1, 2, 3));
942 public void compute_shouldComputeImpactMeasures() {
944 newImpactGroup(RELIABILITY, HIGH, 3),
945 newImpactGroup(RELIABILITY, MEDIUM, 4),
946 newImpactGroup(RELIABILITY, LOW, 1),
947 newImpactGroup(MAINTAINABILITY, MEDIUM, 10),
948 newImpactGroup(MAINTAINABILITY, LOW, 11),
949 newImpactGroup(SECURITY, HIGH, 3))
950 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
951 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
952 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
956 public void compute_whenNoIssues_shouldComputeImpactMeasures() {
958 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
959 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
960 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0));
963 private static String impactMeasureToJson(long total, long high, long medium, long low) {
964 return GSON.toJson(Map.of("total", total, "HIGH", high, "MEDIUM", medium, "LOW", low));
967 private Verifier with(IssueGroupDto... groups) {
968 return new Verifier(groups);
971 private Verifier with(IssueImpactGroupDto... groups) {
972 return new Verifier(groups);
975 private Verifier withNoIssues() {
976 return new Verifier(new IssueGroupDto[0]);
979 private Verifier with(Metric metric, double value) {
980 return new Verifier(new IssueGroupDto[0]).and(metric, value);
983 private Verifier with(Metric metric, String value) {
984 return new Verifier(new IssueGroupDto[0]).andText(metric, value);
987 private class Verifier {
988 private IssueGroupDto[] groups = {};
989 private IssueImpactGroupDto[] impactGroups = {};
990 private final InitialValues initialValues = new InitialValues();
992 private Verifier(IssueGroupDto[] groups) {
993 this.groups = groups;
996 private Verifier(IssueImpactGroupDto[] impactGroups) {
997 this.impactGroups = impactGroups;
1000 Verifier and(Metric metric, double value) {
1001 this.initialValues.values.put(metric, value);
1005 Verifier andText(Metric metric, String value) {
1006 this.initialValues.textValues.put(metric, value);
1010 Verifier assertThatValueIs(Metric metric, double expectedValue) {
1011 TestContext context = run(metric, false);
1012 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1016 Verifier assertThatJsonValueIs(Metric metric, String expectedValue) {
1017 TestContext context = run(metric, false);
1018 assertJson(context.stringValue).isSimilarTo(expectedValue);
1022 Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
1023 TestContext context = run(metric, true);
1024 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1028 Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
1029 TestContext context = run(metric, true);
1030 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedRating);
1034 Verifier assertNoLeakValue(Metric metric) {
1035 TestContext context = run(metric, true);
1036 assertThat(context.ratingValue).isNull();
1040 Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
1041 TestContext context = run(metric, false);
1042 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
1046 Verifier assertNoValue(Metric metric) {
1047 TestContext context = run(metric, false);
1048 assertThat(context.ratingValue).isNull();
1052 private TestContext run(Metric metric, boolean expectLeakFormula) {
1053 MeasureUpdateFormula formula = underTest.getFormulas().stream()
1054 .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
1057 assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
1058 TestContext context = new TestContext(formula.getDependentMetrics(), initialValues);
1059 formula.compute(context, newIssueCounter(groups, impactGroups));
1064 private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups) {
1065 return new IssueCounter(asList(groups), asList(impactGroups));
1068 private static IssueGroupDto newGroup() {
1069 return newGroup(RuleType.CODE_SMELL);
1072 private static IssueGroupDto newGroup(RuleType ruleType) {
1073 IssueGroupDto dto = new IssueGroupDto();
1074 // set non-null fields
1075 dto.setRuleType(ruleType.getDbConstant());
1078 dto.setSeverity(Severity.INFO);
1079 dto.setStatus(Issue.STATUS_OPEN);
1080 dto.setInLeak(false);
1084 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1085 String status, @Nullable String resolution, long count) {
1086 IssueImpactGroupDto dto = new IssueImpactGroupDto();
1087 dto.setSoftwareQuality(softwareQuality);
1088 dto.setSeverity(severity);
1089 dto.setStatus(status);
1090 dto.setResolution(resolution);
1091 dto.setCount(count);
1095 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count) {
1096 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count);
1099 private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
1100 return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
1103 private static IssueGroupDto newResolvedGroup(String resolution, String status) {
1104 return newGroup().setResolution(resolution).setStatus(status);
1107 private static class TestContext implements MeasureUpdateFormula.Context {
1108 private final Set<Metric> dependentMetrics;
1109 private final InitialValues initialValues;
1110 private Double doubleValue;
1111 private Rating ratingValue;
1112 private String stringValue;
1114 private TestContext(Collection<Metric> dependentMetrics, InitialValues initialValues) {
1115 this.dependentMetrics = new HashSet<>(dependentMetrics);
1116 this.initialValues = initialValues;
1120 public List<Double> getChildrenValues() {
1121 return initialValues.childrenValues;
1125 public List<String> getChildrenTextValues() {
1126 return initialValues.childrenTextValues;
1130 public long getChildrenHotspotsReviewed() {
1131 return initialValues.childrenHotspotsReviewed;
1135 public long getChildrenHotspotsToReview() {
1136 return initialValues.childrenHotspotsToReview;
1140 public long getChildrenNewHotspotsReviewed() {
1141 return initialValues.childrenNewHotspotsReviewed;
1145 public long getChildrenNewHotspotsToReview() {
1146 return initialValues.childrenNewHotspotsToReview;
1150 public ComponentDto getComponent() {
1151 throw new UnsupportedOperationException();
1155 public DebtRatingGrid getDebtRatingGrid() {
1156 return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5});
1160 public Optional<Double> getValue(Metric metric) {
1161 if (!dependentMetrics.contains(metric)) {
1162 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
1164 if (initialValues.values.containsKey(metric)) {
1165 return Optional.of(initialValues.values.get(metric));
1167 return Optional.empty();
1171 public Optional<String> getText(Metric metric) {
1172 if (initialValues.textValues.containsKey(metric)) {
1173 return Optional.of(initialValues.textValues.get(metric));
1175 return Optional.empty();
1179 public void setValue(double value) {
1180 this.doubleValue = value;
1184 public void setValue(Rating value) {
1185 this.ratingValue = value;
1189 public void setValue(String value) {
1190 this.stringValue = value;
1194 private class InitialValues {
1195 private final Map<Metric, Double> values = new HashMap<>();
1196 private final List<Double> childrenValues = new ArrayList<>();
1197 private final Map<Metric, String> textValues = new HashMap<>();
1198 private final List<String> childrenTextValues = new ArrayList<>();
1199 private long childrenHotspotsReviewed = 0;
1200 private long childrenNewHotspotsReviewed = 0;
1201 private long childrenHotspotsToReview = 0;
1202 private long childrenNewHotspotsToReview = 0;
1206 private class HierarchyTester {
1207 private final Metric metric;
1208 private final InitialValues initialValues;
1209 private final MeasureUpdateFormula formula;
1211 public HierarchyTester(Metric metric) {
1212 this.metric = metric;
1213 this.initialValues = new InitialValues();
1214 this.formula = underTest.getFormulas().stream().filter(f -> f.getMetric().equals(metric)).findAny().get();
1217 public HierarchyTester withValue(Metric metric, Double value) {
1218 this.initialValues.values.put(metric, value);
1222 public HierarchyTester withValue(Metric metric, String value) {
1223 this.initialValues.textValues.put(metric, value);
1227 public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed, long childrenHotspotsToReview,
1228 long childrenNewHotspotsToReview) {
1229 this.initialValues.childrenHotspotsReviewed = childrenHotspotsReviewed;
1230 this.initialValues.childrenNewHotspotsReviewed = childrenNewHotspotsReviewed;
1231 this.initialValues.childrenHotspotsToReview = childrenHotspotsToReview;
1232 this.initialValues.childrenNewHotspotsToReview = childrenNewHotspotsToReview;
1236 public HierarchyTester withValue(Double value) {
1237 return withValue(metric, value);
1240 public HierarchyTester withValue(String value) {
1241 return withValue(metric, value);
1244 public HierarchyTester withChildrenValues(Double... values) {
1245 this.initialValues.childrenValues.addAll(asList(values));
1249 public HierarchyTester withChildrenValues(String... values) {
1250 this.initialValues.childrenTextValues.addAll(asList(values));
1254 public HierarchyTester expectedResult(@Nullable Double expected) {
1255 TestContext ctx = run();
1256 assertThat(ctx.doubleValue).isEqualTo(expected);
1260 public HierarchyTester expectedJsonResult(@Nullable String expected) {
1261 TestContext ctx = run();
1262 assertJson(ctx.stringValue).isSimilarTo(expected);
1266 public HierarchyTester expectedRating(@Nullable Rating rating) {
1267 TestContext ctx = run();
1268 assertThat(ctx.ratingValue).isEqualTo(rating);
1272 private TestContext run() {
1273 List<Metric> deps = new LinkedList<>(formula.getDependentMetrics());
1274 deps.add(formula.getMetric());
1275 deps.addAll(initialValues.values.keySet());
1276 deps.addAll(initialValues.textValues.keySet());
1277 TestContext context = new TestContext(deps, initialValues);
1278 formula.computeHierarchy(context);