From 212000d472e0c9a818de55cf54f5688d03febf03 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 16 Dec 2015 11:54:58 +0100 Subject: [PATCH] SONAR-6990 support repeated original-duplicate paars from the batch --- .../duplication/DetailedTextBlock.java | 65 +++++++++++++++++++ .../computation/duplication/TextBlock.java | 2 +- .../step/LoadDuplicationsFromReportStep.java | 12 +++- .../LoadDuplicationsFromReportStepTest.java | 44 +++++++++++-- 4 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/duplication/DetailedTextBlock.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/DetailedTextBlock.java b/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/DetailedTextBlock.java new file mode 100644 index 00000000000..a096335c870 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/DetailedTextBlock.java @@ -0,0 +1,65 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.duplication; + +import java.util.Objects; +import javax.annotation.Nullable; + +/** + * Given that: + * , + * we are uniquely (and blindly) identifying each original block reported in the analysis report. + */ +public class DetailedTextBlock extends TextBlock { + private final int id; + /** + * @throws IllegalArgumentException if {@code start} is 0 or less + * @throws IllegalStateException if {@code end} is less than {@code start} + */ + public DetailedTextBlock(int id, int start, int end) { + super(start, end); + this.id = id; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + DetailedTextBlock that = (DetailedTextBlock) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), id); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/TextBlock.java b/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/TextBlock.java index e317e7c9225..43a24c871e4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/TextBlock.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/duplication/TextBlock.java @@ -31,7 +31,7 @@ import static com.google.common.base.Preconditions.checkArgument; * same start line, by smallest size (ie. lowest end line). *

