blob: 142be4aa6831c8a4bea495ab573d1dc6c9bf8360 [file] [log] [blame]
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +01001// Copyright (C) 2017 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.gerrit.server.fixes;
16
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010017import static com.google.gerrit.server.edit.tree.TreeModificationSubject.assertThatList;
dborowitz20c7d692019-05-02 08:53:58 -070018import static com.google.gerrit.testing.GerritJUnit.assertThrows;
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010019import static org.easymock.EasyMock.createMock;
20import static org.easymock.EasyMock.replay;
21
22import com.google.common.collect.ImmutableList;
23import com.google.gerrit.extensions.restapi.BinaryResult;
24import com.google.gerrit.extensions.restapi.ResourceConflictException;
25import com.google.gerrit.reviewdb.client.Comment.Range;
26import com.google.gerrit.reviewdb.client.FixReplacement;
27import com.google.gerrit.server.change.FileContentUtil;
28import com.google.gerrit.server.edit.tree.TreeModification;
29import com.google.gerrit.server.project.ProjectState;
Dave Borowitz14e1ad52018-11-19 12:33:56 -080030import com.google.gerrit.testing.GerritBaseTests;
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010031import java.util.ArrayList;
32import java.util.Comparator;
33import java.util.List;
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010034import org.easymock.EasyMock;
35import org.eclipse.jgit.lib.ObjectId;
36import org.eclipse.jgit.lib.Repository;
37import org.junit.Before;
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010038import org.junit.Test;
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010039
Dave Borowitz14e1ad52018-11-19 12:33:56 -080040public class FixReplacementInterpreterTest extends GerritBaseTests {
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010041 private final FileContentUtil fileContentUtil = createMock(FileContentUtil.class);
42 private final Repository repository = createMock(Repository.class);
43 private final ProjectState projectState = createMock(ProjectState.class);
44 private final ObjectId patchSetCommitId = createMock(ObjectId.class);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010045 private final String filePath1 = "an/arbitrary/file.txt";
46 private final String filePath2 = "another/arbitrary/file.txt";
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010047
48 private FixReplacementInterpreter fixReplacementInterpreter;
49
50 @Before
51 public void setUp() {
52 fixReplacementInterpreter = new FixReplacementInterpreter(fileContentUtil);
53 }
54
55 @Test
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010056 public void noReplacementsResultInNoTreeModifications() throws Exception {
57 List<TreeModification> treeModifications = toTreeModifications();
58 assertThatList(treeModifications).isEmpty();
59 }
60
61 @Test
62 public void treeModificationsTargetCorrectFiles() throws Exception {
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010063 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010064 new FixReplacement(filePath1, new Range(1, 6, 3, 2), "Modified content");
65 FixReplacement fixReplacement2 =
66 new FixReplacement(filePath1, new Range(3, 5, 3, 5), "Second modification");
67 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
68 FixReplacement fixReplacement3 =
69 new FixReplacement(filePath2, new Range(2, 0, 3, 0), "Another modified content");
70 mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010071
72 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +010073 List<TreeModification> treeModifications =
74 toTreeModifications(fixReplacement, fixReplacement3, fixReplacement2);
75 List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
76 assertThatList(sortedTreeModifications)
77 .element(0)
78 .asChangeFileContentModification()
79 .filePath()
80 .isEqualTo(filePath1);
81 assertThatList(sortedTreeModifications)
82 .element(0)
83 .asChangeFileContentModification()
84 .newContent()
85 .startsWith("First");
86 assertThatList(sortedTreeModifications)
87 .element(1)
88 .asChangeFileContentModification()
89 .filePath()
90 .isEqualTo(filePath2);
91 assertThatList(sortedTreeModifications)
92 .element(1)
93 .asChangeFileContentModification()
94 .newContent()
95 .startsWith("1st");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +010096 }
97
98 @Test
99 public void replacementsCanDeleteALine() throws Exception {
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100100 FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 0, 3, 0), "");
101 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100102
103 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100104 List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
105 assertThatList(treeModifications)
106 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100107 .asChangeFileContentModification()
108 .newContent()
109 .isEqualTo("First line\nThird line\n");
110 }
111
112 @Test
113 public void replacementsCanAddALine() throws Exception {
114 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100115 new FixReplacement(filePath1, new Range(2, 0, 2, 0), "A new line\n");
116 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100117
118 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100119 List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
120 assertThatList(treeModifications)
121 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100122 .asChangeFileContentModification()
123 .newContent()
124 .isEqualTo("First line\nA new line\nSecond line\nThird line\n");
125 }
126
127 @Test
128 public void replacementsMaySpanMultipleLines() throws Exception {
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100129 FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(1, 6, 3, 1), "and t");
130 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100131
132 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100133 List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
134 assertThatList(treeModifications)
135 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100136 .asChangeFileContentModification()
137 .newContent()
138 .isEqualTo("First and third line\n");
139 }
140
141 @Test
142 public void replacementsMayOccurOnSameLine() throws Exception {
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100143 FixReplacement fixReplacement1 = new FixReplacement(filePath1, new Range(2, 0, 2, 6), "A");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100144 FixReplacement fixReplacement2 =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100145 new FixReplacement(filePath1, new Range(2, 7, 2, 11), "modification");
146 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100147
148 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100149 List<TreeModification> treeModifications =
150 toTreeModifications(fixReplacement1, fixReplacement2);
151 assertThatList(treeModifications)
152 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100153 .asChangeFileContentModification()
154 .newContent()
155 .isEqualTo("First line\nA modification\nThird line\n");
156 }
157
158 @Test
159 public void replacementsMayTouch() throws Exception {
160 FixReplacement fixReplacement1 =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100161 new FixReplacement(filePath1, new Range(1, 6, 2, 7), "modified ");
162 FixReplacement fixReplacement2 =
163 new FixReplacement(filePath1, new Range(2, 7, 3, 5), "content");
164 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100165
166 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100167 List<TreeModification> treeModifications =
168 toTreeModifications(fixReplacement1, fixReplacement2);
169 assertThatList(treeModifications)
170 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100171 .asChangeFileContentModification()
172 .newContent()
173 .isEqualTo("First modified content line\n");
174 }
175
176 @Test
177 public void replacementsCanAddContentAtEndOfFile() throws Exception {
178 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100179 new FixReplacement(filePath1, new Range(4, 0, 4, 0), "New content");
180 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100181
182 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100183 List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
184 assertThatList(treeModifications)
185 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100186 .asChangeFileContentModification()
187 .newContent()
188 .isEqualTo("First line\nSecond line\nThird line\nNew content");
189 }
190
191 @Test
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100192 public void replacementsCanModifySeveralFilesInAnyOrder() throws Exception {
193 FixReplacement fixReplacement1 =
194 new FixReplacement(filePath1, new Range(1, 1, 3, 2), "Modified content");
195 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
196 FixReplacement fixReplacement2 =
197 new FixReplacement(filePath2, new Range(2, 0, 3, 0), "First modification\n");
198 FixReplacement fixReplacement3 =
199 new FixReplacement(filePath2, new Range(3, 0, 4, 0), "Second modification\n");
200 mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100201
202 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100203 List<TreeModification> treeModifications =
204 toTreeModifications(fixReplacement3, fixReplacement1, fixReplacement2);
205 List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
206 assertThatList(sortedTreeModifications)
207 .element(0)
208 .asChangeFileContentModification()
209 .newContent()
210 .isEqualTo("FModified contentird line\n");
211 assertThatList(sortedTreeModifications)
212 .element(1)
213 .asChangeFileContentModification()
214 .newContent()
215 .isEqualTo("1st line\nFirst modification\nSecond modification\n");
216 }
217
218 @Test
219 public void lineSeparatorCanBeChanged() throws Exception {
220 FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 11, 3, 0), "\r");
221 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
222
223 replay(fileContentUtil);
224 List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
225 assertThatList(treeModifications)
226 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100227 .asChangeFileContentModification()
228 .newContent()
229 .isEqualTo("First line\nSecond line\rThird line\n");
230 }
231
232 @Test
233 public void replacementsDoNotNeedToBeOrderedAccordingToRange() throws Exception {
234 FixReplacement fixReplacement1 =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100235 new FixReplacement(filePath1, new Range(1, 0, 2, 0), "1st modification\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100236 FixReplacement fixReplacement2 =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100237 new FixReplacement(filePath1, new Range(3, 0, 4, 0), "2nd modification\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100238 FixReplacement fixReplacement3 =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100239 new FixReplacement(filePath1, new Range(4, 0, 5, 0), "3rd modification\n");
240 mockFileContent(filePath1, "First line\nSecond line\nThird line\nFourth line\nFifth line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100241
242 replay(fileContentUtil);
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100243 List<TreeModification> treeModifications =
244 toTreeModifications(fixReplacement2, fixReplacement1, fixReplacement3);
245 assertThatList(treeModifications)
246 .onlyElement()
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100247 .asChangeFileContentModification()
248 .newContent()
249 .isEqualTo(
250 "1st modification\nSecond line\n2nd modification\n3rd modification\nFifth line\n");
251 }
252
253 @Test
254 public void replacementsMustNotReferToNotExistingLine() throws Exception {
255 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100256 new FixReplacement(filePath1, new Range(5, 0, 5, 0), "A new line\n");
257 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100258
259 replay(fileContentUtil);
dborowitz20c7d692019-05-02 08:53:58 -0700260 assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100261 }
262
263 @Test
264 public void replacementsMustNotReferToZeroLine() throws Exception {
265 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100266 new FixReplacement(filePath1, new Range(0, 0, 0, 0), "A new line\n");
267 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100268
269 replay(fileContentUtil);
270
dborowitz20c7d692019-05-02 08:53:58 -0700271 assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100272 }
273
274 @Test
275 public void replacementsMustNotReferToNotExistingOffsetOfIntermediateLine() throws Exception {
276 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100277 new FixReplacement(filePath1, new Range(1, 0, 1, 11), "modified");
278 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100279
280 replay(fileContentUtil);
dborowitz20c7d692019-05-02 08:53:58 -0700281 assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100282 }
283
284 @Test
285 public void replacementsMustNotReferToNotExistingOffsetOfLastLine() throws Exception {
286 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100287 new FixReplacement(filePath1, new Range(3, 0, 3, 11), "modified");
288 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100289
290 replay(fileContentUtil);
291
dborowitz20c7d692019-05-02 08:53:58 -0700292 assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100293 }
294
295 @Test
296 public void replacementsMustNotReferToNegativeOffset() throws Exception {
297 FixReplacement fixReplacement =
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100298 new FixReplacement(filePath1, new Range(1, -1, 1, 5), "modified");
299 mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100300
301 replay(fileContentUtil);
dborowitz20c7d692019-05-02 08:53:58 -0700302 assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100303 }
304
305 private void mockFileContent(String filePath, String fileContent) throws Exception {
306 EasyMock.expect(
307 fileContentUtil.getContent(repository, projectState, patchSetCommitId, filePath))
308 .andReturn(BinaryResult.create(fileContent));
309 }
310
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100311 private List<TreeModification> toTreeModifications(FixReplacement... fixReplacements)
312 throws Exception {
313 return fixReplacementInterpreter.toTreeModifications(
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100314 repository, projectState, patchSetCommitId, ImmutableList.copyOf(fixReplacements));
315 }
Alice Kober-Sotzek791f4af2017-03-16 18:02:15 +0100316
317 private static List<TreeModification> getSortedCopy(List<TreeModification> treeModifications) {
318 List<TreeModification> sortedTreeModifications = new ArrayList<>(treeModifications);
319 sortedTreeModifications.sort(Comparator.comparing(TreeModification::getFilePath));
320 return sortedTreeModifications;
321 }
Alice Kober-Sotzek30d6c7d2017-03-09 13:51:02 +0100322}