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.

JavaStatementBuilderTest.java 17KB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.duplications.java;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileNotFoundException;
  24. import java.io.InputStreamReader;
  25. import java.io.Reader;
  26. import java.nio.charset.StandardCharsets;
  27. import java.util.List;
  28. import org.apache.commons.io.IOUtils;
  29. import org.junit.Test;
  30. import org.sonar.duplications.DuplicationsTestUtil;
  31. import org.sonar.duplications.statement.Statement;
  32. import org.sonar.duplications.statement.StatementChunker;
  33. import org.sonar.duplications.token.TokenChunker;
  34. import static org.assertj.core.api.Assertions.assertThat;
  35. public class JavaStatementBuilderTest {
  36. private final TokenChunker tokenChunker = JavaTokenProducer.build();
  37. private final StatementChunker statementChunker = JavaStatementBuilder.build();
  38. private List<Statement> chunk(String sourceCode) {
  39. return statementChunker.chunk(tokenChunker.chunk(sourceCode));
  40. }
  41. @Test
  42. public void shouldIgnoreImportStatement() {
  43. assertThat(chunk("import org.sonar.duplications.java;")).isEmpty();
  44. }
  45. @Test
  46. public void shouldIgnorePackageStatement() {
  47. assertThat(chunk("package org.sonar.duplications.java;")).isEmpty();
  48. }
  49. @Test
  50. public void shouldHandleAnnotation() {
  51. List<Statement> statements = chunk("" +
  52. "@Entity" +
  53. "@Table(name = \"properties\")" +
  54. "@Column(updatable = true, nullable = true)");
  55. assertThat(statements).hasSize(3);
  56. assertThat(statements.get(0).getValue()).isEqualTo("@Entity");
  57. assertThat(statements.get(1).getValue()).isEqualTo("@Table(name=$CHARS)");
  58. assertThat(statements.get(2).getValue()).isEqualTo("@Column(updatable=true,nullable=true)");
  59. }
  60. @Test
  61. public void shouldHandleIf() {
  62. List<Statement> statements = chunk("if (a > b) { something(); }");
  63. assertThat(statements.size()).isEqualTo(2);
  64. assertThat(statements.get(0).getValue()).isEqualTo("if(a>b)");
  65. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  66. statements = chunk("if (a > b) { something(); } else { somethingOther(); }");
  67. assertThat(statements.size()).isEqualTo(4);
  68. assertThat(statements.get(0).getValue()).isEqualTo("if(a>b)");
  69. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  70. assertThat(statements.get(2).getValue()).isEqualTo("else");
  71. assertThat(statements.get(3).getValue()).isEqualTo("somethingOther()");
  72. statements = chunk("if (a > 0) { something(); } else if (a == 0) { somethingOther(); }");
  73. assertThat(statements.size()).isEqualTo(4);
  74. assertThat(statements.get(0).getValue()).isEqualTo("if(a>$NUMBER)");
  75. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  76. assertThat(statements.get(2).getValue()).isEqualTo("elseif(a==$NUMBER)");
  77. assertThat(statements.get(3).getValue()).isEqualTo("somethingOther()");
  78. }
  79. @Test
  80. public void shouldHandleFor() {
  81. List<Statement> statements = chunk("for (int i = 0; i < 10; i++) { something(); }");
  82. assertThat(statements.size()).isEqualTo(2);
  83. assertThat(statements.get(0).getValue()).isEqualTo("for(inti=$NUMBER;i<$NUMBER;i++)");
  84. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  85. statements = chunk("for (Item item : items) { something(); }");
  86. assertThat(statements.size()).isEqualTo(2);
  87. assertThat(statements.get(0).getValue()).isEqualTo("for(Itemitem:items)");
  88. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  89. }
  90. @Test
  91. public void shouldHandleWhile() {
  92. List<Statement> statements = chunk("while (i < args.length) { something(); }");
  93. assertThat(statements.size()).isEqualTo(2);
  94. assertThat(statements.get(0).getValue()).isEqualTo("while(i<args.length)");
  95. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  96. statements = chunk("while (true);");
  97. assertThat(statements.size()).isEqualTo(1);
  98. assertThat(statements.get(0).getValue()).isEqualTo("while(true)");
  99. }
  100. @Test
  101. public void shouldHandleDoWhile() {
  102. List<Statement> statements = chunk("do { something(); } while (true);");
  103. assertThat(statements.size()).isEqualTo(3);
  104. assertThat(statements.get(0).getValue()).isEqualTo("do");
  105. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  106. assertThat(statements.get(2).getValue()).isEqualTo("while(true)");
  107. }
  108. @Test
  109. public void shouldHandleSwitch() {
  110. List<Statement> statements = chunk("" +
  111. "switch (month) {" +
  112. " case 1 : monthString=\"January\"; break;" +
  113. " case 2 : monthString=\"February\"; break;" +
  114. " default: monthString=\"Invalid\";" +
  115. "}");
  116. assertThat(statements.size()).isEqualTo(6);
  117. assertThat(statements.get(0).getValue()).isEqualTo("switch(month)");
  118. assertThat(statements.get(1).getValue()).isEqualTo("case$NUMBER:monthString=$CHARS");
  119. assertThat(statements.get(2).getValue()).isEqualTo("break");
  120. assertThat(statements.get(3).getValue()).isEqualTo("case$NUMBER:monthString=$CHARS");
  121. assertThat(statements.get(4).getValue()).isEqualTo("break");
  122. assertThat(statements.get(5).getValue()).isEqualTo("default:monthString=$CHARS");
  123. }
  124. /**
  125. * See SONAR-2782
  126. */
  127. @Test
  128. public void shouldHandleNestedSwitch() {
  129. List<Statement> statements = chunk("" +
  130. "switch (a) {" +
  131. " case 'a': case 'b': case 'c': something(); break;" +
  132. " case 'd': case 'e': case 'f': somethingOther(); break;" +
  133. "}");
  134. assertThat(statements.size()).isEqualTo(5);
  135. assertThat(statements.get(0).getValue()).isEqualTo("switch(a)");
  136. assertThat(statements.get(1).getValue()).isEqualTo("case$CHARS:case$CHARS:case$CHARS:something()");
  137. assertThat(statements.get(2).getValue()).isEqualTo("break");
  138. assertThat(statements.get(3).getValue()).isEqualTo("case$CHARS:case$CHARS:case$CHARS:somethingOther()");
  139. assertThat(statements.get(4).getValue()).isEqualTo("break");
  140. }
  141. @Test
  142. public void shouldHandleArray() {
  143. List<Statement> statements = chunk("new Integer[] { 1, 2, 3, 4 };");
  144. assertThat(statements.size()).isEqualTo(2);
  145. assertThat(statements.get(0).getValue()).isEqualTo("newInteger[]");
  146. assertThat(statements.get(1).getValue()).isEqualTo("{$NUMBER,$NUMBER,$NUMBER,$NUMBER}");
  147. }
  148. /**
  149. * See SONAR-2837
  150. */
  151. @Test
  152. public void shouldHandleMultidimensionalArray() {
  153. List<Statement> statements = chunk("new Integer[][] { { 1, 2 }, {3, 4} };");
  154. assertThat(statements.size()).isEqualTo(2);
  155. assertThat(statements.get(0).getValue()).isEqualTo("newInteger[][]");
  156. assertThat(statements.get(1).getValue()).isEqualTo("{{$NUMBER,$NUMBER},{$NUMBER,$NUMBER}}");
  157. statements = chunk("new Integer[][] { null, {3, 4} };");
  158. assertThat(statements.size()).isEqualTo(2);
  159. assertThat(statements.get(0).getValue()).isEqualTo("newInteger[][]");
  160. assertThat(statements.get(1).getValue()).isEqualTo("{null,{$NUMBER,$NUMBER}}");
  161. }
  162. @Test
  163. public void shouldHandleTryCatch() {
  164. List<Statement> statements;
  165. statements = chunk("try { } catch (Exception e) { }");
  166. assertThat(statements.size()).isEqualTo(4);
  167. assertThat(statements.get(0).getValue()).isEqualTo("try");
  168. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  169. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exceptione)");
  170. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  171. statements = chunk("try { something(); } catch (Exception e) { }");
  172. assertThat(statements.size()).isEqualTo(4);
  173. assertThat(statements.get(0).getValue()).isEqualTo("try");
  174. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  175. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exceptione)");
  176. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  177. statements = chunk("try { something(); } catch (Exception e) { onException(); }");
  178. assertThat(statements.size()).isEqualTo(4);
  179. assertThat(statements.get(0).getValue()).isEqualTo("try");
  180. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  181. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exceptione)");
  182. assertThat(statements.get(3).getValue()).isEqualTo("onException()");
  183. statements = chunk("try { something(); } catch (Exception1 e) { onException1(); } catch (Exception2 e) { onException2(); }");
  184. assertThat(statements.size()).isEqualTo(6);
  185. assertThat(statements.get(0).getValue()).isEqualTo("try");
  186. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  187. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exception1e)");
  188. assertThat(statements.get(3).getValue()).isEqualTo("onException1()");
  189. assertThat(statements.get(4).getValue()).isEqualTo("catch(Exception2e)");
  190. assertThat(statements.get(5).getValue()).isEqualTo("onException2()");
  191. }
  192. @Test
  193. public void shouldHandleTryFinnaly() {
  194. List<Statement> statements;
  195. statements = chunk("try { } finally { }");
  196. assertThat(statements.size()).isEqualTo(4);
  197. assertThat(statements.get(0).getValue()).isEqualTo("try");
  198. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  199. assertThat(statements.get(2).getValue()).isEqualTo("finally");
  200. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  201. statements = chunk("try { something(); } finally { }");
  202. assertThat(statements.size()).isEqualTo(4);
  203. assertThat(statements.get(0).getValue()).isEqualTo("try");
  204. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  205. assertThat(statements.get(2).getValue()).isEqualTo("finally");
  206. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  207. statements = chunk("try { something(); } finally { somethingOther(); }");
  208. assertThat(statements.size()).isEqualTo(4);
  209. assertThat(statements.get(0).getValue()).isEqualTo("try");
  210. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  211. assertThat(statements.get(2).getValue()).isEqualTo("finally");
  212. assertThat(statements.get(3).getValue()).isEqualTo("somethingOther()");
  213. }
  214. @Test
  215. public void shouldHandleTryCatchFinally() {
  216. List<Statement> statements;
  217. statements = chunk("try { } catch (Exception e) {} finally { }");
  218. assertThat(statements.size()).isEqualTo(6);
  219. assertThat(statements.get(0).getValue()).isEqualTo("try");
  220. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  221. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exceptione)");
  222. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  223. assertThat(statements.get(4).getValue()).isEqualTo("finally");
  224. assertThat(statements.get(5).getValue()).isEqualTo("{}");
  225. statements = chunk("try { something(); } catch (Exception e) { onException(); } finally { somethingOther(); }");
  226. assertThat(statements.size()).isEqualTo(6);
  227. assertThat(statements.get(0).getValue()).isEqualTo("try");
  228. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  229. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exceptione)");
  230. assertThat(statements.get(3).getValue()).isEqualTo("onException()");
  231. assertThat(statements.get(4).getValue()).isEqualTo("finally");
  232. assertThat(statements.get(5).getValue()).isEqualTo("somethingOther()");
  233. }
  234. /**
  235. * Java 7.
  236. */
  237. @Test
  238. public void shouldHandleMultiCatch() {
  239. List<Statement> statements;
  240. statements = chunk("try { } catch (Exception1 | Exception2 e) { }");
  241. assertThat(statements.size()).isEqualTo(4);
  242. assertThat(statements.get(0).getValue()).isEqualTo("try");
  243. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  244. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exception1|Exception2e)");
  245. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  246. statements = chunk("try { something(); } catch (Exception1 | Exception2 e) { }");
  247. assertThat(statements.size()).isEqualTo(4);
  248. assertThat(statements.get(0).getValue()).isEqualTo("try");
  249. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  250. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exception1|Exception2e)");
  251. assertThat(statements.get(3).getValue()).isEqualTo("{}");
  252. statements = chunk("try { something(); } catch (Exception1 | Exception2 e) { onException(); }");
  253. assertThat(statements.size()).isEqualTo(4);
  254. assertThat(statements.get(0).getValue()).isEqualTo("try");
  255. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  256. assertThat(statements.get(2).getValue()).isEqualTo("catch(Exception1|Exception2e)");
  257. assertThat(statements.get(3).getValue()).isEqualTo("onException()");
  258. }
  259. /**
  260. * Java 7.
  261. */
  262. @Test
  263. public void shouldHandleTryWithResource() {
  264. List<Statement> statements;
  265. statements = chunk("try (FileInputStream in = new FileInputStream()) {}");
  266. assertThat(statements.size()).isEqualTo(2);
  267. assertThat(statements.get(0).getValue()).isEqualTo("try(FileInputStreamin=newFileInputStream())");
  268. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  269. statements = chunk("try (FileInputStream in = new FileInputStream(); FileOutputStream out = new FileOutputStream()) {}");
  270. assertThat(statements.size()).isEqualTo(2);
  271. assertThat(statements.get(0).getValue()).isEqualTo("try(FileInputStreamin=newFileInputStream();FileOutputStreamout=newFileOutputStream())");
  272. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  273. statements = chunk("try (FileInputStream in = new FileInputStream(); FileOutputStream out = new FileOutputStream();) {}");
  274. assertThat(statements.size()).isEqualTo(2);
  275. assertThat(statements.get(0).getValue()).isEqualTo("try(FileInputStreamin=newFileInputStream();FileOutputStreamout=newFileOutputStream();)");
  276. assertThat(statements.get(1).getValue()).isEqualTo("{}");
  277. statements = chunk("try (FileInputStream in = new FileInputStream()) { something(); }");
  278. assertThat(statements.size()).isEqualTo(2);
  279. assertThat(statements.get(0).getValue()).isEqualTo("try(FileInputStreamin=newFileInputStream())");
  280. assertThat(statements.get(1).getValue()).isEqualTo("something()");
  281. }
  282. /**
  283. * Java 8.
  284. */
  285. @Test
  286. public void shouldHandleLambda() {
  287. List<Statement> statements;
  288. statements = chunk("List<String> result = lines.stream().filter(line -> !\"mkyong\".equals(line)).collect(Collectors.toList());");
  289. assertThat(statements.size()).isEqualTo(1);
  290. assertThat(statements).extracting(Statement::getValue).containsExactly("List<String>result=lines.stream().filter(line->!$CHARS.equals(line)).collect(Collectors.toList())");
  291. statements = chunk("items.forEach((k,v)->{System.out.println(\"Item : \" + k + \" Count : \" + v); if(\"E\".equals(k)) { System.out.println(\"Hello E\");}});");
  292. assertThat(statements.size()).isEqualTo(5);
  293. assertThat(statements).extracting(Statement::getValue)
  294. .containsExactly("items.forEach((k,v)->",
  295. "System.out.println($CHARS+k+$CHARS+v)",
  296. "if($CHARS.equals(k))",
  297. "System.out.println($CHARS)",
  298. ")");
  299. }
  300. /**
  301. * Java 9.
  302. */
  303. @Test
  304. public void shouldHandleModuleInfo() {
  305. List<Statement> statements;
  306. statements = chunk("module com.application.infra { requires com.application.domain; exports com.application.infra.api; }");
  307. assertThat(statements.size()).isEqualTo(3);
  308. assertThat(statements).extracting(Statement::getValue)
  309. .containsExactly("modulecom.application.infra",
  310. "requirescom.application.domain",
  311. "exportscom.application.infra.api");
  312. }
  313. /**
  314. * Java 11.
  315. */
  316. @Test
  317. public void shouldHandleVar() {
  318. List<Statement> statements;
  319. statements = chunk("IFunc f = (@NonNull var x, final var y) -> Foo.foo(x, y);");
  320. assertThat(statements.size()).isEqualTo(1);
  321. assertThat(statements).extracting(Statement::getValue).containsExactly("IFuncf=(@NonNullvarx,finalvary)->Foo.foo(x,y)");
  322. }
  323. @Test
  324. public void realExamples() {
  325. assertThat(chunk(DuplicationsTestUtil.findFile("/java/MessageResources.java")).size()).isGreaterThan(0);
  326. assertThat(chunk(DuplicationsTestUtil.findFile("/java/RequestUtils.java")).size()).isGreaterThan(0);
  327. }
  328. private List<Statement> chunk(File file) {
  329. Reader reader = null;
  330. try {
  331. reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
  332. return statementChunker.chunk(tokenChunker.chunk(reader));
  333. } catch (FileNotFoundException e) {
  334. throw new RuntimeException(e);
  335. } finally {
  336. IOUtils.closeQuietly(reader);
  337. }
  338. }
  339. }