aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/sonar-cpd-plugin
diff options
context:
space:
mode:
authorEvgeny Mandrikov <mandrikov@gmail.com>2011-11-02 12:04:12 +0400
committerEvgeny Mandrikov <mandrikov@gmail.com>2011-11-02 13:14:33 +0400
commit4910189e692bae6671f47f20719a3828ccb45a41 (patch)
treeab9161b54b0f9fc13d347047cc0463e3930b2d44 /plugins/sonar-cpd-plugin
parent8075c048a3155308e89f764860347bb14246112a (diff)
downloadsonarqube-4910189e692bae6671f47f20719a3828ccb45a41.tar.gz
sonarqube-4910189e692bae6671f47f20719a3828ccb45a41.zip
SONAR-2733 New XML format to store duplications
Diffstat (limited to 'plugins/sonar-cpd-plugin')
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java60
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java138
2 files changed, 177 insertions, 21 deletions
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java
index 6b4cd3ec084..a2dfd55cd7a 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarEngine.java
@@ -26,6 +26,8 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.database.model.ResourceModel;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
import org.sonar.api.resources.*;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.index.ResourcePersister;
@@ -49,7 +51,9 @@ import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.*;
public class SonarEngine extends CpdEngine {
@@ -164,14 +168,7 @@ public class SonarEngine extends CpdEngine {
throw new SonarException(e);
}
- if (clones != null && !clones.isEmpty()) {
- // Save
- DuplicationsData data = new DuplicationsData(resource, context);
- for (CloneGroup clone : clones) {
- poplulateData(data, clone);
- }
- data.save();
- }
+ save(context, resource, clones);
}
} finally {
executorService.shutdown();
@@ -196,22 +193,43 @@ public class SonarEngine extends CpdEngine {
return JavaFile.fromRelativePath(inputFile.getRelativePath(), false);
}
- private void poplulateData(DuplicationsData data, CloneGroup clone) {
- ClonePart origin = clone.getOriginPart();
- int originLines = origin.getLineEnd() - origin.getLineStart() + 1;
-
- data.incrementDuplicatedBlock();
- for (ClonePart part : clone.getCloneParts()) {
- if (part.equals(origin)) {
- continue;
+ static void save(SensorContext context, Resource resource, List<CloneGroup> clones) {
+ if (clones == null || clones.isEmpty()) {
+ return;
+ }
+ // Calculate number of lines and blocks
+ Set<Integer> duplicatedLines = new HashSet<Integer>();
+ double duplicatedBlocks = 0;
+ for (CloneGroup clone : clones) {
+ ClonePart origin = clone.getOriginPart();
+ for (ClonePart part : clone.getCloneParts()) {
+ if (part.getResourceId().equals(origin.getResourceId())) {
+ duplicatedBlocks++;
+ for (int duplicatedLine = part.getLineStart(); duplicatedLine < part.getLineStart() + part.getLines(); duplicatedLine++) {
+ duplicatedLines.add(duplicatedLine);
+ }
+ }
}
- data.cumulate(part.getResourceId(), part.getLineStart(), origin.getLineStart(), originLines);
-
- if (part.getResourceId().equals(origin.getResourceId())) {
- data.incrementDuplicatedBlock();
- data.cumulate(origin.getResourceId(), origin.getLineStart(), part.getLineStart(), originLines);
+ }
+ // Build XML
+ StringBuilder xml = new StringBuilder();
+ xml.append("<duplications>");
+ for (CloneGroup clone : clones) {
+ xml.append("<g>");
+ for (ClonePart part : clone.getCloneParts()) {
+ xml.append("<b s=\"").append(part.getLineStart())
+ .append("\" l=\"").append(part.getLines())
+ .append("\" r=\"").append(part.getResourceId())
+ .append("\"/>");
}
+ xml.append("</g>");
}
+ xml.append("</duplications>");
+ // Save
+ context.saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
+ context.saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, (double) duplicatedLines.size());
+ context.saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, duplicatedBlocks);
+ context.saveMeasure(resource, new Measure(CoreMetrics.DUPLICATIONS_DATA, xml.toString()));
}
}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java
new file mode 100644
index 00000000000..875d217e537
--- /dev/null
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java
@@ -0,0 +1,138 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.plugins.cpd;
+
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.test.IsMeasure;
+import org.sonar.duplications.index.CloneGroup;
+import org.sonar.duplications.index.ClonePart;
+
+public class SonarEngineTest {
+
+ private SensorContext context;
+ private Resource resource;
+
+ @Before
+ public void setUp() {
+ context = mock(SensorContext.class);
+ resource = new JavaFile("key1");
+ }
+
+ @Test
+ public void testNothingToSave() {
+ SonarEngine.save(context, resource, null);
+ SonarEngine.save(context, resource, Collections.EMPTY_LIST);
+
+ verifyZeroInteractions(context);
+ }
+
+ @Test
+ public void testOneSimpleDuplicationBetweenTwoFiles() {
+ List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214)));
+ SonarEngine.save(context, resource, groups);
+
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, 200d);
+ verify(context).saveMeasure(
+ eq(resource),
+ argThat(new IsMeasure(CoreMetrics.DUPLICATIONS_DATA, "<duplications><g>"
+ + "<b s=\"5\" l=\"200\" r=\"key1\"/>"
+ + "<b s=\"15\" l=\"200\" r=\"key2\"/>"
+ + "</g></duplications>")));
+ }
+
+ @Test
+ public void testDuplicationOnSameFile() throws Exception {
+ List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key1", 0, 215, 414)));
+ SonarEngine.save(context, resource, groups);
+
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, 400d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, 2d);
+ verify(context).saveMeasure(
+ eq(resource),
+ argThat(new IsMeasure(CoreMetrics.DUPLICATIONS_DATA, "<duplications><g>"
+ + "<b s=\"5\" l=\"200\" r=\"key1\"/>"
+ + "<b s=\"215\" l=\"200\" r=\"key1\"/>"
+ + "</g></duplications>")));
+ }
+
+ @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)));
+ SonarEngine.save(context, resource, groups);
+
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, 200d);
+ verify(context).saveMeasure(
+ eq(resource),
+ argThat(new IsMeasure(CoreMetrics.DUPLICATIONS_DATA, "<duplications><g>"
+ + "<b s=\"5\" l=\"200\" r=\"key1\"/>"
+ + "<b s=\"15\" l=\"200\" r=\"key2\"/>"
+ + "<b s=\"25\" l=\"200\" r=\"key3\"/>"
+ + "</g></duplications>")));
+ }
+
+ @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)));
+ SonarEngine.save(context, resource, groups);
+
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, 2d);
+ verify(context).saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, 210d);
+ verify(context).saveMeasure(
+ eq(resource),
+ argThat(new IsMeasure(CoreMetrics.DUPLICATIONS_DATA, "<duplications>"
+ + "<g>"
+ + "<b s=\"5\" l=\"200\" r=\"key1\"/>"
+ + "<b s=\"15\" l=\"200\" r=\"key2\"/>"
+ + "</g>"
+ + "<g>"
+ + "<b s=\"15\" l=\"200\" r=\"key1\"/>"
+ + "<b s=\"15\" l=\"200\" r=\"key3\"/>"
+ + "</g>"
+ + "</duplications>")));
+ }
+
+ private CloneGroup newCloneGroup(ClonePart... parts) {
+ return new CloneGroup(0, parts[0], Arrays.asList(parts));
+ }
+
+}