1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.merge;
12
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertFalse;
15 import static org.junit.Assert.assertTrue;
16
17 import java.io.IOException;
18
19 import org.eclipse.jgit.annotations.Nullable;
20 import org.eclipse.jgit.dircache.DirCache;
21 import org.eclipse.jgit.dircache.DirCacheBuilder;
22 import org.eclipse.jgit.dircache.DirCacheEntry;
23 import org.eclipse.jgit.lib.CommitBuilder;
24 import org.eclipse.jgit.lib.FileMode;
25 import org.eclipse.jgit.lib.ObjectId;
26 import org.eclipse.jgit.lib.ObjectInserter;
27 import org.eclipse.jgit.lib.PersonIdent;
28 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
29 import org.eclipse.jgit.treewalk.TreeWalk;
30 import org.junit.Test;
31
32 public class GitlinkMergeTest extends SampleDataRepositoryTestCase {
33 private static final String LINK_ID1 = "DEADBEEFDEADBEEFBABEDEADBEEFDEADBEEFBABE";
34 private static final String LINK_ID2 = "DEADDEADDEADDEADDEADDEADDEADDEADDEADDEAD";
35 private static final String LINK_ID3 = "BEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF";
36
37 private static final String SUBMODULE_PATH = "submodule.link";
38
39 @Test
40 public void testGitLinkMerging_AddNew() throws Exception {
41 assertGitLinkValue(
42 testGitLink(null, null, LINK_ID3, newResolveMerger(), true),
43 LINK_ID3);
44 }
45
46 @Test
47 public void testGitLinkMerging_Delete() throws Exception {
48 assertGitLinkDoesntExist(testGitLink(LINK_ID1, LINK_ID1, null,
49 newResolveMerger(), true));
50 }
51
52 @Test
53 public void testGitLinkMerging_UpdateDelete() throws Exception {
54 testGitLink(LINK_ID1, LINK_ID2, null, newResolveMerger(), false);
55 }
56
57 @Test
58 public void testGitLinkMerging_DeleteUpdate() throws Exception {
59 testGitLink(LINK_ID1, null, LINK_ID3, newResolveMerger(), false);
60 }
61
62 @Test
63 public void testGitLinkMerging_UpdateUpdate() throws Exception {
64 testGitLink(LINK_ID1, LINK_ID2, LINK_ID3, newResolveMerger(), false);
65 }
66
67 @Test
68 public void testGitLinkMerging_bothAddedSameLink() throws Exception {
69 assertGitLinkValue(
70 testGitLink(null, LINK_ID2, LINK_ID2, newResolveMerger(), true),
71 LINK_ID2);
72 }
73
74 @Test
75 public void testGitLinkMerging_bothAddedDifferentLink() throws Exception {
76 testGitLink(null, LINK_ID2, LINK_ID3, newResolveMerger(), false);
77 }
78
79 @Test
80 public void testGitLinkMerging_AddNew_ignoreConflicts() throws Exception {
81 assertGitLinkValue(
82 testGitLink(null, null, LINK_ID3, newIgnoreConflictMerger(),
83 true),
84 LINK_ID3);
85 }
86
87 @Test
88 public void testGitLinkMerging_Delete_ignoreConflicts() throws Exception {
89 assertGitLinkDoesntExist(testGitLink(LINK_ID1, LINK_ID1, null,
90 newIgnoreConflictMerger(), true));
91 }
92
93 @Test
94 public void testGitLinkMerging_UpdateDelete_ignoreConflicts()
95 throws Exception {
96 assertGitLinkValue(testGitLink(LINK_ID1, LINK_ID2, null,
97 newIgnoreConflictMerger(), true), LINK_ID2);
98 }
99
100 @Test
101 public void testGitLinkMerging_DeleteUpdate_ignoreConflicts()
102 throws Exception {
103 assertGitLinkDoesntExist(testGitLink(LINK_ID1, null, LINK_ID3,
104 newIgnoreConflictMerger(), true));
105 }
106
107 @Test
108 public void testGitLinkMerging_UpdateUpdate_ignoreConflicts()
109 throws Exception {
110 assertGitLinkValue(testGitLink(LINK_ID1, LINK_ID2, LINK_ID3,
111 newIgnoreConflictMerger(), true), LINK_ID2);
112 }
113
114 @Test
115 public void testGitLinkMerging_bothAddedSameLink_ignoreConflicts()
116 throws Exception {
117 assertGitLinkValue(testGitLink(null, LINK_ID2, LINK_ID2,
118 newIgnoreConflictMerger(), true), LINK_ID2);
119 }
120
121 @Test
122 public void testGitLinkMerging_bothAddedDifferentLink_ignoreConflicts()
123 throws Exception {
124 assertGitLinkValue(testGitLink(null, LINK_ID2, LINK_ID3,
125 newIgnoreConflictMerger(), true), LINK_ID2);
126 }
127
128 protected Merger testGitLink(@Nullable String baseLink,
129 @Nullable String oursLink, @Nullable String theirsLink,
130 Merger merger, boolean shouldMerge)
131 throws Exception {
132 DirCache treeB = db.readDirCache();
133 DirCache treeO = db.readDirCache();
134 DirCache treeT = db.readDirCache();
135
136 DirCacheBuilder bTreeBuilder = treeB.builder();
137 DirCacheBuilder oTreeBuilder = treeO.builder();
138 DirCacheBuilder tTreeBuilder = treeT.builder();
139
140 maybeAddLink(bTreeBuilder, baseLink);
141 maybeAddLink(oTreeBuilder, oursLink);
142 maybeAddLink(tTreeBuilder, theirsLink);
143
144 bTreeBuilder.finish();
145 oTreeBuilder.finish();
146 tTreeBuilder.finish();
147
148 ObjectInserter ow = db.newObjectInserter();
149 ObjectId b = commit(ow, treeB, new ObjectId[] {});
150 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
151 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
152
153 boolean merge = merger.merge(new ObjectId[] { o, t });
154 assertEquals(Boolean.valueOf(shouldMerge), Boolean.valueOf(merge));
155
156 return merger;
157 }
158
159 private Merger newResolveMerger() {
160 return MergeStrategy.RESOLVE.newMerger(db, true);
161 }
162
163 private Merger newIgnoreConflictMerger() {
164 return new ResolveMerger(db, true) {
165 @Override
166 protected boolean mergeImpl() throws IOException {
167
168 return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
169 true);
170 }
171 };
172 }
173
174 @Test
175 public void testGitLinkMerging_blobWithLink() throws Exception {
176 DirCache treeB = db.readDirCache();
177 DirCache treeO = db.readDirCache();
178 DirCache treeT = db.readDirCache();
179
180 DirCacheBuilder bTreeBuilder = treeB.builder();
181 DirCacheBuilder oTreeBuilder = treeO.builder();
182 DirCacheBuilder tTreeBuilder = treeT.builder();
183
184 bTreeBuilder.add(
185 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob"));
186 oTreeBuilder.add(
187 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
188
189 maybeAddLink(tTreeBuilder, LINK_ID3);
190
191 bTreeBuilder.finish();
192 oTreeBuilder.finish();
193 tTreeBuilder.finish();
194
195 ObjectInserter ow = db.newObjectInserter();
196 ObjectId b = commit(ow, treeB, new ObjectId[] {});
197 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
198 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
199
200 Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
201 boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
202 assertFalse(merge);
203 }
204
205 @Test
206 public void testGitLinkMerging_linkWithBlob() throws Exception {
207 DirCache treeB = db.readDirCache();
208 DirCache treeO = db.readDirCache();
209 DirCache treeT = db.readDirCache();
210
211 DirCacheBuilder bTreeBuilder = treeB.builder();
212 DirCacheBuilder oTreeBuilder = treeO.builder();
213 DirCacheBuilder tTreeBuilder = treeT.builder();
214
215 maybeAddLink(bTreeBuilder, LINK_ID1);
216 maybeAddLink(oTreeBuilder, LINK_ID2);
217 tTreeBuilder.add(
218 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 3"));
219
220 bTreeBuilder.finish();
221 oTreeBuilder.finish();
222 tTreeBuilder.finish();
223
224 ObjectInserter ow = db.newObjectInserter();
225 ObjectId b = commit(ow, treeB, new ObjectId[] {});
226 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
227 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
228
229 Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
230 boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
231 assertFalse(merge);
232 }
233
234 @Test
235 public void testGitLinkMerging_linkWithLink() throws Exception {
236 DirCache treeB = db.readDirCache();
237 DirCache treeO = db.readDirCache();
238 DirCache treeT = db.readDirCache();
239
240 DirCacheBuilder bTreeBuilder = treeB.builder();
241 DirCacheBuilder oTreeBuilder = treeO.builder();
242 DirCacheBuilder tTreeBuilder = treeT.builder();
243
244 bTreeBuilder.add(
245 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob"));
246 maybeAddLink(oTreeBuilder, LINK_ID2);
247 maybeAddLink(tTreeBuilder, LINK_ID3);
248
249 bTreeBuilder.finish();
250 oTreeBuilder.finish();
251 tTreeBuilder.finish();
252
253 ObjectInserter ow = db.newObjectInserter();
254 ObjectId b = commit(ow, treeB, new ObjectId[] {});
255 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
256 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
257
258 Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
259 boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
260 assertFalse(merge);
261 }
262
263 @Test
264 public void testGitLinkMerging_blobWithBlobFromLink() throws Exception {
265 DirCache treeB = db.readDirCache();
266 DirCache treeO = db.readDirCache();
267 DirCache treeT = db.readDirCache();
268
269 DirCacheBuilder bTreeBuilder = treeB.builder();
270 DirCacheBuilder oTreeBuilder = treeO.builder();
271 DirCacheBuilder tTreeBuilder = treeT.builder();
272
273 maybeAddLink(bTreeBuilder, LINK_ID1);
274 oTreeBuilder.add(
275 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
276 tTreeBuilder.add(
277 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 3"));
278
279 bTreeBuilder.finish();
280 oTreeBuilder.finish();
281 tTreeBuilder.finish();
282
283 ObjectInserter ow = db.newObjectInserter();
284 ObjectId b = commit(ow, treeB, new ObjectId[] {});
285 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
286 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
287
288 Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
289 boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
290 assertFalse(merge);
291 }
292
293 @Test
294 public void testGitLinkMerging_linkBlobDeleted() throws Exception {
295
296 DirCache treeB = db.readDirCache();
297 DirCache treeO = db.readDirCache();
298 DirCache treeT = db.readDirCache();
299
300 DirCacheBuilder bTreeBuilder = treeB.builder();
301 DirCacheBuilder oTreeBuilder = treeO.builder();
302 DirCacheBuilder tTreeBuilder = treeT.builder();
303
304 maybeAddLink(bTreeBuilder, LINK_ID1);
305 oTreeBuilder.add(
306 createEntry(SUBMODULE_PATH, FileMode.REGULAR_FILE, "blob 2"));
307
308 bTreeBuilder.finish();
309 oTreeBuilder.finish();
310 tTreeBuilder.finish();
311
312 ObjectInserter ow = db.newObjectInserter();
313 ObjectId b = commit(ow, treeB, new ObjectId[] {});
314 ObjectId o = commit(ow, treeO, new ObjectId[] { b });
315 ObjectId t = commit(ow, treeT, new ObjectId[] { b });
316
317 Merger resolveMerger = MergeStrategy.RESOLVE.newMerger(db);
318 boolean merge = resolveMerger.merge(new ObjectId[] { o, t });
319 assertFalse(merge);
320 }
321
322 private void maybeAddLink(DirCacheBuilder builder,
323 @Nullable String linkId) {
324 if (linkId == null) {
325 return;
326 }
327 DirCacheEntry newLink = createGitLink(SUBMODULE_PATH,
328 ObjectId.fromString(linkId));
329 builder.add(newLink);
330 }
331
332 private void assertGitLinkValue(Merger resolveMerger, String expectedValue)
333 throws Exception {
334 try (TreeWalk tw = new TreeWalk(db)) {
335 tw.setRecursive(true);
336 tw.reset(resolveMerger.getResultTreeId());
337
338 assertTrue(tw.next());
339 assertEquals(SUBMODULE_PATH, tw.getPathString());
340 assertEquals(ObjectId.fromString(expectedValue), tw.getObjectId(0));
341
342 assertFalse(tw.next());
343 }
344 }
345
346 private void assertGitLinkDoesntExist(Merger resolveMerger)
347 throws Exception {
348 try (TreeWalk tw = new TreeWalk(db)) {
349 tw.setRecursive(true);
350 tw.reset(resolveMerger.getResultTreeId());
351
352 assertFalse(tw.next());
353 }
354 }
355
356 private static ObjectId commit(ObjectInserter odi, DirCache treeB,
357 ObjectId[] parentIds) throws Exception {
358 CommitBuilder c = new CommitBuilder();
359 c.setTreeId(treeB.writeTree(odi));
360 c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
361 c.setCommitter(c.getAuthor());
362 c.setParentIds(parentIds);
363 c.setMessage("Tree " + c.getTreeId().name());
364 ObjectId id = odi.insert(c);
365 odi.flush();
366 return id;
367 }
368 }