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.

LoadDuplicationsFromReportStepTest.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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.ce.task.projectanalysis.step;
  21. import java.util.Arrays;
  22. import org.junit.Rule;
  23. import org.junit.Test;
  24. import org.junit.rules.ExpectedException;
  25. import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
  26. import org.sonar.ce.task.projectanalysis.analysis.Branch;
  27. import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
  28. import org.sonar.ce.task.projectanalysis.component.Component;
  29. import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
  30. import org.sonar.ce.task.projectanalysis.component.VisitException;
  31. import org.sonar.ce.task.projectanalysis.duplication.DetailedTextBlock;
  32. import org.sonar.ce.task.projectanalysis.duplication.Duplicate;
  33. import org.sonar.ce.task.projectanalysis.duplication.Duplication;
  34. import org.sonar.ce.task.projectanalysis.duplication.DuplicationRepositoryRule;
  35. import org.sonar.ce.task.projectanalysis.duplication.InExtendedProjectDuplicate;
  36. import org.sonar.ce.task.projectanalysis.duplication.InProjectDuplicate;
  37. import org.sonar.ce.task.projectanalysis.duplication.InnerDuplicate;
  38. import org.sonar.ce.task.projectanalysis.duplication.TextBlock;
  39. import org.sonar.ce.task.step.TestComputationStepContext;
  40. import org.sonar.db.component.BranchType;
  41. import org.sonar.scanner.protocol.output.ScannerReport;
  42. import static org.assertj.core.api.Assertions.assertThat;
  43. import static org.mockito.Mockito.mock;
  44. import static org.mockito.Mockito.when;
  45. import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
  46. import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT;
  47. import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
  48. import static org.sonar.test.ExceptionCauseMatcher.hasType;
  49. public class LoadDuplicationsFromReportStepTest {
  50. private static final int LINE = 2;
  51. private static final int OTHER_LINE = 300;
  52. private static final int ROOT_REF = 1;
  53. private static final int FILE_1_REF = 11;
  54. private static final int FILE_2_REF = 12;
  55. @Rule
  56. public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(
  57. builder(PROJECT, ROOT_REF)
  58. .addChildren(
  59. builder(FILE, FILE_1_REF).build(),
  60. // status has no effect except if it's a PR
  61. builder(FILE, FILE_2_REF).setStatus(Component.Status.SAME).build())
  62. .build());
  63. @Rule
  64. public BatchReportReaderRule reportReader = new BatchReportReaderRule();
  65. @Rule
  66. public DuplicationRepositoryRule duplicationRepository = DuplicationRepositoryRule.create(treeRootHolder);
  67. @Rule
  68. public ExpectedException expectedException = ExpectedException.none();
  69. @Rule
  70. public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
  71. private LoadDuplicationsFromReportStep underTest = new LoadDuplicationsFromReportStep(treeRootHolder, analysisMetadataHolder,
  72. reportReader, duplicationRepository);
  73. @Test
  74. public void verify_description() {
  75. assertThat(underTest.getDescription()).isEqualTo("Load duplications");
  76. }
  77. @Test
  78. public void loads_duplication_without_otherFileRef_as_inner_duplication() {
  79. reportReader.putDuplications(FILE_2_REF, createDuplication(singleLineTextRange(LINE), createInnerDuplicate(LINE + 1)));
  80. TestComputationStepContext context = new TestComputationStepContext();
  81. underTest.execute(context);
  82. assertNoDuplication(FILE_1_REF);
  83. assertDuplications(FILE_2_REF, singleLineDetailedTextBlock(1, LINE), new InnerDuplicate(singleLineTextBlock(LINE + 1)));
  84. assertNbOfDuplications(context, 1);
  85. }
  86. @Test
  87. public void loads_duplication_with_otherFileRef_as_inProject_duplication() {
  88. reportReader.putDuplications(FILE_1_REF, createDuplication(singleLineTextRange(LINE), createInProjectDuplicate(FILE_2_REF, LINE + 1)));
  89. TestComputationStepContext context = new TestComputationStepContext();
  90. underTest.execute(context);
  91. assertDuplications(FILE_1_REF, singleLineDetailedTextBlock(1, LINE), new InProjectDuplicate(treeRootHolder.getComponentByRef(FILE_2_REF), singleLineTextBlock(LINE + 1)));
  92. assertNoDuplication(FILE_2_REF);
  93. assertNbOfDuplications(context, 1);
  94. }
  95. @Test
  96. public void loads_duplication_with_otherFileRef_as_InExtendedProject_duplication() {
  97. Branch branch = mock(Branch.class);
  98. when(branch.getType()).thenReturn(BranchType.PULL_REQUEST);
  99. analysisMetadataHolder.setBranch(branch);
  100. reportReader.putDuplications(FILE_1_REF, createDuplication(singleLineTextRange(LINE), createInProjectDuplicate(FILE_2_REF, LINE + 1)));
  101. TestComputationStepContext context = new TestComputationStepContext();
  102. underTest.execute(context);
  103. assertDuplications(FILE_1_REF, singleLineDetailedTextBlock(1, LINE),
  104. new InExtendedProjectDuplicate(treeRootHolder.getComponentByRef(FILE_2_REF), singleLineTextBlock(LINE + 1)));
  105. assertNoDuplication(FILE_2_REF);
  106. assertNbOfDuplications(context, 1);
  107. }
  108. @Test
  109. public void loads_multiple_duplications_with_multiple_duplicates() {
  110. reportReader.putDuplications(
  111. FILE_2_REF,
  112. createDuplication(
  113. singleLineTextRange(LINE),
  114. createInnerDuplicate(LINE + 1), createInnerDuplicate(LINE + 2), createInProjectDuplicate(FILE_1_REF, LINE), createInProjectDuplicate(FILE_1_REF, LINE + 10)),
  115. createDuplication(
  116. singleLineTextRange(OTHER_LINE),
  117. createInProjectDuplicate(FILE_1_REF, OTHER_LINE)),
  118. createDuplication(
  119. singleLineTextRange(OTHER_LINE + 80),
  120. createInnerDuplicate(LINE), createInnerDuplicate(LINE + 10)));
  121. TestComputationStepContext context = new TestComputationStepContext();
  122. underTest.execute(context);
  123. Component file1Component = treeRootHolder.getComponentByRef(FILE_1_REF);
  124. assertThat(duplicationRepository.getDuplications(FILE_2_REF)).containsOnly(
  125. duplication(
  126. singleLineDetailedTextBlock(1, LINE),
  127. new InnerDuplicate(singleLineTextBlock(LINE + 1)), new InnerDuplicate(singleLineTextBlock(LINE + 2)), new InProjectDuplicate(file1Component, singleLineTextBlock(LINE)),
  128. new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 10))),
  129. duplication(
  130. singleLineDetailedTextBlock(2, OTHER_LINE),
  131. new InProjectDuplicate(file1Component, singleLineTextBlock(OTHER_LINE))),
  132. duplication(
  133. singleLineDetailedTextBlock(3, OTHER_LINE + 80),
  134. new InnerDuplicate(singleLineTextBlock(LINE)), new InnerDuplicate(singleLineTextBlock(LINE + 10))));
  135. assertNbOfDuplications(context, 3);
  136. }
  137. @Test
  138. public void loads_never_consider_originals_from_batch_on_same_lines_as_the_equals() {
  139. reportReader.putDuplications(
  140. FILE_2_REF,
  141. createDuplication(
  142. singleLineTextRange(LINE),
  143. createInnerDuplicate(LINE + 1), createInnerDuplicate(LINE + 2), createInProjectDuplicate(FILE_1_REF, LINE + 2)),
  144. createDuplication(
  145. singleLineTextRange(LINE),
  146. createInnerDuplicate(LINE + 2), createInnerDuplicate(LINE + 3), createInProjectDuplicate(FILE_1_REF, LINE + 2)));
  147. TestComputationStepContext context = new TestComputationStepContext();
  148. underTest.execute(context);
  149. Component file1Component = treeRootHolder.getComponentByRef(FILE_1_REF);
  150. assertThat(duplicationRepository.getDuplications(FILE_2_REF)).containsOnly(
  151. duplication(
  152. singleLineDetailedTextBlock(1, LINE),
  153. new InnerDuplicate(singleLineTextBlock(LINE + 1)), new InnerDuplicate(singleLineTextBlock(LINE + 2)),
  154. new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 2))),
  155. duplication(
  156. singleLineDetailedTextBlock(2, LINE),
  157. new InnerDuplicate(singleLineTextBlock(LINE + 2)), new InnerDuplicate(singleLineTextBlock(LINE + 3)),
  158. new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 2))));
  159. assertNbOfDuplications(context, 2);
  160. }
  161. @Test
  162. public void loads_duplication_with_otherFileRef_throws_IAE_if_component_does_not_exist() {
  163. int line = 2;
  164. reportReader.putDuplications(FILE_1_REF, createDuplication(singleLineTextRange(line), createInProjectDuplicate(666, line + 1)));
  165. expectedException.expect(VisitException.class);
  166. expectedException.expectCause(hasType(IllegalArgumentException.class).andMessage("Component with ref '666' can't be found"));
  167. underTest.execute(new TestComputationStepContext());
  168. }
  169. @Test
  170. public void loads_duplication_with_otherFileRef_throws_IAE_if_references_itself() {
  171. int line = 2;
  172. reportReader.putDuplications(FILE_1_REF, createDuplication(singleLineTextRange(line), createInProjectDuplicate(FILE_1_REF, line + 1)));
  173. expectedException.expect(VisitException.class);
  174. expectedException.expectCause(hasType(IllegalArgumentException.class).andMessage("file and otherFile references can not be the same"));
  175. underTest.execute(new TestComputationStepContext());
  176. }
  177. private void assertDuplications(int fileRef, TextBlock original, Duplicate... duplicates) {
  178. assertThat(duplicationRepository.getDuplications(fileRef)).containsExactly(duplication(original, duplicates));
  179. }
  180. private static Duplication duplication(TextBlock original, Duplicate... duplicates) {
  181. return new Duplication(original, Arrays.asList(duplicates));
  182. }
  183. private TextBlock singleLineTextBlock(int line) {
  184. return new TextBlock(line, line);
  185. }
  186. private DetailedTextBlock singleLineDetailedTextBlock(int id, int line) {
  187. return new DetailedTextBlock(id, line, line);
  188. }
  189. private static ScannerReport.Duplication createDuplication(ScannerReport.TextRange original, ScannerReport.Duplicate... duplicates) {
  190. ScannerReport.Duplication.Builder builder = ScannerReport.Duplication.newBuilder()
  191. .setOriginPosition(original);
  192. for (ScannerReport.Duplicate duplicate : duplicates) {
  193. builder.addDuplicate(duplicate);
  194. }
  195. return builder.build();
  196. }
  197. private static ScannerReport.Duplicate createInnerDuplicate(int line) {
  198. return ScannerReport.Duplicate.newBuilder()
  199. .setRange(singleLineTextRange(line))
  200. .build();
  201. }
  202. private static ScannerReport.Duplicate createInProjectDuplicate(int componentRef, int line) {
  203. return ScannerReport.Duplicate.newBuilder()
  204. .setOtherFileRef(componentRef)
  205. .setRange(singleLineTextRange(line))
  206. .build();
  207. }
  208. private static ScannerReport.TextRange singleLineTextRange(int line) {
  209. return ScannerReport.TextRange.newBuilder()
  210. .setStartLine(line)
  211. .setEndLine(line)
  212. .build();
  213. }
  214. private void assertNoDuplication(int fileRef) {
  215. assertThat(duplicationRepository.getDuplications(fileRef)).isEmpty();
  216. }
  217. private static void assertNbOfDuplications(TestComputationStepContext context, int expected) {
  218. context.getStatistics().assertValue("duplications", expected);
  219. }
  220. }