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 java.util.stream.Stream;
34 import javax.annotation.Nullable;
35 import org.junit.jupiter.api.Test;
36 import org.junit.jupiter.params.ParameterizedTest;
37 import org.junit.jupiter.params.provider.Arguments;
38 import org.junit.jupiter.params.provider.MethodSource;
39 import org.sonar.api.issue.Issue;
40 import org.sonar.api.issue.impact.SoftwareQuality;
41 import org.sonar.api.measures.CoreMetrics;
42 import org.sonar.api.measures.Metric;
43 import org.sonar.api.rule.Severity;
44 import org.sonar.api.rules.RuleType;
45 import org.sonar.core.metric.SoftwareQualitiesMetrics;
46 import org.sonar.db.component.ComponentDto;
47 import org.sonar.db.issue.IssueGroupDto;
48 import org.sonar.db.issue.IssueImpactGroupDto;
49 import org.sonar.db.issue.IssueImpactSeverityGroupDto;
50 import org.sonar.server.measure.DebtRatingGrid;
51 import org.sonar.server.measure.Rating;
53 import static java.util.Arrays.asList;
54 import static org.assertj.core.api.Assertions.assertThat;
55 import static org.junit.jupiter.params.provider.Arguments.arguments;
56 import static org.sonar.api.issue.impact.Severity.BLOCKER;
57 import static org.sonar.api.issue.impact.Severity.HIGH;
58 import static org.sonar.api.issue.impact.Severity.INFO;
59 import static org.sonar.api.issue.impact.Severity.LOW;
60 import static org.sonar.api.issue.impact.Severity.MEDIUM;
61 import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
62 import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
63 import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
64 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A;
65 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
66 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
67 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS;
68 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
69 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING;
70 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
71 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
72 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
73 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
74 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO;
75 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING;
76 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
77 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT;
78 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT;
79 import static org.sonar.server.metric.IssueCountMetrics.PRIORITIZED_RULE_ISSUES;
80 import static org.sonar.test.JsonAssert.assertJson;
82 class MeasureUpdateFormulaFactoryImplTest {
84 private static final Gson GSON = new GsonBuilder().create();
85 private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl();
88 void getFormulaMetrics_include_the_dependent_metrics() {
89 for (MeasureUpdateFormula formula : underTest.getFormulas()) {
90 assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
91 for (Metric<?> dependentMetric : formula.getDependentMetrics()) {
92 assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
98 void hierarchy_adding_numbers() {
99 new HierarchyTester(CoreMetrics.VIOLATIONS)
101 .withChildrenValues(2d, 3d)
104 new HierarchyTester(CoreMetrics.BUGS)
106 .withChildrenValues(2d, 3d)
109 new HierarchyTester(CoreMetrics.NEW_BUGS)
115 void hierarchy_highest_rating() {
116 new HierarchyTester(CoreMetrics.RELIABILITY_RATING)
118 .withChildrenValues(2d, 3d)
119 .expectedRating(Rating.C);
121 // if no children, no need to set a value
122 new HierarchyTester(CoreMetrics.SECURITY_RATING)
124 .expectedResult(null);
126 new HierarchyTester(CoreMetrics.NEW_RELIABILITY_RATING)
128 .withChildrenValues(2d, 3d)
129 .expectedRating(Rating.E);
133 void hierarchy_combining_other_metrics() {
134 new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
135 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
136 .withChildrenHotspotsCounts(10, 10, 2, 10)
139 new HierarchyTester(SECURITY_HOTSPOTS_REVIEWED_STATUS)
140 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
141 .withChildrenHotspotsCounts(2, 10, 10, 10)
144 new HierarchyTester(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
145 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
146 .withChildrenHotspotsCounts(10, 10, 10, 2)
149 new HierarchyTester(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
150 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
151 .withChildrenHotspotsCounts(10, 2, 10, 10)
154 new HierarchyTester(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED)
155 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
156 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
157 .expectedResult(50d);
158 new HierarchyTester(CoreMetrics.SECURITY_REVIEW_RATING)
159 .withValue(SECURITY_HOTSPOTS_REVIEWED, 100d)
160 .expectedRating(Rating.A);
162 new HierarchyTester(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED)
163 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
164 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
165 .expectedResult(50d);
166 new HierarchyTester(CoreMetrics.NEW_SECURITY_REVIEW_RATING)
167 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
168 .expectedRating(Rating.E);
172 void computeHierarchy_shouldRecomputeSoftwareQualityMetricsCombiningOtherMetrics() {
173 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
174 .withValue(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
175 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
176 .expectedResult(25d);
177 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
178 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
179 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
180 .expectedResult(25d);
182 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
183 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
184 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
185 .expectedRating(Rating.D);
187 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
188 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
189 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
190 .expectedRating(Rating.E);
192 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
193 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d)
194 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
195 .expectedRating(Rating.A);
197 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
198 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
199 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
200 .expectedRating(Rating.D);
202 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
203 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
204 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
205 .expectedRating(Rating.E);
207 new HierarchyTester(SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A)
208 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
209 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
213 static List<Metric<?>> softwareQualityRatingMetric() {
215 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING,
216 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
217 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING,
218 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING);
221 @MethodSource("softwareQualityRatingMetric")
223 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnRating(Metric<?> ratingMetric) {
224 new HierarchyTester(ratingMetric)
226 .withChildrenValues(2d, 3d)
227 .expectedRating(Rating.C);
230 static List<Metric<?>> softwareQualitySummingMetric() {
232 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
233 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
234 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT,
235 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
236 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
237 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT);
240 @MethodSource("softwareQualitySummingMetric")
242 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnSumming(Metric<?> summingMetric) {
243 new HierarchyTester(summingMetric)
245 .withChildrenValues(2d, 3d)
250 void test_violations() {
251 withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
252 with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
255 IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
256 with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
258 // include issues on leak
259 IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
260 with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
264 void test_prioritized_rules() {
265 withNoIssues().assertThatValueIs(PRIORITIZED_RULE_ISSUES, 0);
266 with(newGroup().setPrioritizedRule(1), newGroup().setPrioritizedRule(4)).assertThatValueIs(PRIORITIZED_RULE_ISSUES, 5);
271 withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
273 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
274 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
276 newResolvedGroup(RuleType.BUG).setCount(7),
278 newGroup(RuleType.CODE_SMELL).setCount(11))
279 .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
283 void test_code_smells() {
284 withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
286 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
287 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
289 newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
291 newGroup(RuleType.BUG).setCount(11))
292 .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
296 void test_vulnerabilities() {
297 withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
299 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
300 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
302 newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
303 // not vulnerabilities
304 newGroup(RuleType.BUG).setCount(11))
305 .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
309 void test_security_hotspots() {
310 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
312 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
313 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
315 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
317 newGroup(RuleType.BUG).setCount(11))
318 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
322 void test_security_review_ratings() {
324 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
325 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
326 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B);
329 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A);
332 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
333 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true))
334 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.E);
338 void test_security_hotspots_reviewed() {
340 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
341 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
342 .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
345 .assertNoValue(SECURITY_HOTSPOTS_REVIEWED);
349 void test_security_hotspots_reviewed_status() {
351 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
352 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
353 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
356 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
360 void test_security_hotspots_to_review_status() {
362 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
363 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
364 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
367 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
371 void count_unresolved_by_severity() {
373 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
374 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
375 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
376 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
377 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
380 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
381 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
382 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
383 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
384 // exclude security hotspot
385 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
387 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
389 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
390 newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
391 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
392 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
393 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
394 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
395 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
396 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
400 void count_resolved() {
402 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
403 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0);
406 newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
407 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
408 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
409 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
410 newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
411 // exclude security hotspot
412 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
413 // exclude unresolved
414 newGroup(RuleType.VULNERABILITY).setCount(17),
415 newGroup(RuleType.BUG).setCount(19))
416 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
417 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
421 void count_by_status() {
423 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
424 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
425 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
428 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
429 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
430 newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
431 newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
432 newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
433 // exclude security hotspot
434 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
435 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
436 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
437 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
438 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
442 void test_technical_debt() {
443 withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
446 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
447 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
448 // exclude security hotspot
449 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
450 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
452 newGroup(RuleType.BUG).setEffort(7.0),
454 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
455 .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
459 void test_reliability_remediation_effort() {
460 withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
463 newGroup(RuleType.BUG).setEffort(3.0),
464 newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
466 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
468 newResolvedGroup(RuleType.BUG).setEffort(17.0))
469 .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
473 void test_security_remediation_effort() {
474 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
477 newGroup(RuleType.VULNERABILITY).setEffort(3.0),
478 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
480 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
482 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
483 .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
486 private static Stream<Arguments> maintainabilityMetrics() {
488 arguments(TECHNICAL_DEBT, SQALE_DEBT_RATIO, SQALE_RATING),
489 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
490 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
491 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
495 @MethodSource("maintainabilityMetrics")
496 void test_sqale_debt_ratio_and_sqale_rating(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> maintainabilityDebtRatioMetric,
497 Metric<?> maintainabilityRatingMetric) {
499 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
500 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
502 // technical_debt not computed
503 with(CoreMetrics.DEVELOPMENT_COST, "0")
504 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
505 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
506 with(CoreMetrics.DEVELOPMENT_COST, "20")
507 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
508 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
510 // development_cost not computed
511 with(maintainabilityRemediationEffortMetric, 0)
512 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
513 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
514 with(maintainabilityRemediationEffortMetric, 20)
515 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
516 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
518 // input measures are available
519 with(maintainabilityRemediationEffortMetric, 20.0)
520 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
521 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
522 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
524 with(maintainabilityRemediationEffortMetric, 20.0)
525 .andText(CoreMetrics.DEVELOPMENT_COST, "160")
526 .assertThatValueIs(maintainabilityDebtRatioMetric, 12.5)
527 .assertThatValueIs(maintainabilityRatingMetric, Rating.C);
529 Verifier verifier = with(maintainabilityRemediationEffortMetric, 20.0)
530 .andText(CoreMetrics.DEVELOPMENT_COST, "10")
531 .assertThatValueIs(maintainabilityDebtRatioMetric, 200.0);
532 switch (maintainabilityRatingMetric.key()) {
533 case SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, SQALE_RATING_KEY ->
534 verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.E);
535 default -> throw new IllegalArgumentException("Unexpected metric: " + maintainabilityRatingMetric.key());
538 // A is 5% --> min debt is exactly 200*0.05=10
539 with(CoreMetrics.DEVELOPMENT_COST, "200")
540 .and(maintainabilityRemediationEffortMetric, 10.0)
541 .assertThatValueIs(maintainabilityDebtRatioMetric, 5.0)
542 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
544 with(maintainabilityRemediationEffortMetric, 0.0)
545 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
546 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
547 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
549 with(maintainabilityRemediationEffortMetric, 0.0)
550 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
551 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0);
553 with(maintainabilityRemediationEffortMetric, -20.0)
554 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
555 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
556 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
558 // bug, debt can't be negative
559 with(maintainabilityRemediationEffortMetric, -20.0)
560 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
561 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
562 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
564 // bug, cost can't be negative
565 with(maintainabilityRemediationEffortMetric, 20.0)
566 .andText(CoreMetrics.DEVELOPMENT_COST, "-80")
567 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
568 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
571 private static Stream<Arguments> effortToReachAMetrics() {
573 arguments(TECHNICAL_DEBT, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A),
574 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
575 SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A));
579 @MethodSource("effortToReachAMetrics")
580 void test_effort_to_reach_maintainability_rating_A(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> effortToReachAMetric) {
582 .assertThatValueIs(effortToReachAMetric, 0.0);
584 // technical_debt not computed
585 with(CoreMetrics.DEVELOPMENT_COST, 0.0)
586 .assertThatValueIs(effortToReachAMetric, 0.0);
587 with(CoreMetrics.DEVELOPMENT_COST, 20.0)
588 .assertThatValueIs(effortToReachAMetric, 0.0);
590 // development_cost not computed
591 with(maintainabilityRemediationEffortMetric, 0.0)
592 .assertThatValueIs(effortToReachAMetric, 0.0);
593 with(maintainabilityRemediationEffortMetric, 20.0)
594 // development cost is considered as zero, so the effort is to reach... zero
595 .assertThatValueIs(effortToReachAMetric, 20.0);
598 with(CoreMetrics.DEVELOPMENT_COST, "200")
599 .and(maintainabilityRemediationEffortMetric, 40.0)
600 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
601 .assertThatValueIs(effortToReachAMetric, 40.0 - (200.0 * 0.05));
604 with(CoreMetrics.DEVELOPMENT_COST, "200")
605 .and(maintainabilityRemediationEffortMetric, 180.0)
606 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
607 .assertThatValueIs(effortToReachAMetric, 180.0 - (200.0 * 0.05));
610 with(CoreMetrics.DEVELOPMENT_COST, "200")
611 .and(maintainabilityRemediationEffortMetric, 8.0)
612 // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
613 .assertThatValueIs(effortToReachAMetric, 0.0);
615 // exactly lower range of B
616 with(CoreMetrics.DEVELOPMENT_COST, "200")
617 .and(maintainabilityRemediationEffortMetric, 10.0)
618 // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
619 // FIXME need zero to reach A but effective rating is B !
620 .assertThatValueIs(effortToReachAMetric, 0.0);
624 void test_reliability_rating() {
626 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
629 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
630 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
631 // excluded, not a bug
632 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
633 // highest severity of bugs is CRITICAL --> D
634 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
637 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
638 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
640 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
644 void test_software_quality_reliability_rating() {
646 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
649 newImpactGroup(RELIABILITY, BLOCKER, 1))
650 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
653 newImpactGroup(RELIABILITY, HIGH, 1))
654 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
657 newImpactGroup(MAINTAINABILITY, HIGH, 1),
658 newImpactGroup(RELIABILITY, MEDIUM, 1),
659 newImpactGroup(RELIABILITY, LOW, 1),
660 newImpactGroup(SECURITY, MEDIUM, 1))
661 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
664 newImpactGroup(RELIABILITY, LOW, 1))
665 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
668 newImpactGroup(RELIABILITY, INFO, 1))
669 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
673 void test_software_quality_new_reliability_rating() {
675 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
678 newImpactGroup(RELIABILITY, BLOCKER, 1, true))
679 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
682 newImpactGroup(RELIABILITY, HIGH, 1, true),
683 newImpactGroup(RELIABILITY, BLOCKER, 1, false))
684 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
687 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
688 newImpactGroup(RELIABILITY, MEDIUM, 1, true),
689 newImpactGroup(RELIABILITY, LOW, 1, true),
690 newImpactGroup(RELIABILITY, HIGH, 1, false),
691 newImpactGroup(SECURITY, HIGH, 1, true))
692 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
695 newImpactGroup(RELIABILITY, LOW, 1, true),
696 newImpactGroup(RELIABILITY, MEDIUM, 1, false))
697 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
700 newImpactGroup(RELIABILITY, INFO, 1, true),
701 newImpactGroup(RELIABILITY, MEDIUM, 1, false))
702 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
706 void test_security_rating() {
708 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
711 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
712 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
713 // excluded, not a vulnerability
714 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
715 // highest severity of vulnerabilities is CRITICAL --> D
716 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
719 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
720 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
721 // no vulnerabilities --> A
722 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
726 void test_software_quality_security_rating() {
728 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
731 newImpactGroup(SECURITY, BLOCKER, 1))
732 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
735 newImpactGroup(SECURITY, HIGH, 1))
736 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
739 newImpactGroup(MAINTAINABILITY, HIGH, 1),
740 newImpactGroup(SECURITY, MEDIUM, 1),
741 newImpactGroup(SECURITY, LOW, 1),
742 newImpactGroup(RELIABILITY, MEDIUM, 1))
743 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
746 newImpactGroup(SECURITY, LOW, 1))
747 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
750 newImpactGroup(SECURITY, INFO, 2))
751 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
755 void test_software_quality_new_security_rating() {
757 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
760 newImpactGroup(SECURITY, BLOCKER, 1, true))
761 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
764 newImpactGroup(SECURITY, HIGH, 1, true),
765 newImpactGroup(SECURITY, BLOCKER, 1, false))
766 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
769 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
770 newImpactGroup(SECURITY, MEDIUM, 1, true),
771 newImpactGroup(SECURITY, LOW, 1, true),
772 newImpactGroup(SECURITY, HIGH, 1, false),
773 newImpactGroup(RELIABILITY, HIGH, 1, true))
774 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
777 newImpactGroup(SECURITY, LOW, 1, true),
778 newImpactGroup(SECURITY, MEDIUM, 1, false))
779 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
782 newImpactGroup(SECURITY, INFO, 1, true),
783 newImpactGroup(SECURITY, MEDIUM, 1, false))
784 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
788 void test_new_bugs() {
789 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
792 newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
793 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
794 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
796 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
797 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
798 .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
803 void test_new_code_smells() {
804 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
807 newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
808 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
809 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
811 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
812 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
813 .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
817 void test_new_vulnerabilities() {
818 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
821 newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
822 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
823 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
824 // not vulnerabilities
825 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
826 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
827 .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
831 void test_new_security_hotspots() {
832 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0);
835 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
836 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
837 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
839 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
840 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
841 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
845 void test_new_violations() {
846 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
849 newGroup(RuleType.BUG).setInLeak(true).setCount(5),
850 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
851 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
853 newGroup(RuleType.BUG).setInLeak(false).setCount(11),
854 newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
855 newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
856 .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
860 void test_new_blocker_violations() {
862 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
865 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
866 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
867 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
869 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
871 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
872 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
873 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
877 void test_new_critical_violations() {
879 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
882 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
883 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
884 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
886 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
888 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
889 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
890 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
894 void test_new_major_violations() {
896 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
899 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
900 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
901 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
903 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
905 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
906 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
907 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
911 void test_new_minor_violations() {
913 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
916 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
917 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
918 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
920 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
922 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
923 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
924 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
928 void test_new_info_violations() {
930 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
933 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
934 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
935 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
937 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
939 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
940 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
941 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
945 void test_new_accepted_issues() {
947 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0);
950 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(3),
951 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(4),
952 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(30),
953 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(40),
955 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(5),
956 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(50))
957 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
961 void test_new_technical_debt() {
962 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
965 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
967 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
969 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
970 newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
972 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
973 .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
977 void test_new_reliability_remediation_effort() {
978 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
981 newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
983 newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
985 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
987 newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
988 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
992 void test_new_security_remediation_effort() {
993 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
996 newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
998 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
1000 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
1002 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
1003 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
1007 void test_new_reliability_rating() {
1008 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
1011 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
1012 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
1014 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
1016 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
1018 newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
1019 // highest severity of bugs on leak period is minor -> B
1020 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
1024 void test_new_security_rating() {
1025 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
1028 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
1029 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
1031 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
1032 // not vulnerability
1033 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
1035 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
1036 // highest severity of bugs on leak period is minor -> B
1037 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
1041 void test_new_security_review_rating() {
1043 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1044 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1046 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
1047 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B);
1050 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A);
1053 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
1054 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1056 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
1057 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.E);
1061 void test_new_security_hotspots_reviewed() {
1063 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1064 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1066 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1067 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
1070 .assertNoLeakValue(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED);
1074 void test_new_security_hotspots_reviewed_status() {
1076 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1077 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1079 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1080 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
1083 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
1087 void test_new_security_hotspots_to_review_status() {
1089 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1090 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1092 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1093 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
1096 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
1099 private static Stream<Arguments> newMaintainabilityMetrics() {
1101 arguments(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_SQALE_DEBT_RATIO, CoreMetrics.NEW_MAINTAINABILITY_RATING),
1102 arguments(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
1103 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
1104 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
1108 @MethodSource("newMaintainabilityMetrics")
1109 void test_new_sqale_debt_ratio_and_new_maintainability_rating(Metric<?> newMaintainabilityRemediationEffortMetric,
1110 Metric<?> newMaintainabilityDebtRatioMetric,
1111 Metric<?> newMaintainabilityRatingMetric) {
1113 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1114 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1116 // technical_debt not computed
1117 with(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
1118 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1119 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1120 with(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
1121 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1122 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1124 // development_cost not computed
1125 with(newMaintainabilityRemediationEffortMetric, 0)
1126 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1127 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1128 with(newMaintainabilityRemediationEffortMetric, 20)
1129 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1130 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1132 // input measures are available
1133 with(newMaintainabilityRemediationEffortMetric, 20.0)
1134 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1135 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1136 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1138 with(newMaintainabilityRemediationEffortMetric, 20.0)
1139 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
1140 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 12.5)
1141 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.C);
1143 Verifier verifier = with(newMaintainabilityRemediationEffortMetric, 20.0)
1144 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0D)
1145 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 200.0);
1146 switch (newMaintainabilityRatingMetric.key()) {
1147 case NEW_MAINTAINABILITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY ->
1148 verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.E);
1149 default -> throw new IllegalArgumentException("Unexpected metric: " + newMaintainabilityRatingMetric.key());
1152 // A is 5% --> min debt is exactly 200*0.05=10
1153 with(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
1154 .and(newMaintainabilityRemediationEffortMetric, 10.0)
1155 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 5.0)
1156 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1158 with(newMaintainabilityRemediationEffortMetric, 0.0)
1159 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1160 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1161 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1163 with(newMaintainabilityRemediationEffortMetric, 0.0)
1164 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1165 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0);
1167 with(newMaintainabilityRemediationEffortMetric, -20.0)
1168 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1169 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1170 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1172 // bug, debt can't be negative
1173 with(newMaintainabilityRemediationEffortMetric, -20.0)
1174 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1175 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1176 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1178 // bug, cost can't be negative
1179 with(newMaintainabilityRemediationEffortMetric, 20.0)
1180 .and(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
1181 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1182 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1186 void compute_shouldComputeHighImpactAcceptedIssues() {
1188 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
1191 newImpactGroup(RELIABILITY, HIGH, 3),
1192 newImpactGroup(RELIABILITY, MEDIUM, 4),
1193 newImpactGroup(RELIABILITY, LOW, 1),
1194 newImpactGroup(SECURITY, HIGH, 3),
1195 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4),
1196 newImpactGroup(SECURITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 5),
1197 newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
1198 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
1199 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8),
1200 newImpactGroup(RELIABILITY, BLOCKER, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 2))
1201 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8 + 2);
1205 void compute_shouldComputeCountPerImpactSeverityOnOverallCode() {
1207 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES, 0)
1208 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES, 0)
1209 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES, 0)
1210 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES, 0)
1211 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES, 0);
1214 newImpactSeverityGroup(HIGH, 3),
1215 newImpactSeverityGroup(MEDIUM, 4),
1216 newImpactSeverityGroup(LOW, 1),
1217 newImpactSeverityGroup(LOW, 1),
1218 newImpactSeverityGroup(BLOCKER, 7),
1219 newImpactSeverityGroup(INFO, 12),
1220 newImpactSeverityGroup(INFO, 3),
1222 // Should not be counted due to status
1223 newImpactSeverityGroup(HIGH, Issue.STATUS_RESOLVED, 4),
1224 newImpactSeverityGroup(BLOCKER, Issue.STATUS_RESOLVED, 4),
1225 newImpactSeverityGroup(BLOCKER, Issue.STATUS_RESOLVED, 4))
1227 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_BLOCKER_ISSUES, 7)
1228 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_HIGH_ISSUES, 3)
1229 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MEDIUM_ISSUES, 4)
1230 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_LOW_ISSUES, 1 + 1)
1231 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_INFO_ISSUES, 12 + 3)
1236 void compute_shouldComputeCountPerImpactSeverityOnNewCode() {
1238 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES, 0)
1239 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES, 0)
1240 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES, 0)
1241 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES, 0)
1242 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES, 0);
1245 newImpactSeverityGroup(HIGH, 3, true),
1246 newImpactSeverityGroup(MEDIUM, 4, true),
1247 newImpactSeverityGroup(LOW, 1, true),
1248 newImpactSeverityGroup(LOW, 1, true),
1249 newImpactSeverityGroup(BLOCKER, 7, true),
1250 newImpactSeverityGroup(INFO, 12, true),
1251 newImpactSeverityGroup(INFO, 3, true),
1253 // Should not be counted due to status
1254 newImpactSeverityGroup(HIGH, Issue.RESOLUTION_WONT_FIX, 4, true),
1255 newImpactSeverityGroup(BLOCKER, Issue.RESOLUTION_WONT_FIX, 4, true),
1256 newImpactSeverityGroup(BLOCKER, Issue.RESOLUTION_FALSE_POSITIVE, 4, true),
1258 //Should not be counted because on overall code
1259 newImpactSeverityGroup(BLOCKER, 7, false))
1261 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_BLOCKER_ISSUES, 7)
1262 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_HIGH_ISSUES, 3)
1263 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MEDIUM_ISSUES, 4)
1264 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_LOW_ISSUES, 1 + 1)
1265 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_INFO_ISSUES, 12 + 3)
1270 void compute_shouldComputeCountPerSoftwareQualityOnOverallCode() {
1272 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 0)
1273 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES, 0)
1274 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES, 0);
1277 newImpactGroup(RELIABILITY, HIGH, 3),
1278 newImpactGroup(RELIABILITY, MEDIUM, 1, true),
1279 newImpactGroup(SECURITY, MEDIUM, 1),
1280 newImpactGroup(MAINTAINABILITY, MEDIUM, 1),
1281 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
1282 // Should not count due to status
1283 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
1284 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1285 newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
1287 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 1 + 1)
1288 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_ISSUES, 3 + 1)
1289 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_ISSUES, 1)
1294 void compute_shouldComputeCountPerSoftwareQualityOnNewCode() {
1296 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 0)
1297 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES, 0)
1298 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES, 0);
1301 newImpactGroup(RELIABILITY, HIGH, 3, true),
1302 newImpactGroup(RELIABILITY, MEDIUM, 1, true),
1303 newImpactGroup(SECURITY, MEDIUM, 1, true),
1304 newImpactGroup(SECURITY, MEDIUM, 12, true),
1305 newImpactGroup(MAINTAINABILITY, MEDIUM, 1, true),
1306 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
1307 // Should not count due to status
1308 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
1309 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1310 newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1311 // Should not be counted because on overall code
1312 newImpactGroup(MAINTAINABILITY, MEDIUM, 1, false))
1314 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_ISSUES, 1 + 1)
1315 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_ISSUES, 3 + 1)
1316 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_ISSUES, 1 + 12)
1321 void compute_shouldComputeRemediationEffortBasedOnSoftwareQuality() {
1323 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0)
1324 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0)
1325 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0)
1326 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0d)
1327 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0d)
1328 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1331 newImpactGroup(RELIABILITY, HIGH, 3, 1d),
1332 newImpactGroup(RELIABILITY, MEDIUM, 1, 2d, true),
1333 newImpactGroup(SECURITY, MEDIUM, 1, 1d),
1334 newImpactGroup(MAINTAINABILITY, MEDIUM, 1, 1d),
1335 newImpactGroup(MAINTAINABILITY, HIGH, 1, 2d, true),
1336 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
1337 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1338 newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
1339 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d + 2d)
1340 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 1d + 2d)
1341 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 1d)
1342 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 2d)
1343 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 2d)
1344 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1348 void computeHierarchy_shouldComputeImpactMeasures() {
1349 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1350 .withValue(impactMeasureToJson(6, 1, 2, 3))
1351 .withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2))
1352 .expectedJsonResult(impactMeasureToJson(22, 7, 7, 8));
1354 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1355 .withValue(impactMeasureToJson(6, 1, 2, 3))
1356 .expectedJsonResult(impactMeasureToJson(6, 1, 2, 3));
1360 void compute_shouldComputeImpactMeasures() {
1362 newImpactGroup(RELIABILITY, HIGH, 3),
1363 newImpactGroup(RELIABILITY, MEDIUM, 4),
1364 newImpactGroup(RELIABILITY, LOW, 1),
1365 newImpactGroup(MAINTAINABILITY, MEDIUM, 10),
1366 newImpactGroup(MAINTAINABILITY, LOW, 11),
1367 newImpactGroup(SECURITY, HIGH, 3))
1368 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
1369 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
1370 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
1374 void compute_whenNoIssues_shouldComputeImpactMeasures() {
1376 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1377 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1378 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1379 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1380 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1381 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0));
1384 private static String impactMeasureToJson(long total, long high, long medium, long low) {
1385 return GSON.toJson(Map.of("total", total, "HIGH", high, "MEDIUM", medium, "LOW", low));
1388 private Verifier with(IssueGroupDto... groups) {
1389 return new Verifier(groups);
1392 private Verifier with(IssueImpactGroupDto... groups) {
1393 return new Verifier(groups);
1396 private Verifier with(IssueImpactSeverityGroupDto... groups) {
1397 return new Verifier(groups);
1400 private Verifier withNoIssues() {
1401 return new Verifier(new IssueGroupDto[0]);
1404 private Verifier with(Metric metric, double value) {
1405 return new Verifier(new IssueGroupDto[0]).and(metric, value);
1408 private Verifier with(Metric metric, String value) {
1409 return new Verifier(new IssueGroupDto[0]).andText(metric, value);
1412 private class Verifier {
1413 private IssueGroupDto[] groups = {};
1414 private IssueImpactGroupDto[] impactGroups = {};
1415 private IssueImpactSeverityGroupDto[] impactSeverityGroups = {};
1416 private final InitialValues initialValues = new InitialValues();
1418 private Verifier(IssueGroupDto[] groups) {
1419 this.groups = groups;
1422 private Verifier(IssueImpactGroupDto[] impactGroups) {
1423 this.impactGroups = impactGroups;
1426 private Verifier(IssueImpactSeverityGroupDto[] impactSeverityGroups) {
1427 this.impactSeverityGroups = impactSeverityGroups;
1430 Verifier and(Metric metric, double value) {
1431 this.initialValues.values.put(metric, value);
1435 Verifier andText(Metric metric, String value) {
1436 this.initialValues.textValues.put(metric, value);
1440 Verifier assertThatValueIs(Metric metric, double expectedValue) {
1441 TestContext context = run(metric, false);
1442 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1446 Verifier assertThatJsonValueIs(Metric metric, String expectedValue) {
1447 TestContext context = run(metric, false);
1448 assertJson(context.stringValue).isSimilarTo(expectedValue);
1452 Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
1453 TestContext context = run(metric, true);
1454 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1458 Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
1459 TestContext context = run(metric, true);
1460 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedRating);
1464 Verifier assertThatLeakValueIs(Metric metric, String expectedValue) {
1465 TestContext context = run(metric, true);
1466 assertJson(context.stringValue).isSimilarTo(expectedValue);
1470 Verifier assertNoLeakValue(Metric metric) {
1471 TestContext context = run(metric, true);
1472 assertThat(context.ratingValue).isNull();
1476 Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
1477 TestContext context = run(metric, false);
1478 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
1482 Verifier assertNoValue(Metric metric) {
1483 TestContext context = run(metric, false);
1484 assertThat(context.ratingValue).isNull();
1488 private TestContext run(Metric metric, boolean expectLeakFormula) {
1489 MeasureUpdateFormula formula = underTest.getFormulas().stream()
1490 .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
1493 assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
1494 TestContext context = new TestContext(formula.getDependentMetrics(), initialValues);
1495 formula.compute(context, newIssueCounter(groups, impactGroups, impactSeverityGroups));
1500 private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups,
1501 IssueImpactSeverityGroupDto[] impactSeverityGroups) {
1502 return new IssueCounter(asList(groups), asList(impactGroups), asList(impactSeverityGroups));
1505 private static IssueGroupDto newGroup() {
1506 return newGroup(RuleType.CODE_SMELL);
1509 private static IssueGroupDto newGroup(RuleType ruleType) {
1510 IssueGroupDto dto = new IssueGroupDto();
1511 // set non-null fields
1512 dto.setRuleType(ruleType.getDbConstant());
1515 dto.setSeverity(Severity.INFO);
1516 dto.setStatus(Issue.STATUS_OPEN);
1517 dto.setInLeak(false);
1521 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1522 String status, @Nullable String resolution, long count, double effort, boolean inLeak) {
1523 IssueImpactGroupDto dto = new IssueImpactGroupDto();
1524 dto.setSoftwareQuality(softwareQuality);
1525 dto.setSeverity(severity);
1526 dto.setStatus(status);
1527 dto.setResolution(resolution);
1528 dto.setCount(count);
1529 dto.setEffort(effort);
1530 dto.setInLeak(inLeak);
1534 private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity,
1535 @Nullable String resolution, long count, boolean inLeak) {
1536 IssueImpactSeverityGroupDto dto = new IssueImpactSeverityGroupDto();
1537 dto.setSeverity(severity);
1538 dto.setResolution(resolution);
1539 dto.setCount(count);
1540 dto.setInLeak(inLeak);
1544 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1545 String status, @Nullable String resolution, long count) {
1546 return newImpactGroup(softwareQuality, severity, status, resolution, count, 0, false);
1549 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1551 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, false);
1554 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1555 long count, boolean inLeak) {
1556 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, inLeak);
1559 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1560 long count, double effort) {
1561 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, false);
1564 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1565 long count, double effort, boolean inLeak) {
1566 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, inLeak);
1569 private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity, long count) {
1570 return newImpactSeverityGroup(severity, null, count, false);
1573 private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity, long count,
1575 return newImpactSeverityGroup(severity, null, count, inLeak);
1578 private static IssueImpactSeverityGroupDto newImpactSeverityGroup(org.sonar.api.issue.impact.Severity severity,
1579 @Nullable String resolution, long count) {
1580 return newImpactSeverityGroup(severity, resolution, count, false);
1583 private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
1584 return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
1587 private static IssueGroupDto newResolvedGroup(String resolution, String status) {
1588 return newGroup().setResolution(resolution).setStatus(status);
1591 private static class TestContext implements MeasureUpdateFormula.Context {
1592 private final Set<Metric> dependentMetrics;
1593 private final InitialValues initialValues;
1594 private Double doubleValue;
1595 private Rating ratingValue;
1596 private String stringValue;
1598 private TestContext(Collection<Metric> dependentMetrics, InitialValues initialValues) {
1599 this.dependentMetrics = new HashSet<>(dependentMetrics);
1600 this.initialValues = initialValues;
1604 public List<Double> getChildrenValues() {
1605 return initialValues.childrenValues;
1609 public List<String> getChildrenTextValues() {
1610 return initialValues.childrenTextValues;
1614 public long getChildrenHotspotsReviewed() {
1615 return initialValues.childrenHotspotsReviewed;
1619 public long getChildrenHotspotsToReview() {
1620 return initialValues.childrenHotspotsToReview;
1624 public long getChildrenNewHotspotsReviewed() {
1625 return initialValues.childrenNewHotspotsReviewed;
1629 public long getChildrenNewHotspotsToReview() {
1630 return initialValues.childrenNewHotspotsToReview;
1634 public ComponentDto getComponent() {
1635 throw new UnsupportedOperationException();
1639 public DebtRatingGrid getDebtRatingGrid() {
1640 return new DebtRatingGrid(new double[]{0.05, 0.1, 0.2, 0.5});
1644 public Optional<Double> getValue(Metric metric) {
1645 if (!dependentMetrics.contains(metric)) {
1646 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
1648 if (initialValues.values.containsKey(metric)) {
1649 return Optional.of(initialValues.values.get(metric));
1651 return Optional.empty();
1655 public Optional<String> getText(Metric metric) {
1656 if (initialValues.textValues.containsKey(metric)) {
1657 return Optional.of(initialValues.textValues.get(metric));
1659 return Optional.empty();
1663 public void setValue(double value) {
1664 this.doubleValue = value;
1668 public void setValue(Rating value) {
1669 this.ratingValue = value;
1673 public void setValue(String value) {
1674 this.stringValue = value;
1678 private class InitialValues {
1679 private final Map<Metric, Double> values = new HashMap<>();
1680 private final List<Double> childrenValues = new ArrayList<>();
1681 private final Map<Metric, String> textValues = new HashMap<>();
1682 private final List<String> childrenTextValues = new ArrayList<>();
1683 private long childrenHotspotsReviewed = 0;
1684 private long childrenNewHotspotsReviewed = 0;
1685 private long childrenHotspotsToReview = 0;
1686 private long childrenNewHotspotsToReview = 0;
1690 private class HierarchyTester {
1691 private final Metric metric;
1692 private final InitialValues initialValues;
1693 private final MeasureUpdateFormula formula;
1695 public HierarchyTester(Metric metric) {
1696 this.metric = metric;
1697 this.initialValues = new InitialValues();
1698 this.formula = underTest.getFormulas().stream().filter(f -> f.getMetric().equals(metric)).findAny().get();
1701 public HierarchyTester withValue(Metric metric, Double value) {
1702 this.initialValues.values.put(metric, value);
1706 public HierarchyTester withValue(Metric metric, String value) {
1707 this.initialValues.textValues.put(metric, value);
1711 public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed,
1712 long childrenHotspotsToReview,
1713 long childrenNewHotspotsToReview) {
1714 this.initialValues.childrenHotspotsReviewed = childrenHotspotsReviewed;
1715 this.initialValues.childrenNewHotspotsReviewed = childrenNewHotspotsReviewed;
1716 this.initialValues.childrenHotspotsToReview = childrenHotspotsToReview;
1717 this.initialValues.childrenNewHotspotsToReview = childrenNewHotspotsToReview;
1721 public HierarchyTester withValue(Double value) {
1722 return withValue(metric, value);
1725 public HierarchyTester withValue(String value) {
1726 return withValue(metric, value);
1729 public HierarchyTester withChildrenValues(Double... values) {
1730 this.initialValues.childrenValues.addAll(asList(values));
1734 public HierarchyTester withChildrenValues(String... values) {
1735 this.initialValues.childrenTextValues.addAll(asList(values));
1739 public HierarchyTester expectedResult(@Nullable Double expected) {
1740 TestContext ctx = run();
1741 assertThat(ctx.doubleValue).isEqualTo(expected);
1745 public HierarchyTester expectedJsonResult(@Nullable String expected) {
1746 TestContext ctx = run();
1747 assertJson(ctx.stringValue).isSimilarTo(expected);
1751 public HierarchyTester expectedRating(@Nullable Rating rating) {
1752 TestContext ctx = run();
1753 assertThat(ctx.ratingValue).isEqualTo(rating);
1757 private TestContext run() {
1758 List<Metric> deps = new LinkedList<>(formula.getDependentMetrics());
1759 deps.add(formula.getMetric());
1760 deps.addAll(initialValues.values.keySet());
1761 deps.addAll(initialValues.textValues.keySet());
1762 TestContext context = new TestContext(deps, initialValues);
1763 formula.computeHierarchy(context);