diff options
13 files changed, 2249 insertions, 12 deletions
diff --git a/org.eclipse.egit.core.test/META-INF/MANIFEST.MF b/org.eclipse.egit.core.test/META-INF/MANIFEST.MF index e3ee59b6d5..9dd88e3c1f 100644 --- a/org.eclipse.egit.core.test/META-INF/MANIFEST.MF +++ b/org.eclipse.egit.core.test/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", org.eclipse.jdt.launching;bundle-version="[3.4.0,4.0.0)", org.junit4;bundle-version="[4.3.0,5.0.0)" Bundle-ActivationPolicy: lazy -Import-Package: org.eclipse.egit.core;version="[0.9.0,0.10.0)", +Import-Package: org.easymock;version="[2.4.0,3.0.0)", + org.eclipse.egit.core;version="[0.9.0,0.10.0)", org.eclipse.egit.core.op;version="[0.9.0,0.10.0)", org.eclipse.egit.core.project;version="[0.9.0,0.10.0)", org.eclipse.jgit.junit;version="[0.9.0,0.10.0)", diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantComparatorTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantComparatorTest.java new file mode 100644 index 0000000000..2628e2f58e --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantComparatorTest.java @@ -0,0 +1,672 @@ +/******************************************************************************* + * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * + * 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.synchronize; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.io.ByteArrayInputStream; +import java.util.Arrays; + +import org.eclipse.core.resources.IContainer; +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.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.egit.core.op.ConnectProviderOperation; +import org.eclipse.egit.core.project.RepositoryMapping; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; +import org.eclipse.egit.core.test.GitTestCase; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.team.core.variants.IResourceVariant; +import org.junit.Before; +import org.junit.Test; + +public class GitResourceVariantComparatorTest extends GitTestCase { + + private Repository repo; + + @Before + public void setUp() throws Exception { + super.setUp(); + + IProject iProject = project.project; + if (!gitDir.exists()) + new Repository(gitDir).create(); + + new ConnectProviderOperation(iProject, gitDir).execute(null); + repo = RepositoryMapping.getMapping(iProject).getRepository(); + } + + /*============================================ + * compare(IResource, IResourceVariant) tests + *============================================*/ + + /** + * When remote variant wasn't found, compare method is called with null as + * second parameter. In this case compare should return false. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenRemoteDoesNotExist() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(false); + replay(local); + + // then + assertFalse(grvc.compare(local, null)); + verify(local); + } + + /** + * It is possible to have a local file that has same name as a remote folder. + * In some cases that two resources can be compared. In this case compare + * method should return false, because they aren't same resources + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenComparingFileAndContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + replay(local); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(true); + replay(remote); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, remote); + } + + /** + * Comparing two folders that have different path should return false. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenComparingContainerAndContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IPath localPath = createMock(IPath.class); + replay(localPath); + IContainer local = createMock(IContainer.class); + expect(local.exists()).andReturn(true); + expect(local.getFullPath()).andReturn(localPath); + replay(local); + + IPath remotePath = createMock(IPath.class); + replay(remotePath); + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.getFullPath()).andReturn(remotePath); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, localPath, remotePath, remoteResource); + } + + /** + * When comparing two folders that have same path, compare() method should + * return true. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnTrueWhenComparingContainerAndContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IPath path = createMock(IPath.class); + replay(path); + + IContainer local = createMock(IContainer.class); + expect(local.exists()).andReturn(true); + expect(local.getFullPath()).andReturn(path); + replay(local); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.getFullPath()).andReturn(path); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + // then + assertTrue(grvc.compare(local, remote)); + verify(local, path, remoteResource); + } + + /** + * Compare() should return false when comparing two files with different + * content length + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenContentLengthIsDifferent() + throws Exception { + // when + byte[] shortContent = "short content".getBytes(); + byte[] longContent = "very long long content".getBytes(); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()).anyTimes(); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(longContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(shortContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, remote, storage); + } + + /** + * Comparing two files that have same content length but having small + * difference inside content should return false. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenShortContentIsDifferent() throws Exception { + // when + byte[] localContent = "very long long content".getBytes(); + // this typo should be here + byte[] remoteContent = "very long lonk content".getBytes(); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(remoteContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, remote); + } + + /** + * Comparing two 'large' files that have same length and almost identical + * content should return false. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenLongContentIsDifferent() throws Exception { + // when + byte[] localContent = new byte[8192]; + Arrays.fill(localContent, (byte) 'a'); + byte[] remoteContent = new byte[8192]; + Arrays.fill(remoteContent, (byte) 'a'); + remoteContent[8101] = 'b'; + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(remoteContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, remote); + } + + /** + * Comparing two 'large' files that have different length but same content + * should return false. + * <p> + * This and previous three test cases cover almost the same functionality + * but they are covering all return points in compare methods that can be + * used when comparing files content + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenLongContentLengthIsDifferent() + throws Exception { + // when + byte[] localContent = new byte[8192]; + Arrays.fill(localContent, (byte) 'a'); + byte[] remoteContent = new byte[8200]; + Arrays.fill(remoteContent, (byte) 'a'); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(remoteContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertFalse(grvc.compare(local, remote)); + verify(local, remote, storage); + } + + /** + * Comparing two files that have the same content and content length should + * return true + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnTrueWhenShortContentIsDifferent() throws Exception { + // when + byte[] localContent = "very long long content".getBytes(); + byte[] remoteContent = "very long long content".getBytes(); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(remoteContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertTrue(grvc.compare(local, remote)); + verify(local, remote); + } + + /** + * Compare two 'large' files that have same content length and content + * should return true. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnTrueWhenLongContentLengthIsDifferent() + throws Exception { + // when + byte[] localContent = new byte[8192]; + Arrays.fill(localContent, (byte) 'a'); + byte[] remoteContent = new byte[8192]; + Arrays.fill(remoteContent, (byte) 'a'); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + dataSet, null); + + // given + IFile local = createMock(IFile.class); + expect(local.exists()).andReturn(true); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localContent)); + replay(local); + + IStorage storage = createMock(IStorage.class); + expect(storage.getContents()).andReturn( + new ByteArrayInputStream(remoteContent)); + replay(storage); + + IResourceVariant remote = createMock(IResourceVariant.class); + expect(remote.isContainer()).andReturn(false); + expect(remote.getStorage((IProgressMonitor) anyObject())).andReturn( + storage).anyTimes(); + replay(remote); + + // then + assertTrue(grvc.compare(local, remote)); + verify(local, remote, storage); + } + + /** + * When comparing locally not existing file with file that exists in remote, + * compare method should return false. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenBaseDoesntExist() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(false); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, ObjectId.zeroId(), null); + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } + + /** + * Compare() should return false when remote file does not exists, but + * equivalent local file exist. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenRemoteVariantDoesntExist() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, ObjectId.zeroId(), null); + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(false); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } + + /*================================================== + * compare(IResourceVariant, IResourceVariant) tests + *==================================================*/ + + /** + * Return false when comparing incompatible types (file against folder) that + * also maps onto different resources + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenComparingRemoteVariantFileWithContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, ObjectId.zeroId(), null); + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } + + /** + * Return false when comparing incompatible types (folder against file) that + * also map onto different resources + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenComparingRemoteVariantContainerWithFile() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } + + /** + * When comparing two remote variants that have different path compare + * method should return false + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnFalseWhenComparingRemoteVariantContainerWithContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IPath basePath = createMock(IPath.class); + replay(basePath); + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + expect(baseResource.getFullPath()).andReturn(basePath); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IPath remotePath = createMock(IPath.class); + replay(remotePath); + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + expect(remoteResource.getFullPath()).andReturn(remotePath); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource, basePath, remotePath); + } + + /** + * Comparing two remote folders that have same path should return true + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnTrueWhenComparingRemoteVariantContainerWithContainer() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IPath path = createMock(IPath.class); + replay(path); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + expect(baseResource.getFullPath()).andReturn(path); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + expect(remoteResource.getFullPath()).andReturn(path); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + // then + assertTrue(grvc.compare(base, remote)); + verify(baseResource, remoteResource, path); + } + + @Test + @SuppressWarnings("boxing") + /** + * Comparing two remote files that have different git ObjectId should return false. + */ + public void shouldReturnFalseWhenComparingRemoteVariantWithDifferentObjectId() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant( + baseResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + null); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + + // then + assertFalse(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } + + /** + * Comparing two remote files that have the same git ObjectId should return + * true. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnTrueWhenComparingRemoteVariant() { + // when + GitResourceVariantComparator grvc = new GitResourceVariantComparator( + null, null); + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant( + baseResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + null); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + null); + + // then + assertTrue(grvc.compare(base, remote)); + verify(baseResource, remoteResource); + } +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java new file mode 100644 index 0000000000..c80bffb494 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java @@ -0,0 +1,365 @@ +/******************************************************************************* + * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * + * 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.synchronize; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.egit.core.op.BranchOperation; +import org.eclipse.egit.core.op.ConnectProviderOperation; +import org.eclipse.egit.core.op.DisconnectProviderOperation; +import org.eclipse.egit.core.op.TrackOperation; +import org.eclipse.egit.core.project.RepositoryMapping; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; +import org.eclipse.egit.core.test.GitTestCase; +import org.eclipse.egit.core.test.TestProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.team.core.variants.IResourceVariant; +import org.eclipse.team.core.variants.ResourceVariantByteStore; +import org.eclipse.team.core.variants.SessionResourceVariantByteStore; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class GitResourceVariantTreeTest extends GitTestCase { + + private Repository repo; + + private ResourceVariantByteStore store; + + @Before + public void createGitRepository() throws Exception { + IProject iProject = project.project; + if (!gitDir.exists()) + new Repository(gitDir).create(); + + new ConnectProviderOperation(iProject, gitDir).execute(null); + repo = RepositoryMapping.getMapping(iProject).getRepository(); + + store = new SessionResourceVariantByteStore(); + } + + @After + public void clearGitResources() throws Exception { + List<IProject> projects = new ArrayList<IProject>(); + projects.add(project.project); + new DisconnectProviderOperation(projects).execute(null); + + repo.close(); + } + + /** + * roots() method should return list of projects that are associated with + * given repository. In this case there is only one project associated with + * this repository therefore only one root should be returned. + */ + @Test + public void shouldReturnOneRoot() { + // when + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitTestResourceVariantTree(dataSet, + store); + + // then + assertEquals(1, grvt.roots().length); + IResource actualProject = grvt.roots()[0]; + assertEquals(this.project.getProject(), actualProject); + } + + /** + * When we have two or more project associated with repository, roots() + * method should return list of project. In this case we have two project + * associated with particular repository, therefore '2' value is expected. + * @throws Exception + */ + @Test + public void shouldReturnTwoRoots() throws Exception { + // when + // create second project + TestProject secondProject = new TestProject(false, "Project-2"); + IProject secondIProject = secondProject.project; + // add connect project with repository + new ConnectProviderOperation(secondIProject, gitDir).execute(null); + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitTestResourceVariantTree(dataSet, + store); + + // then + assertEquals(2, grvt.roots().length); + IResource actualProject = grvt.roots()[1]; + assertEquals(this.project.project, actualProject); + IResource actualProject1 = grvt.roots()[0]; + assertEquals(secondIProject, actualProject1); + } + + /** + * When we want to obtain list of members, members() method should return + * only members that are in repository. In this test we create Main.java + * file, stage it and commit it. Then we create Main2.java file with we don't + * add to repository. members() method should return one member because only + * one file is in repository. + * @throws Exception + */ + @Test + public void shouldReturnOneMember() throws Exception { + // when + createResourceAndCommit("org.egit.test", "Main.java", "class Main {}", + "Initial commit"); + // create second file that isn't tracked + IPackageFragment iPackage = project + .createPackage("org.egit.test.nested"); + project.createType(iPackage, "Main2.java", "class Main2 {}"); + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + assertEquals(1, grvt.members(project.project).length); + IResource[] members = grvt.members(project.project); + assertEquals("src", members[0].getName()); + } + + /** + * members() method should return only members that are on same level (it + * cannot work recursively). In this test it should return one file and one + * folder member. + * @throws Exception + */ + @Ignore + @Test + public void shouldReturnTwoMembers() throws Exception { + // when + IPackageFragment iPackage = project.createPackage("org.egit.test"); + createResourceAndCommit(iPackage, "Main.java", "class Main {}", + "Initial commit"); + // create second file that isn't tracked + createResourceAndCommit("org.egit.test.nested", "Main2.java", + "class Main2 {}", "Second commit"); + + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + assertEquals(2, grvt.members(iPackage.getResource()).length); + IResource[] members = grvt.members(iPackage.getResource()); + assertEquals("nested", members[0].getName()); + assertEquals("Main.java", members[1].getName()); + } + + /** + * Checks that getResourceVariant will not throw NPE for null argument. This + * method is called with null argument when local or remote resource does + * not exist. + * @throws Exception + */ + @Test + public void shouldReturnNullResourceVariant() throws Exception { + // when + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + assertNull(grvt.getResourceVariant(null)); + } + + /** + * getResourceVariant() should return null when given resource doesn't exist + * in repository. + * @throws Exception + */ + @Test + public void shouldReturnNullResourceVariant2() throws Exception { + // when + IPackageFragment iPackage = project.createPackage("org.egit.test"); + IType mainJava = project.createType(iPackage, "Main.java", + "class Main {}"); + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + assertNull(grvt.getResourceVariant(mainJava.getResource())); + } + + /** + * Check if getResourceVariant() does return the same resource that was + * committed. Passes only when it is run as a single test, not as a part of + * largest test suite + * @throws Exception + */ + @Ignore + @Test + public void shoulReturnSameResourceVariant() throws Exception { + // when + IType mainJava = createResourceAndCommit("org.egit.test", "Main.java", + "class Main {}", "Initial commit"); + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + IResourceVariant actual = grvt.getResourceVariant(mainJava + .getResource()); + assertNotNull(actual); + assertEquals("Main.java", actual.getName()); + + InputStream actualIn = actual.getStorage(new NullProgressMonitor()) + .getContents(); + byte[] actualByte = new byte[actualIn.available()]; + actualIn.read(actualByte); + InputStream expectedIn = ((IFile) mainJava.getResource()).getContents(); + byte[] expectedByte = new byte[expectedIn.available()]; + expectedIn.read(expectedByte); + assertArrayEquals(expectedByte, actualByte); + } + + /** + * Create and commit Main.java file in master branch, then create branch + * "test" checkout nearly created branch and modify Main.java file. + * getResourceVariant() should obtain Main.java file content from "master" + * branch. Passes only when it is run as a single test, not as a part of + * largest test suite + * @throws Exception + */ + @Ignore + @Test + public void shouldReturnDifferentResourceVariant() throws Exception { + // when + IType mainJava = createResourceAndCommit("org.egit.test", "Main.java", + "class Main {}", "Initial commit"); + createBranch("test"); + // checkout branch + new BranchOperation(repo, "refs/heads/test").execute(null); + ((IFile) mainJava.getResource()).appendContents( + new ByteArrayInputStream("// test".getBytes()), 0, null); + addAndCommitResource(mainJava, "Second commit"); + GitSynchronizeData data = new GitSynchronizeData(repo, Constants.HEAD, + Constants.MASTER, false); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + + // given + GitResourceVariantTree grvt = new GitRemoteResourceVariantTree(dataSet, + store); + + // then + IResourceVariant actual = grvt.getResourceVariant(mainJava + .getResource()); + assertNotNull(actual); + assertEquals("Main.java", actual.getName()); + + InputStream actualIn = actual.getStorage(new NullProgressMonitor()) + .getContents(); + byte[] actualByte = new byte[actualIn.available()]; + actualIn.read(actualByte); + InputStream expectedIn = ((IFile) mainJava.getResource()).getContents(); + byte[] expectedByte = new byte[expectedIn.available()]; + expectedIn.read(expectedByte); + + // assert arrays not equals + if (Arrays.equals(expectedByte, actualByte)) { + fail(); + } else { + assertTrue(true); + } + } + + private IType createResourceAndCommit(String packageName, String fileName, + String fileContent, String commitMsg) throws Exception { + IPackageFragment iPackage = project.createPackage(packageName); + return createResourceAndCommit(iPackage, fileName, fileContent, + commitMsg); + } + + private IType createResourceAndCommit(IPackageFragment iPackage, + String fileName, String fileContent, String commitMsg) + throws Exception { + IType mainJava = project.createType(iPackage, fileName, fileContent); + addAndCommitResource(mainJava, commitMsg); + + return mainJava; + } + + private void addAndCommitResource(IType mainJava, String commitMsg) + throws Exception { + List<IResource> resources = new ArrayList<IResource>(); + resources.add(mainJava.getResource()); + IResource[] track = resources.toArray(new IResource[resources.size()]); + new TrackOperation(track).execute(null); // add resource to git + new Git(repo).commit().setMessage(commitMsg).call(); // make commit + } + + private void createBranch(String branchName) throws Exception { + RefUpdate updateRef; + updateRef = repo.updateRef(Constants.R_HEADS + branchName); + Ref startRef = repo.getRef(branchName); + ObjectId startAt = repo.resolve(Constants.HEAD); + String startBranch; + if (startRef != null) + startBranch = branchName; + else + startBranch = startAt.name(); + startBranch = repo.shortenRefName(startBranch); + updateRef.setNewObjectId(startAt); + updateRef + .setRefLogMessage("branch: Created from " + startBranch, false); //$NON-NLS-1$ + updateRef.update(); + } + +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitSyncInfoTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitSyncInfoTest.java new file mode 100644 index 0000000000..a0bc11b057 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitSyncInfoTest.java @@ -0,0 +1,732 @@ +/******************************************************************************* + * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * + * 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.synchronize; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.eclipse.team.core.synchronize.SyncInfo.ADDITION; +import static org.eclipse.team.core.synchronize.SyncInfo.CHANGE; +import static org.eclipse.team.core.synchronize.SyncInfo.CONFLICTING; +import static org.eclipse.team.core.synchronize.SyncInfo.DELETION; +import static org.eclipse.team.core.synchronize.SyncInfo.INCOMING; +import static org.eclipse.team.core.synchronize.SyncInfo.IN_SYNC; +import static org.eclipse.team.core.synchronize.SyncInfo.OUTGOING; +import static org.eclipse.team.core.synchronize.SyncInfo.PSEUDO_CONFLICT; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.util.Arrays; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IPath; +import org.eclipse.egit.core.op.ConnectProviderOperation; +import org.eclipse.egit.core.project.RepositoryMapping; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; +import org.eclipse.egit.core.test.GitTestCase; +import org.eclipse.jgit.api.CommitCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.GitIndex; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.GitIndex.Entry; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevCommitList; +import org.junit.Before; +import org.junit.Test; + +public class GitSyncInfoTest extends GitTestCase { + + private Repository repo; + + private GitResourceVariantComparator comparator; + + @Before + public void setUp() throws Exception { + super.setUp(); + IProject iProject = project.project; + if (!gitDir.exists()) + new Repository(gitDir).create(); + + new ConnectProviderOperation(iProject, gitDir).execute(null); + repo = RepositoryMapping.getMapping(iProject).getRepository(); + + GitSynchronizeData data = new GitSynchronizeData(repo, "", "", true); + GitSynchronizeDataSet dataSet = new GitSynchronizeDataSet(data); + comparator = new GitResourceVariantComparator(dataSet, null); + } + + /** + * File is in sync when local, base and remote objects refer to identical + * file (same git ObjectId). + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnResourceFileInSync() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + ObjectId objectId = stageAndCommit(fileName, localBytes); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, null); + + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, objectId, null); + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(IN_SYNC, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Folders are in sync when they have same name. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnResourceFolderInSync() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(3); + expect(local.getName()).andReturn("src").anyTimes(); + replay(local); + + GitFolderResourceVariant base = new GitFolderResourceVariant(local); + GitFolderResourceVariant remote = new GitFolderResourceVariant(local); + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(IN_SYNC, gsi.getKind()); + verify(local); + } + + /** + * Outgoing change should be returned when base RevCommitList has more + * commits than remote RevCommitList + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnOutgoingFileChange() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + stage(fileName, localBytes); + RevCommit firstCommit = commit(); + localBytes[8120] = 'b'; + ObjectId objectId = stage(fileName, localBytes); + RevCommit secondCommit = commit(); + RevCommitList<RevCommit> baseCommits = new RevCommitList<RevCommit>(); + baseCommits.add(firstCommit); + baseCommits.add(secondCommit); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, baseCommits); // baseComits has two entry + + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + RevCommitList<RevCommit> remoteCommits = new RevCommitList<RevCommit>(); + remoteCommits.add(firstCommit); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + remoteCommits); // remoteCommits has only one entry + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(OUTGOING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Should return incoming change when remote RevCommitList has more commit + * objects then base RevCommitList + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnIncomingFileChange() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + ObjectId objectId = stage(fileName, localBytes); + RevCommit firstCommit = commit(); + RevCommitList<RevCommit> baseCommits = new RevCommitList<RevCommit>(); + baseCommits.add(firstCommit); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, baseCommits); // baseCommits has one element + + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + + stage(fileName, localBytes); + RevCommit secondCommit = commit(); + RevCommitList<RevCommit> remoteCommits = new RevCommitList<RevCommit>(); + remoteCommits.add(secondCommit); + remoteCommits.add(firstCommit); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + remoteCommits); // remoteCommits has two elements + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(INCOMING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Outgoing deletion should be returned when resource exist in base and + * remote but does not exist locally. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnOutgoingDeletion() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IPath path = createMock(IPath.class); + replay(path); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + expect(baseResource.getFullPath()).andReturn(path); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + expect(remoteResource.getFullPath()).andReturn(path); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(OUTGOING | DELETION, gsi.getKind()); + verify(local, baseResource, remoteResource, path); + } + + /** + * Incoming deletion should be returned when file exists locally and in base + * but does not exist in remote resource variant. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnIncomingFileDeletion() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + stage(fileName, localBytes); + RevCommit firstCommit = commit(); + ObjectId objectId = stage(fileName, localBytes); + RevCommit secondCommit = commit(); + RevCommitList<RevCommit> baseCommits = new RevCommitList<RevCommit>(); + baseCommits.add(firstCommit); + baseCommits.add(secondCommit); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, baseCommits); + + GitSyncInfo gsi = new GitSyncInfo(local, base, null, comparator); + gsi.init(); + + // then + assertEquals(INCOMING | DELETION, gsi.getKind()); + verify(local, baseResource); + } + + /** + * Outgoing addition should be returned when resource exists locally but it + * can't be found in base and remote resource variant. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnOutgoingAddition() throws Exception { + // when + + // given + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true).times(2); + expect(baseResource.isDerived()).andReturn(false); + expect(baseResource.getName()).andReturn("Mian.java").anyTimes(); + replay(baseResource); + GitSyncInfo gsi = new GitSyncInfo(baseResource, null, null, comparator); + gsi.init(); + + // then + assertEquals(OUTGOING | ADDITION, gsi.getKind()); + verify(baseResource); + } + + /** + * Conflicting change should be returned when remote and base RevCommitList + * have same number of RevCommit object's but these lists have one ore more + * different RevCommit objects. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFileChange() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + ObjectId objectId = stage(fileName, localBytes); + RevCommit firstCommit = commit(); + RevCommitList<RevCommit> baseCommits = new RevCommitList<RevCommit>(); + baseCommits.add(firstCommit); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, baseCommits); + + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + + stage(fileName, localBytes); + RevCommit secondCommit = commit(); + RevCommitList<RevCommit> remoteCommits = new RevCommitList<RevCommit>(); + remoteCommits.add(secondCommit); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, + repo, + ObjectId.fromString("0123456789012345678901234567890123456789"), + remoteCommits); + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Conflicting change should be returned when file was created locally with + * same name as incoming folder in remote. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFileChange1() throws Exception { + // when + + // given + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(1); + expect(local.getName()).andReturn("test-file").anyTimes(); + replay(local); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, null, null); + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Conflicting change should be returned when local resource differ from + * base resource variant and remote variant does not exist. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFileChange2() throws Exception { + // when + + // given + String fileName = "test-file"; + byte[] localBytes = new byte[8200]; + Arrays.fill(localBytes, (byte) 'a'); + + IFile local = createMock(IFile.class); + expect(local.isDerived()).andReturn(false); + expect(local.exists()).andReturn(true).times(2); + expect(local.getName()).andReturn(fileName).anyTimes(); + expect(local.getProject()).andReturn(project.getProject()); + expect(local.getContents()).andReturn( + new ByteArrayInputStream(localBytes)); + replay(local); + + stage(fileName, localBytes); + RevCommit firstCommit = commit(); + byte[] remoteBytes = Arrays.copyOf(localBytes, localBytes.length); + remoteBytes[8100] = 'b'; + ObjectId objectId = stage(fileName, remoteBytes); + RevCommit secondCommit = commit(); + RevCommitList<RevCommit> baseCommits = new RevCommitList<RevCommit>(); + baseCommits.add(firstCommit); + baseCommits.add(secondCommit); + + IFile baseResource = createMock(IFile.class); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, objectId, baseCommits); + + GitSyncInfo gsi = new GitSyncInfo(local, base, null, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource); + } + + /** + * Conflicting change when folder exists locally and remotely but it does + * not exist in base resource variant. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFolderChange() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(true); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(false); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Conflicting change when folder exists in base but it does not exist in + * local and remote. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFolderChange1() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(false); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(false); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /* + * When local resource is file, base resource variant is folder and remote + * variant is a file, then getKind() should return conflicting change. + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFolderAndFileChange() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(false); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * When remote is folder and base is a file getKind() should return + * conflicting change + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingFileAndFolderChange() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(false); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource baseResource = createMock(IResource.class); + expect(baseResource.exists()).andReturn(true); + replay(baseResource); + GitBlobResourceVariant base = new GitBlobResourceVariant(baseResource, + repo, ObjectId.zeroId(), null); + + IResource remoteResource = createMock(IResource.class); + expect(remoteResource.exists()).andReturn(true); + replay(remoteResource); + GitFolderResourceVariant remote = new GitFolderResourceVariant( + remoteResource); + GitSyncInfo gsi = new GitSyncInfo(local, base, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | CHANGE, gsi.getKind()); + verify(local, baseResource, remoteResource); + } + + /** + * Remote resource variant was not found, local resource does not exist but + * there is a base resource. In such situation we should return conflicting + * deletion. + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingDeletationPseudoConflict() + throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(false); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource baseResource = createMock(IResource.class); + replay(baseResource); + GitFolderResourceVariant base = new GitFolderResourceVariant( + baseResource); + + GitSyncInfo gsi = new GitSyncInfo(local, base, null, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | DELETION | PSEUDO_CONFLICT, gsi.getKind()); + verify(local, baseResource); + } + + /** + * Conflicting addition should be returned when resource exists in local and + * remote but cannot be found in base + * @throws Exception + */ + @Test + @SuppressWarnings("boxing") + public void shouldReturnConflictingAddition() throws Exception { + // when + + // given + IResource local = createMock(IResource.class); + expect(local.exists()).andReturn(true).times(3); + expect(local.isDerived()).andReturn(false); + expect(local.getName()).andReturn("Mian.java").anyTimes(); + replay(local); + + IResource remoteResource = createMock(IResource.class); + replay(remoteResource); + GitBlobResourceVariant remote = new GitBlobResourceVariant( + remoteResource, repo, ObjectId.zeroId(), null); + GitSyncInfo gsi = new GitSyncInfo(local, null, remote, comparator); + gsi.init(); + + // then + assertEquals(CONFLICTING | ADDITION, gsi.getKind()); + verify(local, remoteResource); + } + + private ObjectId stageAndCommit(String fileName, byte[] content) + throws Exception { + ObjectId objectId = stage(fileName, content); + commit(); + + return objectId; + } + + private ObjectId stage(String fileName, byte[] content) throws Exception { + // TODO reimplement using DirCache class + GitIndex index = repo.getIndex(); + File workdir = project.getProject().getFullPath().toFile(); + File file = new File(workdir, fileName); + Entry entry = index.add(workdir, file, content); + index.write(); + + return entry.getObjectId(); + } + + private RevCommit commit() throws Exception { + Git git = new Git(repo); + CommitCommand commit = git.commit(); + commit.setMessage("Initial commit"); + commit.setAuthor("EGit", "egi@eclipse.org"); + return commit.call(); + } + +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitTestResourceVariantTree.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitTestResourceVariantTree.java new file mode 100644 index 0000000000..0cdd595f76 --- /dev/null +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitTestResourceVariantTree.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * + * 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.synchronize; + +import java.io.IOException; + +import org.eclipse.core.resources.IResource; +import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Tree; +import org.eclipse.team.core.variants.ResourceVariantByteStore; + +/** + * Implementation of abstract {@link GitResourceVariantTree} class. It is only + * used in {@link GitResourceVariantTreeTest} for testing public methods that + * are implemented in base class. + */ +class GitTestResourceVariantTree extends GitResourceVariantTree { + + GitTestResourceVariantTree(GitSynchronizeDataSet data, + ResourceVariantByteStore store) { + super(data, store); + } + + @Override + ObjectId getRevObjId(IResource resource) throws IOException { + // not used in test case + return null; + } + + @Override + Tree getRevTree(IResource resource) throws IOException { + // TODO not used in test case + return null; + } + +} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestProject.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestProject.java index 24ab17b388..a20c4b4a3f 100644 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestProject.java +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestProject.java @@ -49,14 +49,19 @@ public class TestProject { this(false); } + public TestProject(boolean remove) throws CoreException { + this(remove, "Project-1"); + } + /** * @param remove * should project be removed if already exists + * @param projectName * @throws CoreException */ - public TestProject(final boolean remove) throws CoreException { + public TestProject(final boolean remove, String projectName) throws CoreException { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - project = root.getProject("Project-1"); + project = root.getProject(projectName); if (remove) project.delete(true, null); project.create(null); diff --git a/org.eclipse.egit.core/META-INF/MANIFEST.MF b/org.eclipse.egit.core/META-INF/MANIFEST.MF index 86dbec0449..4e7b438e4d 100644 --- a/org.eclipse.egit.core/META-INF/MANIFEST.MF +++ b/org.eclipse.egit.core/META-INF/MANIFEST.MF @@ -35,7 +35,8 @@ Export-Package: org.eclipse.egit.core;version="0.9.0"; org.eclipse.egit.core.synchronize.dto;version="0.9.0";uses:="org.eclipse.jgit.lib,org.eclipse.core.resources" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: org.eclipse.jgit.api;version="[0.9.0,0.10.0)", +Import-Package: org.easymock;version="[2.4.0,3.0.0)", + org.eclipse.jgit.api;version="[0.9.0,0.10.0)", org.eclipse.jgit.dircache;version="[0.9.0,0.10.0)", org.eclipse.jgit.errors;version="[0.9.0,0.10.0)", org.eclipse.jgit.lib;version="[0.9.0,0.10.0)", diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/EGitTestCase.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/EGitTestCase.java index 56ba1ebbbd..809d579a5d 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/EGitTestCase.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/EGitTestCase.java @@ -10,12 +10,19 @@ *******************************************************************************/ package org.eclipse.egit.ui.common; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.egit.ui.test.Eclipse; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; +import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; import org.junit.After; import org.junit.BeforeClass; +import org.junit.runner.RunWith; +@RunWith(SWTBotJunit4ClassRunner.class) public abstract class EGitTestCase { static { @@ -38,4 +45,33 @@ public abstract class EGitTestCase { new Eclipse().reset(); } + protected static void waitForWorkspaceRefresh() { + WorkspaceRefreshHook wrh = new WorkspaceRefreshHook(); + ResourcesPlugin.getWorkspace().addResourceChangeListener(wrh); + + try { + bot.waitUntil(wrh, 120000); + } finally { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(wrh); + } + } + + private static class WorkspaceRefreshHook extends DefaultCondition + implements IResourceChangeListener { + private boolean state = false; + + public void resourceChanged(IResourceChangeEvent event) { + if (event.getType() == IResourceChangeEvent.POST_CHANGE) + state = true; + } + + public String getFailureMessage() { + return "Failed waiting for workspace refresh."; + } + + public boolean test() throws Exception { + return state; + } + } + } diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/GitImportRepoWizard.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/GitImportRepoWizard.java index 0a0da09d77..8e551ce35c 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/GitImportRepoWizard.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/common/GitImportRepoWizard.java @@ -10,7 +10,11 @@ *******************************************************************************/ package org.eclipse.egit.ui.common; +import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellCloses; + import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; public class GitImportRepoWizard { @@ -36,4 +40,49 @@ public class GitImportRepoWizard { return new RepoPropertiesPage(); } + public int configuredRepoCount() { + bot.shell("Import Projects from Git").activate(); + + return bot.table(0).rowCount(); + } + + public boolean containsRepo(String projectName) { + SWTBotTable table = bot.table(0); + int repoCount = configuredRepoCount(); + + for (int i = 0; i < repoCount; i++) { + String rowName = table.getTableItem(i).getText(); + if (rowName.contains(projectName)) + return true; + } + return false; + } + + public void selectAndCloneRepository(String repoName) { + bot.shell("Import Projects from Git").activate(); + + SWTBotTable table = bot.table(0); + for (int i = 0; i < table.rowCount(); i++) { + String rowName = table.getTableItem(i).getText(); + if (rowName != null && rowName.startsWith(repoName)) { + table.select(i); + break; + } + } + + bot.button("Next >").click(); + + bot.button("Next >").click(); + + bot.button("Select All").click(); + } + + public void waitForCreate() { + bot.button("Finish").click(); + + SWTBotShell shell = bot.shell("Import Projects from Git"); + + bot.waitUntil(shellCloses(shell), 120000); + } + } diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java index ace9fb3c2b..fc5de0970b 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/AllTests.java @@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * Copyright (C) 2010, Ketan Padegaonkar <KetanPadegaonkar@gmail.com> * * All rights reserved. This program and the accompanying materials @@ -10,6 +10,7 @@ package org.eclipse.egit.ui.test; import org.eclipse.egit.ui.prefpages.configuration.GlobalConfigurationPageTest; import org.eclipse.egit.ui.view.repositories.AllRepositoriesViewTests; +import org.eclipse.egit.ui.view.synchronize.SynchronizeViewTest; import org.eclipse.egit.ui.wizards.clone.GitCloneWizardTest; import org.eclipse.egit.ui.wizards.share.SharingWizardTest; import org.junit.runner.RunWith; @@ -17,8 +18,11 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses( { GitCloneWizardTest.class, GlobalConfigurationPageTest.class, - SharingWizardTest.class, AllRepositoriesViewTests.class }) +@SuiteClasses( { AllRepositoriesViewTests.class, // + GitCloneWizardTest.class, // + GlobalConfigurationPageTest.class, // + SharingWizardTest.class, // + SynchronizeViewTest.class }) public class AllTests { // empty class, don't need anything here } diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java index 1327f8e1a9..d50736ed4f 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/repositories/GitRepositoriesViewTest.java @@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * Copyright (c) 2010 SAP AG. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -508,4 +508,5 @@ public class GitRepositoriesViewTest extends GitRepositoriesViewTestBase { perspective.activate(); } } -}
\ No newline at end of file +} + diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/synchronize/SynchronizeViewTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/synchronize/SynchronizeViewTest.java new file mode 100644 index 0000000000..311841739e --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/view/synchronize/SynchronizeViewTest.java @@ -0,0 +1,331 @@ +/******************************************************************************* + * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org> + * + * 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.ui.view.synchronize; + +import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellCloses; +import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellIsActive; +import static org.junit.Assert.assertEquals; + +import java.io.File; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.egit.ui.common.EGitTestCase; +import org.eclipse.egit.ui.common.GitImportRepoWizard; +import org.eclipse.egit.ui.common.RepoPropertiesPage; +import org.eclipse.egit.ui.common.RepoRemoteBranchesPage; +import org.eclipse.egit.ui.test.ContextMenuHelper; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; +import org.eclipse.swtbot.swt.finder.SWTBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class SynchronizeViewTest extends EGitTestCase { + + private static boolean changePerspective = false; + + // this test fails when is run inside eclipse with Maven POM editor + @Test + public void shouldReturnNoChanges() throws Exception { + // when + changeFilesInProject(); + showSynchronizationDialog("org.eclipse.egit.ui"); + + // given + bot.shell("Synchronize repository: egit" + File.separator + ".git") + .activate(); + + bot.comboBox(0).setSelection("local .git"); + bot.comboBox(1).setSelection("HEAD"); + + bot.comboBox(2).setSelection("local .git"); + bot.comboBox(3).setSelection("master"); + + // do not check 'Include local changes' + + // fire action + bot.button("OK").click(); + + handleConfirmOpenPerspective(); + + // wait for dispose "Git Resource Synchronization" + bot.waitUntil(shellIsActive("Git Resource Synchronization"), 15000); + SWTBotShell gitResSyncShell = bot.shell("Git Resource Synchronization"); + bot.waitUntil(shellCloses(gitResSyncShell), 300000); + + // then + SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); + assertEquals(0, syncViewTree.getAllItems().length); + } + + // this test fails when is run inside eclipse with Maven POM editor + @Test + public void shouldReturnListOfChanges() throws Exception { + // when + changeFilesInProject(); + showSynchronizationDialog("org.eclipse.egit.ui"); + + // given + bot.shell("Synchronize repository: egit" + File.separator + ".git") + .activate(); + + bot.comboBox(0).setSelection("local .git"); + bot.comboBox(1).setSelection("HEAD"); + + bot.comboBox(2).setSelection("local .git"); + bot.comboBox(3).setSelection("master"); + + // include local changes + bot.checkBox("Include local uncommited changes in comparison").click(); + + // fire action + bot.button("OK").click(); + + handleConfirmOpenPerspective(); + + // wait for dispose "Git Resource Synchronization" + bot.waitUntil(shellIsActive("Git Resource Synchronization"), 15000); + SWTBotShell shell = bot.shell("Git Resource Synchronization"); + bot.waitUntil(shellCloses(shell), 300000); + + // then + SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); + assertEquals(2, syncViewTree.getAllItems().length); + + SWTBotTreeItem[] syncItems = syncViewTree.getAllItems(); + assertEquals("org.eclipse.egit.core", syncItems[0].getText()); + assertEquals("org.eclipse.egit.ui", syncItems[1].getText()); + + syncItems[0].expand(); + syncItems[1].expand(); + + assertEquals(1, syncItems[0].getNodes().size()); + assertEquals("pom.xml", syncItems[0].getNodes().get(0)); + assertEquals(1, syncItems[1].getNodes().size()); + assertEquals("pom.xml", syncItems[1].getNodes().get(0)); + } + + @Test + public void shouldCompareBranchAgainstTag() throws Exception { + // when + showSynchronizationDialog("org.eclipse.egit.ui"); + + // given + bot.shell("Synchronize repository: egit" + File.separator + ".git") + .activate(); + + bot.comboBox(0).setSelection("origin"); + bot.comboBox(1).setSelection("stable-0.7"); + + bot.comboBox(2).setSelection("local .git"); + bot.comboBox(3).setSelection("v0.8.1"); + + // fire action + bot.button("OK").click(); + + handleConfirmOpenPerspective(); + + // wait for dispose "Git Resource Synchronization" + bot.waitUntil(shellIsActive("Git Resource Synchronization"), 15000); + SWTBotShell shell = bot.shell("Git Resource Synchronization"); + bot.waitUntil(shellCloses(shell), 300000); + + // then + SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); + assertEquals(8, syncViewTree.getAllItems().length); + } + + @Test + public void shouldCompareTagAgainstTag() throws Exception { + // when + showSynchronizationDialog("org.eclipse.egit.ui"); + + // given + bot.shell("Synchronize repository: egit" + File.separator + ".git") + .activate(); + + bot.comboBox(0).setSelection("local .git"); + bot.comboBox(1).setSelection("v0.7.0"); + + bot.comboBox(2).setSelection("local .git"); + bot.comboBox(3).setSelection("v0.8.1"); + + // fire action + bot.button("OK").click(); + + handleConfirmOpenPerspective(); + + // wait for dispose "Git Resource Synchronization" + bot.waitUntil(shellIsActive("Git Resource Synchronization"), 15000); + SWTBotShell shell = bot.shell("Git Resource Synchronization"); + bot.waitUntil(shellCloses(shell), 300000); + + // then + SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); + assertEquals(8, syncViewTree.getAllItems().length); + } + + // this test always fails with cause: + // Timeout after: 5000 ms.: Could not find context menu with text: + // Synchronize + @Ignore + @Test + public void shouldLaunchSynchronizationFromGitRepositories() + throws Exception { + // when + bot.menu("Window").menu("Show View").menu("Other...").click(); + bot.shell("Show View").bot().tree().expandNode("Git").getNode( + "Git Repositories").doubleClick(); + + SWTBotTree repositoriesTree = bot.viewByTitle("Git Repositories").bot() + .tree(); + SWTBotTreeItem egitRoot = repositoriesTree.getAllItems()[0]; + egitRoot.expand(); + egitRoot.collapse(); + egitRoot.expand(); + SWTBotTreeItem remoteBranch = egitRoot.expandNode("Branches") + .expandNode("Remote Branches"); + SWTBotTreeItem branchNode = remoteBranch.getNode("origin/stable-0.7"); + branchNode.select(); + branchNode.contextMenu("Synchronize").click(); + + handleConfirmOpenPerspective(); + + // wait for dispose "Git Resource Synchronization" + bot.waitUntil(shellIsActive("Git Resource Synchronization"), 15000); + SWTBotShell shell = bot.shell("Git Resource Synchronization"); + bot.waitUntil(shellCloses(shell), 300000); + + // given + + // then + SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); + assertEquals(8, syncViewTree.getAllItems().length); + } + + @Before + public void setupViews() { + bot.perspectiveById("org.eclipse.jdt.ui.JavaPerspective").activate(); + bot.viewByTitle("Package Explorer").show(); + } + + @BeforeClass + public static void setupEnvironment() throws Exception { + // turn off auto building + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceDescription description = workspace.getDescription(); + description.setAutoBuilding(false); + workspace.setDescription(description); + + // obtain copy of EGit project + GitImportRepoWizard importWizard = new GitImportRepoWizard(); + + importWizard.openWizard(); + String repoName = "egit"; + String repoUrl = "git://egit.eclipse.org/egit.git"; + if (!importWizard.containsRepo(repoName)) + addRepository(importWizard, repoUrl); + + importWizard.selectAndCloneRepository(repoName); + importWizard.waitForCreate(); + waitForWorkspaceRefresh(); + } + + @AfterClass + public static void restoreEnvironmentSetup() throws Exception { + // turn off auto building + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceDescription description = workspace.getDescription(); + description.setAutoBuilding(true); + workspace.setDescription(description); + } + + private static void addRepository(GitImportRepoWizard importWizard, + String repoUrl) { + RepoPropertiesPage propertiesPage = importWizard.openCloneWizard(); + + RepoRemoteBranchesPage remoteBranches = propertiesPage + .nextToRemoteBranches(repoUrl); + remoteBranches.selectBranches("master"); + + remoteBranches.nextToWorkingCopy().waitForCreate(); + } + + private void changeFilesInProject() throws Exception { + SWTBot packageExplorerBot = bot.viewByTitle("Package Explorer").bot(); + packageExplorerBot.activeShell(); + SWTBotTree tree = packageExplorerBot.tree(); + + SWTBotTreeItem coreTreeItem = tree.getAllItems()[3]; + coreTreeItem.expand(); + for (String node : coreTreeItem.getNodes()) { + if (node.contains("pom.xml")) { + coreTreeItem.getNode(node).doubleClick(); + break; + } + } + + SWTBotEditor corePomEditor = bot.editorByTitle("pom.xml"); + corePomEditor.toTextEditor() + .insertText("<!-- EGit jUnit test case -->"); + corePomEditor.saveAndClose(); + coreTreeItem.collapse(); + + SWTBotTreeItem uiTreeItem = tree.getAllItems()[6]; + uiTreeItem.expand(); + for (String node : uiTreeItem.getNodes()) { + if (node.contains("pom.xml")) { + uiTreeItem.getNode(node).doubleClick(); + break; + } + } + + SWTBotEditor uiPomEditor = bot.editorByTitle("pom.xml"); + uiPomEditor.toTextEditor().insertText("<!-- EGit jUnit test case -->"); + uiPomEditor.saveAndClose(); + uiTreeItem.collapse(); + } + + private void showSynchronizationDialog(String projectName) { + SWTBot packageExplorerBot = bot.viewByTitle("Package Explorer").bot(); + packageExplorerBot.activeShell(); + SWTBotTree tree = packageExplorerBot.tree(); + + // EGit decorates the project node shown in the package explorer. The + // '>' decorator indicates that there are uncommitted changes present in + // the project. Also the repository and branch name are added as a + // suffix ('[<repo name> <branch name>]' suffix). To bypass this + // decoration we use here this loop. + for (SWTBotTreeItem item : tree.getAllItems()) { + if (item.getText().contains(projectName)) { + item.select(); + break; + } + } + + ContextMenuHelper.clickContextMenu(tree, "Team", "Synchronize..."); + } + + private void handleConfirmOpenPerspective() { + if (!changePerspective) { + changePerspective = true; + bot.waitUntil(shellIsActive("Confirm Open Perspective"), 15000); + bot.checkBox("Remember my decision").click(); + bot.button("No").click(); + } + } + +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/wizards/clone/GitCloneWizardTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/wizards/clone/GitCloneWizardTest.java index 603fdc2bdf..272ce2a928 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/wizards/clone/GitCloneWizardTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/wizards/clone/GitCloneWizardTest.java @@ -25,13 +25,10 @@ import org.eclipse.egit.ui.common.RepoPropertiesPage; import org.eclipse.egit.ui.common.RepoRemoteBranchesPage; import org.eclipse.egit.ui.common.WorkingCopyPage; import org.eclipse.jgit.lib.Repository; -import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(SWTBotJunit4ClassRunner.class) public class GitCloneWizardTest extends EGitTestCase { private GitImportRepoWizard importWizard; |