diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-12-01 11:26:45 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2015-12-01 16:38:08 +0100 |
commit | a70899910e2448abda0ec8c76aff2000318dce49 (patch) | |
tree | 7db055f0637463ed6a9ab32dbbef100632ae0cef /sonar-batch | |
parent | ba7e2918528cba02496907a81d730079953c28ce (diff) | |
download | sonarqube-a70899910e2448abda0ec8c76aff2000318dce49.tar.gz sonarqube-a70899910e2448abda0ec8c76aff2000318dce49.zip |
SONAR-6933 Drop newDuplication() beta API
Diffstat (limited to 'sonar-batch')
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 |