diff options
author | Martin Fleck | 2016-07-27 09:30:15 +0000 |
---|---|---|
committer | Thomas Wolf | 2017-06-13 15:06:00 +0000 |
commit | 9b2db7496f2a3ae7a7bad85e13ab5a03b3b6b7b9 (patch) | |
tree | 67b605d20d205b69a7ba2a193f184b9633cdc021 /org.eclipse.egit.ui.test/src/org/eclipse | |
parent | 02252787aa5e716b4506addccb620e98fa5674ca (diff) | |
download | egit-9b2db7496f2a3ae7a7bad85e13ab5a03b3b6b7b9.tar.gz egit-9b2db7496f2a3ae7a7bad85e13ab5a03b3b6b7b9.tar.xz egit-9b2db7496f2a3ae7a7bad85e13ab5a03b3b6b7b9.zip |
More fitting Decoration Support for ResourceMappings in general
The decoration support for ResourceMappings and WorkingSets is split up
to provide a more fitting decoration for ResourceMappings which are not
WorkingSets.
Includes tests.
Bug: 498546
Signed-off-by: Martin Fleck <mfleck@eclipsesource.com>
Also-by: Stefan Dirix <sdirix@eclipsesource.com>
Change-Id: I6e6306d7f00a3a26ef86178f5261a00e1804db64
Diffstat (limited to 'org.eclipse.egit.ui.test/src/org/eclipse')
6 files changed, 1193 insertions, 72 deletions
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapterTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapterTest.java index 29174f0128..86afc3b831 100644 --- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapterTest.java +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapterTest.java @@ -416,75 +416,3 @@ public class DecoratableResourceAdapterTest extends LocalRepositoryTestCase { } } - -class TestDecoratableResource extends DecoratableResource { - - public TestDecoratableResource(IResource resource) { - super(resource); - } - - public TestDecoratableResource tracked() { - setTracked(true); - return this; - } - - public TestDecoratableResource ignored() { - setIgnored(true); - return this; - } - - public TestDecoratableResource dirty() { - setDirty(true); - return this; - } - - public TestDecoratableResource conflicts() { - setConflicts(true); - return this; - } - - public TestDecoratableResource added() { - setStagingState(StagingState.ADDED); - return this; - } - - public IDecoratableResource modified() { - setStagingState(StagingState.MODIFIED); - return this; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof IDecoratableResource)) - return false; - - IDecoratableResource decoratableResource = (IDecoratableResource) obj; - if (!(decoratableResource.getType() == getType())) - return false; - if (!decoratableResource.getName().equals(getName())) - return false; - if (!(decoratableResource.isTracked() == isTracked())) - return false; - if (!(decoratableResource.isIgnored() == isIgnored())) - return false; - if (!(decoratableResource.isDirty() == isDirty())) - return false; - if (!(decoratableResource.hasConflicts() == hasConflicts())) - return false; - if (!decoratableResource.getStagingState().equals(getStagingState())) - return false; - - return true; - } - - @Override - public int hashCode() { - // this appeases FindBugs - return super.hashCode(); - } - - @Override - public String toString() { - return "TestDecoratableResourceAdapter[" + getName() + (isTracked() ? ", tracked" : "") + (isIgnored() ? ", ignored" : "") + (isDirty() ? ", dirty" : "") + (hasConflicts() ? ",conflicts" : "") + ", staged=" + getStagingState() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$//$NON-NLS-7$//$NON-NLS-8$//$NON-NLS-9$//$NON-NLS-10$//$NON-NLS-11$ - } -} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMappingTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMappingTest.java new file mode 100644 index 0000000000..3b8b392913 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMappingTest.java @@ -0,0 +1,344 @@ +/******************************************************************************* + * Copyright (c) 2017 EclipseSource Services GmbH 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 + * + * Contributors: + * Martin Fleck - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.decorators; + +import static org.eclipse.jgit.junit.JGitTestUtil.write; +import static org.junit.Assert.assertArrayEquals; +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.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceTraversal; +import org.eclipse.egit.core.JobFamilies; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; +import org.eclipse.egit.ui.test.TestUtil; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.MergeResult; +import org.eclipse.jgit.api.MergeResult.MergeStatus; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Before; +import org.junit.Test; + +/** + * A test class for testing {@link DecoratableResourceMapping}. + * + * @author Martin Fleck <mfleck@eclipsesource.com> + * @see DecoratableWorkingSetTest DecoratableWorkingSetTest for specific working + * set tests + */ +public class DecoratableResourceMappingTest + extends GitLightweightDecoratorTest { + + private static final String RM_CONTENT_A_FILE_NAME = "TestFile.testrm_A"; + + private static final String RM_CONTENT_B_FILE_NAME = "TestFile.testrm_B"; + + private IProject project; + + private Git git; + + private IndexDiffCacheEntry indexDiffCacheEntry; + + private File gitDir; + + private ResourceMapping resourceMapping; + + private IFile rmContentA, rmContentB; + + @Before + public void setUp() throws Exception { + gitDir = createProjectAndCommitToRepository(); + project = ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ1); + + rmContentA = createFile(project, RM_CONTENT_A_FILE_NAME, + "Just some content."); + rmContentB = createFile(project, RM_CONTENT_B_FILE_NAME, + "Just some content."); + resourceMapping = new TestResourceMapping(project, rmContentA, + rmContentB); + + ResourceTraversal[] traversals = resourceMapping.getTraversals(null, + null); + assertEquals(1, traversals.length); + ResourceTraversal traversal = traversals[0]; + assertEquals(2, traversal.getResources().length); + assertTrue(traversal.contains(rmContentA)); + assertTrue(traversal.contains(rmContentB)); + + Repository repo = lookupRepository(gitDir); + git = new Git(repo); + indexDiffCacheEntry = org.eclipse.egit.core.Activator.getDefault() + .getIndexDiffCache().getIndexDiffCacheEntry(repo); + waitForIndexDiff(false); + } + + private IndexDiffData waitForIndexDiff(final boolean refreshCache) + throws Exception { + if (refreshCache) + indexDiffCacheEntry.refresh(); + TestUtil.joinJobs(JobFamilies.INDEX_DIFF_CACHE_UPDATE); + return indexDiffCacheEntry.getIndexDiff(); + } + + @Test + public void testNewResourceMappingIsUnstaged() throws Exception { + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA), + newExpectedDecoratableResource(rmContentB), + newExpectedDecoratableResourceMapping() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationUntracked(resourceMapping); + } + + @Test + public void testMixedStagingStateIsModified_AddedNotStaged() + throws Exception { + gitAdd(git, rmContentA); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked().added(), + newExpectedDecoratableResource(rmContentB), + newExpectedDecoratableResourceMapping().tracked().modified() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationStaged(resourceMapping); + } + + @Test + public void testMixedStagingStateIsModified_RemovedAdded() + throws Exception { + gitAdd(git, rmContentA); + gitCommit(git); + gitRemove(git, rmContentA); + gitAdd(git, rmContentB); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked().removed(), + newExpectedDecoratableResource(rmContentB).tracked().added(), + newExpectedDecoratableResourceMapping().tracked().modified() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationStaged(resourceMapping); + } + + @Test + public void testSameStagingStateIsState_Added() throws Exception { + gitAdd(git, rmContentA); + gitAdd(git, rmContentB); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked().added(), + newExpectedDecoratableResource(rmContentB).tracked().added(), + newExpectedDecoratableResourceMapping().tracked().added() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationAdded(resourceMapping); + } + + @Test + public void testAnyTrackedIsTracked() throws Exception { + gitAdd(git, rmContentA); + gitCommit(git); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked(), + newExpectedDecoratableResource(rmContentB), + newExpectedDecoratableResourceMapping().tracked() }; + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationTracked(resourceMapping); + } + + @Test + public void testAllIgnoredIsUnstaged() throws Exception { + IFile gitignore = createFile(project, ".gitignore", "*.testrm_*"); + gitAdd(git, gitignore); + gitAdd(git, rmContentA); + gitAdd(git, rmContentB); + gitCommit(git); + + project.refreshLocal(IResource.DEPTH_INFINITE, null); + rmContentA = findFile(project, RM_CONTENT_A_FILE_NAME); + gitignore = findFile(project, ".gitignore"); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(gitignore).tracked(), + newExpectedDecoratableResource(rmContentA).ignored(), + newExpectedDecoratableResource(rmContentB).ignored(), + newExpectedDecoratableResourceMapping() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, gitignore), + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationUntracked(resourceMapping); + } + + @Test + public void testAnyDirtyIsDirty() throws Exception { + gitAdd(git, rmContentA); + gitAdd(git, rmContentB); + gitCommit(git); + write(rmContentA.getLocation().toFile(), "Changed content"); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked().dirty(), + newExpectedDecoratableResource(rmContentB).tracked(), + newExpectedDecoratableResourceMapping().tracked().dirty() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationDirty(resourceMapping); + } + + @Test + public void testAnyConflictsIsConflicts() throws Exception { + // commit changes on master + gitAdd(git, rmContentA); + gitAdd(git, rmContentB); + RevCommit masterCommit = gitCommit(git); + + // add change on new branch first_topic + git.checkout().setCreateBranch(true).setName("first_topic").call(); + rmContentA = findFile(project, RM_CONTENT_A_FILE_NAME); + write(rmContentA.getLocation().toFile(), "First Topic Content"); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, rmContentA); + RevCommit firstTopicCommit = gitCommit(git); + + // add change on new branch second_topic + git.checkout().setCreateBranch(true).setStartPoint(masterCommit) + .setName("second_topic").call(); + rmContentA = findFile(project, RM_CONTENT_A_FILE_NAME); + write(rmContentA.getLocation().toFile(), "Second Topic Content"); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, rmContentA); + gitCommit(git); + + // merge second_topic with first_topic + MergeResult mergeResult = git.merge().include(firstTopicCommit).call(); + assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus()); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked() + .conflicts(), + newExpectedDecoratableResource(rmContentB).tracked(), + newExpectedDecoratableResourceMapping().tracked().conflicts() }; + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationConflicts(resourceMapping); + } + + /** + * Tests that if the resource mapping is both conflicting and dirty, that + * the conflicting decoration image is used over the dirty decoration image. + * + * @throws Exception + */ + @Test + public void testDecorationConflictingOverDirty() throws Exception { + // commit changes on master + gitAdd(git, rmContentA); + gitAdd(git, rmContentB); + RevCommit masterCommit = gitCommit(git); + + // add change on new branch first_topic + git.checkout().setCreateBranch(true).setName("first_topic").call(); + rmContentA = findFile(project, RM_CONTENT_A_FILE_NAME); + write(rmContentA.getLocation().toFile(), "First Topic Content"); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, rmContentA); + RevCommit firstTopicCommit = gitCommit(git); + + // add change on new branch second_topic + git.checkout().setCreateBranch(true).setStartPoint(masterCommit) + .setName("second_topic").call(); + rmContentA = findFile(project, RM_CONTENT_A_FILE_NAME); + write(rmContentA.getLocation().toFile(), "Second Topic Content"); + project.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, rmContentA); + gitCommit(git); + + // modify b to make it dirty + write(rmContentB.getLocation().toFile(), "Changed content"); + + // merge second_topic with first_topic + MergeResult mergeResult = git.merge().include(firstTopicCommit).call(); + assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus()); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(rmContentA).tracked() + .conflicts(), + newExpectedDecoratableResource(rmContentB).tracked().dirty(), + newExpectedDecoratableResourceMapping().tracked().dirty() + .conflicts() }; + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, rmContentA), + newDecoratableResource(indexDiffData, rmContentB), + newDecoratableResourceMapping(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationConflicts(resourceMapping); + } +}
\ No newline at end of file diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableWorkingSetTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableWorkingSetTest.java new file mode 100644 index 0000000000..6da61346d8 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/DecoratableWorkingSetTest.java @@ -0,0 +1,350 @@ +/******************************************************************************* + * Copyright (c) 2017 EclipseSource Services GmbH 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 + * + * Contributors: + * Martin Fleck - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.decorators; + +import static org.eclipse.jgit.junit.JGitTestUtil.write; +import static org.junit.Assert.assertArrayEquals; +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.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.egit.core.JobFamilies; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; +import org.eclipse.egit.ui.test.TestUtil; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.MergeResult; +import org.eclipse.jgit.api.MergeResult.MergeStatus; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.internal.ide.model.WorkingSetResourceMapping; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * A test class for testing {@link DecoratableWorkingSet}. + * + * @author Martin Fleck <mfleck@eclipsesource.com> + * @see DecoratableResourceMappingTest DecoratableResourceMappingTest for + * general resource mappings + */ +@SuppressWarnings("restriction") +public class DecoratableWorkingSetTest extends GitLightweightDecoratorTest { + + private static final String WORKING_SET_NAME = "TestWorkingSet"; + + private static final IWorkingSetManager WORKING_SET_MANAGER = PlatformUI + .getWorkbench().getWorkingSetManager(); + + private static IWorkingSet WORKING_SET; + static { + WORKING_SET = WORKING_SET_MANAGER.getWorkingSet(WORKING_SET_NAME); + if (WORKING_SET == null) { + WORKING_SET = WORKING_SET_MANAGER.createWorkingSet(WORKING_SET_NAME, + new IAdaptable[0]); + } + } + + private static final String TEST_FILE = "TestFile"; + + private static final String TEST_FILE2 = "TestFile2"; + + private ResourceMapping resourceMapping; + + private File gitDir; + + private IProject project1, project2; + + private Git git; + + private IndexDiffCacheEntry indexDiffCacheEntry; + + @BeforeClass + public static void beforeClassBase() throws Exception { + showAllIcons(); + WORKING_SET_MANAGER.addWorkingSet(WORKING_SET); + } + + @AfterClass + public static void afterClassBase() { + WORKING_SET_MANAGER.removeWorkingSet(WORKING_SET); + } + + @Before + public void setUp() throws Exception { + gitDir = createProjectAndCommitToRepository(REPO1, PROJ1, null); + project1 = ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ1); + project2 = ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ2); + project2.create(null); + project2.open(null); + TestUtil.waitForJobs(50, 5000); + assertTrue("Project is not accessible: " + project2, + project2.isAccessible()); + + setWorkingSet(project1, project2); + resourceMapping = createResourceMapping(); + + Repository repo = lookupRepository(gitDir); + git = new Git(repo); + indexDiffCacheEntry = org.eclipse.egit.core.Activator.getDefault() + .getIndexDiffCache().getIndexDiffCacheEntry(repo); + waitForIndexDiff(false); + } + + @After + public void cleanUp() { + clearWorkingSet(); + } + + private void clearWorkingSet() { + WORKING_SET.setElements(new IAdaptable[0]); + } + + private void setWorkingSet(IAdaptable... elements) { + WORKING_SET.setElements(elements); + } + + private IndexDiffData waitForIndexDiff(final boolean refreshCache) + throws Exception { + if (refreshCache) + indexDiffCacheEntry.refresh(); + TestUtil.joinJobs(JobFamilies.INDEX_DIFF_CACHE_UPDATE); + return indexDiffCacheEntry.getIndexDiff(); + } + + private void assertHasUnstagedChanges(boolean expected, + IDecoratableResource... decoratableResources) { + for (IDecoratableResource d : decoratableResources) { + assertTrue(d.hasUnstagedChanges() == expected); + } + } + + protected ResourceMapping createResourceMapping() { + return new WorkingSetResourceMapping(WORKING_SET); + } + + /** + * Tests that working sets do not show the untracked decoration, but instead + * they are just undecorated. + * + * @throws Exception + */ + @Test + public void testEmptyWorkingSetIsUndecorated() throws Exception { + clearWorkingSet(); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableWorkingSet(WORKING_SET) }; + IDecoratableResource[] actualDRs = { + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertUndecorated(resourceMapping); + } + + @Test + public void testUntrackedContentIsUndecorated() throws Exception { + setWorkingSet(project2); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project2), + newExpectedDecoratableWorkingSet(WORKING_SET) }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project2), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertUndecorated(resourceMapping); + } + + @Test + public void testAnyTrackedIsTracked() throws Exception { + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project1).tracked(), + newExpectedDecoratableResource(project2), + newExpectedDecoratableWorkingSet(WORKING_SET).tracked() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project1), + newDecoratableResource(indexDiffData, project2), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationTracked(resourceMapping); + } + + @Test + public void testStagingStateHasNoInfluence_Modified() throws Exception { + IFile file = createFile(project1, TEST_FILE, "Something"); + gitAdd(git, file); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project1).tracked().modified(), + newExpectedDecoratableResource(file).tracked().added(), + newExpectedDecoratableResource(project2), + newExpectedDecoratableWorkingSet(WORKING_SET).tracked() }; + + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project1), + newDecoratableResource(indexDiffData, file), + newDecoratableResource(indexDiffData, project2), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertDecorationTracked(resourceMapping); + } + + @Test + public void testAnyDirtyIsDirty() throws Exception { + // Create new file and commit + IFile file = createFile(project1, TEST_FILE, "Something"); + gitAdd(git, file); + gitCommit(git); + + // change file content to make it dirty + write(file.getLocation().toFile(), "Change"); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project1).tracked().dirty(), + newExpectedDecoratableResource(file).tracked().dirty(), + newExpectedDecoratableWorkingSet(WORKING_SET).tracked() + .dirty() }; + + waitForIndexDiff(true); + IndexDiffData indexDiffData = indexDiffCacheEntry.getIndexDiff(); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project1), + newDecoratableResource(indexDiffData, file), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertHasUnstagedChanges(true, actualDRs); + assertDecorationDirty(resourceMapping); + } + + @Test + public void testAnyConflictsIsConflicts() throws Exception { + // Create new file and commit + IFile file = createFile(project1, TEST_FILE, "Something"); + gitAdd(git, file); + RevCommit masterCommit = gitCommit(git); + + // Create and checkout new branch, change file content, add and commit + // file + git.checkout().setCreateBranch(true).setName("first_topic").call(); + file = findFile(project1, TEST_FILE); + write(file.getLocation().toFile(), "First Topic Content"); + project1.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, file); + RevCommit firstTopicCommit = gitCommit(git); + + // Create and checkout new branch (from master), change file content, + // add and commit file + git.checkout().setCreateBranch(true).setStartPoint(masterCommit) + .setName("second_topic").call(); + file = findFile(project1, TEST_FILE); + write(file.getLocation().toFile(), "Second Topic Content"); + project1.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, file); + gitCommit(git); + + // merge second_topic with first_topic + MergeResult mergeResult = git.merge().include(firstTopicCommit).call(); + assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus()); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project1).tracked() + .conflicts(), + newExpectedDecoratableResource(file).tracked().conflicts(), + newExpectedDecoratableWorkingSet(WORKING_SET).tracked() + .conflicts() }; + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project1), + newDecoratableResource(indexDiffData, file), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertHasUnstagedChanges(true, actualDRs); + assertDecorationConflicts(resourceMapping); + } + + @Test + public void testDecorationConflictingOverDirty() throws Exception { + // Create new file and commit + IFile file = createFile(project1, TEST_FILE, "Something"); + IFile file2 = createFile(project1, TEST_FILE2, "Another Something"); + gitAdd(git, file); + gitAdd(git, file2); + RevCommit masterCommit = gitCommit(git); + + // Create and checkout new branch, change file content, add and commit + // file + git.checkout().setCreateBranch(true).setName("first_topic").call(); + file = findFile(project1, TEST_FILE); + write(file.getLocation().toFile(), "First Topic Content"); + project1.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, file); + RevCommit firstTopicCommit = gitCommit(git); + + // Create and checkout new branch (from master), change file content, + // add and commit file + git.checkout().setCreateBranch(true).setStartPoint(masterCommit) + .setName("second_topic").call(); + file = findFile(project1, TEST_FILE); + write(file.getLocation().toFile(), "Second Topic Content"); + project1.refreshLocal(IResource.DEPTH_INFINITE, null); + gitAdd(git, file); + gitCommit(git); + + // modify file2 to make it dirty + write(file2.getLocation().toFile(), "Changed content"); + + // merge second_topic with first_topic + MergeResult mergeResult = git.merge().include(firstTopicCommit).call(); + assertEquals(MergeStatus.CONFLICTING, mergeResult.getMergeStatus()); + + IDecoratableResource[] expectedDRs = new IDecoratableResource[] { + newExpectedDecoratableResource(project1).tracked().dirty() + .conflicts(), + newExpectedDecoratableResource(file).tracked().conflicts(), + newExpectedDecoratableResource(file2).tracked().dirty(), + newExpectedDecoratableWorkingSet(WORKING_SET).tracked().dirty() + .conflicts() }; + IndexDiffData indexDiffData = waitForIndexDiff(true); + IDecoratableResource[] actualDRs = { + newDecoratableResource(indexDiffData, project1), + newDecoratableResource(indexDiffData, file), + newDecoratableResource(indexDiffData, file2), + newDecoratableWorkingSet(resourceMapping) }; + + assertArrayEquals(expectedDRs, actualDRs); + assertHasUnstagedChanges(true, actualDRs); + assertDecorationConflicts(resourceMapping); + } +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java new file mode 100644 index 0000000000..a4191585e4 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright (c) 2017 EclipseSource Services GmbH 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 + * + * Contributors: + * Martin Fleck - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.decorators; + +import static org.eclipse.egit.ui.internal.decorators.DecoratableResourceMapping.RESOURCE_MAPPING; +import static org.eclipse.egit.ui.internal.decorators.DecoratableWorkingSet.WORKING_SET; +import static org.eclipse.jgit.junit.JGitTestUtil.write; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.egit.core.AdapterUtils; +import org.eclipse.egit.core.internal.indexdiff.IndexDiffData; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.UIPreferences; +import org.eclipse.egit.ui.common.LocalRepositoryTestCase; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.ui.IWorkingSet; +import org.junit.BeforeClass; + +/** + * An abstract base class providing several convenience methods for tests + * involving the {@link GitLightweightDecorator}. + * + * @author Martin Fleck <mfleck@eclipsesource.com> + */ +public abstract class GitLightweightDecoratorTest + extends LocalRepositoryTestCase { + + protected static final GitLightweightDecorator DECORATOR = new GitLightweightDecorator(); + + @BeforeClass + public static void showAllIcons() throws Exception { + // ensure that all images are shown + IPreferenceStore preferenceStore = Activator.getDefault() + .getPreferenceStore(); + preferenceStore.putValue( + UIPreferences.DECORATOR_SHOW_ASSUME_UNCHANGED_ICON, + Boolean.toString(true)); + preferenceStore.putValue(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON, + Boolean.toString(true)); + preferenceStore.putValue(UIPreferences.DECORATOR_SHOW_DIRTY_ICON, + Boolean.toString(true)); + preferenceStore.putValue(UIPreferences.DECORATOR_SHOW_STAGED_ICON, + Boolean.toString(true)); + preferenceStore.putValue(UIPreferences.DECORATOR_SHOW_TRACKED_ICON, + Boolean.toString(true)); + preferenceStore.putValue(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON, + Boolean.toString(true)); + } + + protected static void assertUndecorated(ResourceMapping resourceMapping) + throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertUndecorated(decoration); + } + + protected static void assertDecorationTracked( + ResourceMapping resourceMapping) throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertTracked(decoration); + } + + protected static void assertDecorationUntracked( + ResourceMapping resourceMapping) throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertUntracked(decoration); + } + + protected static void assertDecorationDirty(ResourceMapping resourceMapping) + throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertDirty(decoration); + } + + protected static void assertDecorationConflicts( + ResourceMapping resourceMapping) throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertConflict(decoration); + } + + protected static void assertDecorationStaged( + ResourceMapping resourceMapping) throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertStaged(decoration); + } + + protected static void assertDecorationAdded(ResourceMapping resourceMapping) + throws Exception { + DecorationResult decoration = decorate(resourceMapping); + assertStagedAdd(decoration); + } + + protected static DecorationResult decorate( + ResourceMapping resourceMapping) { + DecorationResult result = new DecorationResult(); + DECORATOR.decorate(resourceMapping, result); + return result; + } + + protected static void assertTracked(DecorationResult decoration) { + assertTrue("Image does not reflect 'tracked' state.", + isTracked(decoration)); + } + + protected static void assertUntracked(DecorationResult decoration) { + assertTrue("Image does not reflect 'untracked' state.", + isUntracked(decoration)); + } + + protected static void assertStaged(DecorationResult decoration) { + assertTrue("Image does not reflect 'staged' state: " + + decoration.getOverlay(), isStaged(decoration)); + } + + protected static void assertStagedAdd(DecorationResult decoration) { + assertTrue("Image does not reflect 'staged add' state.", + isStagedAdd(decoration)); + } + + protected static void assertStagedRemove(DecorationResult decoration) { + assertTrue("Image does not reflect 'staged remove' state.", + isStagedRemove(decoration)); + } + + protected static void assertConflict(DecorationResult decoration) { + assertTrue("Image does not reflect 'conflict' state.", + isConflict(decoration)); + } + + protected static void assertAssumeUnchaged(DecorationResult decoration) { + assertTrue("Image does not reflect 'assume unchaged' state.", + isAssumeUnchanged(decoration)); + } + + protected static void assertDirty(DecorationResult decoration) { + assertTrue("Image does not reflect 'dirty' state.", + isDirty(decoration)); + } + + protected static void assertUndecorated(DecorationResult decoration) { + assertTrue("Image is not undecorated.", isUndecorated(decoration)); + } + + protected static boolean isTracked(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.TRACKED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isUntracked(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.UNTRACKED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isStaged(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.STAGED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isStagedAdd(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.STAGED_ADDED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isStagedRemove(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.STAGED_REMOVED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isConflict(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.CONFLICT_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isAssumeUnchanged(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.ASSUME_UNCHANGED_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isDirty(DecorationResult decoration) { + return Objects.equals( + GitLightweightDecorator.DecorationHelper.DIRTY_IMAGE, + decoration.getOverlay()); + } + + protected static boolean isUndecorated(DecorationResult decoration) { + return decoration.getOverlay() == null; + } + + protected static IFile createFile(IContainer container, String name, + String content) throws IOException, CoreException { + write(new File(container.getLocation().toFile(), name), content); + container.refreshLocal(IResource.DEPTH_INFINITE, null); + return findFile(container, name); + } + + protected static IResource findResource(IContainer container, String name) { + return container.findMember(name); + } + + protected static IFile findFile(IContainer container, String name) { + IResource resource = findResource(container, name); + return AdapterUtils.adapt(resource, IFile.class); + } + + protected static RevCommit gitCommit(Git git) throws Exception { + return git.commit().setMessage("Commit staged changes.").call(); + } + + protected static void gitAdd(Git git, IFile file) throws Exception { + String filePath = file.getFullPath().toString(); + // remove leading '/' + git.add().addFilepattern(filePath.substring(1)).call(); + } + + protected static void gitRemove(Git git, IFile file) throws Exception { + String filePath = file.getFullPath().toString(); + // remove leading '/' + git.rm().addFilepattern(filePath.substring(1)).call(); + } + + protected static TestDecoratableResource newExpectedDecoratableResource( + IResource resource) { + return new TestDecoratableResource(resource); + } + + protected static TestDecoratableResource newExpectedDecoratableResourceMapping() { + return new TestDecoratableResource("<unknown>", RESOURCE_MAPPING); + } + + protected static TestDecoratableResource newExpectedDecoratableWorkingSet( + IWorkingSet workingSet) { + return new TestDecoratableResource(workingSet.getLabel(), WORKING_SET); + } + + protected static DecoratableResource newDecoratableResource( + IndexDiffData indexDiffData, IResource resource) + throws IOException { + return new DecoratableResourceAdapter(indexDiffData, resource); + } + + protected static DecoratableResource newDecoratableResourceMapping( + ResourceMapping resourceMapping) throws IOException { + return new DecoratableResourceMapping(resourceMapping); + } + + protected static DecoratableResource newDecoratableWorkingSet( + ResourceMapping resourceMapping) throws IOException { + return new DecoratableWorkingSet(resourceMapping); + } +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestDecoratableResource.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestDecoratableResource.java new file mode 100644 index 0000000000..f9a332b884 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestDecoratableResource.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (C) 2011, Philipp Thun <philipp.thun@sap.com> + * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org> + * Copyright (C) 2011, Christian Halstrick <christian.halstrick@sap.com> + * Copyright (C) 2011, Jens Baumgart <jens.baumgart@sap.com> + * Copyright (C) 2013, Robin Stocker <robin@nibor.org> + * Copyright (C) 2017, Martin Fleck <mfleck@eclipsesource.com> + * + * 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.internal.decorators; + +import org.eclipse.core.resources.IResource; + +/** + * A decoratable resource used for testing to easily compare decoratable + * resources and their resource state information. + */ +public class TestDecoratableResource extends DecoratableResource { + + private String name = null; + private int type = -1; + + /** + * Creates a new decoratable resource based on the given resource. + * + * @param resource + * resource to be decorated + */ + public TestDecoratableResource(IResource resource) { + super(resource); + } + + /** + * Creates a new decoratable resource using the specified name and type. For + * comparisons, the name and type must match. + * + * @param name + * name of the decoratable resource + * @param type + * type of the decoratable resource + */ + public TestDecoratableResource(String name, int type) { + super(null); + this.name = name; + this.type = type; + } + + public TestDecoratableResource tracked() { + setTracked(true); + return this; + } + + public TestDecoratableResource ignored() { + setIgnored(true); + return this; + } + + public TestDecoratableResource dirty() { + setDirty(true); + return this; + } + + public TestDecoratableResource conflicts() { + setConflicts(true); + return this; + } + + public TestDecoratableResource added() { + setStagingState(StagingState.ADDED); + return this; + } + + public TestDecoratableResource removed() { + setStagingState(StagingState.REMOVED); + return this; + } + + public TestDecoratableResource modified() { + setStagingState(StagingState.MODIFIED); + return this; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IDecoratableResource)) + return false; + + IDecoratableResource decoratableResource = (IDecoratableResource) obj; + if (!(decoratableResource.getType() == getType())) + return false; + if (!decoratableResource.getName().equals(getName())) + return false; + if (!(decoratableResource.isTracked() == isTracked())) + return false; + if (!(decoratableResource.isIgnored() == isIgnored())) + return false; + if (!(decoratableResource.isDirty() == isDirty())) + return false; + if (!(decoratableResource.hasConflicts() == hasConflicts())) + return false; + if (!decoratableResource.getStagingState().equals(getStagingState())) + return false; + + return true; + } + + @Override + public String getName() { + if (name != null) { + return name; + } + return super.getName(); + } + + @Override + public int getType() { + if (type >= 0) { + return type; + } + return super.getType(); + } + + @Override + public int hashCode() { + // this appeases FindBugs + return super.hashCode(); + } +} diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestResourceMapping.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestResourceMapping.java new file mode 100644 index 0000000000..51b632a09e --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/TestResourceMapping.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2017 EclipseSource Services GmbH 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 + * + * Contributors: + * Martin Fleck - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.decorators; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.resources.mapping.ResourceTraversal; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * An unregistered resource mapping used for testing the decoration of resource + * mappings. + * + * @author Martin Fleck <mfleck@eclipsesource.com> + */ +public class TestResourceMapping extends ResourceMapping { + + private IProject project; + + private IFile mainFile; + + private IFile[] mappedFiles; + + /** + * Creates a new resource mapping whose model object is null. + * + * @param project + * project used in {@link #getProjects()} + * @param mappedFiles + * files used for + * {@link #getTraversals(ResourceMappingContext, IProgressMonitor) + * traversal}. + */ + public TestResourceMapping(IProject project, IFile... mappedFiles) { + this.project = project; + this.mappedFiles = mappedFiles; + } + + /** + * Creates a new resource mapping whose model object is the given main file. + * + * @param mainFile + * file used as {@link #getModelObject() model object} + * @param mappedFiles + * files used for + * {@link #getTraversals(ResourceMappingContext, IProgressMonitor) + * traversal}. + */ + public TestResourceMapping(IFile mainFile, IFile... mappedFiles) { + this.mainFile = mainFile; + this.project = mainFile.getProject(); + this.mappedFiles = mappedFiles; + } + + @Override + public Object getModelObject() { + if (mainFile != null) { + return mainFile; + } + return null; + } + + @Override + public String getModelProviderId() { + return null; + } + + @Override + public IProject[] getProjects() { + return new IProject[] { project }; + } + + @Override + public ResourceTraversal[] getTraversals(ResourceMappingContext context, + IProgressMonitor monitor) throws CoreException { + return new ResourceTraversal[] { + new ResourceTraversal(mappedFiles, + IResource.DEPTH_INFINITE, IResource.NONE) }; + } +} |