aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-12-01 11:26:45 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2015-12-01 16:38:08 +0100
commita70899910e2448abda0ec8c76aff2000318dce49 (patch)
tree7db055f0637463ed6a9ab32dbbef100632ae0cef /sonar-batch
parentba7e2918528cba02496907a81d730079953c28ce (diff)
downloadsonarqube-a70899910e2448abda0ec8c76aff2000318dce49.tar.gz
sonarqube-a70899910e2448abda0ec8c76aff2000318dce49.zip
SONAR-6933 Drop newDuplication() beta API
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/cpd/AbstractCpdEngine.java109
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/cpd/DefaultCpdEngine.java17
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java51
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationValueCoder.java53
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java44
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java62
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java98
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java12
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/cpd/AbstractCpdEngineTest.java227
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java134
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java65
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java155
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java3
16 files changed, 354 insertions, 712 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cpd/AbstractCpdEngine.java b/sonar-batch/src/main/java/org/sonar/batch/cpd/AbstractCpdEngine.java
new file mode 100644
index 00000000000..8905bf5ac07
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/cpd/AbstractCpdEngine.java
@@ -0,0 +1,109 @@
+/*
+ * 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.batch.cpd;
+
+import com.google.common.base.Function;
+import java.util.List;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.batch.index.BatchComponent;
+import org.sonar.batch.index.BatchComponentCache;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReport.Duplicate;
+import org.sonar.batch.protocol.output.BatchReport.Duplication;
+import org.sonar.batch.report.ReportPublisher;
+import org.sonar.duplications.index.CloneGroup;
+import org.sonar.duplications.index.ClonePart;
+
+import static com.google.common.collect.FluentIterable.from;
+
+public abstract class AbstractCpdEngine extends CpdEngine {
+
+ private static final Logger LOG = Loggers.get(AbstractCpdEngine.class);
+
+ static final int MAX_CLONE_GROUP_PER_FILE = 100;
+ static final int MAX_CLONE_PART_PER_GROUP = 100;
+
+ private final ReportPublisher publisher;
+ private final BatchComponentCache batchComponentCache;
+
+ public AbstractCpdEngine(ReportPublisher publisher, BatchComponentCache batchComponentCache) {
+ this.publisher = publisher;
+ this.batchComponentCache = batchComponentCache;
+ }
+
+ protected final void saveDuplications(final InputFile inputFile, List<CloneGroup> duplications) {
+ if (duplications.size() > MAX_CLONE_GROUP_PER_FILE) {
+ LOG.warn("Too many duplication groups on file " + inputFile.relativePath() + ". Keep only the first " + MAX_CLONE_GROUP_PER_FILE + " groups.");
+ }
+ final BatchComponent component = batchComponentCache.get(inputFile);
+ Iterable<org.sonar.batch.protocol.output.BatchReport.Duplication> reportDuplications = from(duplications)
+ .limit(MAX_CLONE_GROUP_PER_FILE)
+ .transform(
+ new Function<CloneGroup, BatchReport.Duplication>() {
+ private final BatchReport.Duplication.Builder dupBuilder = BatchReport.Duplication.newBuilder();
+ private final BatchReport.Duplicate.Builder blockBuilder = BatchReport.Duplicate.newBuilder();
+
+ @Override
+ public BatchReport.Duplication apply(CloneGroup input) {
+ return toReportDuplication(component, inputFile, dupBuilder, blockBuilder, input);
+ }
+
+ });
+ publisher.getWriter().writeComponentDuplications(component.batchId(), reportDuplications);
+ }
+
+ private Duplication toReportDuplication(BatchComponent component, InputFile inputFile, Duplication.Builder dupBuilder, Duplicate.Builder blockBuilder, CloneGroup input) {
+ dupBuilder.clear();
+ ClonePart originBlock = input.getOriginPart();
+ blockBuilder.clear();
+ dupBuilder.setOriginPosition(BatchReport.TextRange.newBuilder()
+ .setStartLine(originBlock.getStartLine())
+ .setEndLine(originBlock.getEndLine())
+ .build());
+ int clonePartCount = 0;
+ for (ClonePart duplicate : input.getCloneParts()) {
+ if (!duplicate.equals(originBlock)) {
+ clonePartCount++;
+ if (clonePartCount > MAX_CLONE_PART_PER_GROUP) {
+ LOG.warn("Too many duplication references on file " + inputFile.relativePath() + " for block at line " + originBlock.getStartLine() + ". Keep only the first "
+ + MAX_CLONE_PART_PER_GROUP + " references.");
+ break;
+ }
+ blockBuilder.clear();
+ String componentKey = duplicate.getResourceId();
+ if (!component.key().equals(componentKey)) {
+ BatchComponent sameProjectComponent = batchComponentCache.get(componentKey);
+ blockBuilder.setOtherFileRef(sameProjectComponent.batchId());
+ }
+ dupBuilder.addDuplicate(blockBuilder
+ .setRange(BatchReport.TextRange.newBuilder()
+ .setStartLine(duplicate.getStartLine())
+ .setEndLine(duplicate.getEndLine())
+ .build())
+ .build());
+ }
+ }
+ return dupBuilder.build();
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cpd/DefaultCpdEngine.java b/sonar-batch/src/main/java/org/sonar/batch/cpd/DefaultCpdEngine.java
index a63b04f0006..2eb64fcc73d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/cpd/DefaultCpdEngine.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/cpd/DefaultCpdEngine.java
@@ -21,9 +21,9 @@ package org.sonar.batch.cpd;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -47,7 +47,9 @@ import org.sonar.duplications.block.Block;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.internal.pmd.TokenizerBridge;
-public class DefaultCpdEngine extends CpdEngine {
+import static com.google.common.collect.FluentIterable.from;
+
+public class DefaultCpdEngine extends AbstractCpdEngine {
private static final Logger LOG = LoggerFactory.getLogger(DefaultCpdEngine.class);
@@ -63,6 +65,7 @@ public class DefaultCpdEngine extends CpdEngine {
private final BatchComponentCache batchComponentCache;
public DefaultCpdEngine(CpdMappings mappings, FileSystem fs, Settings settings, ReportPublisher publisher, BatchComponentCache batchComponentCache) {
+ super(publisher, batchComponentCache);
this.mappings = mappings;
this.fs = fs;
this.settings = settings;
@@ -112,18 +115,20 @@ public class DefaultCpdEngine extends CpdEngine {
String resourceEffectiveKey = ((DefaultInputFile) inputFile).key();
Collection<Block> fileBlocks = index.getByInputFile(inputFile, resourceEffectiveKey);
- Iterable<CloneGroup> filtered;
+ List<CloneGroup> filtered;
try {
List<CloneGroup> duplications = executorService.submit(new JavaCpdEngine.Task(index, fileBlocks)).get(TIMEOUT, TimeUnit.SECONDS);
- filtered = Iterables.filter(duplications, minimumTokensPredicate);
+ filtered = from(duplications)
+ .filter(minimumTokensPredicate)
+ .toList();
} catch (TimeoutException e) {
- filtered = null;
+ filtered = Collections.emptyList();
LOG.warn("Timeout during detection of duplications for " + inputFile, e);
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Fail during detection of duplication for " + inputFile, e);
}
- JavaCpdEngine.save(context, inputFile, filtered);
+ saveDuplications(inputFile, filtered);
}
} finally {
executorService.shutdown();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java b/sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java
index 21bec46e794..d83e049a45a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java
@@ -20,13 +20,13 @@
package org.sonar.batch.cpd;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -34,7 +34,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,8 +43,6 @@ import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.duplication.NewDuplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
import org.sonar.api.config.Settings;
import org.sonar.batch.cpd.index.SonarDuplicationsIndex;
import org.sonar.batch.index.BatchComponentCache;
@@ -55,14 +52,13 @@ import org.sonar.duplications.block.BlockChunker;
import org.sonar.duplications.detector.suffixtree.SuffixTreeCloneDetectionAlgorithm;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.index.CloneIndex;
-import org.sonar.duplications.index.ClonePart;
import org.sonar.duplications.java.JavaStatementBuilder;
import org.sonar.duplications.java.JavaTokenProducer;
import org.sonar.duplications.statement.Statement;
import org.sonar.duplications.statement.StatementChunker;
import org.sonar.duplications.token.TokenChunker;
-public class JavaCpdEngine extends CpdEngine {
+public class JavaCpdEngine extends AbstractCpdEngine {
private static final Logger LOG = LoggerFactory.getLogger(JavaCpdEngine.class);
@@ -73,15 +69,13 @@ public class JavaCpdEngine extends CpdEngine {
*/
private static final int TIMEOUT = 5 * 60;
- private static final int MAX_CLONE_GROUP_PER_FILE = 100;
- private static final int MAX_CLONE_PART_PER_GROUP = 100;
-
private final FileSystem fs;
private final Settings settings;
private final ReportPublisher publisher;
private final BatchComponentCache batchComponentCache;
public JavaCpdEngine(FileSystem fs, Settings settings, ReportPublisher publisher, BatchComponentCache batchComponentCache) {
+ super(publisher, batchComponentCache);
this.fs = fs;
this.settings = settings;
this.publisher = publisher;
@@ -152,13 +146,13 @@ public class JavaCpdEngine extends CpdEngine {
try {
clones = executorService.submit(new Task(index, fileBlocks)).get(TIMEOUT, TimeUnit.SECONDS);
} catch (TimeoutException e) {
- clones = null;
+ clones = Collections.emptyList();
LOG.warn("Timeout during detection of duplications for " + inputFile, e);
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Fail during detection of duplication for " + inputFile, e);
}
- save(context, inputFile, clones);
+ saveDuplications(inputFile, clones);
}
} finally {
executorService.shutdown();
@@ -180,39 +174,4 @@ public class JavaCpdEngine extends CpdEngine {
}
}
- static void save(org.sonar.api.batch.sensor.SensorContext context, InputFile inputFile, @Nullable Iterable<CloneGroup> duplications) {
- if (duplications == null || Iterables.isEmpty(duplications)) {
- return;
- }
-
- saveDuplications(context, inputFile, duplications);
- }
-
- private static void saveDuplications(org.sonar.api.batch.sensor.SensorContext context, InputFile inputFile, Iterable<CloneGroup> duplications) {
- int cloneGroupCount = 0;
- for (CloneGroup duplication : duplications) {
- cloneGroupCount++;
- if (cloneGroupCount > MAX_CLONE_GROUP_PER_FILE) {
- LOG.warn("Too many duplication groups on file " + inputFile.relativePath() + ". Keep only the first " + MAX_CLONE_GROUP_PER_FILE + " groups.");
- break;
- }
- NewDuplication builder = context.newDuplication();
- ClonePart originPart = duplication.getOriginPart();
- builder.originBlock(inputFile, originPart.getStartLine(), originPart.getEndLine());
- int clonePartCount = 0;
- for (ClonePart part : duplication.getCloneParts()) {
- if (!part.equals(originPart)) {
- clonePartCount++;
- if (clonePartCount > MAX_CLONE_PART_PER_GROUP) {
- LOG.warn("Too many duplication references on file " + inputFile.relativePath() + " for block at line " + originPart.getStartLine() + ". Keep only the first "
- + MAX_CLONE_PART_PER_GROUP + " references.");
- break;
- }
- ((DefaultDuplication) builder).isDuplicatedBy(part.getResourceId(), part.getStartLine(), part.getEndLine());
- }
- }
- builder.save();
- }
- }
-
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationValueCoder.java
deleted file mode 100644
index 1ab206e8edf..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationValueCoder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.batch.duplication;
-
-import com.persistit.Value;
-import com.persistit.encoding.CoderContext;
-import com.persistit.encoding.ValueCoder;
-import org.sonar.api.batch.sensor.duplication.Duplication;
-import org.sonar.api.batch.sensor.duplication.Duplication.Block;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-
-class DefaultDuplicationValueCoder implements ValueCoder {
-
- private DuplicationBlockValueCoder blockCoder = new DuplicationBlockValueCoder();
-
- @Override
- public void put(Value value, Object object, CoderContext context) {
- DefaultDuplication c = (DefaultDuplication) object;
- blockCoder.put(value, c.originBlock(), context);
- value.put(c.duplicates().size());
- for (Duplication.Block block : c.duplicates()) {
- blockCoder.put(value, block, context);
- }
- }
-
- @Override
- public Object get(Value value, Class clazz, CoderContext context) {
- DefaultDuplication g = new DefaultDuplication();
- g.setOriginBlock((Block) blockCoder.get(value, Duplication.Block.class, context));
- int count = value.getInt();
- for (int i = 0; i < count; i++) {
- g.duplicates().add((Block) blockCoder.get(value, Duplication.Block.class, context));
- }
- return g;
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java
deleted file mode 100644
index 50dbd316bb7..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.batch.duplication;
-
-import com.persistit.Value;
-import com.persistit.encoding.CoderContext;
-import com.persistit.encoding.ValueCoder;
-import org.sonar.api.batch.sensor.duplication.Duplication;
-
-class DuplicationBlockValueCoder implements ValueCoder {
-
- @Override
- public void put(Value value, Object object, CoderContext context) {
- Duplication.Block b = (Duplication.Block) object;
- value.putUTF(b.resourceKey());
- value.put(b.startLine());
- value.put(b.length());
- }
-
- @Override
- public Object get(Value value, Class clazz, CoderContext context) {
- String resourceKey = value.getString();
- int startLine = value.getInt();
- int length = value.getInt();
- return new Duplication.Block(resourceKey, startLine, length);
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java
deleted file mode 100644
index cfc091d00cb..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.batch.duplication;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Caches;
-
-/**
- * Cache of duplication blocks. This cache is shared amongst all project modules.
- */
-@BatchSide
-public class DuplicationCache {
-
- private final Cache<DefaultDuplication> cache;
- private int sequence = 1;
-
- public DuplicationCache(Caches caches) {
- caches.registerValueCoder(DefaultDuplication.class, new DefaultDuplicationValueCoder());
- cache = caches.createCache("duplications");
- }
-
- public Iterable<String> componentKeys() {
- return Iterables.transform(cache.keySet(), new Function<Object, String>() {
- @Override
- public String apply(Object input) {
- return input.toString();
- }
- });
- }
-
- public Iterable<DefaultDuplication> byComponent(String effectiveKey) {
- return cache.values(effectiveKey);
- }
-
- public DuplicationCache put(String effectiveKey, DefaultDuplication duplication) {
- cache.put(effectiveKey, sequence, duplication);
- sequence++;
- return this;
- }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java
deleted file mode 100644
index 103e90ab281..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.batch.duplication;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
deleted file mode 100644
index 068cb1c10e4..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.batch.report;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import org.sonar.api.batch.sensor.duplication.Duplication.Block;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.index.BatchComponent;
-import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReport.Duplicate;
-import org.sonar.batch.protocol.output.BatchReport.Duplication;
-import org.sonar.batch.protocol.output.BatchReportWriter;
-
-public class DuplicationsPublisher implements ReportPublisherStep {
-
- private final BatchComponentCache resourceCache;
- private final DuplicationCache duplicationCache;
-
- public DuplicationsPublisher(BatchComponentCache resourceCache, DuplicationCache duplicationCache) {
- this.resourceCache = resourceCache;
- this.duplicationCache = duplicationCache;
- }
-
- @Override
- public void publish(BatchReportWriter writer) {
- for (final BatchComponent resource : resourceCache.all()) {
- if (!resource.isFile()) {
- continue;
- }
- Iterable<DefaultDuplication> dups = duplicationCache.byComponent(resource.resource().getEffectiveKey());
- if (dups.iterator().hasNext()) {
- Iterable<org.sonar.batch.protocol.output.BatchReport.Duplication> reportDuplications = Iterables.transform(dups,
- new Function<DefaultDuplication, BatchReport.Duplication>() {
- private final BatchReport.Duplication.Builder dupBuilder = BatchReport.Duplication.newBuilder();
- private final BatchReport.Duplicate.Builder blockBuilder = BatchReport.Duplicate.newBuilder();
-
- @Override
- public BatchReport.Duplication apply(DefaultDuplication input) {
- return toReportDuplication(resource.key(), dupBuilder, blockBuilder, input);
- }
-
- });
- writer.writeComponentDuplications(resource.batchId(), reportDuplications);
- }
- }
- }
-
- private Duplication toReportDuplication(String currentComponentKey, Duplication.Builder dupBuilder, Duplicate.Builder blockBuilder, DefaultDuplication input) {
- dupBuilder.clear();
- Block originBlock = input.originBlock();
- blockBuilder.clear();
- dupBuilder.setOriginPosition(BatchReport.TextRange.newBuilder()
- .setStartLine(originBlock.startLine())
- .setEndLine(originBlock.startLine() + originBlock.length() - 1)
- .build());
- for (Block duplicate : input.duplicates()) {
- blockBuilder.clear();
- String componentKey = duplicate.resourceKey();
- if (!currentComponentKey.equals(componentKey)) {
- BatchComponent sameProjectComponent = resourceCache.get(componentKey);
- if (sameProjectComponent != null) {
- blockBuilder.setOtherFileRef(sameProjectComponent.batchId());
- } else {
- // Should never happens
- throw new IllegalStateException("No cross project duplication supported on batch side: " + componentKey);
- }
- }
- dupBuilder.addDuplicate(blockBuilder
- .setRange(BatchReport.TextRange.newBuilder()
- .setStartLine(duplicate.startLine())
- .setEndLine(duplicate.startLine() + duplicate.length() - 1)
- .build())
- .build());
- }
- return dupBuilder.build();
- }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index b694beb38cf..7c5e87050f9 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -41,7 +41,6 @@ import org.sonar.batch.bootstrap.ExtensionMatcher;
import org.sonar.batch.bootstrap.ExtensionUtils;
import org.sonar.batch.bootstrap.MetricProvider;
import org.sonar.batch.cache.ProjectPersistentCacheProvider;
-import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.index.Caches;
@@ -61,7 +60,6 @@ import org.sonar.batch.report.ActiveRulesPublisher;
import org.sonar.batch.report.AnalysisContextReportPublisher;
import org.sonar.batch.report.ComponentsPublisher;
import org.sonar.batch.report.CoveragePublisher;
-import org.sonar.batch.report.DuplicationsPublisher;
import org.sonar.batch.report.MeasuresPublisher;
import org.sonar.batch.report.MetadataPublisher;
import org.sonar.batch.report.ReportPublisher;
@@ -179,9 +177,6 @@ public class ProjectScanContainer extends ComponentContainer {
// Measures
MeasureCache.class,
- // Duplications
- DuplicationCache.class,
-
ProjectSettings.class,
// Report
@@ -191,7 +186,6 @@ public class ProjectScanContainer extends ComponentContainer {
ActiveRulesPublisher.class,
ComponentsPublisher.class,
MeasuresPublisher.class,
- DuplicationsPublisher.class,
CoveragePublisher.class,
SourcePublisher.class,
TestExecutionAndCoveragePublisher.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java
index cb58332f96c..f6d30a2ae02 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java
@@ -27,8 +27,6 @@ import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.coverage.NewCoverage;
import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
-import org.sonar.api.batch.sensor.duplication.NewDuplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
@@ -115,11 +113,6 @@ public class DefaultSensorContext implements SensorContext {
}
@Override
- public NewDuplication newDuplication() {
- return new DefaultDuplication(sensorStorage);
- }
-
- @Override
public NewCoverage newCoverage() {
return new DefaultCoverage(sensorStorage);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
index bcb38b4958a..1c25a98091b 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
@@ -37,8 +37,6 @@ import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.coverage.CoverageType;
import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
-import org.sonar.api.batch.sensor.duplication.Duplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule;
import org.sonar.api.batch.sensor.internal.SensorStorage;
@@ -53,7 +51,6 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.source.Symbol;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.SonarException;
-import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.BatchComponent;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.issue.ModuleIssues;
@@ -94,18 +91,16 @@ public class DefaultSensorStorage implements SensorStorage {
private final MetricFinder metricFinder;
private final ModuleIssues moduleIssues;
private final CoverageExclusions coverageExclusions;
- private final DuplicationCache duplicationCache;
private final BatchComponentCache componentCache;
private final ReportPublisher reportPublisher;
private final MeasureCache measureCache;
public DefaultSensorStorage(MetricFinder metricFinder, ModuleIssues moduleIssues,
- Settings settings, FileSystem fs, ActiveRules activeRules, DuplicationCache duplicationCache,
+ Settings settings, FileSystem fs, ActiveRules activeRules,
CoverageExclusions coverageExclusions, BatchComponentCache componentCache, ReportPublisher reportPublisher, MeasureCache measureCache) {
this.metricFinder = metricFinder;
this.moduleIssues = moduleIssues;
this.coverageExclusions = coverageExclusions;
- this.duplicationCache = duplicationCache;
this.componentCache = componentCache;
this.reportPublisher = reportPublisher;
this.measureCache = measureCache;
@@ -191,11 +186,6 @@ public class DefaultSensorStorage implements SensorStorage {
}
@Override
- public void store(Duplication duplication) {
- duplicationCache.put(duplication.originBlock().resourceKey(), (DefaultDuplication) duplication);
- }
-
- @Override
public void store(DefaultHighlighting highlighting) {
BatchReportWriter writer = reportPublisher.getWriter();
DefaultInputFile inputFile = (DefaultInputFile) highlighting.inputFile();
diff --git a/sonar-batch/src/test/java/org/sonar/batch/cpd/AbstractCpdEngineTest.java b/sonar-batch/src/test/java/org/sonar/batch/cpd/AbstractCpdEngineTest.java
new file mode 100644
index 00000000000..1f843d8e284
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/cpd/AbstractCpdEngineTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.batch.cpd;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.resources.Project;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.batch.index.BatchComponent;
+import org.sonar.batch.index.BatchComponentCache;
+import org.sonar.batch.protocol.output.BatchReport.Duplication;
+import org.sonar.batch.protocol.output.BatchReportReader;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.batch.report.ReportPublisher;
+import org.sonar.core.util.CloseableIterator;
+import org.sonar.duplications.index.CloneGroup;
+import org.sonar.duplications.index.ClonePart;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AbstractCpdEngineTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private AbstractCpdEngine engine;
+
+ private BatchReportReader reader;
+ private DefaultInputFile inputFile1;
+ private BatchComponent batchComponent1;
+ private BatchComponent batchComponent2;
+ private BatchComponent batchComponent3;
+
+ @Before
+ public void before() throws IOException {
+ File outputDir = temp.newFolder();
+ ReportPublisher reportPublisher = mock(ReportPublisher.class);
+ when(reportPublisher.getWriter()).thenReturn(new BatchReportWriter(outputDir));
+ reader = new BatchReportReader(outputDir);
+ BatchComponentCache componentCache = new BatchComponentCache();
+ Project p = new Project("foo");
+ componentCache.add(p, null).setInputComponent(new DefaultInputModule("foo"));
+ org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
+ inputFile1 = new DefaultInputFile("foo", "src/Foo.php").setLines(5);
+ batchComponent1 = componentCache.add(sampleFile, null).setInputComponent(inputFile1);
+ org.sonar.api.resources.Resource sampleFile2 = org.sonar.api.resources.File.create("src/Foo2.php").setEffectiveKey("foo:src/Foo2.php");
+ batchComponent2 = componentCache.add(sampleFile2, null).setInputComponent(new DefaultInputFile("foo", "src/Foo2.php").setLines(5));
+ org.sonar.api.resources.Resource sampleFile3 = org.sonar.api.resources.File.create("src/Foo3.php").setEffectiveKey("foo:src/Foo3.php");
+ batchComponent3 = componentCache.add(sampleFile3, null).setInputComponent(new DefaultInputFile("foo", "src/Foo3.php").setLines(5));
+ engine = new AbstractCpdEngine(reportPublisher, componentCache) {
+
+ @Override
+ boolean isLanguageSupported(String language) {
+ return false;
+ }
+
+ @Override
+ void analyse(String language, SensorContext context) {
+ }
+ };
+ }
+
+ @Test
+ public void testNothingToSave() {
+ engine.saveDuplications(inputFile1, Collections.EMPTY_LIST);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(0);
+ }
+
+ @Test
+ public void testOneSimpleDuplicationBetweenTwoFiles() {
+ List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart(batchComponent1.key(), 0, 2, 4), new ClonePart(batchComponent2.key(), 0, 15, 17)));
+ engine.saveDuplications(inputFile1, groups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(1);
+ CloseableIterator<Duplication> dups = reader.readComponentDuplications(batchComponent1.batchId());
+ Duplication duplication = dups.next();
+ dups.close();
+ assertThat(duplication.getOriginPosition().getStartLine()).isEqualTo(2);
+ assertThat(duplication.getOriginPosition().getEndLine()).isEqualTo(4);
+ assertThat(duplication.getDuplicateList()).hasSize(1);
+ assertThat(duplication.getDuplicate(0).getOtherFileRef()).isEqualTo(batchComponent2.batchId());
+ assertThat(duplication.getDuplicate(0).getRange().getStartLine()).isEqualTo(15);
+ assertThat(duplication.getDuplicate(0).getRange().getEndLine()).isEqualTo(17);
+ }
+
+ @Test
+ public void testDuplicationOnSameFile() throws Exception {
+ List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart(batchComponent1.key(), 0, 5, 204), new ClonePart(batchComponent1.key(), 0, 215, 414)));
+ engine.saveDuplications(inputFile1, groups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(1);
+ CloseableIterator<Duplication> dups = reader.readComponentDuplications(batchComponent1.batchId());
+ Duplication duplication = dups.next();
+ dups.close();
+ assertThat(duplication.getOriginPosition().getStartLine()).isEqualTo(5);
+ assertThat(duplication.getOriginPosition().getEndLine()).isEqualTo(204);
+ assertThat(duplication.getDuplicateList()).hasSize(1);
+ assertThat(duplication.getDuplicate(0).hasOtherFileRef()).isFalse();
+ assertThat(duplication.getDuplicate(0).getRange().getStartLine()).isEqualTo(215);
+ assertThat(duplication.getDuplicate(0).getRange().getEndLine()).isEqualTo(414);
+ }
+
+ @Test
+ public void testTooManyDuplicates() throws Exception {
+ // 1 origin part + 101 duplicates = 102
+ List<ClonePart> parts = new ArrayList<>(AbstractCpdEngine.MAX_CLONE_PART_PER_GROUP + 2);
+ for (int i = 0; i < AbstractCpdEngine.MAX_CLONE_PART_PER_GROUP + 2; i++) {
+ parts.add(new ClonePart(batchComponent1.key(), i, i, i + 1));
+ }
+ List<CloneGroup> groups = Arrays.asList(CloneGroup.builder().setLength(0).setOrigin(parts.get(0)).setParts(parts).build());
+ engine.saveDuplications(inputFile1, groups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(1);
+ CloseableIterator<Duplication> dups = reader.readComponentDuplications(batchComponent1.batchId());
+ Duplication duplication = dups.next();
+ dups.close();
+ assertThat(duplication.getDuplicateList()).hasSize(AbstractCpdEngine.MAX_CLONE_PART_PER_GROUP);
+
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains("Too many duplication references on file " + inputFile1.relativePath() + " for block at line 0. Keep only the first "
+ + AbstractCpdEngine.MAX_CLONE_PART_PER_GROUP + " references.");
+ }
+
+ @Test
+ public void testTooManyDuplications() throws Exception {
+ // 1 origin part + 101 duplicates = 102
+ List<CloneGroup> dups = new ArrayList<>(AbstractCpdEngine.MAX_CLONE_GROUP_PER_FILE + 1);
+ for (int i = 0; i < AbstractCpdEngine.MAX_CLONE_GROUP_PER_FILE + 1; i++) {
+ ClonePart clonePart = new ClonePart(batchComponent1.key(), i, i, i + 1);
+ ClonePart dupPart = new ClonePart(batchComponent1.key(), i + 1, i + 1, i + 2);
+ dups.add(newCloneGroup(clonePart, dupPart));
+ }
+ engine.saveDuplications(inputFile1, dups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(AbstractCpdEngine.MAX_CLONE_GROUP_PER_FILE);
+
+ assertThat(logTester.logs(LoggerLevel.WARN))
+ .contains("Too many duplication groups on file " + inputFile1.relativePath() + ". Keep only the first " + AbstractCpdEngine.MAX_CLONE_GROUP_PER_FILE + " groups.");
+ }
+
+ @Test
+ public void testOneDuplicatedGroupInvolvingMoreThanTwoFiles() throws Exception {
+ List<CloneGroup> groups = Arrays
+ .asList(newCloneGroup(new ClonePart(batchComponent1.key(), 0, 5, 204), new ClonePart(batchComponent2.key(), 0, 15, 214), new ClonePart(batchComponent3.key(), 0, 25, 224)));
+ engine.saveDuplications(inputFile1, groups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(1);
+ CloseableIterator<Duplication> dups = reader.readComponentDuplications(batchComponent1.batchId());
+ Duplication duplication = dups.next();
+ dups.close();
+ assertThat(duplication.getOriginPosition().getStartLine()).isEqualTo(5);
+ assertThat(duplication.getOriginPosition().getEndLine()).isEqualTo(204);
+ assertThat(duplication.getDuplicateList()).hasSize(2);
+ assertThat(duplication.getDuplicate(0).getOtherFileRef()).isEqualTo(batchComponent2.batchId());
+ assertThat(duplication.getDuplicate(0).getRange().getStartLine()).isEqualTo(15);
+ assertThat(duplication.getDuplicate(0).getRange().getEndLine()).isEqualTo(214);
+ assertThat(duplication.getDuplicate(1).getOtherFileRef()).isEqualTo(batchComponent3.batchId());
+ assertThat(duplication.getDuplicate(1).getRange().getStartLine()).isEqualTo(25);
+ assertThat(duplication.getDuplicate(1).getRange().getEndLine()).isEqualTo(224);
+ }
+
+ @Test
+ public void testTwoDuplicatedGroupsInvolvingThreeFiles() throws Exception {
+ List<CloneGroup> groups = Arrays.asList(
+ newCloneGroup(new ClonePart(batchComponent1.key(), 0, 5, 204), new ClonePart(batchComponent2.key(), 0, 15, 214)),
+ newCloneGroup(new ClonePart(batchComponent1.key(), 0, 15, 214), new ClonePart(batchComponent3.key(), 0, 15, 214)));
+ engine.saveDuplications(inputFile1, groups);
+
+ assertThat(reader.readComponentDuplications(batchComponent1.batchId())).hasSize(2);
+ CloseableIterator<Duplication> dups = reader.readComponentDuplications(batchComponent1.batchId());
+ Duplication duplication1 = dups.next();
+ Duplication duplication2 = dups.next();
+ dups.close();
+ assertThat(duplication1.getOriginPosition().getStartLine()).isEqualTo(5);
+ assertThat(duplication1.getOriginPosition().getEndLine()).isEqualTo(204);
+ assertThat(duplication1.getDuplicateList()).hasSize(1);
+ assertThat(duplication1.getDuplicate(0).getOtherFileRef()).isEqualTo(batchComponent2.batchId());
+ assertThat(duplication1.getDuplicate(0).getRange().getStartLine()).isEqualTo(15);
+ assertThat(duplication1.getDuplicate(0).getRange().getEndLine()).isEqualTo(214);
+
+ assertThat(duplication2.getOriginPosition().getStartLine()).isEqualTo(15);
+ assertThat(duplication2.getOriginPosition().getEndLine()).isEqualTo(214);
+ assertThat(duplication2.getDuplicateList()).hasSize(1);
+ assertThat(duplication2.getDuplicate(0).getOtherFileRef()).isEqualTo(batchComponent3.batchId());
+ assertThat(duplication2.getDuplicate(0).getRange().getStartLine()).isEqualTo(15);
+ assertThat(duplication2.getDuplicate(0).getRange().getEndLine()).isEqualTo(214);
+ }
+
+ private CloneGroup newCloneGroup(ClonePart... parts) {
+ return CloneGroup.builder().setLength(0).setOrigin(parts[0]).setParts(Arrays.asList(parts)).build();
+ }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java b/sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java
deleted file mode 100644
index ea02cec1064..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.batch.cpd;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.duplication.NewDuplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.measure.Measure;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
-import org.sonar.duplications.index.CloneGroup;
-import org.sonar.duplications.index.ClonePart;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class JavaCpdEngineTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- SensorContext context = mock(SensorContext.class);
- DefaultInputFile inputFile;
- private SensorStorage storage = mock(SensorStorage.class);
-
- @Before
- public void before() throws IOException {
- when(context.newMeasure()).then(new Answer<Measure>() {
- @Override
- public Measure answer(InvocationOnMock invocation) throws Throwable {
- return new DefaultMeasure(storage);
- }
- });
- when(context.newDuplication()).then(new Answer<NewDuplication>() {
- @Override
- public NewDuplication answer(InvocationOnMock invocation) throws Throwable {
- return new DefaultDuplication(storage);
- }
- });
- inputFile = (DefaultInputFile) new DefaultInputFile("foo", "src/main/java/Foo.java").setLines(300);
- inputFile.setModuleBaseDir(temp.newFolder().toPath());
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testNothingToSave() {
- JavaCpdEngine.save(context, inputFile, null);
- JavaCpdEngine.save(context, inputFile, Collections.EMPTY_LIST);
-
- verifyZeroInteractions(context);
- }
-
- @Test
- public void testOneSimpleDuplicationBetweenTwoFiles() {
- inputFile.setLines(5);
- List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 2, 4), new ClonePart("key2", 0, 15, 17)));
- JavaCpdEngine.save(context, inputFile, groups);
-
- verify(storage).store(new DefaultDuplication()
- .originBlock(inputFile, 2, 4)
- .isDuplicatedBy("key2", 15, 17));
- }
-
- @Test
- public void testDuplicationOnSameFile() throws Exception {
- List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key1", 0, 215, 414)));
- JavaCpdEngine.save(context, inputFile, groups);
-
- verify(storage).store(new DefaultDuplication()
- .originBlock(inputFile, 5, 204)
- .isDuplicatedBy("key1", 215, 414));
- }
-
- @Test
- public void testOneDuplicatedGroupInvolvingMoreThanTwoFiles() throws Exception {
- List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214), new ClonePart("key3", 0, 25, 224)));
- JavaCpdEngine.save(context, inputFile, groups);
-
- verify(storage).store(new DefaultDuplication()
- .originBlock(inputFile, 5, 204)
- .isDuplicatedBy("key2", 15, 214)
- .isDuplicatedBy("key3", 25, 224));
- }
-
- @Test
- public void testTwoDuplicatedGroupsInvolvingThreeFiles() throws Exception {
- List<CloneGroup> groups = Arrays.asList(
- newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214)),
- newCloneGroup(new ClonePart("key1", 0, 15, 214), new ClonePart("key3", 0, 15, 214)));
- JavaCpdEngine.save(context, inputFile, groups);
-
- verify(storage).store(new DefaultDuplication()
- .originBlock(inputFile, 5, 204)
- .isDuplicatedBy("key2", 15, 214));
- verify(storage).store(new DefaultDuplication()
- .originBlock(inputFile, 15, 214)
- .isDuplicatedBy("key3", 15, 214));
- }
-
- private CloneGroup newCloneGroup(ClonePart... parts) {
- return CloneGroup.builder().setLength(0).setOrigin(parts[0]).setParts(Arrays.asList(parts)).build();
- }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
deleted file mode 100644
index f5913814740..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.batch.duplication;
-
-import org.sonar.batch.index.AbstractCachesTest;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.sensor.duplication.Duplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DuplicationCacheTest extends AbstractCachesTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void should_add_clone_groups() {
- DuplicationCache cache = new DuplicationCache(caches);
-
- DefaultDuplication group1 = new DefaultDuplication()
- .setOriginBlock(new Duplication.Block("foo", 1, 2));
- group1.duplicates().add(new Duplication.Block("foo", 1, 2));
- group1.duplicates().add(new Duplication.Block("foo2", 12, 22));
- group1.duplicates().add(new Duplication.Block("foo3", 13, 23));
-
- DefaultDuplication group2 = new DefaultDuplication()
- .setOriginBlock(new Duplication.Block("2foo", 1, 2));
- group2.duplicates().add(new Duplication.Block("2foo", 1, 2));
- group2.duplicates().add(new Duplication.Block("2foo2", 12, 22));
- group2.duplicates().add(new Duplication.Block("2foo3", 13, 23));
-
- assertThat(cache.componentKeys()).hasSize(0);
-
- cache.put("foo", group1);
- cache.put("foo", group2);
-
- assertThat(cache.componentKeys()).hasSize(1);
- assertThat(cache.byComponent("foo")).hasSize(2);
-
- Iterable<DefaultDuplication> entry = cache.byComponent("foo");
- assertThat(entry.iterator().next().originBlock().resourceKey()).isEqualTo("foo");
-
- }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java
deleted file mode 100644
index 6482786f7dd..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.batch.report;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import org.hamcrest.Description;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.sensor.duplication.Duplication;
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.api.resources.Project;
-import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.index.BatchComponentCache;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.batch.protocol.output.BatchReportReader;
-import org.sonar.batch.protocol.output.BatchReportWriter;
-import org.sonar.core.util.CloseableIterator;
-import org.sonar.core.util.ContextException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DuplicationsPublisherTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- private DuplicationCache duplicationCache;
- private DuplicationsPublisher publisher;
-
- @Before
- public void prepare() {
- BatchComponentCache resourceCache = new BatchComponentCache();
- Project p = new Project("foo");
- resourceCache.add(p, null).setInputComponent(new DefaultInputModule("foo"));
- org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
- resourceCache.add(sampleFile, null).setInputComponent(new DefaultInputFile("foo", "src/Foo.php").setLines(5));
- org.sonar.api.resources.Resource sampleFile2 = org.sonar.api.resources.File.create("src/Foo2.php").setEffectiveKey("foo:src/Foo2.php");
- resourceCache.add(sampleFile2, null).setInputComponent(new DefaultInputFile("foo", "src/Foo2.php").setLines(5));
- duplicationCache = mock(DuplicationCache.class);
- when(duplicationCache.byComponent(anyString())).thenReturn(Collections.<DefaultDuplication>emptyList());
- publisher = new DuplicationsPublisher(resourceCache, duplicationCache);
- }
-
- @Test
- public void publishDuplications_throws_IAE_if_resource_of_duplicate_does_not_exist() throws Exception {
-
- DefaultDuplication dup1 = new DefaultDuplication()
- .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 11, 10))
- .isDuplicatedBy("another", 20, 50);
- when(duplicationCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(dup1));
-
- expectedException.expect(ContextException.class);
- expectedException.expectCause(new CauseMatcher(IllegalStateException.class, "No cross project duplication supported on batch side: another"));
-
- File outputDir = temp.newFolder();
- BatchReportWriter writer = new BatchReportWriter(outputDir);
-
- publisher.publish(writer);
- }
-
- private static class CauseMatcher extends TypeSafeMatcher<Throwable> {
-
- private final Class<? extends Throwable> type;
- private final String expectedMessage;
-
- public CauseMatcher(Class<? extends Throwable> type, String expectedMessage) {
- this.type = type;
- this.expectedMessage = expectedMessage;
- }
-
- @Override
- protected boolean matchesSafely(Throwable item) {
- return item.getClass().isAssignableFrom(type)
- && item.getMessage().contains(expectedMessage);
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("expects type ")
- .appendValue(type)
- .appendText(" and a message ")
- .appendValue(expectedMessage);
- }
- }
-
- @Test
- public void publishDuplications() throws Exception {
-
- DefaultDuplication dup1 = new DefaultDuplication()
- .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 1, 10))
- .isDuplicatedBy("foo:src/Foo.php", 20, 50);
- DefaultDuplication dup2 = new DefaultDuplication()
- .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 11, 10))
- .isDuplicatedBy("foo:src/Foo2.php", 20, 50);
- when(duplicationCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(dup1, dup2));
-
- File outputDir = temp.newFolder();
- BatchReportWriter writer = new BatchReportWriter(outputDir);
-
- publisher.publish(writer);
-
- BatchReportReader reader = new BatchReportReader(outputDir);
-
- assertThat(reader.readComponentDuplications(1)).hasSize(0);
- try (CloseableIterator<BatchReport.Duplication> componentDuplications = reader.readComponentDuplications(2)) {
- org.sonar.batch.protocol.output.BatchReport.Duplication savedDup1 = componentDuplications.next();
- assertThat(savedDup1.getOriginPosition().getStartLine()).isEqualTo(1);
- assertThat(savedDup1.getOriginPosition().getEndLine()).isEqualTo(10);
- assertThat(savedDup1.getDuplicate(0).hasOtherFileRef()).isFalse();
- assertThat(savedDup1.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
- assertThat(savedDup1.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);
-
- org.sonar.batch.protocol.output.BatchReport.Duplication savedDup2 = componentDuplications.next();
- assertThat(savedDup2.getOriginPosition().getStartLine()).isEqualTo(11);
- assertThat(savedDup2.getOriginPosition().getEndLine()).isEqualTo(20);
- assertThat(savedDup2.getDuplicate(0).getOtherFileRef()).isEqualTo(3);
- assertThat(savedDup2.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
- assertThat(savedDup2.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);
-
- assertThat(componentDuplications.hasNext()).isFalse();
- }
-
- }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
index 85ccba5628b..618e5ea3a45 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
@@ -39,7 +39,6 @@ import org.sonar.api.measures.Measure;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.issue.ModuleIssues;
import org.sonar.batch.report.ReportPublisher;
@@ -85,7 +84,7 @@ public class DefaultSensorStorageTest {
when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true);
resourceCache = new BatchComponentCache();
sensorStorage = new DefaultSensorStorage(metricFinder,
- moduleIssues, settings, fs, activeRules, mock(DuplicationCache.class), coverageExclusions, resourceCache, mock(ReportPublisher.class), measureCache);
+ moduleIssues, settings, fs, activeRules, coverageExclusions, resourceCache, mock(ReportPublisher.class), measureCache);
}
@Test