]> source.dussan.org Git - sonarqube.git/blob
4887cc3c2aaf63ea74aa901c7b93ee6c73762f57
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 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.ce.task.projectanalysis.issue;
21
22 import com.google.common.collect.Iterators;
23 import com.tngtech.java.junit.dataprovider.DataProvider;
24 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
25 import com.tngtech.java.junit.dataprovider.UseDataProvider;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.stream.IntStream;
30 import org.apache.commons.codec.digest.DigestUtils;
31 import org.junit.Before;
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.sonar.api.rule.RuleKey;
36 import org.sonar.api.rule.Severity;
37 import org.sonar.api.rules.RuleType;
38 import org.sonar.api.utils.Duration;
39 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
40 import org.sonar.ce.task.projectanalysis.component.Component;
41 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
42 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
43 import org.sonar.ce.task.projectanalysis.issue.commonrule.CommonRuleEngine;
44 import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
45 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
46 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
47 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepository;
48 import org.sonar.ce.task.projectanalysis.source.SourceLinesRepository;
49 import org.sonar.core.issue.DefaultIssue;
50 import org.sonar.core.issue.tracking.Input;
51 import org.sonar.core.util.CloseableIterator;
52 import org.sonar.db.protobuf.DbIssues;
53 import org.sonar.scanner.protocol.Constants;
54 import org.sonar.scanner.protocol.output.ScannerReport;
55 import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
56 import org.sonar.scanner.protocol.output.ScannerReport.TextRange;
57 import org.sonar.server.rule.CommonRuleKeys;
58
59 import static java.util.Arrays.asList;
60 import static java.util.Collections.emptyMap;
61 import static java.util.Collections.singletonList;
62 import static org.assertj.core.api.Assertions.assertThat;
63 import static org.mockito.ArgumentMatchers.any;
64 import static org.mockito.ArgumentMatchers.eq;
65 import static org.mockito.Mockito.mock;
66 import static org.mockito.Mockito.when;
67 import static org.sonar.api.issue.Issue.STATUS_OPEN;
68 import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
69
70 @RunWith(DataProviderRunner.class)
71 public class TrackerRawInputFactoryTest {
72
73   private static final String FILE_UUID = "fake_uuid";
74   private static final String ANOTHER_FILE_UUID = "another_fake_uuid";
75   private static final String EXAMPLE_LINE_OF_CODE_FORMAT = "int example = line + of + code + %d; ";
76   private static final int FILE_REF = 2;
77   private static final int NOT_IN_REPORT_FILE_REF = 3;
78   private static final int ANOTHER_FILE_REF = 4;
79
80   @Rule
81   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT);
82   @Rule
83   public BatchReportReaderRule reportReader = new BatchReportReaderRule();
84   @Rule
85   public ActiveRulesHolderRule activeRulesHolder = new ActiveRulesHolderRule();
86   @Rule
87   public RuleRepositoryRule ruleRepository = new RuleRepositoryRule();
88
89   private static final ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, FILE_REF).setUuid(FILE_UUID).build();
90   private static final ReportComponent ANOTHER_FILE = ReportComponent.builder(Component.Type.FILE, ANOTHER_FILE_REF).setUuid(ANOTHER_FILE_UUID).build();
91   private static final ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(FILE, ANOTHER_FILE).build();
92
93   private final SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
94   private final SourceLinesRepository sourceLinesRepository = mock(SourceLinesRepository.class);
95   private final CommonRuleEngine commonRuleEngine = mock(CommonRuleEngine.class);
96   private final IssueFilter issueFilter = mock(IssueFilter.class);
97   private final TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash,
98     sourceLinesRepository, commonRuleEngine, issueFilter, ruleRepository, activeRulesHolder);
99
100   @Before
101   public void before() {
102     Iterator<String> stringIterator = IntStream.rangeClosed(1, 9)
103       .mapToObj(i -> String.format(EXAMPLE_LINE_OF_CODE_FORMAT, i))
104       .iterator();
105     when(sourceLinesRepository.readLines(any())).thenReturn(CloseableIterator.from(stringIterator));
106   }
107
108   @Test
109   public void load_source_hash_sequences() {
110     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
111     Input<DefaultIssue> input = underTest.create(FILE);
112
113     assertThat(input.getLineHashSequence()).isNotNull();
114     assertThat(input.getLineHashSequence().getHashForLine(1)).isEqualTo("line");
115     assertThat(input.getLineHashSequence().getHashForLine(2)).isEmpty();
116     assertThat(input.getLineHashSequence().getHashForLine(3)).isEmpty();
117
118     assertThat(input.getBlockHashSequence()).isNotNull();
119   }
120
121   @Test
122   public void load_source_hash_sequences_only_on_files() {
123     Input<DefaultIssue> input = underTest.create(PROJECT);
124
125     assertThat(input.getLineHashSequence()).isNotNull();
126     assertThat(input.getBlockHashSequence()).isNotNull();
127   }
128
129   @Test
130   public void load_issues_from_report() {
131     RuleKey ruleKey = RuleKey.of("java", "S001");
132     markRuleAsActive(ruleKey);
133     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
134
135     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
136     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
137       .setTextRange(newTextRange(2))
138       .setMsg("the message")
139       .setRuleRepository(ruleKey.repository())
140       .setRuleKey(ruleKey.rule())
141       .setSeverity(Constants.Severity.BLOCKER)
142       .setGap(3.14)
143       .setQuickFixAvailable(true)
144       .build();
145     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
146     Input<DefaultIssue> input = underTest.create(FILE);
147
148     Collection<DefaultIssue> issues = input.getIssues();
149     assertThat(issues).hasSize(1);
150     DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
151
152     // fields set by analysis report
153     assertThat(issue.ruleKey()).isEqualTo(ruleKey);
154     assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
155     assertThat(issue.line()).isEqualTo(2);
156     assertThat(issue.gap()).isEqualTo(3.14);
157     assertThat(issue.message()).isEqualTo("the message");
158     assertThat(issue.isQuickFixAvailable()).isTrue();
159
160     // fields set by compute engine
161     assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
162     assertThat(issue.tags()).isEmpty();
163     assertInitializedIssue(issue);
164     assertThat(issue.effort()).isNull();
165
166     assertLocationHashIsMadeOf(input, "intexample=line+of+code+2;");
167   }
168
169   @Test
170   public void calculateLocationHash_givenIssueOn3Lines_calculateHashOn3Lines() {
171     RuleKey ruleKey = RuleKey.of("java", "S001");
172     markRuleAsActive(ruleKey);
173     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
174
175     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
176       .setTextRange(TextRange.newBuilder()
177         .setStartLine(1)
178         .setEndLine(3)
179         .setStartOffset(0)
180         .setEndOffset(EXAMPLE_LINE_OF_CODE_FORMAT.length() - 1)
181         .build())
182       .setMsg("the message")
183       .setRuleRepository(ruleKey.repository())
184       .setRuleKey(ruleKey.rule())
185       .build();
186     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
187
188     Input<DefaultIssue> input = underTest.create(FILE);
189
190     assertLocationHashIsMadeOf(input, "intexample=line+of+code+1;intexample=line+of+code+2;intexample=line+of+code+3;");
191   }
192
193   @Test
194   public void calculateLocationHash_givenIssuePartiallyOn1Line_calculateHashOnAPartOfLine() {
195     RuleKey ruleKey = RuleKey.of("java", "S001");
196     markRuleAsActive(ruleKey);
197     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
198
199     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
200       .setTextRange(TextRange.newBuilder()
201         .setStartLine(1)
202         .setEndLine(1)
203         .setStartOffset(13)
204         .setEndOffset(EXAMPLE_LINE_OF_CODE_FORMAT.length() - 1)
205         .build())
206       .setMsg("the message")
207       .setRuleRepository(ruleKey.repository())
208       .setRuleKey(ruleKey.rule())
209       .build();
210     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
211
212     Input<DefaultIssue> input = underTest.create(FILE);
213
214     assertLocationHashIsMadeOf(input, "line+of+code+1;");
215   }
216
217   @Test
218   public void calculateLocationHash_givenIssuePartiallyOn1LineAndPartiallyOnThirdLine_calculateHashAccordingly() {
219     RuleKey ruleKey = RuleKey.of("java", "S001");
220     markRuleAsActive(ruleKey);
221     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
222
223     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
224       .setTextRange(TextRange.newBuilder()
225         .setStartLine(1)
226         .setEndLine(3)
227         .setStartOffset(13)
228         .setEndOffset(11)
229         .build())
230       .setMsg("the message")
231       .setRuleRepository(ruleKey.repository())
232       .setRuleKey(ruleKey.rule())
233       .build();
234     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
235
236     Input<DefaultIssue> input = underTest.create(FILE);
237
238     assertLocationHashIsMadeOf(input, "line+of+code+1;intexample=line+of+code+2;intexample");
239   }
240
241   @Test
242   public void set_rule_name_as_message_when_issue_message_from_report_is_empty() {
243     RuleKey ruleKey = RuleKey.of("java", "S001");
244     markRuleAsActive(ruleKey);
245     registerRule(ruleKey, "Rule 1");
246     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
247     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
248     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
249       .setRuleRepository(ruleKey.repository())
250       .setRuleKey(ruleKey.rule())
251       .setMsg("")
252       .build();
253     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
254     Input<DefaultIssue> input = underTest.create(FILE);
255
256     Collection<DefaultIssue> issues = input.getIssues();
257     assertThat(issues).hasSize(1);
258     DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
259
260     // fields set by analysis report
261     assertThat(issue.ruleKey()).isEqualTo(ruleKey);
262
263     // fields set by compute engine
264     assertInitializedIssue(issue);
265     assertThat(issue.message()).isEqualTo("Rule 1");
266   }
267
268   // SONAR-10781
269   @Test
270   public void load_issues_from_report_missing_secondary_location_component() {
271     RuleKey ruleKey = RuleKey.of("java", "S001");
272     markRuleAsActive(ruleKey);
273     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
274
275     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
276     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
277       .setTextRange(newTextRange(2))
278       .setMsg("the message")
279       .setRuleRepository(ruleKey.repository())
280       .setRuleKey(ruleKey.rule())
281       .setSeverity(Constants.Severity.BLOCKER)
282       .setGap(3.14)
283       .addFlow(ScannerReport.Flow.newBuilder()
284         .addLocation(ScannerReport.IssueLocation.newBuilder()
285           .setComponentRef(FILE_REF)
286           .setMsg("Secondary location in same file")
287           .setTextRange(newTextRange(2)))
288         .addLocation(ScannerReport.IssueLocation.newBuilder()
289           .setComponentRef(NOT_IN_REPORT_FILE_REF)
290           .setMsg("Secondary location in a missing file")
291           .setTextRange(newTextRange(3)))
292         .addLocation(ScannerReport.IssueLocation.newBuilder()
293           .setComponentRef(ANOTHER_FILE_REF)
294           .setMsg("Secondary location in another file")
295           .setTextRange(newTextRange(3)))
296         .build())
297       .build();
298     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
299     Input<DefaultIssue> input = underTest.create(FILE);
300
301     Collection<DefaultIssue> issues = input.getIssues();
302     assertThat(issues).hasSize(1);
303     DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
304
305     DbIssues.Locations locations = issue.getLocations();
306     // fields set by analysis report
307     assertThat(locations.getFlowList()).hasSize(1);
308     assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
309     // Not component id if location is in the same file
310     assertThat(locations.getFlow(0).getLocation(0).getComponentId()).isEmpty();
311     assertThat(locations.getFlow(0).getLocation(1).getComponentId()).isEqualTo(ANOTHER_FILE_UUID);
312   }
313
314   @Test
315   @UseDataProvider("ruleTypeAndStatusByIssueType")
316   public void load_external_issues_from_report(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
317     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
318     ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
319       .setTextRange(newTextRange(2))
320       .setMsg("the message")
321       .setEngineId("eslint")
322       .setRuleId("S001")
323       .setSeverity(Constants.Severity.BLOCKER)
324       .setEffort(20L)
325       .setType(issueType)
326       .build();
327     reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
328     Input<DefaultIssue> input = underTest.create(FILE);
329
330     Collection<DefaultIssue> issues = input.getIssues();
331     assertThat(issues).hasSize(1);
332     DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
333
334     // fields set by analysis report
335     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
336     assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
337     assertThat(issue.line()).isEqualTo(2);
338     assertThat(issue.effort()).isEqualTo(Duration.create(20L));
339     assertThat(issue.message()).isEqualTo("the message");
340     assertThat(issue.type()).isEqualTo(expectedRuleType);
341
342     // fields set by compute engine
343     assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
344     assertThat(issue.tags()).isEmpty();
345     assertInitializedExternalIssue(issue, expectedStatus);
346   }
347
348   @DataProvider
349   public static Object[][] ruleTypeAndStatusByIssueType() {
350     return new Object[][] {
351       {IssueType.CODE_SMELL, RuleType.CODE_SMELL, STATUS_OPEN},
352       {IssueType.BUG, RuleType.BUG, STATUS_OPEN},
353       {IssueType.VULNERABILITY, RuleType.VULNERABILITY, STATUS_OPEN},
354       {IssueType.SECURITY_HOTSPOT, RuleType.SECURITY_HOTSPOT, STATUS_TO_REVIEW}
355     };
356   }
357
358   @Test
359   @UseDataProvider("ruleTypeAndStatusByIssueType")
360   public void load_external_issues_from_report_with_default_effort(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
361     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
362     ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
363       .setTextRange(newTextRange(2))
364       .setMsg("the message")
365       .setEngineId("eslint")
366       .setRuleId("S001")
367       .setSeverity(Constants.Severity.BLOCKER)
368       .setType(issueType)
369       .build();
370     reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
371     Input<DefaultIssue> input = underTest.create(FILE);
372
373     Collection<DefaultIssue> issues = input.getIssues();
374     assertThat(issues).hasSize(1);
375     DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
376
377     // fields set by analysis report
378     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
379     assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
380     assertThat(issue.line()).isEqualTo(2);
381     assertThat(issue.effort()).isEqualTo(Duration.create(0L));
382     assertThat(issue.message()).isEqualTo("the message");
383     assertThat(issue.type()).isEqualTo(expectedRuleType);
384
385     // fields set by compute engine
386     assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
387     assertThat(issue.tags()).isEmpty();
388     assertInitializedExternalIssue(issue, expectedStatus);
389   }
390
391   @Test
392   public void excludes_issues_on_inactive_rules() {
393     RuleKey ruleKey = RuleKey.of("java", "S001");
394     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
395
396     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
397     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
398       .setTextRange(newTextRange(2))
399       .setMsg("the message")
400       .setRuleRepository(ruleKey.repository())
401       .setRuleKey(ruleKey.rule())
402       .setSeverity(Constants.Severity.BLOCKER)
403       .setGap(3.14)
404       .build();
405     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
406     Input<DefaultIssue> input = underTest.create(FILE);
407
408     Collection<DefaultIssue> issues = input.getIssues();
409     assertThat(issues).isEmpty();
410   }
411
412   @Test
413   public void filter_excludes_issues_from_report() {
414     RuleKey ruleKey = RuleKey.of("java", "S001");
415     markRuleAsActive(ruleKey);
416     when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
417     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
418     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
419       .setTextRange(newTextRange(2))
420       .setMsg("the message")
421       .setRuleRepository(ruleKey.repository())
422       .setRuleKey(ruleKey.rule())
423       .setSeverity(Constants.Severity.BLOCKER)
424       .setGap(3.14)
425       .build();
426     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
427     Input<DefaultIssue> input = underTest.create(FILE);
428
429     Collection<DefaultIssue> issues = input.getIssues();
430     assertThat(issues).isEmpty();
431   }
432
433   @Test
434   public void exclude_issues_on_common_rules() {
435     RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "S001");
436     markRuleAsActive(ruleKey);
437     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
438     ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
439       .setMsg("the message")
440       .setRuleRepository(ruleKey.repository())
441       .setRuleKey(ruleKey.rule())
442       .setSeverity(Constants.Severity.BLOCKER)
443       .build();
444     reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
445
446     Input<DefaultIssue> input = underTest.create(FILE);
447
448     assertThat(input.getIssues()).isEmpty();
449   }
450
451   @Test
452   public void load_issues_of_compute_engine_common_rules() {
453     RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
454     markRuleAsActive(ruleKey);
455     when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
456     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
457     DefaultIssue ceIssue = new DefaultIssue()
458       .setRuleKey(ruleKey)
459       .setMessage("not enough coverage")
460       .setGap(10.0);
461     when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
462
463     Input<DefaultIssue> input = underTest.create(FILE);
464
465     assertThat(input.getIssues()).containsOnly(ceIssue);
466     assertInitializedIssue(input.getIssues().iterator().next());
467   }
468
469   @Test
470   public void filter_exclude_issues_on_common_rule() {
471     RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
472     markRuleAsActive(ruleKey);
473     when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
474     when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
475     DefaultIssue ceIssue = new DefaultIssue()
476       .setRuleKey(ruleKey)
477       .setMessage("not enough coverage")
478       .setGap(10.0);
479     when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
480
481     Input<DefaultIssue> input = underTest.create(FILE);
482
483     assertThat(input.getIssues()).isEmpty();
484   }
485
486   private void assertInitializedIssue(DefaultIssue issue) {
487     assertInitializedExternalIssue(issue, STATUS_OPEN);
488     assertThat(issue.effort()).isNull();
489     assertThat(issue.effortInMinutes()).isNull();
490   }
491
492   private void assertInitializedExternalIssue(DefaultIssue issue, String expectedStatus) {
493     assertThat(issue.projectKey()).isEqualTo(PROJECT.getKey());
494     assertThat(issue.componentKey()).isEqualTo(FILE.getKey());
495     assertThat(issue.componentUuid()).isEqualTo(FILE.getUuid());
496     assertThat(issue.resolution()).isNull();
497     assertThat(issue.status()).isEqualTo(expectedStatus);
498     assertThat(issue.key()).isNull();
499     assertThat(issue.authorLogin()).isNull();
500   }
501
502   private void markRuleAsActive(RuleKey ruleKey) {
503     activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null, "qp1"));
504   }
505
506   private void registerRule(RuleKey ruleKey, String name) {
507     DumbRule dumbRule = new DumbRule(ruleKey);
508     dumbRule.setName(name);
509     ruleRepository.add(dumbRule);
510   }
511
512   private TextRange newTextRange(int issueOnLine) {
513     return TextRange.newBuilder()
514       .setStartLine(issueOnLine)
515       .setEndLine(issueOnLine)
516       .setStartOffset(0)
517       .setEndOffset(EXAMPLE_LINE_OF_CODE_FORMAT.length() - 1)
518       .build();
519   }
520
521   private void assertLocationHashIsMadeOf(Input<DefaultIssue> input, String stringToHash) {
522     DefaultIssue defaultIssue = Iterators.getOnlyElement(input.getIssues().iterator());
523     String expectedHash = DigestUtils.md5Hex(stringToHash);
524     DbIssues.Locations locations = defaultIssue.getLocations();
525
526     assertThat(locations.getChecksum()).isEqualTo(expectedHash);
527   }
528
529 }