diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-11-02 12:04:12 +0400 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-11-02 13:14:33 +0400 |
commit | 4910189e692bae6671f47f20719a3828ccb45a41 (patch) | |
tree | ab9161b54b0f9fc13d347047cc0463e3930b2d44 /plugins/sonar-cpd-plugin | |
parent | 8075c048a3155308e89f764860347bb14246112a (diff) | |
download | sonarqube-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.java | 60 | ||||
-rw-r--r-- | plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarEngineTest.java | 138 |
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)); + } + +} |