1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.merge;
45
46 import static java.nio.charset.StandardCharsets.UTF_8;
47 import static org.junit.Assert.assertEquals;
48
49 import java.io.ByteArrayOutputStream;
50 import java.io.IOException;
51
52 import org.eclipse.jgit.diff.RawText;
53 import org.eclipse.jgit.diff.RawTextComparator;
54 import org.eclipse.jgit.lib.Constants;
55 import org.junit.Assume;
56 import org.junit.Test;
57 import org.junit.experimental.theories.DataPoints;
58 import org.junit.experimental.theories.Theories;
59 import org.junit.runner.RunWith;
60
61 @RunWith(Theories.class)
62 public class MergeAlgorithmTest {
63 MergeFormatter fmt=new MergeFormatter();
64
65 private final boolean newlineAtEnd;
66
67 @DataPoints
68 public static boolean[] newlineAtEndDataPoints = { false, true };
69
70 public MergeAlgorithmTest(boolean newlineAtEnd) {
71 this.newlineAtEnd = newlineAtEnd;
72 }
73
74
75
76
77
78
79
80 @Test
81 public void testTwoConflictingModifications() throws IOException {
82 assertEquals(t("a<b=Z>Zdefghij"),
83 merge("abcdefghij", "abZdefghij", "aZZdefghij"));
84 }
85
86
87
88
89
90
91
92
93 @Test
94 public void testOneAgainstTwoConflictingModifications() throws IOException {
95 assertEquals(t("aZ<Z=c>Zefghij"),
96 merge("abcdefghij", "aZZZefghij", "aZcZefghij"));
97 }
98
99
100
101
102
103
104
105 @Test
106 public void testNoAgainstOneModification() throws IOException {
107 assertEquals(t("aZcZefghij"),
108 merge("abcdefghij", "abcdefghij", "aZcZefghij"));
109 }
110
111
112
113
114
115
116
117 @Test
118 public void testTwoNonConflictingModifications() throws IOException {
119 assertEquals(t("YbZdefghij"),
120 merge("abcdefghij", "abZdefghij", "Ybcdefghij"));
121 }
122
123
124
125
126
127
128
129 @Test
130 public void testTwoComplicatedModifications() throws IOException {
131 assertEquals(t("a<ZZZZfZhZj=bYdYYYYiY>"),
132 merge("abcdefghij", "aZZZZfZhZj", "abYdYYYYiY"));
133 }
134
135
136
137
138
139
140
141
142 @Test
143 public void testTwoModificationsWithSharedDelete() throws IOException {
144 assertEquals(t("Cb}n}"),
145 merge("ab}n}n}", "ab}n}", "Cb}n}"));
146 }
147
148
149
150
151
152
153
154
155 @Test
156 public void testModificationsWithMiddleInsert() throws IOException {
157 assertEquals(t("aBcd123123uvwxPq"),
158 merge("abcd123uvwxpq", "aBcd123123uvwxPq", "abcd123123uvwxpq"));
159 }
160
161
162
163
164
165
166
167
168 @Test
169 public void testModificationsWithMiddleDelete() throws IOException {
170 assertEquals(t("Abz}z123Q"),
171 merge("abz}z}z123q", "Abz}z123Q", "abz}z123q"));
172 }
173
174
175
176
177
178
179 @Test
180 public void testConflictAtStart() throws IOException {
181 assertEquals(t("<Z=Y>bcdefghij"),
182 merge("abcdefghij", "Zbcdefghij", "Ybcdefghij"));
183 }
184
185
186
187
188
189
190 @Test
191 public void testConflictAtEnd() throws IOException {
192 assertEquals(t("abcdefghi<Z=Y>"),
193 merge("abcdefghij", "abcdefghiZ", "abcdefghiY"));
194 }
195
196
197
198
199
200
201
202 @Test
203 public void testSameModification() throws IOException {
204 assertEquals(t("abZdefghij"),
205 merge("abcdefghij", "abZdefghij", "abZdefghij"));
206 }
207
208
209
210
211
212
213
214 @Test
215 public void testDeleteVsModify() throws IOException {
216 assertEquals(t("ab<=Z>defghij"),
217 merge("abcdefghij", "abdefghij", "abZdefghij"));
218 }
219
220 @Test
221 public void testInsertVsModify() throws IOException {
222 assertEquals(t("a<bZ=XY>"), merge("ab", "abZ", "aXY"));
223 }
224
225 @Test
226 public void testAdjacentModifications() throws IOException {
227 assertEquals(t("a<Zc=bY>d"), merge("abcd", "aZcd", "abYd"));
228 }
229
230 @Test
231 public void testSeparateModifications() throws IOException {
232 assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe"));
233 }
234
235 @Test
236 public void testBlankLines() throws IOException {
237 assertEquals(t("aZc\nYe"), merge("abc\nde", "aZc\nde", "abc\nYe"));
238 }
239
240
241
242
243
244
245
246
247
248 @Test
249 public void testTwoSimilarModsAndOneInsert() throws IOException {
250 assertEquals(t("aBcDde"), merge("abcde", "aBcde", "aBcDde"));
251 assertEquals(t("IAAAJCAB"), merge("iACAB", "IACAB", "IAAAJCAB"));
252 assertEquals(t("HIAAAJCAB"), merge("HiACAB", "HIACAB", "HIAAAJCAB"));
253 assertEquals(t("AGADEFHIAAAJCAB"),
254 merge("AGADEFHiACAB", "AGADEFHIACAB", "AGADEFHIAAAJCAB"));
255 }
256
257
258
259
260
261
262
263
264
265 @Test
266 public void testTwoSimilarModsAndOneInsertAtEnd() throws IOException {
267 Assume.assumeTrue(newlineAtEnd);
268 assertEquals(t("IAAJ"), merge("iA", "IA", "IAAJ"));
269 assertEquals(t("IAJ"), merge("iA", "IA", "IAJ"));
270 assertEquals(t("IAAAJ"), merge("iA", "IA", "IAAAJ"));
271 }
272
273 @Test
274 public void testTwoSimilarModsAndOneInsertAtEndNoNewlineAtEnd()
275 throws IOException {
276 Assume.assumeFalse(newlineAtEnd);
277 assertEquals(t("I<A=AAJ>"), merge("iA", "IA", "IAAJ"));
278 assertEquals(t("I<A=AJ>"), merge("iA", "IA", "IAJ"));
279 assertEquals(t("I<A=AAAJ>"), merge("iA", "IA", "IAAAJ"));
280 }
281
282
283
284
285
286
287 @Test
288 public void testEmptyTexts() throws IOException {
289
290 assertEquals(t("<AB=>"), merge("A", "AB", ""));
291 assertEquals(t("<=AB>"), merge("A", "", "AB"));
292
293
294 assertEquals(t(""), merge("AB", "AB", ""));
295 assertEquals(t(""), merge("AB", "", "AB"));
296
297
298 assertEquals(t(""), merge("AB", "", ""));
299 }
300
301 private String merge(String commonBase, String ours, String theirs) throws IOException {
302 MergeResult r = new MergeAlgorithm().merge(RawTextComparator.DEFAULT,
303 T(commonBase), T(ours), T(theirs));
304 ByteArrayOutputStream bo=new ByteArrayOutputStream(50);
305 fmt.formatMerge(bo, r, "B", "O", "T", UTF_8);
306 return new String(bo.toByteArray(), UTF_8);
307 }
308
309 public String t(String text) {
310 StringBuilder r = new StringBuilder();
311 for (int i = 0; i < text.length(); i++) {
312 char c = text.charAt(i);
313 switch (c) {
314 case '<':
315 r.append("<<<<<<< O\n");
316 break;
317 case '=':
318 r.append("=======\n");
319 break;
320 case '>':
321 r.append(">>>>>>> T\n");
322 break;
323 default:
324 r.append(c);
325 if (newlineAtEnd || i < text.length() - 1)
326 r.append('\n');
327 }
328 }
329 return r.toString();
330 }
331
332 public RawText T(String text) {
333 return new RawText(Constants.encode(t(text)));
334 }
335 }