]> source.dussan.org Git - sonarqube.git/blob
f71292b5740acf82e7d51176d4c2ea8a7b1875aa
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.duplication.ws;
21
22 import com.google.common.collect.Iterables;
23 import java.util.List;
24 import javax.annotation.Nullable;
25 import org.apache.commons.lang.RandomStringUtils;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.sonar.db.DbTester;
29 import org.sonar.db.component.BranchType;
30 import org.sonar.db.component.ComponentDto;
31 import org.sonar.server.component.ComponentFinder;
32
33 import static java.lang.String.format;
34 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
35 import static org.assertj.core.api.Assertions.assertThat;
36 import static org.sonar.db.component.ComponentTesting.newFileDto;
37
38 public class DuplicationsParserTest {
39
40   @Rule
41   public DbTester db = DbTester.create();
42
43   private final DuplicationsParser parser = new DuplicationsParser(new ComponentFinder(db.getDbClient(), null));
44
45   @Test
46   public void empty_list_when_no_data() {
47     ComponentDto project = db.components().insertPrivateProject();
48     ComponentDto file = db.components().insertComponent(newFileDto(project));
49
50     assertThat(parser.parse(db.getSession(), file, null, null, null)).isEmpty();
51   }
52
53   @Test
54   public void duplication_on_same_file() {
55     ComponentDto project = db.components().insertPrivateProject();
56     ComponentDto file = db.components().insertComponent(newFileDto(project));
57     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file, null, null,
58       format("<duplications>\n" +
59         "  <g>\n" +
60         "    <b s=\"31\" l=\"5\" r=\"%s\"/>\n" +
61         "    <b s=\"20\" l=\"5\" r=\"%s\"/>\n" +
62         "  </g>\n" +
63         "</duplications>", file.getKey(), file.getKey()));
64     assertThat(blocks).hasSize(1);
65
66     List<Duplication> duplications = blocks.get(0).getDuplications();
67     assertThat(duplications).hasSize(2);
68
69     // Smallest line comes first
70     Duplication duplication1 = duplications.get(0);
71     assertThat(duplication1.componentDto()).isEqualTo(file);
72     assertThat(duplication1.from()).isEqualTo(20);
73     assertThat(duplication1.size()).isEqualTo(5);
74
75     Duplication duplication2 = duplications.get(1);
76     assertThat(duplication2.componentDto()).isEqualTo(file);
77     assertThat(duplication2.from()).isEqualTo(31);
78     assertThat(duplication2.size()).isEqualTo(5);
79   }
80
81   @Test
82   public void duplication_on_same_project() {
83     ComponentDto project = db.components().insertPrivateProject();
84     ComponentDto file1 = db.components().insertComponent(newFileDto(project));
85     ComponentDto file2 = db.components().insertComponent(newFileDto(project));
86     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file1, null, null,
87       format("<duplications>\n" +
88         "  <g>\n" +
89         "    <b s=\"20\" l=\"5\" r=\"%s\"/>\n" +
90         "    <b s=\"31\" l=\"5\" r=\"%s\"/>\n" +
91         "  </g>\n" +
92         "</duplications>", file2.getKey(), file1.getKey()));
93     assertThat(blocks).hasSize(1);
94
95     List<Duplication> duplications = blocks.get(0).getDuplications();
96     assertThat(duplications).hasSize(2);
97
98     // Current file comes first
99     Duplication duplication1 = duplications.get(0);
100     assertThat(duplication1.componentDto()).isEqualTo(file1);
101     assertThat(duplication1.from()).isEqualTo(31);
102     assertThat(duplication1.size()).isEqualTo(5);
103
104     Duplication duplication2 = duplications.get(1);
105     assertThat(duplication2.componentDto()).isEqualTo(file2);
106     assertThat(duplication2.from()).isEqualTo(20);
107     assertThat(duplication2.size()).isEqualTo(5);
108   }
109
110   @Test
111   public void duplications_on_different_project() {
112     ComponentDto project1 = db.components().insertPrivateProject();
113     ComponentDto file1 = db.components().insertComponent(newFileDto(project1));
114     ComponentDto file2 = db.components().insertComponent(newFileDto(project1));
115     ComponentDto project2 = db.components().insertPrivateProject();
116     ComponentDto fileOnProject2 = db.components().insertComponent(newFileDto(project2));
117     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file1, null, null,
118       format("<duplications>\n" +
119         "  <g>\n" +
120         "    <b s=\"148\" l=\"24\" r=\"%s\"/>\n" +
121         "    <b s=\"137\" l=\"24\" r=\"%s\"/>\n" +
122         "    <b s=\"111\" l=\"24\" r=\"%s\"/>\n" +
123         "  </g>\n" +
124         "</duplications>", file1.getKey(), fileOnProject2.getKey(), file2.getKey()));
125     assertThat(blocks).hasSize(1);
126
127     List<Duplication> duplications = blocks.get(0).getDuplications();
128     assertThat(duplications).hasSize(3);
129
130     // Current file's project comes first
131
132     Duplication duplication1 = duplications.get(0);
133     assertThat(duplication1.componentDto()).isEqualTo(file1);
134     assertThat(duplication1.from()).isEqualTo(148);
135     assertThat(duplication1.size()).isEqualTo(24);
136
137     Duplication duplication2 = duplications.get(1);
138     assertThat(duplication2.componentDto()).isEqualTo(file2);
139     assertThat(duplication2.from()).isEqualTo(111);
140     assertThat(duplication2.size()).isEqualTo(24);
141
142     // Other project comes last
143
144     Duplication duplication3 = duplications.get(2);
145     assertThat(duplication3.componentDto()).isEqualTo(fileOnProject2);
146     assertThat(duplication3.from()).isEqualTo(137);
147     assertThat(duplication3.size()).isEqualTo(24);
148   }
149
150   @Test
151   public void duplications_on_many_blocks() {
152     ComponentDto project1 = db.components().insertPrivateProject();
153     ComponentDto file1 = db.components().insertComponent(newFileDto(project1)
154       .setKey("org.codehaus.sonar:sonar-plugin-api:src/main/java/org/sonar/api/utils/command/CommandExecutor.java")
155       .setLongName("CommandExecutor"));
156     ComponentDto project2 = db.components().insertPrivateProject();
157     ComponentDto file2 = db.components().insertComponent(newFileDto(project2)
158       .setKey("com.sonarsource.orchestrator:sonar-orchestrator:src/main/java/com/sonar/orchestrator/util/CommandExecutor.java")
159       .setLongName("CommandExecutor"));
160     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file1, null, null,
161       format("<duplications>\n" +
162         "  <g>\n" +
163         "    <b s=\"94\" l=\"101\" r=\"%s\"/>\n" +
164         "    <b s=\"83\" l=\"101\" r=\"%s\"/>\n" +
165         "  </g>\n" +
166         "  <g>\n" +
167         "    <b s=\"38\" l=\"40\" r=\"%s\"/>\n" +
168         "    <b s=\"29\" l=\"39\" r=\"%s\"/>\n" +
169         "  </g>\n" +
170         "</duplications>\n", file2.getKey(), file1.getKey(), file2.getKey(), file1.getKey()));
171     assertThat(blocks).hasSize(2);
172
173     // Block with smaller line should come first
174
175     assertThat(blocks.get(0).getDuplications().get(0).from()).isEqualTo(29);
176     assertThat(blocks.get(0).getDuplications().get(1).from()).isEqualTo(38);
177
178     assertThat(blocks.get(1).getDuplications().get(0).from()).isEqualTo(83);
179     assertThat(blocks.get(1).getDuplications().get(1).from()).isEqualTo(94);
180   }
181
182   @Test
183   public void duplication_on_not_existing_file() {
184     ComponentDto project = db.components().insertPrivateProject();
185     ComponentDto file = db.components().insertComponent(newFileDto(project));
186     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file, null, null,
187       format("<duplications>\n" +
188         "  <g>\n" +
189         "    <b s=\"20\" l=\"5\" r=\"%s\"/>\n" +
190         "    <b s=\"31\" l=\"5\" r=\"%s\"/>\n" +
191         "  </g>\n" +
192         "</duplications>", file.getKey(), "not_existing"));
193     assertThat(blocks).hasSize(1);
194
195     List<Duplication> duplications = blocks.get(0).getDuplications();
196     assertThat(duplications).hasSize(2);
197
198     // Duplications on removed file
199     Duplication duplication1 = duplication(duplications, null);
200     assertThat(duplication1.componentDto()).isNull();
201     assertThat(duplication1.from()).isEqualTo(31);
202     assertThat(duplication1.size()).isEqualTo(5);
203
204     Duplication duplication2 = duplication(duplications, file.getKey());
205     assertThat(duplication2.componentDto()).isEqualTo(file);
206     assertThat(duplication2.from()).isEqualTo(20);
207     assertThat(duplication2.size()).isEqualTo(5);
208   }
209
210   @Test
211   public void compare_duplications() {
212     ComponentDto project1 = db.components().insertPrivateProject();
213     ComponentDto project2 = db.components().insertPrivateProject();
214     ComponentDto currentFile = db.components().insertComponent(newFileDto(project1, null));
215     ComponentDto fileOnSameProject = db.components().insertComponent(newFileDto(project1, null));
216     ComponentDto fileOnDifferentProject = db.components().insertComponent(newFileDto(project2, null));
217
218     DuplicationsParser.DuplicationComparator comparator = new DuplicationsParser.DuplicationComparator(currentFile.uuid(), currentFile.branchUuid());
219
220     // On same file
221     assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
222       Duplication.newComponent(currentFile, 5, 2))).isEqualTo(-1);
223     // Different files on same project
224     assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
225       Duplication.newComponent(fileOnSameProject, 5, 2))).isEqualTo(-1);
226     assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 2, 2),
227       Duplication.newComponent(currentFile, 5, 2))).isOne();
228     // Different files on different projects
229     assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 5, 2),
230       Duplication.newComponent(fileOnDifferentProject, 2, 2))).isEqualTo(-1);
231     assertThat(comparator.compare(Duplication.newComponent(fileOnDifferentProject, 5, 2),
232       Duplication.newComponent(fileOnSameProject, 2, 2))).isOne();
233     // Files on 2 different projects
234     ComponentDto project3 = db.components().insertPrivateProject();
235     assertThat(comparator.compare(Duplication.newComponent(fileOnDifferentProject, 5, 2),
236       Duplication.newComponent(project3, 2, 2))).isOne();
237
238     // With null duplications
239     assertThat(comparator.compare(null, Duplication.newComponent(fileOnSameProject, 2, 2))).isEqualTo(-1);
240     assertThat(comparator.compare(Duplication.newComponent(fileOnSameProject, 2, 2), null)).isEqualTo(-1);
241     assertThat(comparator.compare(null, null)).isEqualTo(-1);
242
243     // On some removed file
244     assertThat(comparator.compare(Duplication.newComponent(currentFile, 2, 2),
245       Duplication.newRemovedComponent("key1", 5, 2))).isEqualTo(-1);
246     assertThat(comparator.compare(Duplication.newRemovedComponent("key2", 2, 2),
247       Duplication.newComponent(currentFile, 5, 2))).isOne();
248   }
249
250   @Test
251   public void duplication_on_branch() {
252     ComponentDto project = db.components().insertPublicProject();
253     String branchName = randomAlphanumeric(248);
254     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey(branchName));
255     ComponentDto file1 = db.components().insertComponent(newFileDto(branch));
256     ComponentDto file2 = db.components().insertComponent(newFileDto(branch));
257     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file1, branchName, null,
258       format("<duplications>\n" +
259         "  <g>\n" +
260         "    <b s=\"20\" l=\"5\" r=\"%s\"/>\n" +
261         "    <b s=\"31\" l=\"5\" r=\"%s\"/>\n" +
262         "  </g>\n" +
263         "</duplications>", file2.getKey(), file1.getKey()));
264     assertThat(blocks).hasSize(1);
265
266     List<Duplication> duplications = blocks.get(0).getDuplications();
267     assertThat(duplications).hasSize(2);
268
269     // Current file comes first
270     Duplication duplication1 = duplications.get(0);
271     assertThat(duplication1.componentDto()).isEqualTo(file1);
272     assertThat(duplication1.componentDto().getKey()).isEqualTo(file1.getKey());
273     assertThat(duplication1.from()).isEqualTo(31);
274     assertThat(duplication1.size()).isEqualTo(5);
275
276     Duplication duplication2 = duplications.get(1);
277     assertThat(duplication2.componentDto()).isEqualTo(file2);
278     assertThat(duplication2.componentDto().getKey()).isEqualTo(file2.getKey());
279     assertThat(duplication2.from()).isEqualTo(20);
280     assertThat(duplication2.size()).isEqualTo(5);
281   }
282
283   @Test
284   public void duplication_on_pull_request() {
285     ComponentDto project = db.components().insertPublicProject();
286     String pullRequestKey = RandomStringUtils.randomAlphanumeric(100);
287     ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setKey(pullRequestKey));
288     ComponentDto file1 = db.components().insertComponent(newFileDto(pullRequest));
289     ComponentDto file2 = db.components().insertComponent(newFileDto(pullRequest));
290     List<DuplicationsParser.Block> blocks = parser.parse(db.getSession(), file1, null, pullRequestKey,
291       format("<duplications>\n" +
292         "  <g>\n" +
293         "    <b s=\"20\" l=\"5\" r=\"%s\"/>\n" +
294         "    <b s=\"31\" l=\"5\" r=\"%s\"/>\n" +
295         "  </g>\n" +
296         "</duplications>", file2.getKey(), file1.getKey()));
297     assertThat(blocks).hasSize(1);
298
299     List<Duplication> duplications = blocks.get(0).getDuplications();
300     assertThat(duplications).hasSize(2);
301
302     // Current file comes first
303     Duplication duplication1 = duplications.get(0);
304     assertThat(duplication1.componentDto()).isEqualTo(file1);
305     assertThat(duplication1.componentDto().getKey()).isEqualTo(file1.getKey());
306     assertThat(duplication1.from()).isEqualTo(31);
307     assertThat(duplication1.size()).isEqualTo(5);
308
309     Duplication duplication2 = duplications.get(1);
310     assertThat(duplication2.componentDto()).isEqualTo(file2);
311     assertThat(duplication2.componentDto().getKey()).isEqualTo(file2.getKey());
312     assertThat(duplication2.from()).isEqualTo(20);
313     assertThat(duplication2.size()).isEqualTo(5);
314   }
315
316   private static Duplication duplication(List<Duplication> duplications, @Nullable final String componentKey) {
317     return Iterables.find(duplications, input -> input != null && (componentKey == null ? input.componentDto() == null
318       : input.componentDto() != null && componentKey.equals(input.componentDto().getKey())));
319   }
320
321 }