You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TrackerTest.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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.core.issue.tracking;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Date;
  24. import java.util.List;
  25. import javax.annotation.CheckForNull;
  26. import javax.annotation.Nullable;
  27. import org.apache.commons.codec.digest.DigestUtils;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.ExpectedException;
  31. import org.sonar.api.rule.RuleKey;
  32. import static java.util.Arrays.asList;
  33. import static org.apache.commons.lang.StringUtils.trim;
  34. import static org.assertj.core.api.Assertions.assertThat;
  35. public class TrackerTest {
  36. public static final RuleKey RULE_SYSTEM_PRINT = RuleKey.of("java", "SystemPrint");
  37. public static final RuleKey RULE_UNUSED_LOCAL_VARIABLE = RuleKey.of("java", "UnusedLocalVariable");
  38. public static final RuleKey RULE_UNUSED_PRIVATE_METHOD = RuleKey.of("java", "UnusedPrivateMethod");
  39. public static final RuleKey RULE_NOT_DESIGNED_FOR_EXTENSION = RuleKey.of("java", "NotDesignedForExtension");
  40. public static final RuleKey RULE_USE_DIAMOND = RuleKey.of("java", "UseDiamond");
  41. public static final RuleKey RULE_MISSING_PACKAGE_INFO = RuleKey.of("java", "MissingPackageInfo");
  42. @Rule
  43. public ExpectedException thrown = ExpectedException.none();
  44. Tracker<Issue, Issue> tracker = new Tracker<>();
  45. /**
  46. * Of course rule must match
  47. */
  48. @Test
  49. public void similar_issues_except_rule_do_not_match() {
  50. FakeInput baseInput = new FakeInput("H1");
  51. baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  52. FakeInput rawInput = new FakeInput("H1");
  53. Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg");
  54. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  55. assertThat(tracking.baseFor(raw)).isNull();
  56. }
  57. @Test
  58. public void line_hash_has_greater_priority_than_line() {
  59. FakeInput baseInput = new FakeInput("H1", "H2", "H3");
  60. Issue base1 = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  61. Issue base2 = baseInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg");
  62. FakeInput rawInput = new FakeInput("a", "b", "H1", "H2", "H3");
  63. Issue raw1 = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg");
  64. Issue raw2 = rawInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "msg");
  65. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  66. assertThat(tracking.baseFor(raw1)).isSameAs(base1);
  67. assertThat(tracking.baseFor(raw2)).isSameAs(base2);
  68. }
  69. /**
  70. * SONAR-2928
  71. */
  72. @Test
  73. public void no_lines_and_different_messages_match() {
  74. FakeInput baseInput = new FakeInput("H1", "H2", "H3");
  75. Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1");
  76. FakeInput rawInput = new FakeInput("H10", "H11", "H12");
  77. Issue raw = rawInput.createIssue(RULE_SYSTEM_PRINT, "msg2");
  78. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  79. assertThat(tracking.baseFor(raw)).isSameAs(base);
  80. }
  81. @Test
  82. public void similar_issues_except_message_match() {
  83. FakeInput baseInput = new FakeInput("H1");
  84. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1");
  85. FakeInput rawInput = new FakeInput("H1");
  86. Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg2");
  87. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  88. assertThat(tracking.baseFor(raw)).isSameAs(base);
  89. }
  90. @Test
  91. public void similar_issues_if_trimmed_messages_match() {
  92. FakeInput baseInput = new FakeInput("H1");
  93. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, " message ");
  94. FakeInput rawInput = new FakeInput("H2");
  95. Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "message");
  96. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  97. assertThat(tracking.baseFor(raw)).isSameAs(base);
  98. }
  99. /**
  100. * Source code of this line was changed, but line and message still match
  101. */
  102. @Test
  103. public void similar_issues_except_line_hash_match() {
  104. FakeInput baseInput = new FakeInput("H1");
  105. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  106. FakeInput rawInput = new FakeInput("H2");
  107. Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  108. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  109. assertThat(tracking.baseFor(raw)).isSameAs(base);
  110. }
  111. @Test
  112. public void similar_issues_except_line_match() {
  113. FakeInput baseInput = new FakeInput("H1", "H2");
  114. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  115. FakeInput rawInput = new FakeInput("H2", "H1");
  116. Issue raw = rawInput.createIssueOnLine(2, RULE_SYSTEM_PRINT, "msg");
  117. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  118. assertThat(tracking.baseFor(raw)).isSameAs(base);
  119. }
  120. /**
  121. * SONAR-2812
  122. */
  123. @Test
  124. public void only_same_line_hash_match_match() {
  125. FakeInput baseInput = new FakeInput("H1", "H2");
  126. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg");
  127. FakeInput rawInput = new FakeInput("H3", "H4", "H1");
  128. Issue raw = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "other message");
  129. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  130. assertThat(tracking.baseFor(raw)).isSameAs(base);
  131. }
  132. @Test
  133. public void do_not_fail_if_base_issue_without_line() {
  134. FakeInput baseInput = new FakeInput("H1", "H2");
  135. Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1");
  136. FakeInput rawInput = new FakeInput("H3", "H4", "H5");
  137. Issue raw = rawInput.createIssue(RULE_UNUSED_LOCAL_VARIABLE, "msg2");
  138. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  139. assertThat(tracking.baseFor(raw)).isNull();
  140. assertThat(tracking.getUnmatchedBases()).containsOnly(base);
  141. }
  142. @Test
  143. public void do_not_fail_if_raw_issue_without_line() {
  144. FakeInput baseInput = new FakeInput("H1", "H2");
  145. Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1");
  146. FakeInput rawInput = new FakeInput("H3", "H4", "H5");
  147. Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg2");
  148. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  149. assertThat(tracking.baseFor(raw)).isNull();
  150. assertThat(tracking.getUnmatchedBases()).containsOnly(base);
  151. }
  152. // SONAR-15091
  153. @Test
  154. public void do_not_fail_if_message_is_null() {
  155. FakeInput baseInput = new FakeInput("H1", "H2");
  156. Issue base = baseInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, null);
  157. FakeInput rawInput = new FakeInput("H1", "H2");
  158. Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, null);
  159. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  160. assertThat(tracking.baseFor(raw)).isNotNull();
  161. }
  162. @Test
  163. public void do_not_fail_if_raw_line_does_not_exist() {
  164. FakeInput baseInput = new FakeInput();
  165. FakeInput rawInput = new FakeInput("H1").addIssue(new Issue(200, "H200", RULE_SYSTEM_PRINT, "msg", org.sonar.api.issue.Issue.STATUS_OPEN, new Date()));
  166. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  167. assertThat(tracking.getUnmatchedRaws()).hasSize(1);
  168. }
  169. /**
  170. * SONAR-3072
  171. */
  172. @Test
  173. public void recognize_blocks_1() {
  174. FakeInput baseInput = FakeInput.createForSourceLines(
  175. "package example1;",
  176. "",
  177. "public class Toto {",
  178. "",
  179. " public void doSomething() {",
  180. " // doSomething",
  181. " }",
  182. "",
  183. " public void doSomethingElse() {",
  184. " // doSomethingElse",
  185. " }",
  186. "}");
  187. Issue base1 = baseInput.createIssueOnLine(7, RULE_SYSTEM_PRINT, "Indentation");
  188. Issue base2 = baseInput.createIssueOnLine(11, RULE_SYSTEM_PRINT, "Indentation");
  189. FakeInput rawInput = FakeInput.createForSourceLines(
  190. "package example1;",
  191. "",
  192. "public class Toto {",
  193. "",
  194. " public Toto(){}",
  195. "",
  196. " public void doSomethingNew() {",
  197. " // doSomethingNew",
  198. " }",
  199. "",
  200. " public void doSomethingElseNew() {",
  201. " // doSomethingElseNew",
  202. " }",
  203. "",
  204. " public void doSomething() {",
  205. " // doSomething",
  206. " }",
  207. "",
  208. " public void doSomethingElse() {",
  209. " // doSomethingElse",
  210. " }",
  211. "}");
  212. Issue raw1 = rawInput.createIssueOnLine(9, RULE_SYSTEM_PRINT, "Indentation");
  213. Issue raw2 = rawInput.createIssueOnLine(13, RULE_SYSTEM_PRINT, "Indentation");
  214. Issue raw3 = rawInput.createIssueOnLine(17, RULE_SYSTEM_PRINT, "Indentation");
  215. Issue raw4 = rawInput.createIssueOnLine(21, RULE_SYSTEM_PRINT, "Indentation");
  216. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  217. assertThat(tracking.baseFor(raw1)).isNull();
  218. assertThat(tracking.baseFor(raw2)).isNull();
  219. assertThat(tracking.baseFor(raw3)).isSameAs(base1);
  220. assertThat(tracking.baseFor(raw4)).isSameAs(base2);
  221. assertThat(tracking.getUnmatchedBases()).isEmpty();
  222. }
  223. // SONAR-10194
  224. @Test
  225. public void no_match_if_only_same_rulekey() {
  226. FakeInput baseInput = FakeInput.createForSourceLines(
  227. "package aa;",
  228. "",
  229. "/**",
  230. " * Hello world",
  231. " *",
  232. " */",
  233. "public class App {",
  234. "",
  235. " public static void main(String[] args) {",
  236. "",
  237. " int magicNumber = 42;",
  238. "",
  239. " String s = new String(\"Very long line that does not meet our maximum 120 character line length criteria and should be wrapped to avoid SonarQube issues.\");\r\n"
  240. +
  241. " }",
  242. "}");
  243. Issue base1 = baseInput.createIssueOnLine(11, RuleKey.of("squid", "S109"), "Assign this magic number 42 to a well-named constant, and use the constant instead.");
  244. Issue base2 = baseInput.createIssueOnLine(13, RuleKey.of("squid", "S00103"), "Split this 163 characters long line (which is greater than 120 authorized).");
  245. FakeInput rawInput = FakeInput.createForSourceLines(
  246. "package aa;",
  247. "",
  248. "/**",
  249. " * Hello world",
  250. " *",
  251. " */",
  252. "public class App {",
  253. "",
  254. " public static void main(String[] args) {",
  255. " ",
  256. " System.out.println(\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vel diam purus. Curabitur ut nisi lacus....\");",
  257. " ",
  258. " int a = 0;",
  259. " ",
  260. " int x = a + 123;",
  261. " }",
  262. "}");
  263. Issue raw1 = rawInput.createIssueOnLine(11, RuleKey.of("squid", "S00103"), "Split this 139 characters long line (which is greater than 120 authorized).");
  264. Issue raw2 = rawInput.createIssueOnLine(15, RuleKey.of("squid", "S109"), "Assign this magic number 123 to a well-named constant, and use the constant instead.");
  265. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  266. assertThat(tracking.baseFor(raw1)).isNull();
  267. assertThat(tracking.baseFor(raw2)).isNull();
  268. assertThat(tracking.getUnmatchedBases()).hasSize(2);
  269. }
  270. /**
  271. * SONAR-3072
  272. */
  273. @Test
  274. public void recognize_blocks_2() {
  275. FakeInput baseInput = FakeInput.createForSourceLines(
  276. "package example2;",
  277. "",
  278. "public class Toto {",
  279. " void method1() {",
  280. " System.out.println(\"toto\");",
  281. " }",
  282. "}");
  283. Issue base1 = baseInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "SystemPrintln");
  284. FakeInput rawInput = FakeInput.createForSourceLines(
  285. "package example2;",
  286. "",
  287. "public class Toto {",
  288. "",
  289. " void method2() {",
  290. " System.out.println(\"toto\");",
  291. " }",
  292. "",
  293. " void method1() {",
  294. " System.out.println(\"toto\");",
  295. " }",
  296. "",
  297. " void method3() {",
  298. " System.out.println(\"toto\");",
  299. " }",
  300. "}");
  301. Issue raw1 = rawInput.createIssueOnLine(6, RULE_SYSTEM_PRINT, "SystemPrintln");
  302. Issue raw2 = rawInput.createIssueOnLine(10, RULE_SYSTEM_PRINT, "SystemPrintln");
  303. Issue raw3 = rawInput.createIssueOnLine(14, RULE_SYSTEM_PRINT, "SystemPrintln");
  304. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  305. assertThat(tracking.baseFor(raw1)).isNull();
  306. assertThat(tracking.baseFor(raw2)).isSameAs(base1);
  307. assertThat(tracking.baseFor(raw3)).isNull();
  308. }
  309. @Test
  310. public void recognize_blocks_3() {
  311. FakeInput baseInput = FakeInput.createForSourceLines(
  312. "package sample;",
  313. "",
  314. "public class Sample {",
  315. "\t",
  316. "\tpublic Sample(int i) {",
  317. "\t\tint j = i+1;", // UnusedLocalVariable
  318. "\t}",
  319. "",
  320. "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension
  321. "\t\treturn true;",
  322. "\t}",
  323. "",
  324. "\tprivate String myMethod() {", // UnusedPrivateMethod
  325. "\t\treturn \"hello\";",
  326. "\t}",
  327. "}");
  328. Issue base1 = baseInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'.");
  329. Issue base2 = baseInput.createIssueOnLine(13, RULE_UNUSED_PRIVATE_METHOD, "Avoid unused private methods such as 'myMethod()'.");
  330. Issue base3 = baseInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION,
  331. "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.");
  332. FakeInput rawInput = FakeInput.createForSourceLines(
  333. "package sample;",
  334. "",
  335. "public class Sample {",
  336. "",
  337. "\tpublic Sample(int i) {",
  338. "\t\tint j = i+1;", // UnusedLocalVariable is still there
  339. "\t}",
  340. "\t",
  341. "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension is still there
  342. "\t\treturn true;",
  343. "\t}",
  344. "\t",
  345. "\tprivate String myMethod() {", // issue UnusedPrivateMethod is fixed because it's called at line 18
  346. "\t\treturn \"hello\";",
  347. "\t}",
  348. "",
  349. " public void newIssue() {",
  350. " String msg = myMethod();", // new issue UnusedLocalVariable
  351. " }",
  352. "}");
  353. Issue newRaw = rawInput.createIssueOnLine(18, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'msg'.");
  354. Issue rawSameAsBase1 = rawInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'.");
  355. Issue rawSameAsBase3 = rawInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION,
  356. "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.");
  357. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  358. assertThat(tracking.baseFor(newRaw)).isNull();
  359. assertThat(tracking.baseFor(rawSameAsBase1)).isSameAs(base1);
  360. assertThat(tracking.baseFor(rawSameAsBase3)).isSameAs(base3);
  361. assertThat(tracking.getUnmatchedBases()).containsOnly(base2);
  362. }
  363. /**
  364. * https://jira.sonarsource.com/browse/SONAR-7595
  365. */
  366. @Test
  367. public void match_only_one_issue_when_multiple_blocks_match_the_same_block() {
  368. FakeInput baseInput = FakeInput.createForSourceLines(
  369. "public class Toto {",
  370. " private final Deque<Set<DataItem>> one = new ArrayDeque<Set<DataItem>>();",
  371. " private final Deque<Set<DataItem>> two = new ArrayDeque<Set<DataItem>>();",
  372. " private final Deque<Integer> three = new ArrayDeque<Integer>();",
  373. " private final Deque<Set<Set<DataItem>>> four = new ArrayDeque<Set<DataItem>>();");
  374. Issue base1 = baseInput.createIssueOnLine(2, RULE_USE_DIAMOND, "Use diamond");
  375. baseInput.createIssueOnLine(3, RULE_USE_DIAMOND, "Use diamond");
  376. baseInput.createIssueOnLine(4, RULE_USE_DIAMOND, "Use diamond");
  377. baseInput.createIssueOnLine(5, RULE_USE_DIAMOND, "Use diamond");
  378. FakeInput rawInput = FakeInput.createForSourceLines(
  379. "public class Toto {",
  380. " // move all lines",
  381. " private final Deque<Set<DataItem>> one = new ArrayDeque<Set<DataItem>>();",
  382. " private final Deque<Set<DataItem>> two = new ArrayDeque<>();",
  383. " private final Deque<Integer> three = new ArrayDeque<>();",
  384. " private final Deque<Set<Set<DataItem>>> four = new ArrayDeque<>();");
  385. Issue raw1 = rawInput.createIssueOnLine(3, RULE_USE_DIAMOND, "Use diamond");
  386. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  387. assertThat(tracking.getUnmatchedBases()).hasSize(3);
  388. assertThat(tracking.baseFor(raw1)).isEqualTo(base1);
  389. }
  390. @Test
  391. public void match_issues_with_same_rule_key_on_project_level() {
  392. FakeInput baseInput = new FakeInput();
  393. Issue base1 = baseInput.createIssue(RULE_MISSING_PACKAGE_INFO, "[com.test:abc] Missing package-info.java in package.");
  394. Issue base2 = baseInput.createIssue(RULE_MISSING_PACKAGE_INFO, "[com.test:abc/def] Missing package-info.java in package.");
  395. FakeInput rawInput = new FakeInput();
  396. Issue raw1 = rawInput.createIssue(RULE_MISSING_PACKAGE_INFO, "[com.test:abc/def] Missing package-info.java in package.");
  397. Issue raw2 = rawInput.createIssue(RULE_MISSING_PACKAGE_INFO, "[com.test:abc] Missing package-info.java in package.");
  398. Tracking<Issue, Issue> tracking = tracker.trackNonClosed(rawInput, baseInput);
  399. assertThat(tracking.getUnmatchedBases()).isEmpty();
  400. assertThat(tracking.baseFor(raw1)).isEqualTo(base2);
  401. assertThat(tracking.baseFor(raw2)).isEqualTo(base1);
  402. }
  403. private static class Issue implements Trackable {
  404. private final RuleKey ruleKey;
  405. private final Integer line;
  406. private final String message, lineHash;
  407. private final String status;
  408. private final Date updateDate;
  409. Issue(@Nullable Integer line, String lineHash, RuleKey ruleKey, @Nullable String message, String status, Date updateDate) {
  410. this.line = line;
  411. this.lineHash = lineHash;
  412. this.ruleKey = ruleKey;
  413. this.status = status;
  414. this.updateDate = updateDate;
  415. this.message = trim(message);
  416. }
  417. @Override
  418. public Integer getLine() {
  419. return line;
  420. }
  421. @CheckForNull
  422. @Override
  423. public String getMessage() {
  424. return message;
  425. }
  426. @Override
  427. public String getLineHash() {
  428. return lineHash;
  429. }
  430. @Override
  431. public RuleKey getRuleKey() {
  432. return ruleKey;
  433. }
  434. @Override
  435. public String getStatus() {
  436. return status;
  437. }
  438. @Override
  439. public Date getUpdateDate() {
  440. return updateDate;
  441. }
  442. }
  443. private static class FakeInput implements Input<Issue> {
  444. private final List<Issue> issues = new ArrayList<>();
  445. private final List<String> lineHashes;
  446. FakeInput(String... lineHashes) {
  447. this.lineHashes = asList(lineHashes);
  448. }
  449. static FakeInput createForSourceLines(String... lines) {
  450. String[] hashes = new String[lines.length];
  451. for (int i = 0; i < lines.length; i++) {
  452. hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", ""));
  453. }
  454. return new FakeInput(hashes);
  455. }
  456. Issue createIssueOnLine(int line, RuleKey ruleKey, String message) {
  457. Issue issue = new Issue(line, lineHashes.get(line - 1), ruleKey, message, org.sonar.api.issue.Issue.STATUS_OPEN, new Date());
  458. issues.add(issue);
  459. return issue;
  460. }
  461. /**
  462. * No line (line 0)
  463. */
  464. Issue createIssue(RuleKey ruleKey, @Nullable String message) {
  465. Issue issue = new Issue(null, "", ruleKey, message, org.sonar.api.issue.Issue.STATUS_OPEN, new Date());
  466. issues.add(issue);
  467. return issue;
  468. }
  469. FakeInput addIssue(Issue issue) {
  470. this.issues.add(issue);
  471. return this;
  472. }
  473. @Override
  474. public LineHashSequence getLineHashSequence() {
  475. return new LineHashSequence(lineHashes);
  476. }
  477. @Override
  478. public BlockHashSequence getBlockHashSequence() {
  479. return new BlockHashSequence(getLineHashSequence(), 2);
  480. }
  481. @Override
  482. public Collection<Issue> getIssues() {
  483. return issues;
  484. }
  485. }
  486. }