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.server.measure.DebtRatingGrid;
50 import org.sonar.server.measure.Rating;
52 import static java.util.Arrays.asList;
53 import static org.assertj.core.api.Assertions.assertThat;
54 import static org.junit.jupiter.params.provider.Arguments.arguments;
55 import static org.sonar.api.issue.impact.Severity.BLOCKER;
56 import static org.sonar.api.issue.impact.Severity.HIGH;
57 import static org.sonar.api.issue.impact.Severity.INFO;
58 import static org.sonar.api.issue.impact.Severity.LOW;
59 import static org.sonar.api.issue.impact.Severity.MEDIUM;
60 import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
61 import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
62 import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
63 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A;
64 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
65 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
66 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS;
67 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
68 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING;
69 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
70 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
71 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
72 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
73 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO;
74 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING;
75 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
76 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT;
77 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT;
78 import static org.sonar.server.metric.IssueCountMetrics.PRIORITIZED_RULE_ISSUES;
79 import static org.sonar.test.JsonAssert.assertJson;
81 class MeasureUpdateFormulaFactoryImplTest {
83 private static final Gson GSON = new GsonBuilder().create();
84 private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl();
87 void getFormulaMetrics_include_the_dependent_metrics() {
88 for (MeasureUpdateFormula formula : underTest.getFormulas()) {
89 assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
90 for (Metric<?> dependentMetric : formula.getDependentMetrics()) {
91 assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
97 void hierarchy_adding_numbers() {
98 new HierarchyTester(CoreMetrics.VIOLATIONS)
100 .withChildrenValues(2d, 3d)
103 new HierarchyTester(CoreMetrics.BUGS)
105 .withChildrenValues(2d, 3d)
108 new HierarchyTester(CoreMetrics.NEW_BUGS)
114 void hierarchy_highest_rating() {
115 new HierarchyTester(CoreMetrics.RELIABILITY_RATING)
117 .withChildrenValues(2d, 3d)
118 .expectedRating(Rating.C);
120 // if no children, no need to set a value
121 new HierarchyTester(CoreMetrics.SECURITY_RATING)
123 .expectedResult(null);
125 new HierarchyTester(CoreMetrics.NEW_RELIABILITY_RATING)
127 .withChildrenValues(2d, 3d)
128 .expectedRating(Rating.E);
132 void hierarchy_combining_other_metrics() {
133 new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
134 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
135 .withChildrenHotspotsCounts(10, 10, 2, 10)
138 new HierarchyTester(SECURITY_HOTSPOTS_REVIEWED_STATUS)
139 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
140 .withChildrenHotspotsCounts(2, 10, 10, 10)
143 new HierarchyTester(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
144 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
145 .withChildrenHotspotsCounts(10, 10, 10, 2)
148 new HierarchyTester(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
149 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
150 .withChildrenHotspotsCounts(10, 2, 10, 10)
153 new HierarchyTester(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED)
154 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
155 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
156 .expectedResult(50d);
157 new HierarchyTester(CoreMetrics.SECURITY_REVIEW_RATING)
158 .withValue(SECURITY_HOTSPOTS_REVIEWED, 100d)
159 .expectedRating(Rating.A);
161 new HierarchyTester(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED)
162 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
163 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
164 .expectedResult(50d);
165 new HierarchyTester(CoreMetrics.NEW_SECURITY_REVIEW_RATING)
166 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
167 .expectedRating(Rating.E);
171 void computeHierarchy_shouldRecomputeSoftwareQualityMetricsCombiningOtherMetrics() {
172 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
173 .withValue(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
174 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
175 .expectedResult(25d);
176 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
177 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
178 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
179 .expectedResult(25d);
181 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
182 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
183 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
184 .expectedRating(Rating.D);
186 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
187 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
188 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
189 .expectedRating(Rating.E);
191 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
192 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d)
193 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
194 .expectedRating(Rating.A);
196 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
197 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
198 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
199 .expectedRating(Rating.D);
201 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
202 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 21d)
203 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
204 .expectedRating(Rating.E);
206 new HierarchyTester(SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A)
207 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
208 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
212 static List<Metric<?>> softwareQualityRatingMetric() {
214 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING,
215 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
216 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING,
217 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING);
220 @MethodSource("softwareQualityRatingMetric")
222 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnRating(Metric<?> ratingMetric) {
223 new HierarchyTester(ratingMetric)
225 .withChildrenValues(2d, 3d)
226 .expectedRating(Rating.C);
229 static List<Metric<?>> softwareQualitySummingMetric() {
231 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
232 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
233 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT,
234 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
235 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
236 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT);
239 @MethodSource("softwareQualitySummingMetric")
241 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnSumming(Metric<?> summingMetric) {
242 new HierarchyTester(summingMetric)
244 .withChildrenValues(2d, 3d)
249 void test_violations() {
250 withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
251 with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
254 IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
255 with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
257 // include issues on leak
258 IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
259 with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
263 void test_prioritized_rules() {
264 withNoIssues().assertThatValueIs(PRIORITIZED_RULE_ISSUES, 0);
265 with(newGroup().setPrioritizedRule(1), newGroup().setPrioritizedRule(4)).assertThatValueIs(PRIORITIZED_RULE_ISSUES, 5);
270 withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
272 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
273 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
275 newResolvedGroup(RuleType.BUG).setCount(7),
277 newGroup(RuleType.CODE_SMELL).setCount(11))
278 .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
282 void test_code_smells() {
283 withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
285 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
286 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
288 newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
290 newGroup(RuleType.BUG).setCount(11))
291 .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
295 void test_vulnerabilities() {
296 withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
298 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
299 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
301 newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
302 // not vulnerabilities
303 newGroup(RuleType.BUG).setCount(11))
304 .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
308 void test_security_hotspots() {
309 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
311 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
312 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
314 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
316 newGroup(RuleType.BUG).setCount(11))
317 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
321 void test_security_review_ratings() {
323 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
324 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
325 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B);
328 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A);
331 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
332 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true))
333 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.E);
337 void test_security_hotspots_reviewed() {
339 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
340 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
341 .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
344 .assertNoValue(SECURITY_HOTSPOTS_REVIEWED);
348 void test_security_hotspots_reviewed_status() {
350 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
351 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
352 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
355 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
359 void test_security_hotspots_to_review_status() {
361 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
362 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
363 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
366 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
370 void count_unresolved_by_severity() {
372 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
373 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
374 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
375 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
376 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
379 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
380 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
381 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
382 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
383 // exclude security hotspot
384 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
386 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
388 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
389 newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
390 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
391 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
392 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
393 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
394 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
395 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
399 void count_resolved() {
401 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
402 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0);
405 newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
406 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
407 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
408 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
409 newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
410 // exclude security hotspot
411 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
412 // exclude unresolved
413 newGroup(RuleType.VULNERABILITY).setCount(17),
414 newGroup(RuleType.BUG).setCount(19))
415 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
416 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
420 void count_by_status() {
422 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
423 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
424 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
427 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
428 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
429 newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
430 newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
431 newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
432 // exclude security hotspot
433 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
434 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
435 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
436 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
437 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
441 void test_technical_debt() {
442 withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
445 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
446 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
447 // exclude security hotspot
448 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
449 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
451 newGroup(RuleType.BUG).setEffort(7.0),
453 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
454 .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
458 void test_reliability_remediation_effort() {
459 withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
462 newGroup(RuleType.BUG).setEffort(3.0),
463 newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
465 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
467 newResolvedGroup(RuleType.BUG).setEffort(17.0))
468 .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
472 void test_security_remediation_effort() {
473 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
476 newGroup(RuleType.VULNERABILITY).setEffort(3.0),
477 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
479 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
481 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
482 .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
485 private static Stream<Arguments> maintainabilityMetrics() {
487 arguments(TECHNICAL_DEBT, SQALE_DEBT_RATIO, SQALE_RATING),
488 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
489 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
490 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
494 @MethodSource("maintainabilityMetrics")
495 void test_sqale_debt_ratio_and_sqale_rating(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> maintainabilityDebtRatioMetric,
496 Metric<?> maintainabilityRatingMetric) {
498 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
499 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
501 // technical_debt not computed
502 with(CoreMetrics.DEVELOPMENT_COST, "0")
503 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
504 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
505 with(CoreMetrics.DEVELOPMENT_COST, "20")
506 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
507 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
509 // development_cost not computed
510 with(maintainabilityRemediationEffortMetric, 0)
511 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
512 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
513 with(maintainabilityRemediationEffortMetric, 20)
514 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
515 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
517 // input measures are available
518 with(maintainabilityRemediationEffortMetric, 20.0)
519 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
520 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
521 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
523 with(maintainabilityRemediationEffortMetric, 20.0)
524 .andText(CoreMetrics.DEVELOPMENT_COST, "160")
525 .assertThatValueIs(maintainabilityDebtRatioMetric, 12.5)
526 .assertThatValueIs(maintainabilityRatingMetric, Rating.C);
528 Verifier verifier = with(maintainabilityRemediationEffortMetric, 20.0)
529 .andText(CoreMetrics.DEVELOPMENT_COST, "10")
530 .assertThatValueIs(maintainabilityDebtRatioMetric, 200.0);
531 switch (maintainabilityRatingMetric.key()) {
532 case SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY, SQALE_RATING_KEY ->
533 verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.E);
534 default -> throw new IllegalArgumentException("Unexpected metric: " + maintainabilityRatingMetric.key());
537 // A is 5% --> min debt is exactly 200*0.05=10
538 with(CoreMetrics.DEVELOPMENT_COST, "200")
539 .and(maintainabilityRemediationEffortMetric, 10.0)
540 .assertThatValueIs(maintainabilityDebtRatioMetric, 5.0)
541 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
543 with(maintainabilityRemediationEffortMetric, 0.0)
544 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
545 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
546 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
548 with(maintainabilityRemediationEffortMetric, 0.0)
549 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
550 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0);
552 with(maintainabilityRemediationEffortMetric, -20.0)
553 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
554 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
555 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
557 // bug, debt can't be negative
558 with(maintainabilityRemediationEffortMetric, -20.0)
559 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
560 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
561 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
563 // bug, cost can't be negative
564 with(maintainabilityRemediationEffortMetric, 20.0)
565 .andText(CoreMetrics.DEVELOPMENT_COST, "-80")
566 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
567 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
570 private static Stream<Arguments> effortToReachAMetrics() {
572 arguments(TECHNICAL_DEBT, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A),
573 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
574 SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A));
578 @MethodSource("effortToReachAMetrics")
579 void test_effort_to_reach_maintainability_rating_A(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> effortToReachAMetric) {
581 .assertThatValueIs(effortToReachAMetric, 0.0);
583 // technical_debt not computed
584 with(CoreMetrics.DEVELOPMENT_COST, 0.0)
585 .assertThatValueIs(effortToReachAMetric, 0.0);
586 with(CoreMetrics.DEVELOPMENT_COST, 20.0)
587 .assertThatValueIs(effortToReachAMetric, 0.0);
589 // development_cost not computed
590 with(maintainabilityRemediationEffortMetric, 0.0)
591 .assertThatValueIs(effortToReachAMetric, 0.0);
592 with(maintainabilityRemediationEffortMetric, 20.0)
593 // development cost is considered as zero, so the effort is to reach... zero
594 .assertThatValueIs(effortToReachAMetric, 20.0);
597 with(CoreMetrics.DEVELOPMENT_COST, "200")
598 .and(maintainabilityRemediationEffortMetric, 40.0)
599 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
600 .assertThatValueIs(effortToReachAMetric, 40.0 - (200.0 * 0.05));
603 with(CoreMetrics.DEVELOPMENT_COST, "200")
604 .and(maintainabilityRemediationEffortMetric, 180.0)
605 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
606 .assertThatValueIs(effortToReachAMetric, 180.0 - (200.0 * 0.05));
609 with(CoreMetrics.DEVELOPMENT_COST, "200")
610 .and(maintainabilityRemediationEffortMetric, 8.0)
611 // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
612 .assertThatValueIs(effortToReachAMetric, 0.0);
614 // exactly lower range of B
615 with(CoreMetrics.DEVELOPMENT_COST, "200")
616 .and(maintainabilityRemediationEffortMetric, 10.0)
617 // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
618 // FIXME need zero to reach A but effective rating is B !
619 .assertThatValueIs(effortToReachAMetric, 0.0);
623 void test_reliability_rating() {
625 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
628 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
629 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
630 // excluded, not a bug
631 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
632 // highest severity of bugs is CRITICAL --> D
633 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
636 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
637 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
639 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
643 void test_software_quality_reliability_rating() {
645 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
648 newImpactGroup(RELIABILITY, BLOCKER, 1))
649 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
652 newImpactGroup(RELIABILITY, HIGH, 1))
653 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
656 newImpactGroup(MAINTAINABILITY, HIGH, 1),
657 newImpactGroup(RELIABILITY, MEDIUM, 1),
658 newImpactGroup(RELIABILITY, LOW, 1),
659 newImpactGroup(SECURITY, MEDIUM, 1))
660 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
663 newImpactGroup(RELIABILITY, LOW, 1))
664 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
667 newImpactGroup(RELIABILITY, INFO, 1))
668 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
672 void test_software_quality_new_reliability_rating() {
674 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
677 newImpactGroup(RELIABILITY, BLOCKER, 1, true))
678 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.E);
681 newImpactGroup(RELIABILITY, HIGH, 1, true),
682 newImpactGroup(RELIABILITY, BLOCKER, 1, false))
683 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.D);
686 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
687 newImpactGroup(RELIABILITY, MEDIUM, 1, true),
688 newImpactGroup(RELIABILITY, LOW, 1, true),
689 newImpactGroup(RELIABILITY, HIGH, 1, false),
690 newImpactGroup(SECURITY, HIGH, 1, true))
691 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
694 newImpactGroup(RELIABILITY, LOW, 1, true),
695 newImpactGroup(RELIABILITY, MEDIUM, 1, false))
696 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
699 newImpactGroup(RELIABILITY, INFO, 1, true),
700 newImpactGroup(RELIABILITY, MEDIUM, 1, false))
701 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
705 void test_security_rating() {
707 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
710 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
711 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
712 // excluded, not a vulnerability
713 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
714 // highest severity of vulnerabilities is CRITICAL --> D
715 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
718 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
719 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
720 // no vulnerabilities --> A
721 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
725 void test_software_quality_security_rating() {
727 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
730 newImpactGroup(SECURITY, BLOCKER, 1))
731 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
734 newImpactGroup(SECURITY, HIGH, 1))
735 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
738 newImpactGroup(MAINTAINABILITY, HIGH, 1),
739 newImpactGroup(SECURITY, MEDIUM, 1),
740 newImpactGroup(SECURITY, LOW, 1),
741 newImpactGroup(RELIABILITY, MEDIUM, 1))
742 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
745 newImpactGroup(SECURITY, LOW, 1))
746 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
749 newImpactGroup(SECURITY, INFO, 2))
750 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
754 void test_software_quality_new_security_rating() {
756 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
759 newImpactGroup(SECURITY, BLOCKER, 1, true))
760 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.E);
763 newImpactGroup(SECURITY, HIGH, 1, true),
764 newImpactGroup(SECURITY, BLOCKER, 1, false))
765 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.D);
768 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
769 newImpactGroup(SECURITY, MEDIUM, 1, true),
770 newImpactGroup(SECURITY, LOW, 1, true),
771 newImpactGroup(SECURITY, HIGH, 1, false),
772 newImpactGroup(RELIABILITY, HIGH, 1, true))
773 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
776 newImpactGroup(SECURITY, LOW, 1, true),
777 newImpactGroup(SECURITY, MEDIUM, 1, false))
778 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
781 newImpactGroup(SECURITY, INFO, 1, true),
782 newImpactGroup(SECURITY, MEDIUM, 1, false))
783 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
787 void test_new_bugs() {
788 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
791 newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
792 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
793 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
795 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
796 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
797 .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
802 void test_new_code_smells() {
803 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
806 newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
807 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
808 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
810 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
811 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
812 .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
816 void test_new_vulnerabilities() {
817 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
820 newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
821 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
822 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
823 // not vulnerabilities
824 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
825 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
826 .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
830 void test_new_security_hotspots() {
831 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0);
834 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
835 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
836 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
838 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
839 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
840 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
844 void test_new_violations() {
845 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
848 newGroup(RuleType.BUG).setInLeak(true).setCount(5),
849 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
850 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
852 newGroup(RuleType.BUG).setInLeak(false).setCount(11),
853 newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
854 newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
855 .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
859 void test_new_blocker_violations() {
861 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
864 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
865 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
866 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
868 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
870 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
871 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
872 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
876 void test_new_critical_violations() {
878 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
881 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
882 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
883 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
885 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
887 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
888 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
889 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
893 void test_new_major_violations() {
895 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
898 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
899 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
900 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
902 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
904 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
905 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
906 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
910 void test_new_minor_violations() {
912 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
915 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
916 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
917 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
919 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
921 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
922 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
923 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
927 void test_new_info_violations() {
929 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
932 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
933 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
934 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
936 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
938 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
939 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
940 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
944 void test_new_accepted_issues() {
946 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0);
949 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(3),
950 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(4),
951 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(30),
952 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(40),
954 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(5),
955 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(50))
956 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
960 void test_new_technical_debt() {
961 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
964 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
966 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
968 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
969 newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
971 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
972 .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
976 void test_new_reliability_remediation_effort() {
977 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
980 newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
982 newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
984 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
986 newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
987 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
991 void test_new_security_remediation_effort() {
992 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
995 newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
997 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
999 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
1001 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
1002 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
1006 void test_new_reliability_rating() {
1007 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
1010 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
1011 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
1013 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
1015 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
1017 newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
1018 // highest severity of bugs on leak period is minor -> B
1019 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
1023 void test_new_security_rating() {
1024 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
1027 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
1028 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
1030 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
1031 // not vulnerability
1032 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
1034 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
1035 // highest severity of bugs on leak period is minor -> B
1036 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
1040 void test_new_security_review_rating() {
1042 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1043 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1045 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
1046 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B);
1049 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A);
1052 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
1053 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1055 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
1056 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.E);
1060 void test_new_security_hotspots_reviewed() {
1062 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1063 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1065 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1066 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
1069 .assertNoLeakValue(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED);
1073 void test_new_security_hotspots_reviewed_status() {
1075 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1076 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1078 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1079 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
1082 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
1086 void test_new_security_hotspots_to_review_status() {
1088 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1089 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1091 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1092 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
1095 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
1098 private static Stream<Arguments> newMaintainabilityMetrics() {
1100 arguments(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_SQALE_DEBT_RATIO, CoreMetrics.NEW_MAINTAINABILITY_RATING),
1101 arguments(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
1102 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
1103 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
1107 @MethodSource("newMaintainabilityMetrics")
1108 void test_new_sqale_debt_ratio_and_new_maintainability_rating(Metric<?> newMaintainabilityRemediationEffortMetric,
1109 Metric<?> newMaintainabilityDebtRatioMetric,
1110 Metric<?> newMaintainabilityRatingMetric) {
1112 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1113 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1115 // technical_debt not computed
1116 with(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
1117 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1118 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1119 with(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
1120 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1121 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1123 // development_cost not computed
1124 with(newMaintainabilityRemediationEffortMetric, 0)
1125 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1126 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1127 with(newMaintainabilityRemediationEffortMetric, 20)
1128 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1129 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1131 // input measures are available
1132 with(newMaintainabilityRemediationEffortMetric, 20.0)
1133 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1134 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1135 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1137 with(newMaintainabilityRemediationEffortMetric, 20.0)
1138 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
1139 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 12.5)
1140 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.C);
1142 Verifier verifier = with(newMaintainabilityRemediationEffortMetric, 20.0)
1143 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0D)
1144 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 200.0);
1145 switch (newMaintainabilityRatingMetric.key()) {
1146 case NEW_MAINTAINABILITY_RATING_KEY, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY ->
1147 verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.E);
1148 default -> throw new IllegalArgumentException("Unexpected metric: " + newMaintainabilityRatingMetric.key());
1151 // A is 5% --> min debt is exactly 200*0.05=10
1152 with(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
1153 .and(newMaintainabilityRemediationEffortMetric, 10.0)
1154 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 5.0)
1155 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1157 with(newMaintainabilityRemediationEffortMetric, 0.0)
1158 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1159 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1160 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1162 with(newMaintainabilityRemediationEffortMetric, 0.0)
1163 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1164 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0);
1166 with(newMaintainabilityRemediationEffortMetric, -20.0)
1167 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1168 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1169 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1171 // bug, debt can't be negative
1172 with(newMaintainabilityRemediationEffortMetric, -20.0)
1173 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1174 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1175 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1177 // bug, cost can't be negative
1178 with(newMaintainabilityRemediationEffortMetric, 20.0)
1179 .and(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
1180 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1181 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1185 void compute_shouldComputeHighImpactAcceptedIssues() {
1187 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
1190 newImpactGroup(RELIABILITY, HIGH, 3),
1191 newImpactGroup(RELIABILITY, MEDIUM, 4),
1192 newImpactGroup(RELIABILITY, LOW, 1),
1193 newImpactGroup(SECURITY, HIGH, 3),
1194 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4),
1195 newImpactGroup(SECURITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 5),
1196 newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
1197 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
1198 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8))
1199 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
1203 void compute_shouldComputeRemediationEffortBasedOnSoftwareQuality() {
1205 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0)
1206 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0)
1207 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0)
1208 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0d)
1209 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0d)
1210 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1213 newImpactGroup(RELIABILITY, HIGH, 3, 1d),
1214 newImpactGroup(RELIABILITY, MEDIUM, 1, 2d, true),
1215 newImpactGroup(SECURITY, MEDIUM, 1, 1d),
1216 newImpactGroup(MAINTAINABILITY, MEDIUM, 1, 1d),
1217 newImpactGroup(MAINTAINABILITY, HIGH, 1, 2d, true),
1218 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
1219 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1220 newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
1221 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d + 2d)
1222 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 1d + 2d)
1223 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 1d)
1224 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 2d)
1225 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 2d)
1226 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1230 void computeHierarchy_shouldComputeImpactMeasures() {
1231 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1232 .withValue(impactMeasureToJson(6, 1, 2, 3))
1233 .withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2))
1234 .expectedJsonResult(impactMeasureToJson(22, 7, 7, 8));
1236 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1237 .withValue(impactMeasureToJson(6, 1, 2, 3))
1238 .expectedJsonResult(impactMeasureToJson(6, 1, 2, 3));
1242 void compute_shouldComputeImpactMeasures() {
1244 newImpactGroup(RELIABILITY, HIGH, 3),
1245 newImpactGroup(RELIABILITY, MEDIUM, 4),
1246 newImpactGroup(RELIABILITY, LOW, 1),
1247 newImpactGroup(MAINTAINABILITY, MEDIUM, 10),
1248 newImpactGroup(MAINTAINABILITY, LOW, 11),
1249 newImpactGroup(SECURITY, HIGH, 3))
1250 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
1251 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
1252 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
1256 void compute_whenNoIssues_shouldComputeImpactMeasures() {
1258 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1259 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1260 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1261 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1262 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1263 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0));
1266 private static String impactMeasureToJson(long total, long high, long medium, long low) {
1267 return GSON.toJson(Map.of("total", total, "HIGH", high, "MEDIUM", medium, "LOW", low));
1270 private Verifier with(IssueGroupDto... groups) {
1271 return new Verifier(groups);
1274 private Verifier with(IssueImpactGroupDto... groups) {
1275 return new Verifier(groups);
1278 private Verifier withNoIssues() {
1279 return new Verifier(new IssueGroupDto[0]);
1282 private Verifier with(Metric metric, double value) {
1283 return new Verifier(new IssueGroupDto[0]).and(metric, value);
1286 private Verifier with(Metric metric, String value) {
1287 return new Verifier(new IssueGroupDto[0]).andText(metric, value);
1290 private class Verifier {
1291 private IssueGroupDto[] groups = {};
1292 private IssueImpactGroupDto[] impactGroups = {};
1293 private final InitialValues initialValues = new InitialValues();
1295 private Verifier(IssueGroupDto[] groups) {
1296 this.groups = groups;
1299 private Verifier(IssueImpactGroupDto[] impactGroups) {
1300 this.impactGroups = impactGroups;
1303 Verifier and(Metric metric, double value) {
1304 this.initialValues.values.put(metric, value);
1308 Verifier andText(Metric metric, String value) {
1309 this.initialValues.textValues.put(metric, value);
1313 Verifier assertThatValueIs(Metric metric, double expectedValue) {
1314 TestContext context = run(metric, false);
1315 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1319 Verifier assertThatJsonValueIs(Metric metric, String expectedValue) {
1320 TestContext context = run(metric, false);
1321 assertJson(context.stringValue).isSimilarTo(expectedValue);
1325 Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
1326 TestContext context = run(metric, true);
1327 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1331 Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
1332 TestContext context = run(metric, true);
1333 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedRating);
1337 Verifier assertThatLeakValueIs(Metric metric, String expectedValue) {
1338 TestContext context = run(metric, true);
1339 assertJson(context.stringValue).isSimilarTo(expectedValue);
1343 Verifier assertNoLeakValue(Metric metric) {
1344 TestContext context = run(metric, true);
1345 assertThat(context.ratingValue).isNull();
1349 Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
1350 TestContext context = run(metric, false);
1351 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
1355 Verifier assertNoValue(Metric metric) {
1356 TestContext context = run(metric, false);
1357 assertThat(context.ratingValue).isNull();
1361 private TestContext run(Metric metric, boolean expectLeakFormula) {
1362 MeasureUpdateFormula formula = underTest.getFormulas().stream()
1363 .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
1366 assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
1367 TestContext context = new TestContext(formula.getDependentMetrics(), initialValues);
1368 formula.compute(context, newIssueCounter(groups, impactGroups));
1373 private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups) {
1374 return new IssueCounter(asList(groups), asList(impactGroups));
1377 private static IssueGroupDto newGroup() {
1378 return newGroup(RuleType.CODE_SMELL);
1381 private static IssueGroupDto newGroup(RuleType ruleType) {
1382 IssueGroupDto dto = new IssueGroupDto();
1383 // set non-null fields
1384 dto.setRuleType(ruleType.getDbConstant());
1387 dto.setSeverity(Severity.INFO);
1388 dto.setStatus(Issue.STATUS_OPEN);
1389 dto.setInLeak(false);
1393 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1394 String status, @Nullable String resolution, long count, double effort, boolean inLeak) {
1395 IssueImpactGroupDto dto = new IssueImpactGroupDto();
1396 dto.setSoftwareQuality(softwareQuality);
1397 dto.setSeverity(severity);
1398 dto.setStatus(status);
1399 dto.setResolution(resolution);
1400 dto.setCount(count);
1401 dto.setEffort(effort);
1402 dto.setInLeak(inLeak);
1406 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1407 String status, @Nullable String resolution, long count) {
1408 return newImpactGroup(softwareQuality, severity, status, resolution, count, 0, false);
1411 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1413 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, false);
1416 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1417 long count, boolean inLeak) {
1418 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, inLeak);
1421 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1422 long count, double effort) {
1423 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, false);
1426 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1427 long count, double effort, boolean inLeak) {
1428 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, inLeak);
1431 private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
1432 return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
1435 private static IssueGroupDto newResolvedGroup(String resolution, String status) {
1436 return newGroup().setResolution(resolution).setStatus(status);
1439 private static class TestContext implements MeasureUpdateFormula.Context {
1440 private final Set<Metric> dependentMetrics;
1441 private final InitialValues initialValues;
1442 private Double doubleValue;
1443 private Rating ratingValue;
1444 private String stringValue;
1446 private TestContext(Collection<Metric> dependentMetrics, InitialValues initialValues) {
1447 this.dependentMetrics = new HashSet<>(dependentMetrics);
1448 this.initialValues = initialValues;
1452 public List<Double> getChildrenValues() {
1453 return initialValues.childrenValues;
1457 public List<String> getChildrenTextValues() {
1458 return initialValues.childrenTextValues;
1462 public long getChildrenHotspotsReviewed() {
1463 return initialValues.childrenHotspotsReviewed;
1467 public long getChildrenHotspotsToReview() {
1468 return initialValues.childrenHotspotsToReview;
1472 public long getChildrenNewHotspotsReviewed() {
1473 return initialValues.childrenNewHotspotsReviewed;
1477 public long getChildrenNewHotspotsToReview() {
1478 return initialValues.childrenNewHotspotsToReview;
1482 public ComponentDto getComponent() {
1483 throw new UnsupportedOperationException();
1487 public DebtRatingGrid getDebtRatingGrid() {
1488 return new DebtRatingGrid(new double[]{0.05, 0.1, 0.2, 0.5});
1492 public Optional<Double> getValue(Metric metric) {
1493 if (!dependentMetrics.contains(metric)) {
1494 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
1496 if (initialValues.values.containsKey(metric)) {
1497 return Optional.of(initialValues.values.get(metric));
1499 return Optional.empty();
1503 public Optional<String> getText(Metric metric) {
1504 if (initialValues.textValues.containsKey(metric)) {
1505 return Optional.of(initialValues.textValues.get(metric));
1507 return Optional.empty();
1511 public void setValue(double value) {
1512 this.doubleValue = value;
1516 public void setValue(Rating value) {
1517 this.ratingValue = value;
1521 public void setValue(String value) {
1522 this.stringValue = value;
1526 private class InitialValues {
1527 private final Map<Metric, Double> values = new HashMap<>();
1528 private final List<Double> childrenValues = new ArrayList<>();
1529 private final Map<Metric, String> textValues = new HashMap<>();
1530 private final List<String> childrenTextValues = new ArrayList<>();
1531 private long childrenHotspotsReviewed = 0;
1532 private long childrenNewHotspotsReviewed = 0;
1533 private long childrenHotspotsToReview = 0;
1534 private long childrenNewHotspotsToReview = 0;
1538 private class HierarchyTester {
1539 private final Metric metric;
1540 private final InitialValues initialValues;
1541 private final MeasureUpdateFormula formula;
1543 public HierarchyTester(Metric metric) {
1544 this.metric = metric;
1545 this.initialValues = new InitialValues();
1546 this.formula = underTest.getFormulas().stream().filter(f -> f.getMetric().equals(metric)).findAny().get();
1549 public HierarchyTester withValue(Metric metric, Double value) {
1550 this.initialValues.values.put(metric, value);
1554 public HierarchyTester withValue(Metric metric, String value) {
1555 this.initialValues.textValues.put(metric, value);
1559 public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed,
1560 long childrenHotspotsToReview,
1561 long childrenNewHotspotsToReview) {
1562 this.initialValues.childrenHotspotsReviewed = childrenHotspotsReviewed;
1563 this.initialValues.childrenNewHotspotsReviewed = childrenNewHotspotsReviewed;
1564 this.initialValues.childrenHotspotsToReview = childrenHotspotsToReview;
1565 this.initialValues.childrenNewHotspotsToReview = childrenNewHotspotsToReview;
1569 public HierarchyTester withValue(Double value) {
1570 return withValue(metric, value);
1573 public HierarchyTester withValue(String value) {
1574 return withValue(metric, value);
1577 public HierarchyTester withChildrenValues(Double... values) {
1578 this.initialValues.childrenValues.addAll(asList(values));
1582 public HierarchyTester withChildrenValues(String... values) {
1583 this.initialValues.childrenTextValues.addAll(asList(values));
1587 public HierarchyTester expectedResult(@Nullable Double expected) {
1588 TestContext ctx = run();
1589 assertThat(ctx.doubleValue).isEqualTo(expected);
1593 public HierarchyTester expectedJsonResult(@Nullable String expected) {
1594 TestContext ctx = run();
1595 assertJson(ctx.stringValue).isSimilarTo(expected);
1599 public HierarchyTester expectedRating(@Nullable Rating rating) {
1600 TestContext ctx = run();
1601 assertThat(ctx.ratingValue).isEqualTo(rating);
1605 private TestContext run() {
1606 List<Metric> deps = new LinkedList<>(formula.getDependentMetrics());
1607 deps.add(formula.getMetric());
1608 deps.addAll(initialValues.values.keySet());
1609 deps.addAll(initialValues.textValues.keySet());
1610 TestContext context = new TestContext(deps, initialValues);
1611 formula.computeHierarchy(context);