*/ -public final class TextBlock implements Comparable { +public class TextBlock implements Comparable { private final int start; private final int end; diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStep.java index 3006266bfc2..6d0927f9f71 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStep.java @@ -27,6 +27,7 @@ import org.sonar.server.computation.component.CrawlerDepthLimit; import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler; import org.sonar.server.computation.component.TreeRootHolder; import org.sonar.server.computation.component.TypeAwareVisitorAdapter; +import org.sonar.server.computation.duplication.DetailedTextBlock; import org.sonar.server.computation.duplication.DuplicationRepository; import org.sonar.server.computation.duplication.TextBlock; @@ -59,8 +60,9 @@ public class LoadDuplicationsFromReportStep implements ComputationStep { public void visitFile(Component file) { CloseableIterator duplications = batchReportReader.readComponentDuplications(file.getReportAttributes().getRef()); try { + int idGenerator = 1; while (duplications.hasNext()) { - loadDuplications(file, duplications.next()); + loadDuplications(file, duplications.next(), idGenerator++); } } finally { duplications.close(); @@ -69,8 +71,8 @@ public class LoadDuplicationsFromReportStep implements ComputationStep { }).visit(treeRootHolder.getRoot()); } - private void loadDuplications(Component file, BatchReport.Duplication duplication) { - TextBlock original = convert(duplication.getOriginPosition()); + private void loadDuplications(Component file, BatchReport.Duplication duplication, int id) { + DetailedTextBlock original = convert(duplication.getOriginPosition(), id); for (BatchReport.Duplicate duplicate : duplication.getDuplicateList()) { if (duplicate.hasOtherFileRef()) { duplicationRepository.addDuplication(file, original, treeRootHolder.getComponentByRef(duplicate.getOtherFileRef()), convert(duplicate.getRange())); @@ -83,4 +85,8 @@ public class LoadDuplicationsFromReportStep implements ComputationStep { private static TextBlock convert(BatchReport.TextRange textRange) { return new TextBlock(textRange.getStartLine(), textRange.getEndLine()); } + + private static DetailedTextBlock convert(BatchReport.TextRange textRange, int id) { + return new DetailedTextBlock(id, textRange.getStartLine(), textRange.getEndLine()); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStepTest.java index 5515924be2e..b1423876afd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/LoadDuplicationsFromReportStepTest.java @@ -28,6 +28,7 @@ import org.sonar.server.computation.batch.BatchReportReaderRule; import org.sonar.server.computation.batch.TreeRootHolderRule; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.VisitException; +import org.sonar.server.computation.duplication.DetailedTextBlock; import org.sonar.server.computation.duplication.Duplicate; import org.sonar.server.computation.duplication.Duplication; import org.sonar.server.computation.duplication.DuplicationRepositoryRule; @@ -85,7 +86,7 @@ public class LoadDuplicationsFromReportStepTest { underTest.execute(); assertNoDuplication(FILE_1_REF); - assertDuplications(FILE_2_REF, singleLineTextBlock(LINE), new InnerDuplicate(singleLineTextBlock(LINE + 1))); + assertDuplications(FILE_2_REF, singleLineDetailedTextBlock(1, LINE), new InnerDuplicate(singleLineTextBlock(LINE + 1))); } @Test @@ -94,7 +95,7 @@ public class LoadDuplicationsFromReportStepTest { underTest.execute(); - assertDuplications(FILE_1_REF, singleLineTextBlock(LINE), new InProjectDuplicate(treeRootHolder.getComponentByRef(FILE_2_REF), singleLineTextBlock(LINE + 1))); + assertDuplications(FILE_1_REF, singleLineDetailedTextBlock(1, LINE), new InProjectDuplicate(treeRootHolder.getComponentByRef(FILE_2_REF), singleLineTextBlock(LINE + 1))); assertNoDuplication(FILE_2_REF); } @@ -118,20 +119,49 @@ public class LoadDuplicationsFromReportStepTest { Component file1Component = treeRootHolder.getComponentByRef(FILE_1_REF); assertThat(duplicationRepository.getDuplications(FILE_2_REF)).containsOnly( duplication( - singleLineTextBlock(LINE), + singleLineDetailedTextBlock(1, LINE), new InnerDuplicate(singleLineTextBlock(LINE + 1)), new InnerDuplicate(singleLineTextBlock(LINE + 2)), new InProjectDuplicate(file1Component, singleLineTextBlock(LINE)), new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 10))), duplication( - singleLineTextBlock(OTHER_LINE), + singleLineDetailedTextBlock(2, OTHER_LINE), new InProjectDuplicate(file1Component, singleLineTextBlock(OTHER_LINE)) ), duplication( - singleLineTextBlock(OTHER_LINE + 80), + singleLineDetailedTextBlock(3, OTHER_LINE + 80), new InnerDuplicate(singleLineTextBlock(LINE)), new InnerDuplicate(singleLineTextBlock(LINE + 10)) ) ); } + @Test + public void loads_never_consider_originals_from_batch_on_same_lines_as_the_equals() { + reportReader.putDuplications( + FILE_2_REF, + createDuplication( + singleLineTextRange(LINE), + createInnerDuplicate(LINE + 1), createInnerDuplicate(LINE + 2), createInProjectDuplicate(FILE_1_REF, LINE + 2)), + createDuplication( + singleLineTextRange(LINE), + createInnerDuplicate(LINE + 2), createInnerDuplicate(LINE + 3), createInProjectDuplicate(FILE_1_REF, LINE + 2)) + ); + + underTest.execute(); + + Component file1Component = treeRootHolder.getComponentByRef(FILE_1_REF); + assertThat(duplicationRepository.getDuplications(FILE_2_REF)).containsOnly( + duplication( + singleLineDetailedTextBlock(1, LINE), + new InnerDuplicate(singleLineTextBlock(LINE + 1)), new InnerDuplicate(singleLineTextBlock(LINE + 2)), + new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 2)) + ), + duplication( + singleLineDetailedTextBlock(2, LINE), + new InnerDuplicate(singleLineTextBlock(LINE + 2)), new InnerDuplicate(singleLineTextBlock(LINE + 3)), + new InProjectDuplicate(file1Component, singleLineTextBlock(LINE + 2)) + ) + ); + } + @Test public void loads_duplication_with_otherFileRef_throws_IAE_if_component_does_not_exist() { int line = 2; @@ -166,6 +196,10 @@ public class LoadDuplicationsFromReportStepTest { return new TextBlock(line, line); } + private DetailedTextBlock singleLineDetailedTextBlock(int id, int line) { + return new DetailedTextBlock(id, line, line); + } + private static BatchReport.Duplication createDuplication(BatchReport.TextRange original, BatchReport.Duplicate... duplicates) { BatchReport.Duplication.Builder builder = BatchReport.Duplication.newBuilder() .setOriginPosition(original); -- 2.39.5