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.ce.task.projectanalysis.issue;
22 import java.util.Arrays;
23 import java.util.List;
25 import javax.annotation.Nullable;
26 import org.assertj.core.data.MapEntry;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.sonar.api.issue.impact.Severity;
30 import org.sonar.api.issue.impact.SoftwareQuality;
31 import org.sonar.api.rules.RuleType;
32 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
33 import org.sonar.ce.task.projectanalysis.component.Component;
34 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
35 import org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry;
36 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
37 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
38 import org.sonar.core.issue.DefaultIssue;
39 import org.sonar.db.rule.RuleTesting;
41 import static java.util.Arrays.stream;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.assertj.core.api.Assertions.entry;
44 import static org.mockito.ArgumentMatchers.any;
45 import static org.mockito.ArgumentMatchers.eq;
46 import static org.mockito.Mockito.mock;
47 import static org.mockito.Mockito.when;
48 import static org.sonar.api.issue.Issue.RESOLUTION_FALSE_POSITIVE;
49 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
50 import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX;
51 import static org.sonar.api.issue.Issue.STATUS_CLOSED;
52 import static org.sonar.api.issue.Issue.STATUS_CONFIRMED;
53 import static org.sonar.api.issue.Issue.STATUS_OPEN;
54 import static org.sonar.api.issue.Issue.STATUS_RESOLVED;
55 import static org.sonar.api.issue.impact.Severity.HIGH;
56 import static org.sonar.api.issue.impact.Severity.MEDIUM;
57 import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES;
58 import static org.sonar.api.measures.CoreMetrics.ACCEPTED_ISSUES_KEY;
59 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS;
60 import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS_KEY;
61 import static org.sonar.api.measures.CoreMetrics.BUGS;
62 import static org.sonar.api.measures.CoreMetrics.BUGS_KEY;
63 import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS;
64 import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY;
65 import static org.sonar.api.measures.CoreMetrics.CONFIRMED_ISSUES;
66 import static org.sonar.api.measures.CoreMetrics.CONFIRMED_ISSUES_KEY;
67 import static org.sonar.api.measures.CoreMetrics.CRITICAL_VIOLATIONS;
68 import static org.sonar.api.measures.CoreMetrics.CRITICAL_VIOLATIONS_KEY;
69 import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES;
70 import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY;
71 import static org.sonar.api.measures.CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES;
72 import static org.sonar.api.measures.CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES_KEY;
73 import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS;
74 import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS;
75 import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY;
76 import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS;
77 import static org.sonar.api.measures.CoreMetrics.NEW_ACCEPTED_ISSUES;
78 import static org.sonar.api.measures.CoreMetrics.NEW_ACCEPTED_ISSUES_KEY;
79 import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKER_VIOLATIONS;
80 import static org.sonar.api.measures.CoreMetrics.NEW_BLOCKER_VIOLATIONS_KEY;
81 import static org.sonar.api.measures.CoreMetrics.NEW_BUGS;
82 import static org.sonar.api.measures.CoreMetrics.NEW_BUGS_KEY;
83 import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS;
84 import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS_KEY;
85 import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS;
86 import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY;
87 import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS;
88 import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS;
89 import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY;
90 import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS;
91 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS;
92 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY;
93 import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS;
94 import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY;
95 import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES;
96 import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES_KEY;
97 import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES;
98 import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY;
99 import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES;
100 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS;
101 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
102 import static org.sonar.api.measures.CoreMetrics.VIOLATIONS;
103 import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY;
104 import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES;
105 import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY;
106 import static org.sonar.api.rule.Severity.BLOCKER;
107 import static org.sonar.api.rule.Severity.CRITICAL;
108 import static org.sonar.api.rule.Severity.MAJOR;
109 import static org.sonar.api.rules.RuleType.BUG;
110 import static org.sonar.api.rules.RuleType.CODE_SMELL;
111 import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
112 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
113 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
114 import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
116 public class IssueCounterTest {
118 private static final Component FILE1 = builder(Component.Type.FILE, 1).build();
119 private static final Component FILE2 = builder(Component.Type.FILE, 2).build();
120 private static final Component FILE3 = builder(Component.Type.FILE, 3).build();
121 private static final Component PROJECT = builder(Component.Type.PROJECT, 4).addChildren(FILE1, FILE2, FILE3).build();
124 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
127 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
130 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
133 .add(REOPENED_ISSUES)
134 .add(CONFIRMED_ISSUES)
135 .add(BLOCKER_VIOLATIONS)
136 .add(CRITICAL_VIOLATIONS)
137 .add(MAJOR_VIOLATIONS)
138 .add(MINOR_VIOLATIONS)
139 .add(INFO_VIOLATIONS)
141 .add(NEW_BLOCKER_VIOLATIONS)
142 .add(NEW_CRITICAL_VIOLATIONS)
143 .add(NEW_MAJOR_VIOLATIONS)
144 .add(NEW_MINOR_VIOLATIONS)
145 .add(NEW_INFO_VIOLATIONS)
146 .add(FALSE_POSITIVE_ISSUES)
147 .add(ACCEPTED_ISSUES)
150 .add(VULNERABILITIES)
151 .add(SECURITY_HOTSPOTS)
152 .add(NEW_CODE_SMELLS)
154 .add(NEW_VULNERABILITIES)
155 .add(NEW_SECURITY_HOTSPOTS)
156 .add(NEW_ACCEPTED_ISSUES)
157 .add(HIGH_IMPACT_ACCEPTED_ISSUES);
160 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
161 private NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class);
162 private IssueCounter underTest = new IssueCounter(metricRepository, measureRepository, newIssueClassifier);
165 public void count_issues_by_status() {
166 // bottom-up traversal -> from files to project
167 underTest.beforeComponent(FILE1);
168 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER));
169 underTest.onIssue(FILE1, createIssue(RESOLUTION_FIXED, STATUS_CLOSED, MAJOR));
170 underTest.onIssue(FILE1, createIssue(RESOLUTION_FALSE_POSITIVE, STATUS_RESOLVED, MAJOR));
171 underTest.afterComponent(FILE1);
173 underTest.beforeComponent(FILE2);
174 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, BLOCKER));
175 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, MAJOR));
176 underTest.afterComponent(FILE2);
178 underTest.beforeComponent(FILE3);
179 // Security hotspot should be ignored
180 underTest.onIssue(FILE3, createSecurityHotspot().setStatus(STATUS_OPEN));
181 underTest.afterComponent(FILE3);
183 underTest.beforeComponent(PROJECT);
184 underTest.afterComponent(PROJECT);
186 assertMeasures(FILE1, entry(VIOLATIONS_KEY, 1), entry(OPEN_ISSUES_KEY, 1), entry(CONFIRMED_ISSUES_KEY, 0));
187 assertMeasures(FILE2, entry(VIOLATIONS_KEY, 2), entry(OPEN_ISSUES_KEY, 0), entry(CONFIRMED_ISSUES_KEY, 2));
188 assertMeasures(FILE3, entry(VIOLATIONS_KEY, 0));
189 assertMeasures(PROJECT, entry(VIOLATIONS_KEY, 3), entry(OPEN_ISSUES_KEY, 1), entry(CONFIRMED_ISSUES_KEY, 2));
193 public void count_issues_by_resolution() {
194 // bottom-up traversal -> from files to project
195 underTest.beforeComponent(FILE1);
196 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER));
197 underTest.onIssue(FILE1, createIssue(RESOLUTION_FIXED, STATUS_CLOSED, MAJOR));
198 underTest.onIssue(FILE1, createIssue(RESOLUTION_FALSE_POSITIVE, STATUS_RESOLVED, MAJOR));
199 underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MAJOR));
200 underTest.afterComponent(FILE1);
202 underTest.beforeComponent(FILE2);
203 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, BLOCKER));
204 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, MAJOR));
205 underTest.onIssue(FILE2, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MAJOR));
206 underTest.afterComponent(FILE2);
208 underTest.beforeComponent(FILE3);
209 // Security hotspot should be ignored
210 underTest.onIssue(FILE3, createSecurityHotspot().setResolution(RESOLUTION_WONT_FIX));
211 underTest.afterComponent(FILE3);
213 underTest.beforeComponent(PROJECT);
214 underTest.afterComponent(PROJECT);
216 assertMeasures(FILE1, entry(VIOLATIONS_KEY, 1), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(ACCEPTED_ISSUES_KEY, 1));
217 assertMeasures(FILE2, entry(VIOLATIONS_KEY, 2), entry(FALSE_POSITIVE_ISSUES_KEY, 0), entry(ACCEPTED_ISSUES_KEY, 1));
218 assertMeasures(FILE3, entry(VIOLATIONS_KEY, 0));
219 assertMeasures(PROJECT, entry(VIOLATIONS_KEY, 3), entry(FALSE_POSITIVE_ISSUES_KEY, 1), entry(ACCEPTED_ISSUES_KEY, 2));
223 public void count_unresolved_issues_by_severity() {
224 // bottom-up traversal -> from files to project
225 underTest.beforeComponent(FILE1);
226 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER));
227 // this resolved issue is ignored
228 underTest.onIssue(FILE1, createIssue(RESOLUTION_FIXED, STATUS_CLOSED, MAJOR));
229 underTest.afterComponent(FILE1);
231 underTest.beforeComponent(FILE2);
232 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, BLOCKER));
233 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, MAJOR));
234 underTest.afterComponent(FILE2);
236 underTest.beforeComponent(PROJECT);
237 // Security hotspot should be ignored
238 underTest.onIssue(FILE3, createSecurityHotspot().setSeverity(MAJOR));
239 underTest.afterComponent(PROJECT);
241 assertMeasures(FILE1, entry(BLOCKER_VIOLATIONS_KEY, 1), entry(CRITICAL_VIOLATIONS_KEY, 0), entry(MAJOR_VIOLATIONS_KEY, 0));
242 assertMeasures(FILE2, entry(BLOCKER_VIOLATIONS_KEY, 1), entry(CRITICAL_VIOLATIONS_KEY, 0), entry(MAJOR_VIOLATIONS_KEY, 1));
243 assertMeasures(PROJECT, entry(BLOCKER_VIOLATIONS_KEY, 2), entry(CRITICAL_VIOLATIONS_KEY, 0), entry(MAJOR_VIOLATIONS_KEY, 1));
247 public void count_unresolved_issues_by_type() {
248 // bottom-up traversal -> from files to project
249 // file1 : one open code smell, one closed code smell (which will be excluded from metric)
250 underTest.beforeComponent(FILE1);
251 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER).setType(CODE_SMELL));
252 underTest.onIssue(FILE1, createIssue(RESOLUTION_FIXED, STATUS_CLOSED, MAJOR).setType(CODE_SMELL));
253 underTest.afterComponent(FILE1);
256 underTest.beforeComponent(FILE2);
257 underTest.onIssue(FILE2, createIssue(null, STATUS_CONFIRMED, BLOCKER).setType(BUG));
258 underTest.afterComponent(FILE2);
260 // file3 : one unresolved security hotspot
261 underTest.beforeComponent(FILE3);
262 underTest.onIssue(FILE3, createSecurityHotspot());
263 underTest.onIssue(FILE3, createSecurityHotspot().setResolution(RESOLUTION_WONT_FIX).setStatus(STATUS_CLOSED));
264 underTest.afterComponent(FILE3);
266 underTest.beforeComponent(PROJECT);
267 underTest.afterComponent(PROJECT);
269 assertMeasures(FILE1, entry(CODE_SMELLS_KEY, 1), entry(BUGS_KEY, 0), entry(VULNERABILITIES_KEY, 0), entry(SECURITY_HOTSPOTS_KEY, 0));
270 assertMeasures(FILE2, entry(CODE_SMELLS_KEY, 0), entry(BUGS_KEY, 1), entry(VULNERABILITIES_KEY, 0), entry(SECURITY_HOTSPOTS_KEY, 0));
271 assertMeasures(FILE3, entry(CODE_SMELLS_KEY, 0), entry(BUGS_KEY, 0), entry(VULNERABILITIES_KEY, 0), entry(SECURITY_HOTSPOTS_KEY, 1));
272 assertMeasures(PROJECT, entry(CODE_SMELLS_KEY, 1), entry(BUGS_KEY, 1), entry(VULNERABILITIES_KEY, 0), entry(SECURITY_HOTSPOTS_KEY, 1));
276 public void count_new_issues() {
277 when(newIssueClassifier.isEnabled()).thenReturn(true);
279 underTest.beforeComponent(FILE1);
280 // created before -> existing issues (so ignored)
281 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER).setType(CODE_SMELL));
282 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER).setType(BUG));
284 // created after -> 4 new issues but 1 is closed
285 underTest.onIssue(FILE1, createNewIssue(null, STATUS_OPEN, CRITICAL).setType(CODE_SMELL));
286 underTest.onIssue(FILE1, createNewIssue(null, STATUS_OPEN, CRITICAL).setType(BUG));
287 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_FIXED, STATUS_CLOSED, MAJOR).setType(BUG));
288 underTest.onIssue(FILE1, createNewSecurityHotspot());
289 underTest.onIssue(FILE1, createNewSecurityHotspot().setResolution(RESOLUTION_WONT_FIX).setStatus(STATUS_CLOSED));
290 underTest.afterComponent(FILE1);
292 underTest.beforeComponent(FILE2);
293 underTest.afterComponent(FILE2);
295 underTest.beforeComponent(PROJECT);
296 underTest.afterComponent(PROJECT);
298 assertValues(FILE1, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
299 entry(NEW_CODE_SMELLS_KEY, 1), entry(NEW_BUGS_KEY, 1), entry(NEW_VULNERABILITIES_KEY, 0), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
300 assertValues(PROJECT, entry(NEW_VIOLATIONS_KEY, 2), entry(NEW_CRITICAL_VIOLATIONS_KEY, 2), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
301 entry(NEW_CODE_SMELLS_KEY, 1), entry(NEW_BUGS_KEY, 1), entry(NEW_VULNERABILITIES_KEY, 0), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
305 public void count_new_accepted_issues() {
306 when(newIssueClassifier.isEnabled()).thenReturn(true);
308 underTest.beforeComponent(FILE1);
309 // created before -> existing issues (so ignored)
310 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, CRITICAL));
311 underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, CRITICAL));
313 // created after -> 2 accepted, 1 open, 1 hotspot
314 underTest.onIssue(FILE1, createNewIssue(null, STATUS_OPEN, CRITICAL));
315 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, CRITICAL));
316 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, CRITICAL));
317 underTest.onIssue(FILE1, createNewSecurityHotspot());
318 underTest.afterComponent(FILE1);
320 underTest.beforeComponent(PROJECT);
321 underTest.afterComponent(PROJECT);
323 assertValues(FILE1, entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 2), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
324 assertValues(PROJECT, entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 2), entry(NEW_SECURITY_HOTSPOTS_KEY, 1));
328 public void count_high_impact_accepted_issues() {
329 when(newIssueClassifier.isEnabled()).thenReturn(true);
331 underTest.beforeComponent(FILE1);
332 // created before -> existing issues with 1 high impact accepted
333 underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, HIGH));
334 underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
335 underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MEDIUM));
337 // created after -> 2 high impact accepted
338 underTest.onIssue(FILE1, createNewIssue(null, STATUS_OPEN, HIGH));
339 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
340 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, HIGH));
341 underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, MEDIUM));
342 underTest.onIssue(FILE1, createNewSecurityHotspot());
343 underTest.afterComponent(FILE1);
345 underTest.beforeComponent(PROJECT);
346 underTest.afterComponent(PROJECT);
348 assertValues(FILE1, entry(VIOLATIONS_KEY, 2), entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 3),
349 entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 3));
350 assertValues(PROJECT, entry(VIOLATIONS_KEY, 2), entry(NEW_VIOLATIONS_KEY, 1), entry(NEW_ACCEPTED_ISSUES_KEY, 3),
351 entry(HIGH_IMPACT_ACCEPTED_ISSUES_KEY, 3));
355 public void exclude_hotspots_from_issue_counts() {
356 // bottom-up traversal -> from files to project
357 underTest.beforeComponent(FILE1);
358 underTest.onIssue(FILE1, createSecurityHotspot());
359 underTest.onIssue(FILE1, createSecurityHotspot());
360 underTest.afterComponent(FILE1);
362 underTest.beforeComponent(FILE2);
363 underTest.onIssue(FILE2, createSecurityHotspot());
364 underTest.afterComponent(FILE2);
366 underTest.beforeComponent(FILE3);
367 underTest.afterComponent(FILE3);
369 underTest.beforeComponent(PROJECT);
370 underTest.afterComponent(PROJECT);
372 assertMeasures(FILE1, entry(VIOLATIONS_KEY, 0), entry(OPEN_ISSUES_KEY, 0), entry(CONFIRMED_ISSUES_KEY, 0));
373 assertMeasures(FILE2, entry(VIOLATIONS_KEY, 0), entry(OPEN_ISSUES_KEY, 0), entry(CONFIRMED_ISSUES_KEY, 0));
374 assertMeasures(FILE3, entry(VIOLATIONS_KEY, 0));
375 assertMeasures(PROJECT, entry(VIOLATIONS_KEY, 0), entry(OPEN_ISSUES_KEY, 0), entry(CONFIRMED_ISSUES_KEY, 0));
379 public void exclude_new_hotspots_from_issue_counts() {
380 when(newIssueClassifier.isEnabled()).thenReturn(true);
382 underTest.beforeComponent(FILE1);
383 // created before -> existing issues (so ignored)
384 underTest.onIssue(FILE1, createSecurityHotspot());
385 underTest.onIssue(FILE1, createSecurityHotspot());
387 // created after, but closed
388 underTest.onIssue(FILE1, createNewSecurityHotspot().setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_WONT_FIX));
390 for (String severity : Arrays.asList(CRITICAL, BLOCKER, MAJOR)) {
391 DefaultIssue issue = createNewSecurityHotspot();
392 issue.setSeverity(severity);
393 underTest.onIssue(FILE1, issue);
395 underTest.afterComponent(FILE1);
397 underTest.beforeComponent(FILE2);
398 underTest.afterComponent(FILE2);
400 underTest.beforeComponent(PROJECT);
401 underTest.afterComponent(PROJECT);
403 assertValues(FILE1, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
404 entry(NEW_VULNERABILITIES_KEY, 0));
405 assertValues(PROJECT, entry(NEW_VIOLATIONS_KEY, 0), entry(NEW_CRITICAL_VIOLATIONS_KEY, 0), entry(NEW_BLOCKER_VIOLATIONS_KEY, 0), entry(NEW_MAJOR_VIOLATIONS_KEY, 0),
406 entry(NEW_VULNERABILITIES_KEY, 0));
410 private final void assertValues(Component componentRef, MapEntry<String, Integer>... entries) {
411 assertThat(measureRepository.getRawMeasures(componentRef).entrySet()
413 .map(e -> entry(e.getKey(), e.getValue().getIntValue())))
418 private final void assertMeasures(Component componentRef, Map.Entry<String, Integer>... entries) {
419 List<MeasureRepoEntry> expected = stream(entries)
420 .map(e -> entryOf(e.getKey(), newMeasureBuilder().create(e.getValue())))
423 assertThat(measureRepository.getRawMeasures(componentRef).entrySet().stream().map(e -> entryOf(e.getKey(), e.getValue())))
424 .containsAll(expected);
427 private DefaultIssue createNewIssue(@Nullable String resolution, String status, String severity) {
428 return createNewIssue(resolution, status, severity, CODE_SMELL);
431 private DefaultIssue createNewIssue(@Nullable String resolution, String status, Severity impactSeverity) {
432 DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL);
433 issue.addImpact(SoftwareQuality.MAINTAINABILITY, impactSeverity);
437 private DefaultIssue createNewIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) {
438 DefaultIssue issue = createIssue(resolution, status, severity, ruleType);
439 when(newIssueClassifier.isNew(any(), eq(issue))).thenReturn(true);
443 private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity) {
444 return createIssue(resolution, status, severity, CODE_SMELL);
447 private static DefaultIssue createIssue(@Nullable String resolution, String status, Severity impactSeverity) {
448 DefaultIssue issue = createIssue(resolution, status, MAJOR, CODE_SMELL);
449 issue.addImpact(SoftwareQuality.MAINTAINABILITY, impactSeverity);
453 private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) {
454 return new DefaultIssue()
455 .setResolution(resolution).setStatus(status)
456 .setSeverity(severity).setRuleKey(RuleTesting.XOO_X1)
460 private static DefaultIssue createSecurityHotspot() {
461 return createIssue(null, STATUS_OPEN, "MAJOR", SECURITY_HOTSPOT);
464 private DefaultIssue createNewSecurityHotspot() {
465 return createNewIssue(null, STATUS_OPEN, "MAJOR", SECURITY_HOTSPOT);