diff options
author | Laurent Delaigue | 2014-02-28 09:36:45 +0000 |
---|---|---|
committer | Laurent Delaigue | 2015-05-04 13:44:00 +0000 |
commit | 274817ca5ed97a4ce20255ceb8b0056809063f5c (patch) | |
tree | d7121d1e0a940a3e5b114b849e6d69055f31e8ff /org.eclipse.egit.core.test | |
parent | 767f77b7c86a9e03834957bf9848f9e9fabc5732 (diff) | |
download | egit-274817ca5ed97a4ce20255ceb8b0056809063f5c.tar.gz egit-274817ca5ed97a4ce20255ceb8b0056809063f5c.tar.xz egit-274817ca5ed97a4ce20255ceb8b0056809063f5c.zip |
Introduce internal API to integrate Team merging.
Team provides a number of APIs to provide access to merge,
comparison and synchronization features. This introduces a
git-specific Subscriber implementation that can retrieve
information from three different sources, along with
implementations to use the index or a TreeWalk to populate
these three 'sources'.
CQ: 9453
Bug: 418151
JGit-Dependency: I722352e619794988791c452545d57b17dada407a
Change-Id: Ieda23bb556d342f421f03b93c7faa160998598aa
Also-by: Laurent Goubet <laurent.goubet@obeo.fr>
Signed-off-by: Axel Richard <axel.richard@obeo.fr>
Signed-off-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.egit.core.test')
5 files changed, 1051 insertions, 0 deletions
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/DirCacheResourceVariantTreeProviderTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/DirCacheResourceVariantTreeProviderTest.java new file mode 100644 index 0000000000..37929acd17 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/DirCacheResourceVariantTreeProviderTest.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (C) 2015 Obeo and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.core.internal.merge; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.egit.core.op.MergeOperation; +import org.junit.Test; + +public class DirCacheResourceVariantTreeProviderTest extends VariantsTestCase { + @Test + public void testDirCacheAddToIndex() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + testRepo.appendFileContent(file1, INITIAL_CONTENT_1); + + // untracked file : not part of the index + DirCacheResourceVariantTreeProvider treeProvider = new DirCacheResourceVariantTreeProvider( + repo); + assertTrue(treeProvider.getKnownResources().isEmpty()); + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getSourceTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getRemoteTree().hasResourceVariant(iFile1)); + + testRepo.addToIndex(iFile1); + + // We now have a stage 0, but this isn't represented in the resource + // variant tree provider + treeProvider = new DirCacheResourceVariantTreeProvider(repo); + assertTrue(treeProvider.getKnownResources().isEmpty()); + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getSourceTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getRemoteTree().hasResourceVariant(iFile1)); + } + + @Test + public void testDirCacheTreesNoConflict() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2, + "second file - initial commit"); + + IFile iFile1 = testRepo.getIFile(iProject, file1); + IFile iFile2 = testRepo.getIFile(iProject, file2); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + final String branchChanges = "branch changes\n"; + setContentsAndCommit(testRepo, iFile2, branchChanges + + INITIAL_CONTENT_2, "branch commit"); + + testRepo.checkoutBranch(MASTER); + + final String masterChanges = "\nsome changes"; + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + masterChanges, "master commit"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + // end setup + + // try and merge the branch into master + new MergeOperation(repo, BRANCH).execute(null); + + // no conflict on either file : nothing in the trees + DirCacheResourceVariantTreeProvider treeProvider = new DirCacheResourceVariantTreeProvider( + repo); + assertTrue(treeProvider.getKnownResources().isEmpty()); + + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile2)); + + assertFalse(treeProvider.getSourceTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getSourceTree().hasResourceVariant(iFile2)); + + assertFalse(treeProvider.getRemoteTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getRemoteTree().hasResourceVariant(iFile2)); + } + + @Test + public void testDirCacheTreesConflictOnOne() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2, + "second file - initial commit"); + + IFile iFile1 = testRepo.getIFile(iProject, file1); + IFile iFile2 = testRepo.getIFile(iProject, file2); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + final String branchChanges = "branch changes\n"; + setContentsAndCommit(testRepo, iFile1, branchChanges + + INITIAL_CONTENT_1, "branch commit"); + setContentsAndCommit(testRepo, iFile2, branchChanges + + INITIAL_CONTENT_2, "branch commit"); + + testRepo.checkoutBranch(MASTER); + + final String masterChanges = "\nsome changes"; + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + masterChanges, "master commit"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + // end setup + + // try and merge the branch into master + new MergeOperation(repo, BRANCH).execute(null); + + // conflict on file 1 : present in all three trees + // no conflict on file 2 : not present in any tree + DirCacheResourceVariantTreeProvider treeProvider = new DirCacheResourceVariantTreeProvider( + repo); + assertTrue(treeProvider.getKnownResources().contains(iFile1)); + assertFalse(treeProvider.getKnownResources().contains(iFile2)); + + assertTrue(treeProvider.getBaseTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile2)); + + assertTrue(treeProvider.getSourceTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getSourceTree().hasResourceVariant(iFile2)); + + assertTrue(treeProvider.getRemoteTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getRemoteTree().hasResourceVariant(iFile2)); + } + + @Test + public void testDirCacheTreesConflict() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + + IFile iFile1 = testRepo.getIFile(iProject, file1); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + final String branchChanges = "branch changes\n"; + setContentsAndCommit(testRepo, iFile1, branchChanges + + INITIAL_CONTENT_1, "branch commit"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2 + + "branch", "second file - initial commit - branch"); + + testRepo.checkoutBranch(MASTER); + + final String masterChanges = "some changes\n"; + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + masterChanges, "master commit - file1"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2 + + "master", "second file - initial commit - master"); + IFile iFile2 = testRepo.getIFile(iProject, file2); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + // end setup + + // try and merge the branch into master + new MergeOperation(repo, BRANCH).execute(null); + + // conflict on file 1 : file 1 has three stages. + // conflict on file 2, but was not in the base : only stage 2 and 3 + DirCacheResourceVariantTreeProvider treeProvider = new DirCacheResourceVariantTreeProvider( + repo); + assertTrue(treeProvider.getKnownResources().contains(iFile1)); + assertTrue(treeProvider.getKnownResources().contains(iFile2)); + + assertTrue(treeProvider.getBaseTree().hasResourceVariant(iFile1)); + assertFalse(treeProvider.getBaseTree().hasResourceVariant(iFile2)); + + assertTrue(treeProvider.getSourceTree().hasResourceVariant(iFile1)); + assertTrue(treeProvider.getSourceTree().hasResourceVariant(iFile2)); + + assertTrue(treeProvider.getRemoteTree().hasResourceVariant(iFile1)); + assertTrue(treeProvider.getRemoteTree().hasResourceVariant(iFile2)); + } +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/GitResourceVariantTreeSubscriberTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/GitResourceVariantTreeSubscriberTest.java new file mode 100644 index 0000000000..11046f2985 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/GitResourceVariantTreeSubscriberTest.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * Copyright (C) 2015 Obeo and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.core.internal.merge; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.NameConflictTreeWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.team.core.diff.IDiff; +import org.eclipse.team.core.diff.IThreeWayDiff; +import org.eclipse.team.core.history.IFileRevision; +import org.eclipse.team.core.mapping.provider.ResourceDiff; +import org.eclipse.team.core.synchronize.SyncInfo; +import org.eclipse.team.core.variants.IResourceVariant; +import org.junit.Before; +import org.junit.Test; + +public class GitResourceVariantTreeSubscriberTest extends VariantsTestCase { + private static final String BRANCH_CHANGES = "branch changes\n"; + + private static final String MASTER_CHANGES = "\nsome changes"; + + private static final String BASE = "base"; + + private File file1; + + private File file2; + + private IFile iFile1; + + private IFile iFile2; + + @Before + public void setUp() throws Exception { + super.setUp(); + + file1 = testRepo.createFile(iProject, "file1"); + file2 = testRepo.createFile(iProject, "file2"); + + iFile1 = testRepo.getIFile(iProject, file1); + iFile2 = testRepo.getIFile(iProject, file2); + } + + @Test + public void testSubscriber() throws Exception { + GitResourceVariantTreeProvider provider = createTreeProvider(); + GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( + provider); + + assertTrue(subscriber.isSupervised(iProject)); + assertTrue(subscriber.isSupervised(iFile1)); + assertTrue(subscriber.isSupervised(iFile2)); + + assertSame(provider.getBaseTree(), subscriber.getBaseTree()); + assertSame(provider.getRemoteTree(), subscriber.getRemoteTree()); + assertSame(provider.getSourceTree(), subscriber.getSourceTree()); + + assertNotNull(subscriber.getDiff(iProject)); + assertNotNull(subscriber.getDiff(iFile1)); + assertNotNull(subscriber.getDiff(iFile2)); + + assertNotNull(subscriber.getSyncInfo(iProject)); + assertNotNull(subscriber.getSyncInfo(iFile1)); + assertNotNull(subscriber.getSyncInfo(iFile2)); + + } + + @Test + public void testSyncInfo() throws Exception { + GitResourceVariantTreeProvider provider = createTreeProvider(); + GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( + provider); + + final SyncInfo projectInfo = subscriber.getSyncInfo(iProject); + assertNotNull(projectInfo); + assertEquals(SyncInfo.CONFLICTING | SyncInfo.CHANGE, + projectInfo.getKind()); + + final SyncInfo syncInfo1 = subscriber.getSyncInfo(iFile1); + assertNotNull(syncInfo1); + assertEquals(SyncInfo.OUTGOING | SyncInfo.CHANGE, syncInfo1.getKind()); + IResourceVariant baseVariant1 = syncInfo1.getBase(); + IResourceVariant remoteVariant1 = syncInfo1.getRemote(); + assertContentEquals(baseVariant1, INITIAL_CONTENT_1); + assertContentEquals(remoteVariant1, INITIAL_CONTENT_1); + + final SyncInfo syncInfo2 = subscriber.getSyncInfo(iFile2); + assertNotNull(syncInfo2); + assertEquals(SyncInfo.INCOMING | SyncInfo.CHANGE, syncInfo2.getKind()); + IResourceVariant baseVariant2 = syncInfo2.getBase(); + IResourceVariant remoteVariant2 = syncInfo2.getRemote(); + assertContentEquals(baseVariant2, INITIAL_CONTENT_2); + assertContentEquals(remoteVariant2, BRANCH_CHANGES + INITIAL_CONTENT_2); + } + + @Test + public void testDiff() throws Exception { + GitResourceVariantTreeProvider provider = createTreeProvider(); + GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( + provider); + + final IDiff diff1 = subscriber.getDiff(iFile1); + assertTrue(diff1 instanceof IThreeWayDiff); + assertEquals(IDiff.CHANGE, diff1.getKind()); + assertEquals(IThreeWayDiff.OUTGOING, + ((IThreeWayDiff) diff1).getDirection()); + final IDiff localDiff1 = ((IThreeWayDiff) diff1).getLocalChange(); + final IDiff remoteDiff1 = ((IThreeWayDiff) diff1).getRemoteChange(); + assertNull(remoteDiff1); + assertTrue(localDiff1 instanceof ResourceDiff); + final IFileRevision localState1 = ((ResourceDiff) localDiff1) + .getAfterState(); + final IFileRevision baseState1 = ((ResourceDiff) localDiff1) + .getBeforeState(); + assertNotNull(localState1); + assertNotNull(baseState1); + assertTrue(iFile1.getName().equals(localState1.getName())); + assertTrue(iFile1.getName().equals(baseState1.getName())); + final IStorage localStorage1 = localState1 + .getStorage(new NullProgressMonitor()); + final IStorage baseStorage1 = baseState1 + .getStorage(new NullProgressMonitor()); + assertContentEquals(localStorage1, INITIAL_CONTENT_1 + MASTER_CHANGES); + assertContentEquals(baseStorage1, INITIAL_CONTENT_1); + + final IDiff diff2 = subscriber.getDiff(iFile2); + assertTrue(diff2 instanceof IThreeWayDiff); + assertEquals(IDiff.CHANGE, diff2.getKind()); + assertEquals(IThreeWayDiff.INCOMING, + ((IThreeWayDiff) diff2).getDirection()); + final IDiff localDiff2 = ((IThreeWayDiff) diff2).getLocalChange(); + final IDiff remoteDiff2 = ((IThreeWayDiff) diff2).getRemoteChange(); + assertTrue(remoteDiff2 instanceof ResourceDiff); + assertNull(localDiff2); + final IFileRevision remoteState2 = ((ResourceDiff) remoteDiff2) + .getAfterState(); + final IFileRevision ancestorState2 = ((ResourceDiff) remoteDiff2) + .getBeforeState(); + assertTrue(iFile2.getName().equals(ancestorState2.getName())); + assertTrue(iFile2.getName().equals(remoteState2.getName())); + final IStorage ancestorStorage2 = ancestorState2 + .getStorage(new NullProgressMonitor()); + final IStorage remoteStorage2 = remoteState2 + .getStorage(new NullProgressMonitor()); + assertContentEquals(ancestorStorage2, INITIAL_CONTENT_2); + assertContentEquals(remoteStorage2, BRANCH_CHANGES + INITIAL_CONTENT_2); + } + + @Test + public void testAddLocalAndRemote() throws Exception { + GitResourceVariantTreeProvider provider = createTreeProviderWithAdditions(); + GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( + provider); + + final IDiff diff1 = subscriber.getDiff(iFile1); + assertTrue(diff1 instanceof IThreeWayDiff); + assertEquals(IDiff.ADD, diff1.getKind()); + assertEquals(IThreeWayDiff.OUTGOING, + ((IThreeWayDiff) diff1).getDirection()); + final IDiff localDiff1 = ((IThreeWayDiff) diff1).getLocalChange(); + final IDiff remoteDiff1 = ((IThreeWayDiff) diff1).getRemoteChange(); + assertTrue(localDiff1 instanceof ResourceDiff); + assertNull(remoteDiff1); + final IFileRevision ancestorState1 = ((ResourceDiff) localDiff1) + .getBeforeState(); + final IFileRevision localState1 = ((ResourceDiff) localDiff1) + .getAfterState(); + assertTrue(iFile1.getName().equals(localState1.getName())); + assertNull(ancestorState1); + final IStorage localStorage1 = localState1 + .getStorage(new NullProgressMonitor()); + assertContentEquals(localStorage1, INITIAL_CONTENT_1); + + final IDiff diff2 = subscriber.getDiff(iFile2); + assertTrue(diff2 instanceof IThreeWayDiff); + assertEquals(IDiff.ADD, diff2.getKind()); + assertEquals(IThreeWayDiff.INCOMING, + ((IThreeWayDiff) diff2).getDirection()); + final IDiff localDiff2 = ((IThreeWayDiff) diff2).getLocalChange(); + final IDiff remoteDiff2 = ((IThreeWayDiff) diff2).getRemoteChange(); + assertTrue(remoteDiff2 instanceof ResourceDiff); + assertNull(localDiff2); + final IFileRevision ancestorState2 = ((ResourceDiff) remoteDiff2) + .getBeforeState(); + final IFileRevision remoteState2 = ((ResourceDiff) remoteDiff2) + .getAfterState(); + assertNull(ancestorState2); + assertTrue(iFile2.getName().equals(remoteState2.getName())); + final IStorage remoteStorage2 = remoteState2 + .getStorage(new NullProgressMonitor()); + assertContentEquals(remoteStorage2, INITIAL_CONTENT_2); + } + + @Test + public void testRemoveLocalAndRemote() throws Exception { + GitResourceVariantTreeProvider provider = createTreeProviderWithDeletions(); + GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( + provider); + + // file1 has been removed locally + final IDiff diff1 = subscriber.getDiff(iFile1); + assertTrue(diff1 instanceof IThreeWayDiff); + assertEquals(IDiff.REMOVE, diff1.getKind()); + assertEquals(IThreeWayDiff.OUTGOING, + ((IThreeWayDiff) diff1).getDirection()); + final IDiff localDiff1 = ((IThreeWayDiff) diff1).getLocalChange(); + final IDiff remoteDiff1 = ((IThreeWayDiff) diff1).getRemoteChange(); + assertTrue(localDiff1 instanceof ResourceDiff); + assertNull(remoteDiff1); + final IFileRevision ancestorState1 = ((ResourceDiff) localDiff1) + .getBeforeState(); + final IFileRevision localState1 = ((ResourceDiff) localDiff1) + .getAfterState(); + assertTrue(iFile1.getName().equals(ancestorState1.getName())); + assertNull(localState1); + final IStorage ancestorStorage1 = ancestorState1 + .getStorage(new NullProgressMonitor()); + assertContentEquals(ancestorStorage1, INITIAL_CONTENT_1); + + // file2 has been removed remotely + final IDiff diff2 = subscriber.getDiff(iFile2); + assertTrue(diff2 instanceof IThreeWayDiff); + assertEquals(IDiff.REMOVE, diff2.getKind()); + assertEquals(IThreeWayDiff.INCOMING, + ((IThreeWayDiff) diff2).getDirection()); + final IDiff localDiff2 = ((IThreeWayDiff) diff2).getLocalChange(); + final IDiff remoteDiff2 = ((IThreeWayDiff) diff2).getRemoteChange(); + assertTrue(remoteDiff2 instanceof ResourceDiff); + assertNull(localDiff2); + final IFileRevision ancestorState2 = ((ResourceDiff) remoteDiff2) + .getBeforeState(); + final IFileRevision remoteState2 = ((ResourceDiff) remoteDiff2) + .getAfterState(); + assertTrue(iFile2.getName().equals(ancestorState2.getName())); + assertNull(remoteState2); + final IStorage rancestorStorage2 = ancestorState2 + .getStorage(new NullProgressMonitor()); + assertContentEquals(rancestorStorage2, INITIAL_CONTENT_2); + } + + private GitResourceVariantTreeProvider createTreeProvider() + throws Exception { + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + testRepo.appendContentAndCommit(iProject, file2, + INITIAL_CONTENT_2, "second file - initial commit"); + testRepo.createBranch(MASTER, BASE); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + setContentsAndCommit(testRepo, iFile2, BRANCH_CHANGES + + INITIAL_CONTENT_2, "branch commit"); + + testRepo.checkoutBranch(MASTER); + + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + MASTER_CHANGES, "master commit"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + + // as if we tried to merge branch into master + try (RevWalk walk = new RevWalk(repo)) { + RevTree baseTree = walk.parseTree(repo.resolve(BASE)); + RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); + RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); + TreeWalk treeWalk = new NameConflictTreeWalk(repo); + treeWalk.addTree(baseTree); + treeWalk.addTree(sourceTree); + treeWalk.addTree(remoteTree); + return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, + 1, 2); + } + } + + private GitResourceVariantTreeProvider createTreeProviderWithAdditions() + throws Exception { + testRepo.createBranch(MASTER, BASE); + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + file2 = testRepo.createFile(iProject, "file2"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2, + "Creation of file2 in branch2."); + + testRepo.checkoutBranch(MASTER); + file1 = testRepo.createFile(iProject, "file1"); + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "Creation of file1 in branch1."); + + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + + // as if we tried to merge branch3 into branch2 + try (RevWalk walk = new RevWalk(repo)) { + RevTree baseTree = walk.parseTree(repo.resolve(BASE)); + RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); + RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); + TreeWalk treeWalk = new NameConflictTreeWalk(repo); + treeWalk.addTree(baseTree); + treeWalk.addTree(sourceTree); + treeWalk.addTree(remoteTree); + return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, + 1, 2); + } + } + + private GitResourceVariantTreeProvider createTreeProviderWithDeletions() + throws Exception { + file1 = testRepo.createFile(iProject, "file1"); + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "Creation of file1 in branch1."); + file2 = testRepo.createFile(iProject, "file2"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2, + "Creation of file2 in branch2."); + testRepo.createBranch(MASTER, BASE); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + testRepo.untrack(file2); + testRepo.commit("Removed file2 in branch."); + + testRepo.checkoutBranch(MASTER); + testRepo.untrack(file1); + testRepo.commit("Removed file1 in master."); + + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + + // as if we tried to merge branch3 into branch2 + try (RevWalk walk = new RevWalk(repo)) { + RevTree baseTree = walk.parseTree(repo.resolve(BASE)); + RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); + RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); + TreeWalk treeWalk = new NameConflictTreeWalk(repo); + treeWalk.addTree(baseTree); + treeWalk.addTree(sourceTree); + treeWalk.addTree(remoteTree); + return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, + 1, 2); + } + } +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/ResourceVariantTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/ResourceVariantTest.java new file mode 100644 index 0000000000..ede07fa3d3 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/ResourceVariantTest.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * Copyright (C) 2015 Obeo and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.core.internal.merge; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.egit.core.internal.storage.AbstractGitResourceVariant; +import org.eclipse.egit.core.internal.storage.IndexResourceVariant; +import org.eclipse.egit.core.internal.storage.TreeParserResourceVariant; +import org.eclipse.egit.core.op.MergeOperation; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.junit.Test; + +public class ResourceVariantTest extends VariantsTestCase { + private final static String BASE_BRANCH = "base"; + + private final static String BRANCH_CHANGE = "branch changes\n"; + + private final static String MASTER_CHANGE = "master changes\n"; + + @Test + public void testIndexVariants() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + IFile iFile2 = testRepo.getIFile(iProject, file2); + + setupUnconflictingBranches(); + + List<String> possibleNames = Arrays.asList(iFile1.getName(), + iFile2.getName()); + DirCache cache = repo.readDirCache(); + for (int i = 0; i < cache.getEntryCount(); i++) { + final DirCacheEntry entry = cache.getEntry(i); + + AbstractGitResourceVariant variant = IndexResourceVariant.create( + repo, entry); + + assertEquals(entry.getObjectId().getName(), + variant.getContentIdentifier()); + assertTrue(possibleNames.contains(variant.getName())); + assertEquals(entry.getObjectId(), variant.getObjectId()); + assertEquals(entry.getRawMode(), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + assertContentEquals(variant, INITIAL_CONTENT_1 + MASTER_CHANGE); + } else { + assertContentEquals(variant, INITIAL_CONTENT_2 + MASTER_CHANGE); + } + } + + testRepo.checkoutBranch(BRANCH); + + cache = repo.readDirCache(); + for (int i = 0; i < cache.getEntryCount(); i++) { + final DirCacheEntry entry = cache.getEntry(i); + + AbstractGitResourceVariant variant = IndexResourceVariant.create( + repo, entry); + assertEquals(entry.getObjectId().getName(), + variant.getContentIdentifier()); + assertTrue(possibleNames.contains(variant.getName())); + assertEquals(entry.getObjectId(), variant.getObjectId()); + assertEquals(entry.getRawMode(), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + assertContentEquals(variant, BRANCH_CHANGE + INITIAL_CONTENT_1); + } else { + assertContentEquals(variant, BRANCH_CHANGE + INITIAL_CONTENT_2); + } + } + } + + @Test + public void testIndexVariantsConflict() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + setupConflictingBranches(); + // end setup + + // create a conflict to force multiple stages + new MergeOperation(repo, BRANCH).execute(null); + + DirCache cache = repo.readDirCache(); + // 3 stages for file 1, 2 stages for file 2 + assertEquals(5, cache.getEntryCount()); + for (int i = 0; i < cache.getEntryCount(); i++) { + final DirCacheEntry entry = cache.getEntry(i); + + AbstractGitResourceVariant variant = IndexResourceVariant.create( + repo, entry); + assertEquals(entry.getObjectId().getName(), + variant.getContentIdentifier()); + assertEquals(entry.getObjectId(), variant.getObjectId()); + assertEquals(entry.getRawMode(), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + switch (entry.getStage()) { + case DirCacheEntry.STAGE_1: + assertContentEquals(variant, INITIAL_CONTENT_1); + break; + case DirCacheEntry.STAGE_2: + assertContentEquals(variant, INITIAL_CONTENT_1 + + MASTER_CHANGE); + break; + case DirCacheEntry.STAGE_3: + assertContentEquals(variant, BRANCH_CHANGE + + INITIAL_CONTENT_1); + break; + case DirCacheEntry.STAGE_0: + default: + fail("Unexpected entry stage " + entry.getStage() + + " in the index for file " + entry.getPathString()); + break; + } + } else { + switch (entry.getStage()) { + case DirCacheEntry.STAGE_2: + assertContentEquals(variant, INITIAL_CONTENT_2 + + MASTER_CHANGE); + break; + case DirCacheEntry.STAGE_3: + assertContentEquals(variant, BRANCH_CHANGE + + INITIAL_CONTENT_2); + break; + case DirCacheEntry.STAGE_0: + case DirCacheEntry.STAGE_1: + default: + fail("Unexpected entry stage " + entry.getStage() + + " in the index for file " + entry.getPathString()); + break; + } + } + } + } + + @Test + public void testTreeWalkBranchVariants() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + setupUnconflictingBranches(); + + ObjectId baseId = repo.resolve(BRANCH); + RevWalk walk = new RevWalk(repo); + TreeWalk tw = new TreeWalk(repo); + tw.addTree(walk.parseTree(baseId)); + + while (tw.next()) { + AbstractGitResourceVariant variant = TreeParserResourceVariant + .create(repo, tw.getTree(0, CanonicalTreeParser.class)); + + assertEquals(tw.getObjectId(0).getName(), + variant.getContentIdentifier()); + assertEquals(tw.getObjectId(0), variant.getObjectId()); + assertEquals(tw.getRawMode(0), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + assertContentEquals(variant, BRANCH_CHANGE + INITIAL_CONTENT_1); + } else if (!tw.isSubtree()) { + assertContentEquals(variant, BRANCH_CHANGE + INITIAL_CONTENT_2); + } + + if (tw.isSubtree()) { + tw.enterSubtree(); + } + } + } + + @Test + public void testTreeWalkMasterVariants() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + setupUnconflictingBranches(); + + ObjectId baseId = repo.resolve(MASTER); + RevWalk walk = new RevWalk(repo); + TreeWalk tw = new TreeWalk(repo); + tw.addTree(walk.parseTree(baseId)); + + while (tw.next()) { + AbstractGitResourceVariant variant = TreeParserResourceVariant + .create(repo, tw.getTree(0, CanonicalTreeParser.class)); + + assertEquals(tw.getObjectId(0).getName(), + variant.getContentIdentifier()); + assertEquals(tw.getObjectId(0), variant.getObjectId()); + assertEquals(tw.getRawMode(0), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + assertContentEquals(variant, INITIAL_CONTENT_1 + MASTER_CHANGE); + } else if (!tw.isSubtree()) { + assertContentEquals(variant, INITIAL_CONTENT_2 + MASTER_CHANGE); + } + + if (tw.isSubtree()) { + tw.enterSubtree(); + } + } + } + + @Test + public void testTreeWalkBaseVariants() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + setupUnconflictingBranches(); + + ObjectId baseId = repo.resolve(BASE_BRANCH); + RevWalk walk = new RevWalk(repo); + TreeWalk tw = new TreeWalk(repo); + tw.addTree(walk.parseTree(baseId)); + + while (tw.next()) { + AbstractGitResourceVariant variant = TreeParserResourceVariant + .create(repo, tw.getTree(0, CanonicalTreeParser.class)); + + assertEquals(tw.getObjectId(0).getName(), + variant.getContentIdentifier()); + assertEquals(tw.getObjectId(0), variant.getObjectId()); + assertEquals(tw.getRawMode(0), variant.getRawMode()); + if (iFile1.getName().equals(variant.getName())) { + assertContentEquals(variant, INITIAL_CONTENT_1); + } else if (!tw.isSubtree()) { + fail("file2 shouldn't exist in our base."); + } + + if (tw.isSubtree()) { + tw.enterSubtree(); + } + } + } + + private void setupUnconflictingBranches() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + + testRepo.createBranch(MASTER, BASE_BRANCH); + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + setContentsAndCommit(testRepo, iFile1, BRANCH_CHANGE + + INITIAL_CONTENT_1, "branch commit"); + testRepo.appendContentAndCommit(iProject, file2, BRANCH_CHANGE + + INITIAL_CONTENT_2, "second file - initial commit - branch"); + + testRepo.checkoutBranch(MASTER); + + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + MASTER_CHANGE, "master commit - file1"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2 + + MASTER_CHANGE, "second file - initial commit - master"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + } + + private void setupConflictingBranches() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + IFile iFile1 = testRepo.getIFile(iProject, file1); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + setContentsAndCommit(testRepo, iFile1, BRANCH_CHANGE + + INITIAL_CONTENT_1, "branch commit"); + testRepo.appendContentAndCommit(iProject, file2, BRANCH_CHANGE + + INITIAL_CONTENT_2, "second file - initial commit - branch"); + + testRepo.checkoutBranch(MASTER); + + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + MASTER_CHANGE, "master commit - file1"); + testRepo.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_2 + + MASTER_CHANGE, "second file - initial commit - master"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + } +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/TreeWalkResourceVariantTreeProviderTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/TreeWalkResourceVariantTreeProviderTest.java new file mode 100644 index 0000000000..d1508c728a --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/TreeWalkResourceVariantTreeProviderTest.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (C) 2015 Obeo and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.core.internal.merge; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.NameConflictTreeWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.team.core.variants.IResourceVariant; +import org.junit.Test; + +public class TreeWalkResourceVariantTreeProviderTest extends VariantsTestCase { + @Test + public void testTreeWalkTrees() throws Exception { + File file1 = testRepo.createFile(iProject, "file1"); + File file2 = testRepo.createFile(iProject, "file2"); + + testRepo.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_1, + "first file - initial commit"); + RevCommit baseCommit = testRepo.appendContentAndCommit(iProject, file2, + INITIAL_CONTENT_2, "second file - initial commit"); + + IFile iFile1 = testRepo.getIFile(iProject, file1); + IFile iFile2 = testRepo.getIFile(iProject, file2); + + testRepo.createAndCheckoutBranch(MASTER, BRANCH); + + final String branchChanges = "branch changes\n"; + setContentsAndCommit(testRepo, iFile2, branchChanges + + INITIAL_CONTENT_2, "branch commit"); + + testRepo.checkoutBranch(MASTER); + + final String masterChanges = "\nsome changes"; + setContentsAndCommit(testRepo, iFile1, INITIAL_CONTENT_1 + + masterChanges, "master commit"); + iProject.refreshLocal(IResource.DEPTH_INFINITE, + new NullProgressMonitor()); + // end setup + + // as if we tried to merge branch into master + try (RevWalk walk = new RevWalk(repo)) { + RevTree baseTree = walk.parseTree(baseCommit.getId()); + RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); + RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); + TreeWalk treeWalk = new NameConflictTreeWalk(repo); + treeWalk.addTree(baseTree); + treeWalk.addTree(sourceTree); + treeWalk.addTree(remoteTree); + TreeWalkResourceVariantTreeProvider treeProvider = new TreeWalkResourceVariantTreeProvider( + repo, treeWalk, 0, 1, 2); + + assertEquals(1, treeProvider.getRoots().size()); + assertTrue(treeProvider.getRoots().contains(iProject)); + + assertTrue(treeProvider.getKnownResources().contains(iFile1)); + assertTrue(treeProvider.getKnownResources().contains(iFile2)); + + IResourceVariant file1BaseVariant = treeProvider.getBaseTree() + .getResourceVariant(iFile1); + IResourceVariant file2BaseVariant = treeProvider.getBaseTree() + .getResourceVariant(iFile2); + assertContentEquals(file1BaseVariant, INITIAL_CONTENT_1); + assertContentEquals(file2BaseVariant, INITIAL_CONTENT_2); + + IResourceVariant file1TheirsVariant = treeProvider.getRemoteTree() + .getResourceVariant(iFile1); + IResourceVariant file2TheirsVariant = treeProvider.getRemoteTree() + .getResourceVariant(iFile2); + assertContentEquals(file1TheirsVariant, INITIAL_CONTENT_1); + assertContentEquals(file2TheirsVariant, branchChanges + + INITIAL_CONTENT_2); + + IResourceVariant file1OursVariant = treeProvider.getSourceTree() + .getResourceVariant(iFile1); + IResourceVariant file2OursVariant = treeProvider.getSourceTree() + .getResourceVariant(iFile2); + assertContentEquals(file1OursVariant, INITIAL_CONTENT_1 + + masterChanges); + assertContentEquals(file2OursVariant, INITIAL_CONTENT_2); + } + } +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/VariantsTestCase.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/VariantsTestCase.java new file mode 100644 index 0000000000..2e2a9e7cb8 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/merge/VariantsTestCase.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (C) 2015 Obeo and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.egit.core.internal.merge; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.util.Scanner; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.egit.core.project.RepositoryMapping; +import org.eclipse.egit.core.test.GitTestCase; +import org.eclipse.egit.core.test.TestRepository; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.team.core.variants.IResourceVariant; +import org.junit.After; +import org.junit.Before; + +public abstract class VariantsTestCase extends GitTestCase { + protected final String INITIAL_CONTENT_1 = "some content for the first file"; + + protected final String INITIAL_CONTENT_2 = "some content for the second file"; + + protected static final String MASTER = Constants.R_HEADS + Constants.MASTER; + + protected static final String BRANCH = Constants.R_HEADS + "branch"; + + protected Repository repo; + + protected IProject iProject; + + protected TestRepository testRepo; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + iProject = project.project; + testRepo = new TestRepository(gitDir); + testRepo.connect(iProject); + repo = RepositoryMapping.getMapping(iProject).getRepository(); + + // make initial commit + try (Git git = new Git(repo)) { + git.commit().setAuthor("JUnit", "junit@jgit.org") + .setMessage("Initial commit").call(); + } + } + + @After + @Override + public void tearDown() throws Exception { + testRepo.disconnect(iProject); + testRepo.dispose(); + repo = null; + + super.tearDown(); + } + + protected RevCommit setContentsAndCommit(TestRepository testRepository, + IFile targetFile, String newContents, String commitMessage) + throws Exception { + targetFile.setContents( + new ByteArrayInputStream(newContents.getBytes()), + IResource.FORCE, new NullProgressMonitor()); + testRepository.addToIndex(targetFile); + return testRepository.commit(commitMessage); + } + + protected void assertContentEquals(IResourceVariant variant, + String expectedContents) throws Exception { + assertContentEquals(variant.getStorage(new NullProgressMonitor()), + expectedContents); + } + + protected void assertContentEquals(IStorage storage, String expectedContents) + throws Exception { + try (Scanner scanner = new Scanner(storage.getContents())) { + scanner.useDelimiter("\\A"); + String fileContent = ""; + if (scanner.hasNext()) { + fileContent = scanner.next(); + } + assertEquals(expectedContents, fileContent); + } + } +} |