aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server/src
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2018-10-22 10:06:52 +0200
committerSonarTech <sonartech@sonarsource.com>2018-11-07 20:21:03 +0100
commit7f59b2e51acb56b9d280fbeea4564194f3dd07cd (patch)
treec4ecd37498f71cf84ec1c0a29b341750448070dc /server/sonar-server/src
parentc7153cbc9057fa19651dba01c8d9c94ff5e1f4b2 (diff)
downloadsonarqube-7f59b2e51acb56b9d280fbeea4564194f3dd07cd.tar.gz
sonarqube-7f59b2e51acb56b9d280fbeea4564194f3dd07cd.zip
SONAR-11394 Calculate estimated overall duplication in SLB
Diffstat (limited to 'server/sonar-server/src')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/duplication/ws/Duplication.java77
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsParser.java172
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java113
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/duplication/ws/DuplicationsParserTest.java109
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowResponseBuilderTest.java61
5 files changed, 347 insertions, 185 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/Duplication.java b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/Duplication.java
new file mode 100644
index 00000000000..88c38fdc548
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/Duplication.java
@@ -0,0 +1,77 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.duplication.ws;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.component.ComponentDto;
+
+public class Duplication {
+ private final ComponentDto componentDto;
+ private final String componentDbKey;
+ private final Integer from;
+ private final Integer size;
+ private final boolean removed;
+
+ static Duplication newRemovedComponent(String componentDbKey, Integer from, Integer size) {
+ return new Duplication(null, componentDbKey, from, size, true);
+ }
+
+ static Duplication newTextComponent(String componentDbKey, Integer from, Integer size) {
+ return new Duplication(null, componentDbKey, from, size, false);
+ }
+
+ static Duplication newComponent(ComponentDto componentDto, Integer from, Integer size) {
+ return new Duplication(componentDto, componentDto.getDbKey(), from, size, false);
+ }
+
+ private Duplication(@Nullable ComponentDto componentDto, String componentDbKey, Integer from, Integer size, boolean removed) {
+ this.componentDto = componentDto;
+ this.componentDbKey = componentDbKey;
+ this.from = from;
+ this.size = size;
+ this.removed = removed;
+ }
+
+ String componentDbKey() {
+ return componentDbKey;
+ }
+
+ Integer from() {
+ return from;
+ }
+
+ Integer size() {
+ return size;
+ }
+
+ public boolean removed() {
+ return removed;
+ }
+
+ /**
+ * can be null if the file wasn't found in DB. This can happen if the target was removed (cross-project duplications) or
+ * if the target refers to an unchanged file in SLBs/PRs.
+ */
+ @CheckForNull
+ public ComponentDto componentDto() {
+ return componentDto;
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsParser.java b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsParser.java
index 8482626bb25..f6cc09f3196 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsParser.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsParser.java
@@ -22,11 +22,11 @@ package org.sonar.server.duplication.ws;
import com.google.common.annotations.VisibleForTesting;
import java.io.Serializable;
import java.io.StringReader;
-import java.util.Collections;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.xml.stream.XMLInputFactory;
@@ -40,12 +40,9 @@ import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentDto;
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-
@ServerSide
public class DuplicationsParser {
-
+ private static final BlockComparator BLOCK_COMPARATOR = new BlockComparator();
private final ComponentDao componentDao;
public DuplicationsParser(ComponentDao componentDao) {
@@ -53,53 +50,76 @@ public class DuplicationsParser {
}
public List<Block> parse(DbSession session, ComponentDto component, @Nullable String branch, @Nullable String pullRequest, @Nullable String duplicationsData) {
- Map<String, ComponentDto> componentsByKey = newHashMap();
- List<Block> blocks = newArrayList();
- if (duplicationsData != null) {
- try {
- SMInputFactory inputFactory = initStax();
- SMHierarchicCursor root = inputFactory.rootElementCursor(new StringReader(duplicationsData));
- root.advance(); // <duplications>
- SMInputCursor cursor = root.childElementCursor("g");
- while (cursor.getNext() != null) {
- List<Duplication> duplications = newArrayList();
- SMInputCursor bCursor = cursor.childElementCursor("b");
- while (bCursor.getNext() != null) {
- String from = bCursor.getAttrValue("s");
- String size = bCursor.getAttrValue("l");
- String componentKey = bCursor.getAttrValue("r");
- if (from != null && size != null && componentKey != null) {
- duplications.add(createDuplication(componentsByKey, branch, pullRequest, from, size, componentKey, session));
+ Map<String, ComponentDto> componentsByKey = new HashMap<>();
+ List<Block> blocks = new ArrayList<>();
+ if (duplicationsData == null) {
+ return blocks;
+ }
+
+ DuplicationComparator duplicationComparator = new DuplicationComparator(component.uuid(), component.projectUuid());
+
+ try {
+ SMInputFactory inputFactory = initStax();
+ SMHierarchicCursor root = inputFactory.rootElementCursor(new StringReader(duplicationsData));
+ root.advance(); // <duplications>
+ SMInputCursor cursor = root.childElementCursor("g");
+ while (cursor.getNext() != null) {
+ List<Duplication> duplications = new ArrayList<>();
+ SMInputCursor bCursor = cursor.childElementCursor("b");
+ while (bCursor.getNext() != null) {
+ String from = bCursor.getAttrValue("s");
+ String size = bCursor.getAttrValue("l");
+ boolean onlyText = Boolean.parseBoolean(bCursor.getAttrValue("t"));
+ String componentDbKey = bCursor.getAttrValue("r");
+ if (from != null && size != null && componentDbKey != null) {
+ if (onlyText) {
+ // flag means that the target refers to an unchanged file in SLBs/PRs that doesn't exist in DB.
+ // Display as text without a link or other details.
+ duplications.add(Duplication.newTextComponent(componentDbKey, Integer.valueOf(from), Integer.valueOf(size)));
+ } else {
+ duplications.add(createDuplication(componentsByKey, branch, pullRequest, from, size, componentDbKey, session));
}
}
- Collections.sort(duplications, new DuplicationComparator(component.uuid(), component.projectUuid()));
- blocks.add(new Block(duplications));
}
- Collections.sort(blocks, new BlockComparator());
- } catch (XMLStreamException e) {
- throw new IllegalStateException("XML is not valid", e);
+ duplications.sort(duplicationComparator);
+ blocks.add(new Block(duplications));
}
+ blocks.sort(BLOCK_COMPARATOR);
+ return blocks;
+ } catch (XMLStreamException e) {
+ throw new IllegalStateException("XML is not valid", e);
}
- return blocks;
}
- private Duplication createDuplication(Map<String, ComponentDto> componentsByKey, @Nullable String branch, @Nullable String pullRequest, String from, String size,
- String componentDbKey, DbSession session) {
+ private Duplication createDuplication(Map<String, ComponentDto> componentsByKey, @Nullable String branch, @Nullable String pullRequest, String from,
+ String size, String componentDbKey, DbSession session) {
String componentKey = convertToKey(componentDbKey);
- ComponentDto component = componentsByKey.get(componentKey);
- if (component == null) {
- Optional<ComponentDto> componentDtoOptional;
- if (branch != null) {
- componentDtoOptional = componentDao.selectByKeyAndBranch(session, componentKey, branch);
- } else if (pullRequest != null) {
- componentDtoOptional = componentDao.selectByKeyAndPullRequest(session, componentKey, pullRequest);
- } else {
- componentDtoOptional = componentDao.selectByKey(session, componentKey);
- }
- component = componentDtoOptional.isPresent() ? componentDtoOptional.get() : null;
+
+ ComponentDto component;
+ if (componentsByKey.containsKey(componentKey)) {
+ component = componentsByKey.get(componentKey);
+ } else {
+ component = loadComponent(session, componentKey, branch, pullRequest);
componentsByKey.put(componentKey, component);
}
- return new Duplication(component, Integer.valueOf(from), Integer.valueOf(size));
+
+ if (component != null) {
+ return Duplication.newComponent(component, Integer.valueOf(from), Integer.valueOf(size));
+ } else {
+ //This can happen if the target was removed (cross-project duplications)
+ return Duplication.newRemovedComponent(componentKey, Integer.valueOf(from), Integer.valueOf(size));
+ }
+ }
+
+ @CheckForNull
+ private ComponentDto loadComponent(DbSession session, String componentKey, @Nullable String branch, @Nullable String pullRequest) {
+ if (branch != null) {
+ return componentDao.selectByKeyAndBranch(session, componentKey, branch).orElse(null);
+ } else if (pullRequest != null) {
+ return componentDao.selectByKeyAndPullRequest(session, componentKey, pullRequest).orElse(null);
+ } else {
+ return componentDao.selectByKey(session, componentKey).orElse(null);
+ }
}
private static String convertToKey(String dbKey) {
@@ -116,15 +136,21 @@ public class DuplicationsParser {
return new SMInputFactory(xmlFactory);
}
+ /**
+ * Sorts the duplications with the following criteria:
+ * - Duplications in the same file by starting line
+ * - Duplications in the same project
+ * - Cross project duplications
+ */
@VisibleForTesting
static class DuplicationComparator implements Comparator<Duplication>, Serializable {
private static final long serialVersionUID = 1;
- private final String uuid;
+ private final String fileUuid;
private final String projectUuid;
- DuplicationComparator(String uuid, String projectUuid) {
- this.uuid = uuid;
+ DuplicationComparator(String fileUuid, String projectUuid) {
+ this.fileUuid = fileUuid;
this.projectUuid = projectUuid;
}
@@ -133,34 +159,40 @@ public class DuplicationsParser {
if (d1 == null || d2 == null) {
return -1;
}
- ComponentDto file1 = d1.file();
- ComponentDto file2 = d2.file();
+ ComponentDto file1 = d1.componentDto();
+ ComponentDto file2 = d2.componentDto();
- if (file1 == null || file2 == null) {
- return -1;
- }
- if (file1.equals(d2.file())) {
+ if (file1 != null && file1.equals(file2)) {
// if duplication on same file => order by starting line
return d1.from().compareTo(d2.from());
}
- if (file1.uuid().equals(uuid)) {
+ if (sameFile(file1) && !sameFile(file2)) {
// the current resource must be displayed first
return -1;
}
- if (file2.uuid().equals(uuid)) {
+ if (sameFile(file2) && !sameFile(file1)) {
// the current resource must be displayed first
return 1;
}
- if (StringUtils.equals(file1.projectUuid(), projectUuid) && !StringUtils.equals(file2.projectUuid(), projectUuid)) {
+ if (sameProject(file1) && !sameProject(file2)) {
// if resource is in the same project, this it must be displayed first
return -1;
}
- if (StringUtils.equals(file2.projectUuid(), projectUuid) && !StringUtils.equals(file1.projectUuid(), projectUuid)) {
+ if (sameProject(file2) && !sameProject(file1)) {
// if resource is in the same project, this it must be displayed first
return 1;
}
+
return d1.from().compareTo(d2.from());
}
+
+ private boolean sameFile(@Nullable ComponentDto otherDto) {
+ return otherDto != null && StringUtils.equals(otherDto.uuid(), fileUuid);
+ }
+
+ private boolean sameProject(@Nullable ComponentDto otherDto) {
+ return otherDto == null || StringUtils.equals(otherDto.projectUuid(), projectUuid);
+ }
}
private static class BlockComparator implements Comparator<Block>, Serializable {
@@ -180,34 +212,6 @@ public class DuplicationsParser {
}
}
- public static class Duplication {
- private final ComponentDto file;
- private final Integer from;
- private final Integer size;
-
- Duplication(@Nullable ComponentDto file, Integer from, Integer size) {
- this.file = file;
- this.from = from;
- this.size = size;
- }
-
- /**
- * File can be null when duplication is linked on a removed file
- */
- @CheckForNull
- ComponentDto file() {
- return file;
- }
-
- Integer from() {
- return from;
- }
-
- Integer size() {
- return size;
- }
- }
-
static class Block {
private final List<Duplication> duplications;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java
index 7f792ca70d7..4212ca7be74 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java
@@ -20,10 +20,13 @@
package org.sonar.server.duplication.ws;
import com.google.common.annotations.VisibleForTesting;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDao;
@@ -32,62 +35,87 @@ import org.sonarqube.ws.Duplications;
import org.sonarqube.ws.Duplications.Block;
import org.sonarqube.ws.Duplications.ShowResponse;
-import static com.google.common.collect.Maps.newHashMap;
import static org.sonar.core.util.Protobuf.setNullable;
-// TODO Add UT on branch
public class ShowResponseBuilder {
private final ComponentDao componentDao;
+ private final Map<String, Reference> refByComponentKey = new HashMap<>();
public ShowResponseBuilder(DbClient dbClient) {
this.componentDao = dbClient.componentDao();
}
- @VisibleForTesting
- ShowResponseBuilder(ComponentDao componentDao) {
+ @VisibleForTesting ShowResponseBuilder(ComponentDao componentDao) {
this.componentDao = componentDao;
}
ShowResponse build(DbSession session, List<DuplicationsParser.Block> blocks, @Nullable String branch, @Nullable String pullRequest) {
ShowResponse.Builder response = ShowResponse.newBuilder();
- Map<String, String> refByComponentKey = newHashMap();
blocks.stream()
- .map(block -> toWsDuplication(block, refByComponentKey))
+ .map(this::toWsDuplication)
.forEach(response::addDuplications);
- writeFiles(session, response, refByComponentKey, branch, pullRequest);
-
+ writeFileRefs(session, response, branch, pullRequest);
return response.build();
}
- private static Duplications.Duplication.Builder toWsDuplication(DuplicationsParser.Block block, Map<String, String> refByComponentKey) {
+ private Duplications.Duplication.Builder toWsDuplication(DuplicationsParser.Block block) {
Duplications.Duplication.Builder wsDuplication = Duplications.Duplication.newBuilder();
block.getDuplications().stream()
- .map(d -> toWsBlock(refByComponentKey, d))
+ .map(this::toWsBlock)
.forEach(wsDuplication::addBlocks);
return wsDuplication;
}
- private static Block.Builder toWsBlock(Map<String, String> refByComponentKey, DuplicationsParser.Duplication duplication) {
- String ref = null;
- ComponentDto componentDto = duplication.file();
- if (componentDto != null) {
- String componentKey = componentDto.getDbKey();
- ref = refByComponentKey.computeIfAbsent(componentKey, k -> Integer.toString(refByComponentKey.size() + 1));
+ private Block.Builder toWsBlock(Duplication duplication) {
+ Block.Builder block = Block.newBuilder();
+
+ if (!duplication.removed()) {
+ Reference ref = refByComponentKey.computeIfAbsent(duplication.componentDbKey(), k -> new Reference(
+ Integer.toString(refByComponentKey.size() + 1),
+ duplication.componentDto(),
+ duplication.componentDbKey()));
+ block.setRef(ref.id);
}
- Block.Builder block = Block.newBuilder();
block.setFrom(duplication.from());
block.setSize(duplication.size());
- setNullable(ref, block::setRef);
return block;
}
- private static Duplications.File toWsFile(ComponentDto file, @Nullable ComponentDto project, @Nullable ComponentDto subProject, @Nullable String branch,
- @Nullable String pullRequest) {
+ private void writeFileRefs(DbSession session, ShowResponse.Builder response, @Nullable String branch, @Nullable String pullRequest) {
+ Map<String, ComponentDto> projectsByUuid = new HashMap<>();
+ Map<String, ComponentDto> parentModulesByUuid = new HashMap<>();
+
+ for (Map.Entry<String, Reference> entry : refByComponentKey.entrySet()) {
+ Reference ref = entry.getValue();
+ ComponentDto file = ref.dto();
+
+ if (file != null) {
+ ComponentDto project = getProject(file.projectUuid(), projectsByUuid, session);
+ ComponentDto parentModule = getParentProject(file.getRootUuid(), parentModulesByUuid, session);
+ response.putFiles(ref.id(), toWsFile(file, project, parentModule, branch, pullRequest));
+ } else {
+ response.putFiles(ref.id(), toWsFile(ref.componentKey(), branch, pullRequest));
+ }
+ }
+ }
+
+ private static Duplications.File toWsFile(String componentKey, @Nullable String branch, @Nullable String pullRequest) {
+ Duplications.File.Builder wsFile = Duplications.File.newBuilder();
+ String keyWithoutBranch = ComponentDto.removeBranchAndPullRequestFromKey(componentKey);
+ wsFile.setKey(keyWithoutBranch);
+ wsFile.setName(StringUtils.substringAfterLast(keyWithoutBranch, ":"));
+ setNullable(branch, wsFile::setBranch);
+ setNullable(pullRequest, wsFile::setPullRequest);
+ return wsFile.build();
+ }
+
+ private static Duplications.File toWsFile(ComponentDto file, @Nullable ComponentDto project, @Nullable ComponentDto subProject,
+ @Nullable String branch, @Nullable String pullRequest) {
Duplications.File.Builder wsFile = Duplications.File.newBuilder();
wsFile.setKey(file.getKey());
wsFile.setUuid(file.uuid());
@@ -110,25 +138,6 @@ public class ShowResponseBuilder {
return wsFile.build();
}
- private void writeFiles(DbSession session, ShowResponse.Builder response, Map<String, String> refByComponentKey, @Nullable String branch, @Nullable String pullRequest) {
- Map<String, ComponentDto> projectsByUuid = newHashMap();
- Map<String, ComponentDto> parentModulesByUuid = newHashMap();
- Map<String, Duplications.File> filesByRef = response.getMutableFiles();
-
- for (Map.Entry<String, String> entry : refByComponentKey.entrySet()) {
- String componentKey = entry.getKey();
- String ref = entry.getValue();
- Optional<ComponentDto> fileOptional = componentDao.selectByKey(session, componentKey);
- if (fileOptional.isPresent()) {
- ComponentDto file = fileOptional.get();
-
- ComponentDto project = getProject(file.projectUuid(), projectsByUuid, session);
- ComponentDto parentModule = getParentProject(file.getRootUuid(), parentModulesByUuid, session);
- filesByRef.put(ref, toWsFile(file, project, parentModule, branch, pullRequest));
- }
- }
- }
-
private ComponentDto getProject(String projectUuid, Map<String, ComponentDto> projectsByUuid, DbSession session) {
ComponentDto project = projectsByUuid.get(projectUuid);
if (project == null) {
@@ -153,4 +162,30 @@ public class ShowResponseBuilder {
return project;
}
+ private static class Reference {
+ private final String id;
+ private final ComponentDto dto;
+ private final String componentKey;
+
+ public Reference(String id, @Nullable ComponentDto dto, String componentKey) {
+ this.id = id;
+ this.dto = dto;
+ this.componentKey = componentKey;
+ }
+
+ public String id() {
+ return id;
+ }
+
+ @CheckForNull
+ public ComponentDto dto() {
+ return dto;
+ }
+
+ public String componentKey() {
+ return componentKey;
+ }
+
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/DuplicationsParserTest.java b/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/DuplicationsParserTest.java
index d45ce9934fc..bb13f39ff2d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/DuplicationsParserTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/DuplicationsParserTest.java
@@ -37,7 +37,7 @@ public class DuplicationsParserTest {
@Rule
public DbTester db = DbTester.create();
- DuplicationsParser parser = new DuplicationsParser(db.getDbClient().componentDao());
+ private DuplicationsParser parser = new DuplicationsParser(db.getDbClient().componentDao());
@Test
public void empty_list_when_no_data() {
@@ -60,17 +60,17 @@ public class DuplicationsParserTest {
"</duplications>", file.getDbKey(), file.getDbKey()));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(2);
// Smallest line comes first
- DuplicationsParser.Duplication duplication1 = duplications.get(0);
- assertThat(duplication1.file()).isEqualTo(file);
+ Duplication duplication1 = duplications.get(0);
+ assertThat(duplication1.componentDto()).isEqualTo(file);
assertThat(duplication1.from()).isEqualTo(20);
assertThat(duplication1.size()).isEqualTo(5);
- DuplicationsParser.Duplication duplication2 = duplications.get(1);
- assertThat(duplication2.file()).isEqualTo(file);
+ Duplication duplication2 = duplications.get(1);
+ assertThat(duplication2.componentDto()).isEqualTo(file);
assertThat(duplication2.from()).isEqualTo(31);
assertThat(duplication2.size()).isEqualTo(5);
}
@@ -89,17 +89,17 @@ public class DuplicationsParserTest {
"</duplications>", file2.getDbKey(), file1.getDbKey()));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(2);
// Current file comes first
- DuplicationsParser.Duplication duplication1 = duplications.get(0);
- assertThat(duplication1.file()).isEqualTo(file1);
+ Duplication duplication1 = duplications.get(0);
+ assertThat(duplication1.componentDto()).isEqualTo(file1);
assertThat(duplication1.from()).isEqualTo(31);
assertThat(duplication1.size()).isEqualTo(5);
- DuplicationsParser.Duplication duplication2 = duplications.get(1);
- assertThat(duplication2.file()).isEqualTo(file2);
+ Duplication duplication2 = duplications.get(1);
+ assertThat(duplication2.componentDto()).isEqualTo(file2);
assertThat(duplication2.from()).isEqualTo(20);
assertThat(duplication2.size()).isEqualTo(5);
}
@@ -121,25 +121,25 @@ public class DuplicationsParserTest {
"</duplications>", file1.getDbKey(), fileOnProject2.getDbKey(), file2.getDbKey()));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(3);
// Current file's project comes first
- DuplicationsParser.Duplication duplication1 = duplications.get(0);
- assertThat(duplication1.file()).isEqualTo(file1);
+ Duplication duplication1 = duplications.get(0);
+ assertThat(duplication1.componentDto()).isEqualTo(file1);
assertThat(duplication1.from()).isEqualTo(148);
assertThat(duplication1.size()).isEqualTo(24);
- DuplicationsParser.Duplication duplication2 = duplications.get(1);
- assertThat(duplication2.file()).isEqualTo(file2);
+ Duplication duplication2 = duplications.get(1);
+ assertThat(duplication2.componentDto()).isEqualTo(file2);
assertThat(duplication2.from()).isEqualTo(111);
assertThat(duplication2.size()).isEqualTo(24);
// Other project comes last
- DuplicationsParser.Duplication duplication3 = duplications.get(2);
- assertThat(duplication3.file()).isEqualTo(fileOnProject2);
+ Duplication duplication3 = duplications.get(2);
+ assertThat(duplication3.componentDto()).isEqualTo(fileOnProject2);
assertThat(duplication3.from()).isEqualTo(137);
assertThat(duplication3.size()).isEqualTo(24);
}
@@ -189,17 +189,17 @@ public class DuplicationsParserTest {
"</duplications>", file.getDbKey(), "not_existing"));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(2);
// Duplications on removed file
- DuplicationsParser.Duplication duplication1 = duplication(duplications, null);
- assertThat(duplication1.file()).isNull();
+ Duplication duplication1 = duplication(duplications, null);
+ assertThat(duplication1.componentDto()).isNull();
assertThat(duplication1.from()).isEqualTo(31);
assertThat(duplication1.size()).isEqualTo(5);
- DuplicationsParser.Duplication duplication2 = duplication(duplications, file.getDbKey());
- assertThat(duplication2.file()).isEqualTo(file);
+ Duplication duplication2 = duplication(duplications, file.getDbKey());
+ assertThat(duplication2.componentDto()).isEqualTo(file);
assertThat(duplication2.from()).isEqualTo(20);
assertThat(duplication2.size()).isEqualTo(5);
}
@@ -215,26 +215,33 @@ public class DuplicationsParserTest {
DuplicationsParser.DuplicationComparator comparator = new DuplicationsParser.DuplicationComparator(currentFile.uuid(), currentFile.projectUuid());
// On same file
- assertThat(comparator.compare(new DuplicationsParser.Duplication(currentFile, 2, 2), new DuplicationsParser.Duplication(currentFile, 5, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
+ Duplication.newComponent(currentFile, 5, 2))).isEqualTo(-1);
// Different files on same project
- assertThat(comparator.compare(new DuplicationsParser.Duplication(currentFile, 2, 2), new DuplicationsParser.Duplication(fileOnSameProject, 5, 2))).isEqualTo(-1);
- assertThat(comparator.compare(new DuplicationsParser.Duplication(fileOnSameProject, 2, 2), new DuplicationsParser.Duplication(currentFile, 5, 2))).isEqualTo(1);
+ assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
+ Duplication.newComponent(fileOnSameProject, 5, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 2, 2),
+ Duplication.newComponent(currentFile, 5, 2))).isEqualTo(1);
// Different files on different projects
- assertThat(comparator.compare(new DuplicationsParser.Duplication(fileOnSameProject, 5, 2), new DuplicationsParser.Duplication(fileOnDifferentProject, 2, 2))).isEqualTo(-1);
- assertThat(comparator.compare(new DuplicationsParser.Duplication(fileOnDifferentProject, 5, 2), new DuplicationsParser.Duplication(fileOnSameProject, 2, 2))).isEqualTo(1);
+ assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 5, 2),
+ Duplication.newComponent(fileOnDifferentProject, 2, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newComponent(fileOnDifferentProject, 5, 2),
+ Duplication.newComponent(fileOnSameProject, 2, 2))).isEqualTo(1);
// Files on 2 different projects
ComponentDto project3 = db.components().insertPrivateProject();
- assertThat(comparator.compare(new DuplicationsParser.Duplication(fileOnDifferentProject, 5, 2),
- new DuplicationsParser.Duplication(project3, 2, 2))).isEqualTo(1);
+ assertThat(comparator.compare(Duplication.newComponent(fileOnDifferentProject, 5, 2),
+ Duplication.newComponent(project3, 2, 2))).isEqualTo(1);
// With null duplications
- assertThat(comparator.compare(null, new DuplicationsParser.Duplication(fileOnSameProject, 2, 2))).isEqualTo(-1);
- assertThat(comparator.compare(new DuplicationsParser.Duplication(fileOnSameProject, 2, 2), null)).isEqualTo(-1);
+ assertThat(comparator.compare(null, Duplication.newComponent(fileOnSameProject, 2, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 2, 2), null)).isEqualTo(-1);
assertThat(comparator.compare(null, null)).isEqualTo(-1);
// On some removed file
- assertThat(comparator.compare(new DuplicationsParser.Duplication(currentFile, 2, 2), new DuplicationsParser.Duplication(null, 5, 2))).isEqualTo(-1);
- assertThat(comparator.compare(new DuplicationsParser.Duplication(null, 2, 2), new DuplicationsParser.Duplication(currentFile, 5, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
+ Duplication.newRemovedComponent("key1", 5, 2))).isEqualTo(-1);
+ assertThat(comparator.compare(Duplication.newRemovedComponent("key2", 2, 2),
+ Duplication.newComponent(currentFile, 5, 2))).isEqualTo(1);
}
@Test
@@ -252,19 +259,19 @@ public class DuplicationsParserTest {
"</duplications>", file2.getDbKey(), file1.getDbKey()));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(2);
// Current file comes first
- DuplicationsParser.Duplication duplication1 = duplications.get(0);
- assertThat(duplication1.file()).isEqualTo(file1);
- assertThat(duplication1.file().getKey()).isEqualTo(file1.getKey());
+ Duplication duplication1 = duplications.get(0);
+ assertThat(duplication1.componentDto()).isEqualTo(file1);
+ assertThat(duplication1.componentDto().getKey()).isEqualTo(file1.getKey());
assertThat(duplication1.from()).isEqualTo(31);
assertThat(duplication1.size()).isEqualTo(5);
- DuplicationsParser.Duplication duplication2 = duplications.get(1);
- assertThat(duplication2.file()).isEqualTo(file2);
- assertThat(duplication2.file().getKey()).isEqualTo(file2.getKey());
+ Duplication duplication2 = duplications.get(1);
+ assertThat(duplication2.componentDto()).isEqualTo(file2);
+ assertThat(duplication2.componentDto().getKey()).isEqualTo(file2.getKey());
assertThat(duplication2.from()).isEqualTo(20);
assertThat(duplication2.size()).isEqualTo(5);
}
@@ -284,26 +291,26 @@ public class DuplicationsParserTest {
"</duplications>", file2.getDbKey(), file1.getDbKey()));
assertThat(blocks).hasSize(1);
- List<DuplicationsParser.Duplication> duplications = blocks.get(0).getDuplications();
+ List<Duplication> duplications = blocks.get(0).getDuplications();
assertThat(duplications).hasSize(2);
// Current file comes first
- DuplicationsParser.Duplication duplication1 = duplications.get(0);
- assertThat(duplication1.file()).isEqualTo(file1);
- assertThat(duplication1.file().getKey()).isEqualTo(file1.getKey());
+ Duplication duplication1 = duplications.get(0);
+ assertThat(duplication1.componentDto()).isEqualTo(file1);
+ assertThat(duplication1.componentDto().getKey()).isEqualTo(file1.getKey());
assertThat(duplication1.from()).isEqualTo(31);
assertThat(duplication1.size()).isEqualTo(5);
- DuplicationsParser.Duplication duplication2 = duplications.get(1);
- assertThat(duplication2.file()).isEqualTo(file2);
- assertThat(duplication2.file().getKey()).isEqualTo(file2.getKey());
+ Duplication duplication2 = duplications.get(1);
+ assertThat(duplication2.componentDto()).isEqualTo(file2);
+ assertThat(duplication2.componentDto().getKey()).isEqualTo(file2.getKey());
assertThat(duplication2.from()).isEqualTo(20);
assertThat(duplication2.size()).isEqualTo(5);
}
- private static DuplicationsParser.Duplication duplication(List<DuplicationsParser.Duplication> duplications, @Nullable final String componentKey) {
- return Iterables.find(duplications, input -> input != null && (componentKey == null ? input.file() == null
- : input.file() != null && componentKey.equals(input.file().getDbKey())));
+ private static Duplication duplication(List<Duplication> duplications, @Nullable final String componentKey) {
+ return Iterables.find(duplications, input -> input != null && (componentKey == null ? input.componentDto() == null
+ : input.componentDto() != null && componentKey.equals(input.componentDto().getDbKey())));
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowResponseBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowResponseBuilderTest.java
index 4042c185b33..082652ad33b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowResponseBuilderTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/duplication/ws/ShowResponseBuilderTest.java
@@ -51,8 +51,8 @@ public class ShowResponseBuilderTest {
ComponentDto file2 = db.components().insertComponent(newFileDto(module));
List<DuplicationsParser.Block> blocks = newArrayList();
blocks.add(new DuplicationsParser.Block(newArrayList(
- new DuplicationsParser.Duplication(file1, 57, 12),
- new DuplicationsParser.Duplication(file2, 73, 12))));
+ Duplication.newComponent(file1, 57, 12),
+ Duplication.newComponent(file2, 73, 12))));
test(blocks, null, null,
"{\n" +
@@ -96,8 +96,8 @@ public class ShowResponseBuilderTest {
ComponentDto file2 = db.components().insertComponent(newFileDto(project));
List<DuplicationsParser.Block> blocks = newArrayList();
blocks.add(new DuplicationsParser.Block(newArrayList(
- new DuplicationsParser.Duplication(file1, 57, 12),
- new DuplicationsParser.Duplication(file2, 73, 12))));
+ Duplication.newComponent(file1, 57, 12),
+ Duplication.newComponent(file2, 73, 12))));
test(blocks, null, null,
"{\n" +
@@ -136,9 +136,9 @@ public class ShowResponseBuilderTest {
ComponentDto file = db.components().insertComponent(newFileDto(project));
List<DuplicationsParser.Block> blocks = newArrayList();
blocks.add(new DuplicationsParser.Block(newArrayList(
- new DuplicationsParser.Duplication(file, 57, 12),
+ Duplication.newComponent(file, 57, 12),
// Duplication on a removed file
- new DuplicationsParser.Duplication(null, 73, 12))));
+ Duplication.newRemovedComponent("key", 73, 12))));
test(blocks, null, null,
"{\n" +
@@ -166,6 +166,45 @@ public class ShowResponseBuilderTest {
}
@Test
+ public void write_duplications_with_a_component_without_details() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ List<DuplicationsParser.Block> blocks = newArrayList();
+ blocks.add(new DuplicationsParser.Block(newArrayList(
+ Duplication.newComponent(file, 57, 12),
+ // Duplication on a file without details
+ Duplication.newTextComponent("project:path/to/file", 73, 12))));
+
+ test(blocks, null, null,
+ "{\n" +
+ " \"duplications\": [\n" +
+ " {\n" +
+ " \"blocks\": [\n" +
+ " {\n" +
+ " \"from\": 57, \"size\": 12, \"_ref\": \"1\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"from\": 73, \"size\": 12\n" +
+ " }\n" +
+ " ]\n" +
+ " }," +
+ " ],\n" +
+ " \"files\": {\n" +
+ " \"1\": {\n" +
+ " \"key\": \"" + file.getKey() + "\",\n" +
+ " \"name\": \"" + file.longName() + "\",\n" +
+ " \"project\": \"" + project.getKey() + "\",\n" +
+ " \"projectName\": \"" + project.longName() + "\",\n" +
+ " }\n" +
+ " \"2\": {\n" +
+ " \"key\": \"project:path/to/file\",\n" +
+ " \"name\": \"path/to/file\",\n" +
+ " }\n" +
+ " }" +
+ "}");
+ }
+
+ @Test
public void write_duplications_on_branch() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
@@ -173,8 +212,8 @@ public class ShowResponseBuilderTest {
ComponentDto file2 = db.components().insertComponent(newFileDto(branch));
List<DuplicationsParser.Block> blocks = newArrayList();
blocks.add(new DuplicationsParser.Block(newArrayList(
- new DuplicationsParser.Duplication(file1, 57, 12),
- new DuplicationsParser.Duplication(file2, 73, 12))));
+ Duplication.newComponent(file1, 57, 12),
+ Duplication.newComponent(file2, 73, 12))));
test(blocks, branch.getBranch(), null,
"{\n" +
@@ -217,8 +256,8 @@ public class ShowResponseBuilderTest {
ComponentDto file2 = db.components().insertComponent(newFileDto(pullRequest));
List<DuplicationsParser.Block> blocks = newArrayList();
blocks.add(new DuplicationsParser.Block(newArrayList(
- new DuplicationsParser.Duplication(file1, 57, 12),
- new DuplicationsParser.Duplication(file2, 73, 12))));
+ Duplication.newComponent(file1, 57, 12),
+ Duplication.newComponent(file2, 73, 12))));
test(blocks, null, pullRequest.getPullRequest(),
"{\n" +
@@ -255,7 +294,7 @@ public class ShowResponseBuilderTest {
@Test
public void write_nothing_when_no_data() {
- test(Collections.emptyList(), null, null,"{\"duplications\": [], \"files\": {}}");
+ test(Collections.emptyList(), null, null, "{\"duplications\": [], \"files\": {}}");
}
private void test(List<DuplicationsParser.Block> blocks, @Nullable String branch, @Nullable String pullRequest, String expected) {