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.HIGH;
56 import static org.sonar.api.issue.impact.Severity.LOW;
57 import static org.sonar.api.issue.impact.Severity.MEDIUM;
58 import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
59 import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY;
60 import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
61 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A;
62 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
63 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
64 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS;
65 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
66 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING;
67 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
68 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
69 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
70 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
71 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO;
72 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING;
73 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
74 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT;
75 import static org.sonar.core.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT;
76 import static org.sonar.server.metric.IssueCountMetrics.PRIORITIZED_RULE_ISSUES;
77 import static org.sonar.test.JsonAssert.assertJson;
79 class MeasureUpdateFormulaFactoryImplTest {
81 private static final Gson GSON = new GsonBuilder().create();
82 private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl();
85 void getFormulaMetrics_include_the_dependent_metrics() {
86 for (MeasureUpdateFormula formula : underTest.getFormulas()) {
87 assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
88 for (Metric<?> dependentMetric : formula.getDependentMetrics()) {
89 assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
95 void hierarchy_adding_numbers() {
96 new HierarchyTester(CoreMetrics.VIOLATIONS)
98 .withChildrenValues(2d, 3d)
101 new HierarchyTester(CoreMetrics.BUGS)
103 .withChildrenValues(2d, 3d)
106 new HierarchyTester(CoreMetrics.NEW_BUGS)
112 void hierarchy_highest_rating() {
113 new HierarchyTester(CoreMetrics.RELIABILITY_RATING)
115 .withChildrenValues(2d, 3d)
116 .expectedRating(Rating.C);
118 // if no children, no need to set a value
119 new HierarchyTester(CoreMetrics.SECURITY_RATING)
121 .expectedResult(null);
123 new HierarchyTester(CoreMetrics.NEW_RELIABILITY_RATING)
125 .withChildrenValues(2d, 3d)
126 .expectedRating(Rating.E);
130 void hierarchy_combining_other_metrics() {
131 new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
132 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
133 .withChildrenHotspotsCounts(10, 10, 2, 10)
136 new HierarchyTester(SECURITY_HOTSPOTS_REVIEWED_STATUS)
137 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
138 .withChildrenHotspotsCounts(2, 10, 10, 10)
141 new HierarchyTester(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS)
142 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
143 .withChildrenHotspotsCounts(10, 10, 10, 2)
146 new HierarchyTester(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
147 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
148 .withChildrenHotspotsCounts(10, 2, 10, 10)
151 new HierarchyTester(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED)
152 .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
153 .withValue(SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
154 .expectedResult(50d);
155 new HierarchyTester(CoreMetrics.SECURITY_REVIEW_RATING)
156 .withValue(SECURITY_HOTSPOTS_REVIEWED, 100d)
157 .expectedRating(Rating.A);
159 new HierarchyTester(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED)
160 .withValue(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d)
161 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 1d)
162 .expectedResult(50d);
163 new HierarchyTester(CoreMetrics.NEW_SECURITY_REVIEW_RATING)
164 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
165 .expectedRating(Rating.E);
169 void computeHierarchy_shouldRecomputeSoftwareQualityMetricsCombiningOtherMetrics() {
170 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
171 .withValue(SECURITY_HOTSPOTS_REVIEWED, 0d)
172 .expectedRating(Rating.D);
173 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING)
174 .withValue(NEW_SECURITY_HOTSPOTS_REVIEWED, 0d)
175 .expectedRating(Rating.D);
176 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
177 .withValue(SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
178 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
179 .expectedResult(25d);
180 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO)
181 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
182 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
183 .expectedResult(25d);
185 new HierarchyTester(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
186 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
187 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
188 .expectedRating(Rating.D);
190 new HierarchyTester(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING)
191 .withValue(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
192 .withValue(CoreMetrics.NEW_DEVELOPMENT_COST, 40d)
193 .expectedRating(Rating.D);
195 new HierarchyTester(SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A)
196 .withValue(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 10d)
197 .withValue(CoreMetrics.DEVELOPMENT_COST, "40")
201 static List<Metric<?>> softwareQualityRatingMetric() {
203 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING,
204 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING,
205 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING,
206 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING);
209 @MethodSource("softwareQualityRatingMetric")
211 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnRating(Metric<?> ratingMetric) {
212 new HierarchyTester(ratingMetric)
214 .withChildrenValues(2d, 3d)
215 .expectedRating(Rating.C);
218 static List<Metric<?>> softwareQualitySummingMetric() {
220 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
221 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
222 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT,
223 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
224 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT,
225 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT);
228 @MethodSource("softwareQualitySummingMetric")
230 void computeHierarchy_shoudRecomputeSoftwareQualityMetricsBasedOnSumming(Metric<?> summingMetric) {
231 new HierarchyTester(summingMetric)
233 .withChildrenValues(2d, 3d)
238 void test_violations() {
239 withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
240 with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
243 IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
244 with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
246 // include issues on leak
247 IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
248 with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
252 void test_prioritized_rules() {
253 withNoIssues().assertThatValueIs(PRIORITIZED_RULE_ISSUES, 0);
254 with(newGroup().setPrioritizedRule(1), newGroup().setPrioritizedRule(4)).assertThatValueIs(PRIORITIZED_RULE_ISSUES, 5);
259 withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
261 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
262 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
264 newResolvedGroup(RuleType.BUG).setCount(7),
266 newGroup(RuleType.CODE_SMELL).setCount(11))
267 .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
271 void test_code_smells() {
272 withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
274 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
275 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
277 newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
279 newGroup(RuleType.BUG).setCount(11))
280 .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
284 void test_vulnerabilities() {
285 withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
287 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
288 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
290 newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
291 // not vulnerabilities
292 newGroup(RuleType.BUG).setCount(11))
293 .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
297 void test_security_hotspots() {
298 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
300 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
301 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
303 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
305 newGroup(RuleType.BUG).setCount(11))
306 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
310 void test_security_review_ratings() {
312 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
313 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
314 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.B)
315 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.B);
318 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.A)
319 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.A);
322 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
323 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true))
324 .assertThatValueIs(SECURITY_REVIEW_RATING, Rating.E)
325 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.D);
329 void test_security_hotspots_reviewed() {
331 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
332 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
333 .assertThatValueIs(SECURITY_HOTSPOTS_REVIEWED, 75.0);
336 .assertNoValue(SECURITY_HOTSPOTS_REVIEWED);
340 void test_security_hotspots_reviewed_status() {
342 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
343 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
344 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
347 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
351 void test_security_hotspots_to_review_status() {
353 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
354 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
355 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
358 .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
362 void count_unresolved_by_severity() {
364 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
365 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
366 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
367 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
368 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
371 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
372 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
373 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
374 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
375 // exclude security hotspot
376 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
378 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
380 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
381 newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
382 newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
383 .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
384 .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
385 .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
386 .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
387 .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
391 void count_resolved() {
393 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
394 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0);
397 newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
398 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
399 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
400 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
401 newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
402 // exclude security hotspot
403 newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
404 // exclude unresolved
405 newGroup(RuleType.VULNERABILITY).setCount(17),
406 newGroup(RuleType.BUG).setCount(19))
407 .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
408 .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 7 + 11);
412 void count_by_status() {
414 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
415 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
416 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
419 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
420 newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
421 newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
422 newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
423 newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
424 // exclude security hotspot
425 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
426 newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
427 .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
428 .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
429 .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
433 void test_technical_debt() {
434 withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
437 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
438 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
439 // exclude security hotspot
440 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
441 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
443 newGroup(RuleType.BUG).setEffort(7.0),
445 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
446 .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
450 void test_reliability_remediation_effort() {
451 withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
454 newGroup(RuleType.BUG).setEffort(3.0),
455 newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
457 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
459 newResolvedGroup(RuleType.BUG).setEffort(17.0))
460 .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
464 void test_security_remediation_effort() {
465 withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
468 newGroup(RuleType.VULNERABILITY).setEffort(3.0),
469 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
471 newGroup(RuleType.CODE_SMELL).setEffort(7.0),
473 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
474 .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
477 private static Stream<Arguments> maintainabilityMetrics() {
479 arguments(TECHNICAL_DEBT, SQALE_DEBT_RATIO, SQALE_RATING),
480 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
481 SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
485 @MethodSource("maintainabilityMetrics")
486 void test_sqale_debt_ratio_and_sqale_rating(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> maintainabilityDebtRatioMetric, Metric<?> maintainabilityRatingMetric) {
488 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
489 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
491 // technical_debt not computed
492 with(CoreMetrics.DEVELOPMENT_COST, "0")
493 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
494 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
495 with(CoreMetrics.DEVELOPMENT_COST, "20")
496 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
497 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
499 // development_cost not computed
500 with(maintainabilityRemediationEffortMetric, 0)
501 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
502 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
503 with(maintainabilityRemediationEffortMetric, 20)
504 .assertThatValueIs(maintainabilityDebtRatioMetric, 0)
505 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
507 // input measures are available
508 with(maintainabilityRemediationEffortMetric, 20.0)
509 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
510 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
511 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
513 with(maintainabilityRemediationEffortMetric, 20.0)
514 .andText(CoreMetrics.DEVELOPMENT_COST, "160")
515 .assertThatValueIs(maintainabilityDebtRatioMetric, 12.5)
516 .assertThatValueIs(maintainabilityRatingMetric, Rating.C);
518 Verifier verifier = with(maintainabilityRemediationEffortMetric, 20.0)
519 .andText(CoreMetrics.DEVELOPMENT_COST, "10")
520 .assertThatValueIs(maintainabilityDebtRatioMetric, 200.0);
521 switch (maintainabilityRatingMetric.key()) {
522 case SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY -> verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.D);
523 case SQALE_RATING_KEY -> verifier.assertThatValueIs(maintainabilityRatingMetric, Rating.E);
524 default -> throw new IllegalArgumentException("Unexpected metric: " + maintainabilityRatingMetric.key());
527 // A is 5% --> min debt is exactly 200*0.05=10
528 with(CoreMetrics.DEVELOPMENT_COST, "200")
529 .and(maintainabilityRemediationEffortMetric, 10.0)
530 .assertThatValueIs(maintainabilityDebtRatioMetric, 5.0)
531 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
533 with(maintainabilityRemediationEffortMetric, 0.0)
534 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
535 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
536 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
538 with(maintainabilityRemediationEffortMetric, 0.0)
539 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
540 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0);
542 with(maintainabilityRemediationEffortMetric, -20.0)
543 .andText(CoreMetrics.DEVELOPMENT_COST, "0")
544 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
545 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
547 // bug, debt can't be negative
548 with(maintainabilityRemediationEffortMetric, -20.0)
549 .andText(CoreMetrics.DEVELOPMENT_COST, "80")
550 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
551 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
553 // bug, cost can't be negative
554 with(maintainabilityRemediationEffortMetric, 20.0)
555 .andText(CoreMetrics.DEVELOPMENT_COST, "-80")
556 .assertThatValueIs(maintainabilityDebtRatioMetric, 0.0)
557 .assertThatValueIs(maintainabilityRatingMetric, Rating.A);
560 private static Stream<Arguments> effortToReachAMetrics() {
562 arguments(TECHNICAL_DEBT, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A),
563 arguments(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT,
564 SoftwareQualitiesMetrics.EFFORT_TO_REACH_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_A));
568 @MethodSource("effortToReachAMetrics")
569 void test_effort_to_reach_maintainability_rating_A(Metric<?> maintainabilityRemediationEffortMetric, Metric<?> effortToReachAMetric) {
571 .assertThatValueIs(effortToReachAMetric, 0.0);
573 // technical_debt not computed
574 with(CoreMetrics.DEVELOPMENT_COST, 0.0)
575 .assertThatValueIs(effortToReachAMetric, 0.0);
576 with(CoreMetrics.DEVELOPMENT_COST, 20.0)
577 .assertThatValueIs(effortToReachAMetric, 0.0);
579 // development_cost not computed
580 with(maintainabilityRemediationEffortMetric, 0.0)
581 .assertThatValueIs(effortToReachAMetric, 0.0);
582 with(maintainabilityRemediationEffortMetric, 20.0)
583 // development cost is considered as zero, so the effort is to reach... zero
584 .assertThatValueIs(effortToReachAMetric, 20.0);
587 with(CoreMetrics.DEVELOPMENT_COST, "200")
588 .and(maintainabilityRemediationEffortMetric, 40.0)
589 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
590 .assertThatValueIs(effortToReachAMetric, 40.0 - (200.0 * 0.05));
593 with(CoreMetrics.DEVELOPMENT_COST, "200")
594 .and(maintainabilityRemediationEffortMetric, 180.0)
595 // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
596 .assertThatValueIs(effortToReachAMetric, 180.0 - (200.0 * 0.05));
599 with(CoreMetrics.DEVELOPMENT_COST, "200")
600 .and(maintainabilityRemediationEffortMetric, 8.0)
601 // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
602 .assertThatValueIs(effortToReachAMetric, 0.0);
604 // exactly lower range of B
605 with(CoreMetrics.DEVELOPMENT_COST, "200")
606 .and(maintainabilityRemediationEffortMetric, 10.0)
607 // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
608 // FIXME need zero to reach A but effective rating is B !
609 .assertThatValueIs(effortToReachAMetric, 0.0);
613 void test_reliability_rating() {
615 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
618 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
619 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
620 // excluded, not a bug
621 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
622 // highest severity of bugs is CRITICAL --> D
623 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
626 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
627 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
629 .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
633 void test_software_quality_reliability_rating() {
635 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
638 newImpactGroup(MAINTAINABILITY, HIGH, 1),
639 newImpactGroup(RELIABILITY, MEDIUM, 1),
640 newImpactGroup(RELIABILITY, LOW, 1),
641 newImpactGroup(SECURITY, MEDIUM, 1))
642 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
645 newImpactGroup(RELIABILITY, LOW, 1))
646 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
650 void test_software_quality_new_reliability_rating() {
652 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.A);
655 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
656 newImpactGroup(RELIABILITY, MEDIUM, 1, true),
657 newImpactGroup(RELIABILITY, LOW, 1, true),
658 newImpactGroup(RELIABILITY, HIGH, 1, false),
659 newImpactGroup(SECURITY, HIGH, 1, true))
660 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.C);
663 newImpactGroup(RELIABILITY, LOW, 1, true),
664 newImpactGroup(RELIABILITY, MEDIUM, 1, false))
665 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, Rating.B);
669 void test_security_rating() {
671 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
674 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
675 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
676 // excluded, not a vulnerability
677 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
678 // highest severity of vulnerabilities is CRITICAL --> D
679 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
682 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
683 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
684 // no vulnerabilities --> A
685 .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
689 void test_software_quality_security_rating() {
691 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
694 newImpactGroup(MAINTAINABILITY, HIGH, 1),
695 newImpactGroup(SECURITY, MEDIUM, 1),
696 newImpactGroup(SECURITY, LOW, 1),
697 newImpactGroup(RELIABILITY, MEDIUM, 1))
698 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
701 newImpactGroup(SECURITY, LOW, 1))
702 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
706 void test_software_quality_new_security_rating() {
708 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.A);
711 newImpactGroup(MAINTAINABILITY, HIGH, 1, true),
712 newImpactGroup(SECURITY, MEDIUM, 1, true),
713 newImpactGroup(SECURITY, LOW, 1, true),
714 newImpactGroup(SECURITY, HIGH, 1, false),
715 newImpactGroup(RELIABILITY, HIGH, 1, true))
716 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.C);
719 newImpactGroup(SECURITY, LOW, 1, true),
720 newImpactGroup(SECURITY, MEDIUM, 1, false))
721 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, Rating.B);
725 void test_new_bugs() {
726 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
729 newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
730 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
731 newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
733 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
734 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
735 .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
740 void test_new_code_smells() {
741 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
744 newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
745 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
746 newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
748 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
749 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
750 .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
754 void test_new_vulnerabilities() {
755 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
758 newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
759 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
760 newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
761 // not vulnerabilities
762 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
763 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
764 .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
768 void test_new_security_hotspots() {
769 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0);
772 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
773 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
774 newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
776 newGroup(RuleType.BUG).setInLeak(true).setCount(9),
777 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
778 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
782 void test_new_violations() {
783 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
786 newGroup(RuleType.BUG).setInLeak(true).setCount(5),
787 newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
788 newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
790 newGroup(RuleType.BUG).setInLeak(false).setCount(11),
791 newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
792 newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
793 .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
797 void test_new_blocker_violations() {
799 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
802 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
803 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
804 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
806 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
808 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
809 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
810 .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
814 void test_new_critical_violations() {
816 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
819 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
820 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
821 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
823 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
825 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
826 newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
827 .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
831 void test_new_major_violations() {
833 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
836 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
837 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
838 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
840 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
842 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
843 newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
844 .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
848 void test_new_minor_violations() {
850 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
853 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
854 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
855 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
857 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
859 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
860 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
861 .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
865 void test_new_info_violations() {
867 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
870 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
871 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
872 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
874 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
876 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
877 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
878 .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
882 void test_new_accepted_issues() {
884 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0);
887 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(3),
888 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(4),
889 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setInLeak(true).setCount(30),
890 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(true).setCount(40),
892 newGroup(RuleType.CODE_SMELL).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(5),
893 newGroup(RuleType.BUG).setResolution(Issue.RESOLUTION_WONT_FIX).setInLeak(false).setCount(50))
894 .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 4 + 40);
898 void test_new_technical_debt() {
899 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
902 newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
904 newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
906 newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
907 newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
909 newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
910 .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
914 void test_new_reliability_remediation_effort() {
915 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
918 newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
920 newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
922 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
924 newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
925 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
929 void test_new_security_remediation_effort() {
930 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
933 newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
935 newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
937 newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
939 newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
940 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
944 void test_new_reliability_rating() {
945 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
948 newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
949 newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
951 newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
953 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
955 newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
956 // highest severity of bugs on leak period is minor -> B
957 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
961 void test_new_security_rating() {
962 withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
965 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
966 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
968 newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
970 newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
972 newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
973 // highest severity of bugs on leak period is minor -> B
974 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
978 void test_new_security_review_rating() {
980 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
981 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
983 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
984 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.B)
985 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.B);
988 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.A)
989 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.A);
992 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(3).setInLeak(true),
993 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
995 newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
996 .assertThatLeakValueIs(NEW_SECURITY_REVIEW_RATING, Rating.E)
997 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, Rating.D);
1001 void test_new_security_hotspots_reviewed() {
1003 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1004 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1006 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1007 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
1010 .assertNoLeakValue(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED);
1014 void test_new_security_hotspots_reviewed_status() {
1016 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1017 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1019 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1020 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
1023 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
1027 void test_new_security_hotspots_to_review_status() {
1029 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
1030 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
1032 newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
1033 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
1036 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
1039 private static Stream<Arguments> newMaintainabilityMetrics() {
1041 arguments(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_SQALE_DEBT_RATIO, CoreMetrics.NEW_MAINTAINABILITY_RATING),
1042 arguments(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_DEBT_RATIO,
1043 SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING));
1047 @MethodSource("newMaintainabilityMetrics")
1048 void test_new_sqale_debt_ratio_and_new_maintainability_rating(Metric<?> newMaintainabilityRemediationEffortMetric, Metric<?> newMaintainabilityDebtRatioMetric,
1049 Metric<?> newMaintainabilityRatingMetric) {
1051 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1052 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1054 // technical_debt not computed
1055 with(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
1056 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1057 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1058 with(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
1059 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1060 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1062 // development_cost not computed
1063 with(newMaintainabilityRemediationEffortMetric, 0)
1064 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1065 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1066 with(newMaintainabilityRemediationEffortMetric, 20)
1067 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0)
1068 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1070 // input measures are available
1071 with(newMaintainabilityRemediationEffortMetric, 20.0)
1072 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1073 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1074 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1076 with(newMaintainabilityRemediationEffortMetric, 20.0)
1077 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
1078 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 12.5)
1079 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.C);
1081 Verifier verifier = with(newMaintainabilityRemediationEffortMetric, 20.0)
1082 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0D)
1083 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 200.0);
1084 switch (newMaintainabilityRatingMetric.key()) {
1085 case NEW_MAINTAINABILITY_RATING_KEY -> verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.E);
1086 case SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY -> verifier.assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.D);
1087 default -> throw new IllegalArgumentException("Unexpected metric: " + newMaintainabilityRatingMetric.key());
1090 // A is 5% --> min debt is exactly 200*0.05=10
1091 with(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
1092 .and(newMaintainabilityRemediationEffortMetric, 10.0)
1093 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 5.0)
1094 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1096 with(newMaintainabilityRemediationEffortMetric, 0.0)
1097 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1098 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1099 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1101 with(newMaintainabilityRemediationEffortMetric, 0.0)
1102 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1103 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0);
1105 with(newMaintainabilityRemediationEffortMetric, -20.0)
1106 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
1107 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1108 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1110 // bug, debt can't be negative
1111 with(newMaintainabilityRemediationEffortMetric, -20.0)
1112 .and(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
1113 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1114 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1116 // bug, cost can't be negative
1117 with(newMaintainabilityRemediationEffortMetric, 20.0)
1118 .and(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
1119 .assertThatLeakValueIs(newMaintainabilityDebtRatioMetric, 0.0)
1120 .assertThatLeakValueIs(newMaintainabilityRatingMetric, Rating.A);
1124 void compute_shouldComputeHighImpactAcceptedIssues() {
1126 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
1129 newImpactGroup(RELIABILITY, HIGH, 3),
1130 newImpactGroup(RELIABILITY, MEDIUM, 4),
1131 newImpactGroup(RELIABILITY, LOW, 1),
1132 newImpactGroup(SECURITY, HIGH, 3),
1133 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4),
1134 newImpactGroup(SECURITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 5),
1135 newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
1136 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
1137 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8))
1138 .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
1142 void compute_shouldComputeRemediationEffortBasedOnSoftwareQuality() {
1144 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0)
1145 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0)
1146 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0)
1147 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 0d)
1148 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 0d)
1149 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1152 newImpactGroup(RELIABILITY, HIGH, 3, 1d),
1153 newImpactGroup(RELIABILITY, MEDIUM, 1, 2d, true),
1154 newImpactGroup(SECURITY, MEDIUM, 1, 1d),
1155 newImpactGroup(MAINTAINABILITY, MEDIUM, 1, 1d),
1156 newImpactGroup(MAINTAINABILITY, HIGH, 1, 2d, true),
1157 newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4, 1d, false),
1158 newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false),
1159 newImpactGroup(MAINTAINABILITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8, 1d, false))
1160 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 1d + 2d)
1161 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 1d + 2d)
1162 .assertThatValueIs(SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 1d)
1163 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_REMEDIATION_EFFORT, 2d)
1164 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_REMEDIATION_EFFORT, 2d)
1165 .assertThatLeakValueIs(SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_REMEDIATION_EFFORT, 0d);
1169 void computeHierarchy_shouldComputeImpactMeasures() {
1170 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1171 .withValue(impactMeasureToJson(6, 1, 2, 3))
1172 .withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2))
1173 .expectedJsonResult(impactMeasureToJson(22, 7, 7, 8));
1175 new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
1176 .withValue(impactMeasureToJson(6, 1, 2, 3))
1177 .expectedJsonResult(impactMeasureToJson(6, 1, 2, 3));
1181 void compute_shouldComputeImpactMeasures() {
1183 newImpactGroup(RELIABILITY, HIGH, 3),
1184 newImpactGroup(RELIABILITY, MEDIUM, 4),
1185 newImpactGroup(RELIABILITY, LOW, 1),
1186 newImpactGroup(MAINTAINABILITY, MEDIUM, 10),
1187 newImpactGroup(MAINTAINABILITY, LOW, 11),
1188 newImpactGroup(SECURITY, HIGH, 3))
1189 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(8, 3, 4, 1))
1190 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(21, 0, 10, 11))
1191 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(3, 3, 0, 0));
1195 void compute_whenNoIssues_shouldComputeImpactMeasures() {
1197 .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1198 .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1199 .assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1200 .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1201 .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0))
1202 .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0));
1205 private static String impactMeasureToJson(long total, long high, long medium, long low) {
1206 return GSON.toJson(Map.of("total", total, "HIGH", high, "MEDIUM", medium, "LOW", low));
1209 private Verifier with(IssueGroupDto... groups) {
1210 return new Verifier(groups);
1213 private Verifier with(IssueImpactGroupDto... groups) {
1214 return new Verifier(groups);
1217 private Verifier withNoIssues() {
1218 return new Verifier(new IssueGroupDto[0]);
1221 private Verifier with(Metric metric, double value) {
1222 return new Verifier(new IssueGroupDto[0]).and(metric, value);
1225 private Verifier with(Metric metric, String value) {
1226 return new Verifier(new IssueGroupDto[0]).andText(metric, value);
1229 private class Verifier {
1230 private IssueGroupDto[] groups = {};
1231 private IssueImpactGroupDto[] impactGroups = {};
1232 private final InitialValues initialValues = new InitialValues();
1234 private Verifier(IssueGroupDto[] groups) {
1235 this.groups = groups;
1238 private Verifier(IssueImpactGroupDto[] impactGroups) {
1239 this.impactGroups = impactGroups;
1242 Verifier and(Metric metric, double value) {
1243 this.initialValues.values.put(metric, value);
1247 Verifier andText(Metric metric, String value) {
1248 this.initialValues.textValues.put(metric, value);
1252 Verifier assertThatValueIs(Metric metric, double expectedValue) {
1253 TestContext context = run(metric, false);
1254 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1258 Verifier assertThatJsonValueIs(Metric metric, String expectedValue) {
1259 TestContext context = run(metric, false);
1260 assertJson(context.stringValue).isSimilarTo(expectedValue);
1264 Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
1265 TestContext context = run(metric, true);
1266 assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
1270 Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
1271 TestContext context = run(metric, true);
1272 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedRating);
1276 Verifier assertThatLeakValueIs(Metric metric, String expectedValue) {
1277 TestContext context = run(metric, true);
1278 assertJson(context.stringValue).isSimilarTo(expectedValue);
1282 Verifier assertNoLeakValue(Metric metric) {
1283 TestContext context = run(metric, true);
1284 assertThat(context.ratingValue).isNull();
1288 Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
1289 TestContext context = run(metric, false);
1290 assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
1294 Verifier assertNoValue(Metric metric) {
1295 TestContext context = run(metric, false);
1296 assertThat(context.ratingValue).isNull();
1300 private TestContext run(Metric metric, boolean expectLeakFormula) {
1301 MeasureUpdateFormula formula = underTest.getFormulas().stream()
1302 .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
1305 assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
1306 TestContext context = new TestContext(formula.getDependentMetrics(), initialValues);
1307 formula.compute(context, newIssueCounter(groups, impactGroups));
1312 private static IssueCounter newIssueCounter(IssueGroupDto[] groups, IssueImpactGroupDto[] impactGroups) {
1313 return new IssueCounter(asList(groups), asList(impactGroups));
1316 private static IssueGroupDto newGroup() {
1317 return newGroup(RuleType.CODE_SMELL);
1320 private static IssueGroupDto newGroup(RuleType ruleType) {
1321 IssueGroupDto dto = new IssueGroupDto();
1322 // set non-null fields
1323 dto.setRuleType(ruleType.getDbConstant());
1326 dto.setSeverity(Severity.INFO);
1327 dto.setStatus(Issue.STATUS_OPEN);
1328 dto.setInLeak(false);
1332 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1333 String status, @Nullable String resolution, long count, double effort, boolean inLeak) {
1334 IssueImpactGroupDto dto = new IssueImpactGroupDto();
1335 dto.setSoftwareQuality(softwareQuality);
1336 dto.setSeverity(severity);
1337 dto.setStatus(status);
1338 dto.setResolution(resolution);
1339 dto.setCount(count);
1340 dto.setEffort(effort);
1341 dto.setInLeak(inLeak);
1345 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
1346 String status, @Nullable String resolution, long count) {
1347 return newImpactGroup(softwareQuality, severity, status, resolution, count, 0, false);
1350 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count) {
1351 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, false);
1354 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, boolean inLeak) {
1355 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, 0, inLeak);
1358 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, double effort) {
1359 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, false);
1362 private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count, double effort, boolean inLeak) {
1363 return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count, effort, inLeak);
1366 private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
1367 return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
1370 private static IssueGroupDto newResolvedGroup(String resolution, String status) {
1371 return newGroup().setResolution(resolution).setStatus(status);
1374 private static class TestContext implements MeasureUpdateFormula.Context {
1375 private final Set<Metric> dependentMetrics;
1376 private final InitialValues initialValues;
1377 private Double doubleValue;
1378 private Rating ratingValue;
1379 private String stringValue;
1381 private TestContext(Collection<Metric> dependentMetrics, InitialValues initialValues) {
1382 this.dependentMetrics = new HashSet<>(dependentMetrics);
1383 this.initialValues = initialValues;
1387 public List<Double> getChildrenValues() {
1388 return initialValues.childrenValues;
1392 public List<String> getChildrenTextValues() {
1393 return initialValues.childrenTextValues;
1397 public long getChildrenHotspotsReviewed() {
1398 return initialValues.childrenHotspotsReviewed;
1402 public long getChildrenHotspotsToReview() {
1403 return initialValues.childrenHotspotsToReview;
1407 public long getChildrenNewHotspotsReviewed() {
1408 return initialValues.childrenNewHotspotsReviewed;
1412 public long getChildrenNewHotspotsToReview() {
1413 return initialValues.childrenNewHotspotsToReview;
1417 public ComponentDto getComponent() {
1418 throw new UnsupportedOperationException();
1422 public DebtRatingGrid getDebtRatingGrid() {
1423 return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5});
1427 public Optional<Double> getValue(Metric metric) {
1428 if (!dependentMetrics.contains(metric)) {
1429 throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
1431 if (initialValues.values.containsKey(metric)) {
1432 return Optional.of(initialValues.values.get(metric));
1434 return Optional.empty();
1438 public Optional<String> getText(Metric metric) {
1439 if (initialValues.textValues.containsKey(metric)) {
1440 return Optional.of(initialValues.textValues.get(metric));
1442 return Optional.empty();
1446 public void setValue(double value) {
1447 this.doubleValue = value;
1451 public void setValue(Rating value) {
1452 this.ratingValue = value;
1456 public void setValue(String value) {
1457 this.stringValue = value;
1461 private class InitialValues {
1462 private final Map<Metric, Double> values = new HashMap<>();
1463 private final List<Double> childrenValues = new ArrayList<>();
1464 private final Map<Metric, String> textValues = new HashMap<>();
1465 private final List<String> childrenTextValues = new ArrayList<>();
1466 private long childrenHotspotsReviewed = 0;
1467 private long childrenNewHotspotsReviewed = 0;
1468 private long childrenHotspotsToReview = 0;
1469 private long childrenNewHotspotsToReview = 0;
1473 private class HierarchyTester {
1474 private final Metric metric;
1475 private final InitialValues initialValues;
1476 private final MeasureUpdateFormula formula;
1478 public HierarchyTester(Metric metric) {
1479 this.metric = metric;
1480 this.initialValues = new InitialValues();
1481 this.formula = underTest.getFormulas().stream().filter(f -> f.getMetric().equals(metric)).findAny().get();
1484 public HierarchyTester withValue(Metric metric, Double value) {
1485 this.initialValues.values.put(metric, value);
1489 public HierarchyTester withValue(Metric metric, String value) {
1490 this.initialValues.textValues.put(metric, value);
1494 public HierarchyTester withChildrenHotspotsCounts(long childrenHotspotsReviewed, long childrenNewHotspotsReviewed, long childrenHotspotsToReview,
1495 long childrenNewHotspotsToReview) {
1496 this.initialValues.childrenHotspotsReviewed = childrenHotspotsReviewed;
1497 this.initialValues.childrenNewHotspotsReviewed = childrenNewHotspotsReviewed;
1498 this.initialValues.childrenHotspotsToReview = childrenHotspotsToReview;
1499 this.initialValues.childrenNewHotspotsToReview = childrenNewHotspotsToReview;
1503 public HierarchyTester withValue(Double value) {
1504 return withValue(metric, value);
1507 public HierarchyTester withValue(String value) {
1508 return withValue(metric, value);
1511 public HierarchyTester withChildrenValues(Double... values) {
1512 this.initialValues.childrenValues.addAll(asList(values));
1516 public HierarchyTester withChildrenValues(String... values) {
1517 this.initialValues.childrenTextValues.addAll(asList(values));
1521 public HierarchyTester expectedResult(@Nullable Double expected) {
1522 TestContext ctx = run();
1523 assertThat(ctx.doubleValue).isEqualTo(expected);
1527 public HierarchyTester expectedJsonResult(@Nullable String expected) {
1528 TestContext ctx = run();
1529 assertJson(ctx.stringValue).isSimilarTo(expected);
1533 public HierarchyTester expectedRating(@Nullable Rating rating) {
1534 TestContext ctx = run();
1535 assertThat(ctx.ratingValue).isEqualTo(rating);
1539 private TestContext run() {
1540 List<Metric> deps = new LinkedList<>(formula.getDependentMetrics());
1541 deps.add(formula.getMetric());
1542 deps.addAll(initialValues.values.keySet());
1543 deps.addAll(initialValues.textValues.keySet());
1544 TestContext context = new TestContext(deps, initialValues);
1545 formula.computeHierarchy(context);