Fix synchronize with deleted resources
[egit/eclipse.git] / org.eclipse.egit.core.test / src / org / eclipse / egit / core / synchronize / GitSubscriberResourceMappingContextTest.java
blob6e090f2b0d2f92770c013d679a5e0d8b132ced8b
1 /*******************************************************************************
2 * Copyright (C) 2013, Laurent Goubet <laurent.goubet@obeo.fr> and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *******************************************************************************/
8 package org.eclipse.egit.core.synchronize;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertTrue;
14 import java.io.ByteArrayInputStream;
15 import java.io.File;
16 import java.io.UnsupportedEncodingException;
18 import org.eclipse.core.resources.IContainer;
19 import org.eclipse.core.resources.IFile;
20 import org.eclipse.core.resources.IFolder;
21 import org.eclipse.core.resources.IProject;
22 import org.eclipse.core.resources.IResource;
23 import org.eclipse.core.resources.mapping.RemoteResourceMappingContext;
24 import org.eclipse.core.resources.mapping.ResourceTraversal;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.NullProgressMonitor;
27 import org.eclipse.egit.core.project.RepositoryMapping;
28 import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
29 import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
30 import org.eclipse.egit.core.test.GitTestCase;
31 import org.eclipse.egit.core.test.TestRepository;
32 import org.eclipse.jgit.api.Git;
33 import org.eclipse.jgit.junit.JGitTestUtil;
34 import org.eclipse.jgit.lib.Constants;
35 import org.eclipse.jgit.lib.Repository;
36 import org.eclipse.jgit.revwalk.RevCommit;
37 import org.junit.Before;
38 import org.junit.Test;
40 public class GitSubscriberResourceMappingContextTest extends GitTestCase {
42 private static final String MASTER = Constants.R_HEADS + Constants.MASTER;
44 private static final String BRANCH = Constants.R_HEADS + "branch";
46 private Repository repo;
48 private IProject iProject;
50 private TestRepository testRepo;
52 @Override
53 @Before
54 public void setUp() throws Exception {
55 super.setUp();
57 iProject = project.project;
58 testRepo = new TestRepository(gitDir);
59 testRepo.connect(iProject);
60 repo = RepositoryMapping.getMapping(iProject).getRepository();
62 // make initial commit
63 try (Git git = new Git(repo)) {
64 git.commit().setAuthor("JUnit", "junit@jgit.org")
65 .setMessage("Initial commit").call();
69 @Test
70 public void hasLocalChange() throws Exception {
71 File file1 = testRepo.createFile(iProject, "a.txt");
72 File file2 = testRepo.createFile(iProject, "b.txt");
73 testRepo.appendContentAndCommit(iProject, file1, "content a",
74 "commit a");
75 testRepo.appendContentAndCommit(iProject, file2, "content b",
76 "commit b");
78 IFile iFile1 = testRepo.getIFile(iProject, file1);
79 IFile iFile2 = testRepo.getIFile(iProject, file2);
81 RemoteResourceMappingContext context = prepareContext(MASTER, MASTER);
82 assertFalse(context.hasLocalChange(iFile1, new NullProgressMonitor()));
83 assertFalse(context.hasLocalChange(iFile2, new NullProgressMonitor()));
85 JGitTestUtil.write(file1, "changed content a");
86 JGitTestUtil.write(file2, "changed content b");
88 refresh(context, iFile1, iFile2);
89 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
90 assertTrue(context.hasLocalChange(iFile2, new NullProgressMonitor()));
92 JGitTestUtil.write(file2, "content b");
94 refresh(context, iFile2);
95 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
96 assertFalse(context.hasLocalChange(iFile2, new NullProgressMonitor()));
99 @Test
100 public void hasLocalChangeWithFileRemoval() throws Exception {
101 File file1 = testRepo.createFile(iProject, "a.txt");
102 File file2 = testRepo.createFile(iProject, "b.txt");
103 File file3 = testRepo.createFile(iProject, "c.txt");
105 IFile iFile1 = testRepo.getIFile(iProject, file1);
106 IFile iFile2 = testRepo.getIFile(iProject, file2);
107 IFile iFile3 = testRepo.getIFile(iProject, file3);
109 RemoteResourceMappingContext context = prepareContext(MASTER, MASTER);
110 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
111 assertTrue(context.hasLocalChange(iFile2, new NullProgressMonitor()));
112 assertTrue(context.hasLocalChange(iFile3, new NullProgressMonitor()));
114 iFile1.delete(false, null);
115 refresh(context, iFile1, iFile2, iFile3);
116 assertTrue(context.hasLocalChange(iFile2, new NullProgressMonitor()));
117 assertTrue(context.hasLocalChange(iFile3, new NullProgressMonitor()));
120 @Test
121 public void hasLocalChangeInNewFolder() throws Exception {
122 iProject.getFolder("folder").create(false, true, null);
123 RemoteResourceMappingContext context = prepareContext(MASTER, MASTER);
124 // Folder is now known, but not yet file in it
126 File file = testRepo.createFile(iProject, "folder/b.txt");
127 IFile iFile = testRepo.getIFile(iProject, file);
128 refresh(context, iFile);
129 assertTrue(context.hasLocalChange(iFile, new NullProgressMonitor()));
131 testRepo.addToIndex(iProject, file);
132 refresh(context, iFile);
133 assertTrue(context.hasLocalChange(iFile, new NullProgressMonitor()));
135 JGitTestUtil.write(file, "changed content b");
136 refresh(context, iFile);
137 assertTrue(context.hasLocalChange(iFile, new NullProgressMonitor()));
140 @Test
141 public void hasRemoteChanges() throws Exception {
142 File file1 = testRepo.createFile(iProject, "file1.sample");
143 File file2 = testRepo.createFile(iProject, "file2.sample");
145 testRepo.appendContentAndCommit(iProject, file1,
146 "initial content - file 1",
147 "first file - initial commit MASTER");
148 testRepo.appendContentAndCommit(iProject, file2,
149 "initial content - file 2",
150 "second file - initial commit MASTER");
152 IFile iFile1 = testRepo.getIFile(iProject, file1);
153 IFile iFile2 = testRepo.getIFile(iProject, file2);
155 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
157 setContentsAndCommit(iFile1, "change in branch - file 1",
158 "branch commit - file1");
159 setContentsAndCommit(iFile2, "change in branch - file 2",
160 "branch commit - file2");
162 testRepo.checkoutBranch(MASTER);
164 RemoteResourceMappingContext context = prepareContext(MASTER, BRANCH);
165 assertFalse(context.hasLocalChange(iFile1, new NullProgressMonitor()));
166 assertTrue(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
167 assertFalse(context.hasLocalChange(iFile2, new NullProgressMonitor()));
168 assertTrue(context.hasRemoteChange(iFile2, new NullProgressMonitor()));
170 setContents(iFile1, "change in master - file 1");
171 refresh(context, iFile1);
172 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
173 assertTrue(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
175 setContents(iFile2, "change in branch - file 2");
176 refresh(context, iFile2);
177 assertTrue(context.hasLocalChange(iFile2, new NullProgressMonitor()));
178 assertTrue(context.hasRemoteChange(iFile2, new NullProgressMonitor()));
180 setContentsAndCommit(iFile1, "change in branch - file 1",
181 "change in master (same as in branch) - file 2");
182 refresh(context, iFile1);
183 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
184 assertTrue(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
187 @Test
188 public void hasRemoteChangeInNewFile() throws Exception {
189 File file1 = testRepo.createFile(iProject, "file1.sample");
190 String initialContent1 = "some content for the first file";
191 testRepo.appendContentAndCommit(iProject, file1, initialContent1,
192 "first file - initial commit");
193 IFile iFile1 = testRepo.getIFile(iProject, file1);
195 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
197 File file2 = testRepo.createFile(iProject, "file2.sample");
198 String initialContent2 = "some content for the second file";
199 testRepo.appendContentAndCommit(iProject, file2, initialContent2,
200 "second file - initial commit");
201 IFile iFile2 = testRepo.getIFile(iProject, file2);
203 testRepo.checkoutBranch(MASTER);
205 RemoteResourceMappingContext context = prepareContext(MASTER, BRANCH);
206 assertFalse(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
207 assertTrue(context.hasRemoteChange(iFile2, new NullProgressMonitor()));
210 @Test
211 public void hasRemoteChangeInNewFolder() throws Exception {
212 File file1 = testRepo.createFile(iProject, "file1.sample");
213 String initialContent1 = "some content for the first file";
214 testRepo.appendContentAndCommit(iProject, file1, initialContent1,
215 "first file - initial commit");
216 IFile iFile1 = testRepo.getIFile(iProject, file1);
218 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
220 iProject.getFolder("folder").create(true, true,
221 new NullProgressMonitor());
222 File file2 = testRepo.createFile(iProject, "folder/file2.sample");
223 String initialContent2 = "some content for the second file";
224 testRepo.appendContentAndCommit(iProject, file2, initialContent2,
225 "second file - initial commit");
226 IFile iFile2 = testRepo.getIFile(iProject, file2);
228 testRepo.checkoutBranch(MASTER);
230 RemoteResourceMappingContext context = prepareContext(MASTER, BRANCH);
231 assertFalse(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
232 assertTrue(context.hasRemoteChange(iFile2, new NullProgressMonitor()));
235 @Test
236 public void hasLocalAndRemoteChange() throws Exception {
237 File file1 = testRepo.createFile(iProject, "file1.sample");
238 testRepo.appendContentAndCommit(iProject, file1, "initial content",
239 "first commit in master");
240 IFile iFile1 = testRepo.getIFile(iProject, file1);
242 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
243 setContentsAndCommit(iFile1, "changed content in branch",
244 "first commit in BRANCH");
246 testRepo.checkoutBranch(MASTER);
247 setContentsAndCommit(iFile1, "changed content in master",
248 "second commit in MASTER");
250 RemoteResourceMappingContext context = prepareContext(MASTER, BRANCH);
251 assertTrue(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
252 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
255 @Test
256 public void hasLocalAndRemoteChangeInSubFolder() throws Exception {
257 File file1 = testRepo.createFile(iProject, "folder/file1.sample");
258 testRepo.appendContentAndCommit(iProject, file1, "initial content",
259 "first commit in master");
260 IFile iFile1 = testRepo.getIFile(iProject, file1);
262 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
263 setContentsAndCommit(iFile1, "changed content in branch",
264 "first commit in BRANCH");
266 testRepo.checkoutBranch(MASTER);
267 setContentsAndCommit(iFile1, "changed content in master",
268 "second commit in MASTER");
270 RemoteResourceMappingContext context = prepareContext(MASTER, BRANCH);
271 assertTrue(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
272 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
275 @Test
276 public void hasLocalChangeWhenRefreshingParentFolder() throws Exception {
277 IFolder folder = iProject.getFolder("newfolder");
278 folder.create(false, true, null);
280 IFile file = folder.getFile("a.txt");
281 file.create(new ByteArrayInputStream("a".getBytes("UTF-8")), false,
282 null);
284 RemoteResourceMappingContext context = prepareContext(MASTER, MASTER);
285 refresh(context, file);
287 assertTrue(context.hasLocalChange(file, new NullProgressMonitor()));
289 file.delete(false, null);
291 // Refresh of folder, not file directly
292 refresh(context, folder);
294 assertFalse(context.hasLocalChange(file, new NullProgressMonitor()));
297 @Test
298 public void hasDeletion() throws Exception {
299 File file1 = testRepo.createFile(iProject, "file1.sample");
300 testRepo.appendContentAndCommit(iProject, file1, "initial content",
301 "first commit in master");
303 IFile iFile1 = testRepo.getIFile(iProject, file1);
305 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
306 iFile1.delete(true, new NullProgressMonitor());
307 try (Git git = new Git(testRepo.getRepository())) {
308 git.add()
309 .addFilepattern(iProject.getName() + '/' + iFile1.getName())
310 .setUpdate(true)
311 .call();
313 testRepo.commit("Deleted file1.sample");
315 RemoteResourceMappingContext context = prepareContext(BRANCH, MASTER);
316 boolean hasFile1 = false;
317 for (IResource member : context.fetchMembers(iProject,
318 new NullProgressMonitor())) {
319 if (iFile1.getName().equals(member.getName())) {
320 hasFile1 = true;
321 break;
324 assertTrue(hasFile1);
325 assertFalse(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
326 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
329 @Test
330 public void hasNestedDeletion() throws Exception {
331 File file1 = testRepo.createFile(iProject,
332 "sub/subfolder/file1.sample");
333 testRepo.appendContentAndCommit(iProject, file1, "initial content",
334 "first commit in master");
336 IFile iFile1 = testRepo.getIFile(iProject, file1);
338 assertTrue(iFile1.exists());
340 IContainer subfolder = iFile1.getParent();
342 assertTrue(subfolder instanceof IFolder);
343 assertEquals("subfolder", subfolder.getName());
345 IContainer sub = subfolder.getParent();
347 assertTrue(sub instanceof IFolder);
348 assertEquals("sub", sub.getName());
350 testRepo.createAndCheckoutBranch(MASTER, BRANCH);
351 iFile1.delete(true, new NullProgressMonitor());
352 subfolder.delete(true, new NullProgressMonitor());
353 sub.delete(true, new NullProgressMonitor());
354 try (Git git = new Git(testRepo.getRepository())) {
355 git.add()
356 .addFilepattern(
357 iProject.getName() + "/sub/subfolder/file1.sample")
358 .setUpdate(true).call();
360 testRepo.commit("Deleted sub/subfolder/file1.sample");
362 assertFalse(iFile1.exists());
363 assertFalse(subfolder.exists());
364 assertFalse(sub.exists());
366 RemoteResourceMappingContext context = prepareContext(BRANCH, MASTER);
367 boolean hasFile1 = false;
368 for (IResource member : context.fetchMembers(iProject,
369 new NullProgressMonitor())) {
370 if (sub.getName().equals(member.getName())) {
371 for (IResource child : context.fetchMembers(sub,
372 new NullProgressMonitor())) {
373 if (subfolder.getName().equals(child.getName())) {
374 for (IResource grandchild : context.fetchMembers(
375 subfolder, new NullProgressMonitor())) {
376 if (iFile1.getName().equals(grandchild.getName())) {
377 hasFile1 = true;
378 break;
381 break;
384 break;
387 assertTrue(hasFile1);
388 assertFalse(context.hasRemoteChange(iFile1, new NullProgressMonitor()));
389 assertTrue(context.hasLocalChange(iFile1, new NullProgressMonitor()));
390 assertTrue(
391 context.hasLocalChange(subfolder, new NullProgressMonitor()));
392 assertTrue(context.hasLocalChange(sub, new NullProgressMonitor()));
395 private RevCommit setContentsAndCommit(IFile targetFile,
396 String newContents, String commitMessage)
397 throws Exception {
398 setContents(targetFile, newContents);
399 return addAndCommit(targetFile, commitMessage);
402 private RevCommit addAndCommit(IFile targetFile, String commitMessage) throws Exception {
403 testRepo.addToIndex(targetFile);
404 return testRepo.commit(commitMessage);
407 private void setContents(IFile targetFile, String newContents)
408 throws CoreException, UnsupportedEncodingException {
409 targetFile.setContents(
410 new ByteArrayInputStream(newContents.getBytes("UTF-8")),
411 IResource.FORCE, new NullProgressMonitor());
414 private RemoteResourceMappingContext prepareContext(String srcRev,
415 String dstRev) throws Exception {
416 GitSynchronizeData gsd = new GitSynchronizeData(repo, srcRev, dstRev,
417 true);
418 GitSynchronizeDataSet gsds = new GitSynchronizeDataSet(gsd);
419 GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber(
420 gsds);
421 subscriber.init(new NullProgressMonitor());
423 return new GitSubscriberResourceMappingContext(subscriber, gsds);
426 private void refresh(RemoteResourceMappingContext context,
427 IResource... resources) throws Exception {
428 context.refresh(new ResourceTraversal[] { new ResourceTraversal(
429 resources, IResource.DEPTH_INFINITE, 0) }, 0,
430 new NullProgressMonitor());