]> source.dussan.org Git - sonarqube.git/blob
f23aa1c8cc12d34c28795dca871b8cb13aa0f6f4
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2020 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.measure.live;
21
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.Set;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.rules.ExpectedException;
31 import org.sonar.api.issue.Issue;
32 import org.sonar.api.measures.CoreMetrics;
33 import org.sonar.api.measures.Metric;
34 import org.sonar.api.rule.Severity;
35 import org.sonar.api.rules.RuleType;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.db.issue.IssueGroupDto;
38 import org.sonar.server.measure.DebtRatingGrid;
39 import org.sonar.server.measure.Rating;
40
41 import static java.util.Arrays.asList;
42 import static org.assertj.core.api.Assertions.assertThat;
43
44 public class IssueMetricFormulaFactoryImplTest {
45   @Rule
46   public ExpectedException expectedException = ExpectedException.none();
47
48   private IssueMetricFormulaFactoryImpl underTest = new IssueMetricFormulaFactoryImpl();
49
50   @Test
51   public void getFormulaMetrics_include_the_dependent_metrics() {
52     for (IssueMetricFormula formula : underTest.getFormulas()) {
53       assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric());
54       for (Metric dependentMetric : formula.getDependentMetrics()) {
55         assertThat(underTest.getFormulaMetrics()).contains(dependentMetric);
56       }
57     }
58   }
59
60   @Test
61   public void test_violations() {
62     withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0);
63     with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5);
64
65     // exclude resolved
66     IssueGroupDto resolved = newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED);
67     with(newGroup(), newGroup(), resolved).assertThatValueIs(CoreMetrics.VIOLATIONS, 2);
68
69     // include issues on leak
70     IssueGroupDto onLeak = newGroup().setCount(11).setInLeak(true);
71     with(newGroup(), newGroup(), onLeak).assertThatValueIs(CoreMetrics.VIOLATIONS, 1 + 1 + 11);
72   }
73
74   @Test
75   public void test_bugs() {
76     withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0);
77     with(
78       newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3),
79       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5),
80       // exclude resolved
81       newResolvedGroup(RuleType.BUG).setCount(7),
82       // not bugs
83       newGroup(RuleType.CODE_SMELL).setCount(11))
84         .assertThatValueIs(CoreMetrics.BUGS, 3 + 5);
85   }
86
87   @Test
88   public void test_code_smells() {
89     withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0);
90     with(
91       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
92       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setCount(5),
93       // exclude resolved
94       newResolvedGroup(RuleType.CODE_SMELL).setCount(7),
95       // not code smells
96       newGroup(RuleType.BUG).setCount(11))
97         .assertThatValueIs(CoreMetrics.CODE_SMELLS, 3 + 5);
98   }
99
100   @Test
101   public void test_vulnerabilities() {
102     withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0);
103     with(
104       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
105       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5),
106       // exclude resolved
107       newResolvedGroup(RuleType.VULNERABILITY).setCount(7),
108       // not vulnerabilities
109       newGroup(RuleType.BUG).setCount(11))
110         .assertThatValueIs(CoreMetrics.VULNERABILITIES, 3 + 5);
111   }
112
113   @Test
114   public void test_security_hotspots() {
115     withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0);
116     with(
117       newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3),
118       newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(5),
119       // exclude resolved
120       newResolvedGroup(RuleType.SECURITY_HOTSPOT).setCount(7),
121       // not hotspots
122       newGroup(RuleType.BUG).setCount(11))
123         .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 3 + 5);
124   }
125
126   @Test
127   public void test_security_review_rating() {
128     with(
129       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
130       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
131         .assertThatValueIs(CoreMetrics.SECURITY_REVIEW_RATING, Rating.B);
132
133     withNoIssues()
134       .assertThatValueIs(CoreMetrics.SECURITY_REVIEW_RATING, Rating.A);
135   }
136
137   @Test
138   public void test_security_hotspots_reviewed() {
139     with(
140       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
141       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
142         .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED, 75.0);
143
144     withNoIssues()
145       .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED, 100.0);
146   }
147
148   @Test
149   public void count_unresolved_by_severity() {
150     withNoIssues()
151       .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0)
152       .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0)
153       .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 0)
154       .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
155       .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
156
157     with(
158       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3),
159       newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(5),
160       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(7),
161       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(11),
162       // exclude security hotspot
163       newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.CRITICAL).setCount(15),
164       // include leak
165       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(13),
166       // exclude resolved
167       newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(17),
168       newResolvedGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(19),
169       newResolvedGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.INFO).setCount(21))
170         .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 11 + 13)
171         .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 7)
172         .assertThatValueIs(CoreMetrics.MAJOR_VIOLATIONS, 3 + 5)
173         .assertThatValueIs(CoreMetrics.MINOR_VIOLATIONS, 0)
174         .assertThatValueIs(CoreMetrics.INFO_VIOLATIONS, 0);
175   }
176
177   @Test
178   public void count_resolved() {
179     withNoIssues()
180       .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0)
181       .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 0);
182
183     with(
184       newResolvedGroup(Issue.RESOLUTION_FIXED, Issue.STATUS_RESOLVED).setCount(3),
185       newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(5),
186       newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.MAJOR).setCount(7),
187       newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_CLOSED).setSeverity(Severity.BLOCKER).setCount(11),
188       newResolvedGroup(Issue.RESOLUTION_REMOVED, Issue.STATUS_CLOSED).setCount(13),
189       // exclude security hotspot
190       newResolvedGroup(Issue.RESOLUTION_WONT_FIX, Issue.STATUS_RESOLVED).setCount(15).setRuleType(RuleType.SECURITY_HOTSPOT.getDbConstant()),
191       // exclude unresolved
192       newGroup(RuleType.VULNERABILITY).setCount(17),
193       newGroup(RuleType.BUG).setCount(19))
194         .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 5)
195         .assertThatValueIs(CoreMetrics.WONT_FIX_ISSUES, 7 + 11);
196   }
197
198   @Test
199   public void count_by_status() {
200     withNoIssues()
201       .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0)
202       .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0)
203       .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 0);
204
205     with(
206       newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.BLOCKER).setCount(3),
207       newGroup().setStatus(Issue.STATUS_CONFIRMED).setSeverity(Severity.INFO).setCount(5),
208       newGroup().setStatus(Issue.STATUS_REOPENED).setCount(7),
209       newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_OPEN).setCount(9),
210       newGroup(RuleType.BUG).setStatus(Issue.STATUS_OPEN).setCount(11),
211       // exclude security hotspot
212       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_OPEN).setCount(12),
213       newResolvedGroup(Issue.RESOLUTION_FALSE_POSITIVE, Issue.STATUS_CLOSED).setCount(13))
214         .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 3 + 5)
215         .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 9 + 11)
216         .assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
217   }
218
219   @Test
220   public void test_technical_debt() {
221     withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
222
223     with(
224       newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(false),
225       newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(true),
226       // exclude security hotspot
227       newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9).setInLeak(true),
228       newGroup(RuleType.SECURITY_HOTSPOT).setEffort(11).setInLeak(false),
229       // not code smells
230       newGroup(RuleType.BUG).setEffort(7.0),
231       // exclude resolved
232       newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0))
233         .assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 3.0 + 5.0);
234   }
235
236   @Test
237   public void test_reliability_remediation_effort() {
238     withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0);
239
240     with(
241       newGroup(RuleType.BUG).setEffort(3.0),
242       newGroup(RuleType.BUG).setEffort(5.0).setSeverity(Severity.BLOCKER),
243       // not bugs
244       newGroup(RuleType.CODE_SMELL).setEffort(7.0),
245       // exclude resolved
246       newResolvedGroup(RuleType.BUG).setEffort(17.0))
247         .assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 3.0 + 5.0);
248   }
249
250   @Test
251   public void test_security_remediation_effort() {
252     withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0);
253
254     with(
255       newGroup(RuleType.VULNERABILITY).setEffort(3.0),
256       newGroup(RuleType.VULNERABILITY).setEffort(5.0).setSeverity(Severity.BLOCKER),
257       // not vulnerability
258       newGroup(RuleType.CODE_SMELL).setEffort(7.0),
259       // exclude resolved
260       newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0))
261         .assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 3.0 + 5.0);
262   }
263
264   @Test
265   public void test_sqale_debt_ratio_and_sqale_rating() {
266     withNoIssues()
267       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
268       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
269
270     // technical_debt not computed
271     with(CoreMetrics.DEVELOPMENT_COST, 0)
272       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
273       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
274     with(CoreMetrics.DEVELOPMENT_COST, 20)
275       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
276       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
277
278     // development_cost not computed
279     with(CoreMetrics.TECHNICAL_DEBT, 0)
280       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
281       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
282     with(CoreMetrics.TECHNICAL_DEBT, 20)
283       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0)
284       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
285
286     // input measures are available
287     with(CoreMetrics.TECHNICAL_DEBT, 20.0)
288       .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
289       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
290       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
291
292     with(CoreMetrics.TECHNICAL_DEBT, 20.0)
293       .and(CoreMetrics.DEVELOPMENT_COST, 160.0)
294       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 12.5)
295       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.C);
296
297     with(CoreMetrics.TECHNICAL_DEBT, 20.0)
298       .and(CoreMetrics.DEVELOPMENT_COST, 10.0)
299       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 200.0)
300       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.E);
301
302     // A is 5% --> min debt is exactly 200*0.05=10
303     with(CoreMetrics.DEVELOPMENT_COST, 200.0)
304       .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
305       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 5.0)
306       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
307
308     with(CoreMetrics.TECHNICAL_DEBT, 0.0)
309       .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
310       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
311       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
312
313     with(CoreMetrics.TECHNICAL_DEBT, 0.0)
314       .and(CoreMetrics.DEVELOPMENT_COST, 80.0)
315       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0);
316
317     with(CoreMetrics.TECHNICAL_DEBT, -20.0)
318       .and(CoreMetrics.DEVELOPMENT_COST, 0.0)
319       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
320       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
321
322     // bug, debt can't be negative
323     with(CoreMetrics.TECHNICAL_DEBT, -20.0)
324       .and(CoreMetrics.DEVELOPMENT_COST, 80.0)
325       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
326       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
327
328     // bug, cost can't be negative
329     with(CoreMetrics.TECHNICAL_DEBT, 20.0)
330       .and(CoreMetrics.DEVELOPMENT_COST, -80.0)
331       .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0.0)
332       .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A);
333   }
334
335   @Test
336   public void test_effort_to_reach_maintainability_rating_A() {
337     withNoIssues()
338       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
339
340     // technical_debt not computed
341     with(CoreMetrics.DEVELOPMENT_COST, 0.0)
342       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
343     with(CoreMetrics.DEVELOPMENT_COST, 20.0)
344       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
345
346     // development_cost not computed
347     with(CoreMetrics.TECHNICAL_DEBT, 0.0)
348       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
349     with(CoreMetrics.TECHNICAL_DEBT, 20.0)
350       // development cost is considered as zero, so the effort is to reach... zero
351       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 20.0);
352
353     // B to A
354     with(CoreMetrics.DEVELOPMENT_COST, 200.0)
355       .and(CoreMetrics.TECHNICAL_DEBT, 40.0)
356       // B is 5% --> goal is to reach 200*0.05=10 --> effort is 40-10=30
357       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 40.0 - (200.0 * 0.05));
358
359     // E to A
360     with(CoreMetrics.DEVELOPMENT_COST, 200.0)
361       .and(CoreMetrics.TECHNICAL_DEBT, 180.0)
362       // B is 5% --> goal is to reach 200*0.05=10 --> effort is 180-10=170
363       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 180.0 - (200.0 * 0.05));
364
365     // already A
366     with(CoreMetrics.DEVELOPMENT_COST, 200.0)
367       .and(CoreMetrics.TECHNICAL_DEBT, 8.0)
368       // B is 5% --> goal is to reach 200*0.05=10 --> debt is already at 8 --> effort to reach A is zero
369       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
370
371     // exactly lower range of B
372     with(CoreMetrics.DEVELOPMENT_COST, 200.0)
373       .and(CoreMetrics.TECHNICAL_DEBT, 10.0)
374       // B is 5% --> goal is to reach 200*0.05=10 --> debt is 10 --> effort to reach A is zero
375       // FIXME need zero to reach A but effective rating is B !
376       .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0);
377   }
378
379   @Test
380   public void test_reliability_rating() {
381     withNoIssues()
382       .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
383
384     with(
385       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(1),
386       newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(5),
387       // excluded, not a bug
388       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
389         // highest severity of bugs is CRITICAL --> D
390         .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.D);
391
392     with(
393       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
394       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(5))
395         // no bugs --> A
396         .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A);
397   }
398
399   @Test
400   public void test_security_rating() {
401     withNoIssues()
402       .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
403
404     with(
405       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setCount(1),
406       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(5),
407       // excluded, not a vulnerability
408       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setCount(3))
409         // highest severity of vulnerabilities is CRITICAL --> D
410         .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.D);
411
412     with(
413       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3),
414       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setCount(5))
415         // no vulnerabilities --> A
416         .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A);
417   }
418
419   @Test
420   public void test_new_bugs() {
421     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0);
422
423     with(
424       newGroup(RuleType.BUG).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
425       newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
426       newGroup(RuleType.BUG).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
427       // not bugs
428       newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(9),
429       newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
430         .assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 5 + 7);
431   }
432
433   @Test
434   public void test_new_code_smells() {
435     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0);
436
437     with(
438       newGroup(RuleType.CODE_SMELL).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
439       newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
440       newGroup(RuleType.CODE_SMELL).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
441       // not code smells
442       newGroup(RuleType.BUG).setInLeak(true).setCount(9),
443       newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(11))
444         .assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 5 + 7);
445   }
446
447   @Test
448   public void test_new_vulnerabilities() {
449     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0);
450
451     with(
452       newGroup(RuleType.VULNERABILITY).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
453       newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
454       newGroup(RuleType.VULNERABILITY).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
455       // not vulnerabilities
456       newGroup(RuleType.BUG).setInLeak(true).setCount(9),
457       newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
458         .assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 5 + 7);
459   }
460
461   @Test
462   public void test_new_security_hotspots() {
463     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0.0);
464
465     with(
466       newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(false).setSeverity(Severity.MAJOR).setCount(3),
467       newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.CRITICAL).setCount(5),
468       newGroup(RuleType.SECURITY_HOTSPOT).setInLeak(true).setSeverity(Severity.MINOR).setCount(7),
469       // not hotspots
470       newGroup(RuleType.BUG).setInLeak(true).setCount(9),
471       newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(11))
472         .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 5 + 7);
473   }
474
475   @Test
476   public void test_new_violations() {
477     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0);
478
479     with(
480       newGroup(RuleType.BUG).setInLeak(true).setCount(5),
481       newGroup(RuleType.CODE_SMELL).setInLeak(true).setCount(7),
482       newGroup(RuleType.VULNERABILITY).setInLeak(true).setCount(9),
483       // not in leak
484       newGroup(RuleType.BUG).setInLeak(false).setCount(11),
485       newGroup(RuleType.CODE_SMELL).setInLeak(false).setCount(13),
486       newGroup(RuleType.VULNERABILITY).setInLeak(false).setCount(17))
487         .assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 5 + 7 + 9);
488   }
489
490   @Test
491   public void test_new_blocker_violations() {
492     withNoIssues()
493       .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0);
494
495     with(
496       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(3),
497       newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(5),
498       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true).setCount(7),
499       // not blocker
500       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
501       // not in leak
502       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(11),
503       newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false).setCount(13))
504         .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 3 + 5 + 7);
505   }
506
507   @Test
508   public void test_new_critical_violations() {
509     withNoIssues()
510       .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0);
511
512     with(
513       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(3),
514       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(5),
515       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(7),
516       // not CRITICAL
517       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(9),
518       // not in leak
519       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(11),
520       newGroup(RuleType.BUG).setSeverity(Severity.CRITICAL).setInLeak(false).setCount(13))
521         .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 3 + 5 + 7);
522   }
523
524   @Test
525   public void test_new_major_violations() {
526     withNoIssues()
527       .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0);
528
529     with(
530       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(true).setCount(3),
531       newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(true).setCount(5),
532       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setInLeak(true).setCount(7),
533       // not MAJOR
534       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
535       // not in leak
536       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setInLeak(false).setCount(11),
537       newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setInLeak(false).setCount(13))
538         .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 3 + 5 + 7);
539   }
540
541   @Test
542   public void test_new_minor_violations() {
543     withNoIssues()
544       .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0);
545
546     with(
547       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(true).setCount(3),
548       newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(true).setCount(5),
549       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setInLeak(true).setCount(7),
550       // not MINOR
551       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
552       // not in leak
553       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MINOR).setInLeak(false).setCount(11),
554       newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setInLeak(false).setCount(13))
555         .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 3 + 5 + 7);
556   }
557
558   @Test
559   public void test_new_info_violations() {
560     withNoIssues()
561       .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0);
562
563     with(
564       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(true).setCount(3),
565       newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(true).setCount(5),
566       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setInLeak(true).setCount(7),
567       // not INFO
568       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.CRITICAL).setInLeak(true).setCount(9),
569       // not in leak
570       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.INFO).setInLeak(false).setCount(11),
571       newGroup(RuleType.BUG).setSeverity(Severity.INFO).setInLeak(false).setCount(13))
572         .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 3 + 5 + 7);
573   }
574
575   @Test
576   public void test_new_technical_debt() {
577     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0);
578
579     with(
580       newGroup(RuleType.CODE_SMELL).setEffort(3.0).setInLeak(true),
581       // not in leak
582       newGroup(RuleType.CODE_SMELL).setEffort(5.0).setInLeak(false),
583       // not code smells
584       newGroup(RuleType.SECURITY_HOTSPOT).setEffort(9.0).setInLeak(true),
585       newGroup(RuleType.BUG).setEffort(7.0).setInLeak(true),
586       // exclude resolved
587       newResolvedGroup(RuleType.CODE_SMELL).setEffort(17.0).setInLeak(true))
588         .assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 3.0);
589   }
590
591   @Test
592   public void test_new_reliability_remediation_effort() {
593     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0);
594
595     with(
596       newGroup(RuleType.BUG).setEffort(3.0).setInLeak(true),
597       // not in leak
598       newGroup(RuleType.BUG).setEffort(5.0).setInLeak(false),
599       // not bugs
600       newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
601       // exclude resolved
602       newResolvedGroup(RuleType.BUG).setEffort(17.0).setInLeak(true))
603         .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 3.0);
604   }
605
606   @Test
607   public void test_new_security_remediation_effort() {
608     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0);
609
610     with(
611       newGroup(RuleType.VULNERABILITY).setEffort(3.0).setInLeak(true),
612       // not in leak
613       newGroup(RuleType.VULNERABILITY).setEffort(5.0).setInLeak(false),
614       // not vulnerability
615       newGroup(RuleType.CODE_SMELL).setEffort(7.0).setInLeak(true),
616       // exclude resolved
617       newResolvedGroup(RuleType.VULNERABILITY).setEffort(17.0).setInLeak(true))
618         .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 3.0);
619   }
620
621   @Test
622   public void test_new_reliability_rating() {
623     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A);
624
625     with(
626       newGroup(RuleType.BUG).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
627       newGroup(RuleType.BUG).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
628       // not in leak
629       newGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(false),
630       // not bug
631       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
632       // exclude resolved
633       newResolvedGroup(RuleType.BUG).setSeverity(Severity.BLOCKER).setInLeak(true))
634         // highest severity of bugs on leak period is minor -> B
635         .assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.B);
636   }
637
638   @Test
639   public void test_new_security_rating() {
640     withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A);
641
642     with(
643       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.INFO).setCount(3).setInLeak(true),
644       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MINOR).setCount(1).setInLeak(true),
645       // not in leak
646       newGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(false),
647       // not vulnerability
648       newGroup(RuleType.CODE_SMELL).setSeverity(Severity.BLOCKER).setInLeak(true),
649       // exclude resolved
650       newResolvedGroup(RuleType.VULNERABILITY).setSeverity(Severity.BLOCKER).setInLeak(true))
651         // highest severity of bugs on leak period is minor -> B
652         .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.B);
653   }
654
655   @Test
656   public void test_new_security_review_rating() {
657     with(
658       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
659       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
660       // not in leak
661       newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Issue.STATUS_TO_REVIEW).setInLeak(false))
662         .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REVIEW_RATING, Rating.B);
663
664     withNoIssues()
665       .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REVIEW_RATING, Rating.A);
666   }
667
668   @Test
669   public void test_new_security_hotspots_reviewed() {
670     with(
671       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true),
672       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true),
673       // not in leak
674       newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
675         .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 75.0);
676
677     withNoIssues()
678       .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 100.0);
679   }
680
681   @Test
682   public void test_new_sqale_debt_ratio_and_new_maintainability_rating() {
683     withNoIssues()
684       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
685       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
686
687     // technical_debt not computed
688     withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0)
689       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
690       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
691     withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 20)
692       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
693       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
694
695     // development_cost not computed
696     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0)
697       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
698       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
699     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20)
700       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0)
701       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
702
703     // input measures are available
704     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
705       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
706       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
707       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
708
709     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
710       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 160.0)
711       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 12.5)
712       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.C);
713
714     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
715       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 10.0)
716       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 200.0)
717       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.E);
718
719     // A is 5% --> min debt is exactly 200*0.05=10
720     withLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 200.0)
721       .andLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 10.0)
722       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 5.0)
723       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
724
725     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
726       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
727       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
728       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
729
730     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0)
731       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
732       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0);
733
734     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
735       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 0.0)
736       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
737       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
738
739     // bug, debt can't be negative
740     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, -20.0)
741       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, 80.0)
742       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
743       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
744
745     // bug, cost can't be negative
746     withLeak(CoreMetrics.NEW_TECHNICAL_DEBT, 20.0)
747       .andLeak(CoreMetrics.NEW_DEVELOPMENT_COST, -80.0)
748       .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0.0)
749       .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
750   }
751
752   private Verifier with(IssueGroupDto... groups) {
753     return new Verifier(groups);
754   }
755
756   private Verifier withNoIssues() {
757     return new Verifier(new IssueGroupDto[0]);
758   }
759
760   private Verifier with(Metric metric, double value) {
761     return new Verifier(new IssueGroupDto[0]).and(metric, value);
762   }
763
764   private Verifier withLeak(Metric metric, double leakValue) {
765     return new Verifier(new IssueGroupDto[0]).andLeak(metric, leakValue);
766   }
767
768   private class Verifier {
769     private final IssueGroupDto[] groups;
770     private final Map<Metric, Double> values = new HashMap<>();
771     private final Map<Metric, Double> leakValues = new HashMap<>();
772
773     private Verifier(IssueGroupDto[] groups) {
774       this.groups = groups;
775     }
776
777     Verifier and(Metric metric, double value) {
778       this.values.put(metric, value);
779       return this;
780     }
781
782     Verifier andLeak(Metric metric, double value) {
783       this.leakValues.put(metric, value);
784       return this;
785     }
786
787     Verifier assertThatValueIs(Metric metric, double expectedValue) {
788       TestContext context = run(metric, false);
789       assertThat(context.doubleValue).isNotNull().isEqualTo(expectedValue);
790       return this;
791     }
792
793     Verifier assertThatLeakValueIs(Metric metric, double expectedValue) {
794       TestContext context = run(metric, true);
795       assertThat(context.doubleLeakValue).isNotNull().isEqualTo(expectedValue);
796       return this;
797     }
798
799     Verifier assertThatLeakValueIs(Metric metric, Rating expectedRating) {
800       TestContext context = run(metric, true);
801       assertThat(context.ratingLeakValue).isNotNull().isEqualTo(expectedRating);
802       return this;
803     }
804
805     Verifier assertThatValueIs(Metric metric, Rating expectedValue) {
806       TestContext context = run(metric, false);
807       assertThat(context.ratingValue).isNotNull().isEqualTo(expectedValue);
808       return this;
809     }
810
811     private TestContext run(Metric metric, boolean expectLeakFormula) {
812       IssueMetricFormula formula = underTest.getFormulas().stream()
813         .filter(f -> f.getMetric().getKey().equals(metric.getKey()))
814         .findFirst()
815         .get();
816       assertThat(formula.isOnLeak()).isEqualTo(expectLeakFormula);
817       TestContext context = new TestContext(formula.getDependentMetrics(), values, leakValues);
818       formula.compute(context, newIssueCounter(groups));
819       return context;
820     }
821   }
822
823   private static IssueCounter newIssueCounter(IssueGroupDto... issues) {
824     return new IssueCounter(asList(issues));
825   }
826
827   private static IssueGroupDto newGroup() {
828     return newGroup(RuleType.CODE_SMELL);
829   }
830
831   private static IssueGroupDto newGroup(RuleType ruleType) {
832     IssueGroupDto dto = new IssueGroupDto();
833     // set non-null fields
834     dto.setRuleType(ruleType.getDbConstant());
835     dto.setCount(1);
836     dto.setEffort(0.0);
837     dto.setSeverity(Severity.INFO);
838     dto.setStatus(Issue.STATUS_OPEN);
839     dto.setInLeak(false);
840     return dto;
841   }
842
843   private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
844     return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
845   }
846
847   private static IssueGroupDto newResolvedGroup(String resolution, String status) {
848     return newGroup().setResolution(resolution).setStatus(status);
849   }
850
851   private static class TestContext implements IssueMetricFormula.Context {
852     private final Set<Metric> dependentMetrics;
853     private Double doubleValue;
854     private Rating ratingValue;
855     private Double doubleLeakValue;
856     private Rating ratingLeakValue;
857     private final Map<Metric, Double> values;
858     private final Map<Metric, Double> leakValues;
859
860     private TestContext(Collection<Metric> dependentMetrics, Map<Metric, Double> values, Map<Metric, Double> leakValues) {
861       this.dependentMetrics = new HashSet<>(dependentMetrics);
862       this.values = values;
863       this.leakValues = leakValues;
864     }
865
866     @Override
867     public ComponentDto getComponent() {
868       throw new UnsupportedOperationException();
869     }
870
871     @Override
872     public DebtRatingGrid getDebtRatingGrid() {
873       return new DebtRatingGrid(new double[] {0.05, 0.1, 0.2, 0.5});
874     }
875
876     @Override
877     public Optional<Double> getValue(Metric metric) {
878       if (!dependentMetrics.contains(metric)) {
879         throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
880       }
881       if (values.containsKey(metric)) {
882         return Optional.of(values.get(metric));
883       }
884       return Optional.empty();
885     }
886
887     @Override
888     public Optional<Double> getLeakValue(Metric metric) {
889       if (!dependentMetrics.contains(metric)) {
890         throw new IllegalStateException("Metric " + metric.getKey() + " is not declared as a dependency");
891       }
892       if (leakValues.containsKey(metric)) {
893         return Optional.of(leakValues.get(metric));
894       }
895       return Optional.empty();
896     }
897
898     @Override
899     public void setValue(double value) {
900       this.doubleValue = value;
901     }
902
903     @Override
904     public void setValue(Rating value) {
905       this.ratingValue = value;
906     }
907
908     @Override
909     public void setLeakValue(double value) {
910       this.doubleLeakValue = value;
911     }
912
913     @Override
914     public void setLeakValue(Rating value) {
915       this.ratingLeakValue = value;
916     }
917   }
918 }