Skip to content

Content of file GitRepositoriesViewTest.java

/*******************************************************************************
 * Copyright (c) 2010, 2019 SAP AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Mathias Kinzler (SAP AG) - initial implementation
 *    Tobias Baumann <tobbaumann@gmail.com> - Bug #494269
 *******************************************************************************/
package org.eclipse.egit.ui.view.repositories;

import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellCloses;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
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.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.egit.core.RepositoryUtil;
import org.eclipse.egit.core.op.StashCreateOperation;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.common.StagingViewTester;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.tree.StashedCommitNode;
import org.eclipse.egit.ui.test.ContextMenuHelper;
import org.eclipse.egit.ui.test.TestUtil;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.utils.TableCollection;
import org.eclipse.swtbot.swt.finder.waits.Conditions;
import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotText;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
import org.eclipse.ui.internal.wizards.AbstractExtensionWizardRegistry;
import org.eclipse.ui.wizards.IWizardCategory;
import org.eclipse.ui.wizards.IWizardDescriptor;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * SWTBot Tests for the Git Repositories View.
 *
 * <pre>
 * TODO
 * global copy and paste command
 * bare repository support including copy of path from workdir
 * copy path from file and folder
 * paste with empty and invalid path
 * create branch with selection not on a ref
 * tags altogether
 * fetch and push to configured remote
 * import wizard outside the "golden path"
 * </pre>
 */
@RunWith(SWTBotJunit4ClassRunner.class)
public class GitRepositoriesViewTest extends GitRepositoriesViewTestBase {

	private File repositoryFile;

	private boolean initialLinkingState;

	@Before
	public void prepare() throws Exception {
		setVerboseBranchMode(false);
		initialLinkingState = setLinkWithSelection(false);
		repositoryFile = createProjectAndCommitToRepository();
		RepositoryUtil.INSTANCE.addConfiguredRepository(repositoryFile);
	}

	@After
	public void resetLinkingState() {
		setLinkWithSelection(initialLinkingState);
	}

	/**
	 * First level should have 5 children
	 *
	 * @throws Exception
	 */
	@Test
	public void testExpandFirstLevel() throws Exception {
		SWTBotTree tree = getOrOpenView().bot().tree();
		SWTBotTreeItem item = TestUtil.expandAndWait(
				myRepoViewUtil.getRootItem(tree, repositoryFile));
		SWTBotTreeItem[] children = item.getItems();
		assertEquals("Wrong number of children", 5, children.length);
	}

	/**
	 * Tests that the tree does not suddenly have a node with a null repository.
	 *
	 * @throws Exception
	 * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=552622">bug
	 *      552622</a>
	 */
	@Test
	public void testWithStagingView() throws Exception {
		// Fails consistently on Mac without the fix from bug 552622 and
		// succeeds with that fix. On Jenkins this test never failed?!
		SWTBotTree tree = getOrOpenView().bot().tree();
		StagingViewTester stagingViewTester = StagingViewTester
				.openStagingView();
		TestUtil.waitForDecorations();
		SWTBotTreeItem item = myRepoViewUtil.getRootItem(tree, repositoryFile);
		item.select();
		TestUtil.waitForDecorations();
		stagingViewTester.getView().close();
		TestUtil.waitForDecorations();
		SWTBotTreeItem[] items = tree.getAllItems();
		boolean[] hasNull = { false };
		String[] unknownClass = { "" };
		tree.widget.getDisplay().syncExec(() -> {
			for (SWTBotTreeItem i : items) {
				Object obj = i.widget.getData();
				if (!(obj instanceof RepositoryTreeNode)) {
					unknownClass[0] = obj.getClass().getName();
					break;
				}
				if (((RepositoryTreeNode) obj).getRepository() == null) {
					hasNull[0] = true;
					break;
				}
			}
		});
		assertEquals("Unknown tree element", "", unknownClass[0]);
		assertFalse("Tree has node with null repository", hasNull[0]);
	}

	/**
	 * Open (expand, file->editor, branch->checkout)
	 *
	 * @throws Exception
	 */
	@Test
	public void testOpen() throws Exception {
		// expand first level
		SWTBotTree tree = getOrOpenView().bot().tree();
		SWTBotTreeItem item = myRepoViewUtil.getRootItem(tree, repositoryFile);
		item.collapse();
		refreshAndWait();
		item = myRepoViewUtil.getRootItem(tree, repositoryFile);
		assertTrue("Item should not be expanded", !item.isExpanded());
		item.doubleClick();
		assertTrue("Item should be expanded", item.isExpanded());
		// open a file in editor
		item = TestUtil.expandAndWait(
				myRepoViewUtil.getWorkdirItem(tree, repositoryFile));
		SWTBotTreeItem fileiItem = TestUtil.expandAndWait(item.getNode(PROJ1))
				.getNode(FOLDER);
		fileiItem = TestUtil.expandAndWait(fileiItem).getNode(FILE1).select();
		fileiItem.doubleClick();
		assertTrue(bot.activeEditor().getTitle().equals(FILE1));
		bot.activeEditor().close();
		refreshAndWait();

		// opening current branch is a no-op
		String contentMaster = getTestFileContent();
		// open a branch (checkout)
		checkoutWithDoubleClick(tree, "stable");
		String contentStable = getTestFileContent();
		assertNotEquals("Content of master and stable should differ",
				contentMaster, contentStable);
	}

	private void checkoutWithDoubleClick(SWTBotTree tree, String branch)
			throws Exception {
		SWTBotTreeItem node = myRepoViewUtil.getLocalBranchesItem(tree,
				repositoryFile);
		TestUtil.expandAndWait(node).getNode(branch).doubleClick();
		SWTBotShell shell = bot
				.shell(UIText.RepositoriesView_CheckoutConfirmationTitle);
		shell.bot()
				.button(UIText.RepositoriesView_CheckoutConfirmationDefaultButtonLabel)
				.click();
		TestUtil.joinJobs(JobFamilies.CHECKOUT);
		refreshAndWait();
	}

	/**
	 * Checks for the Symbolic Reference node
	 *
	 * @throws Exception
	 */
	@Test
	public void testExpandSymbolicRef() throws Exception {
		SWTBotTree tree = getOrOpenView().bot().tree();
		SWTBotTreeItem item = TestUtil.expandAndWait(
				myRepoViewUtil.getSymbolicRefsItem(tree, repositoryFile));
		List<String> children = item.getNodes();
		boolean found = false;
		for (String child : children) {
			if (child.contains(Constants.HEAD)) {
				found = true;
				break;
			}
		}
		assertTrue(found);
	}

	/**
	 * Checks the first level of the working directory
	 *
	 * @throws Exception
	 */
	@Test
	public void testExpandWorkDir() throws Exception {
		SWTBotTree tree = getOrOpenView().bot().tree();
		Repository myRepository = lookupRepository(repositoryFile);
		List<String> children = Arrays
				.asList(myRepository.getWorkTree().list());
Possible null pointer dereference in org.eclipse.egit.ui.view.repositories.GitRepositoriesViewTest.testExpandWorkDir() due to return value of called method

The return value from a method is dereferenced without a null check, and the return value of that method is one that should generally be checked for null. This may lead to a NullPointerException when the code is executed.

List<String> treeChildren = TestUtil .expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)) .getNodes(); assertTrue(children.containsAll(treeChildren) && treeChildren.containsAll(children)); SWTBotTreeItem item = TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)); item = TestUtil.expandAndWait(item.getNode(PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)); item.getNode(FILE1); } /** * Checks is some context menus are available, should be replaced with real * tests * * @throws Exception */ @Test public void testContextMenuRepository() throws Exception { removeSmartImportWizardToForceGitImportWizardUsage(); Activator.getDefault().getPreferenceStore() .setValue(UIPreferences.ALWAYS_USE_STAGING_VIEW, false); // We just check if the dialogs open, the actual commit and import // projects // is tested elsewhere SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = myRepoViewUtil.getRootItem(tree, repositoryFile); item.select(); assertClickOpens(tree, myUtil.getPluginLocalizedValue("RepoViewCommit.label"), UIText.CommitDialog_CommitChanges); assertClickOpens(tree, myUtil.getPluginLocalizedValue("RepoViewImportProjects.label"), NLS.bind(UIText.GitCreateProjectViaWizardWizard_WizardTitle, repositoryFile)); Activator.getDefault().getPreferenceStore() .setValue(UIPreferences.ALWAYS_USE_STAGING_VIEW, true); } /** * Show properties * * @throws Exception */ @Test public void testShowProperties() throws Exception { SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = myRepoViewUtil.getRootItem(tree, repositoryFile); item.select(); ContextMenuHelper.clickContextMenuSync(tree, myUtil.getPluginLocalizedValue("ShowIn"), "Properties"); SWTBotView propertieView = bot.viewById(IPageLayout.ID_PROP_SHEET); assertTrue(propertieView.isActive()); } /** * Import wizard golden path test * * @throws Exception */ @Test public void testImportWizard() throws Exception { removeSmartImportWizardToForceGitImportWizardUsage(); deleteAllProjects(); assertProjectExistence(PROJ1, false); SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = myRepoViewUtil.getRootItem(tree, repositoryFile); String wizardTitle = NLS.bind( UIText.GitCreateProjectViaWizardWizard_WizardTitle, repositoryFile.getPath()); // start wizard from root item item.select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("ImportProjectsCommand")); SWTBotShell shell = bot.shell(wizardTitle); bot.radio(UIText.GitSelectWizardPage_ImportExistingButton).click(); TableCollection selected = shell.bot().tree().selection(); String wizardNodeText = selected.get(0, 0); // wizard directory should be working dir String expected = myRepoViewUtil.getWorkdirItem(tree, repositoryFile) .getText(); // One or the other or both or none might contain decorations assertTrue(expected.contains(wizardNodeText) || wizardNodeText.contains(expected)); shell.close(); tree = getOrOpenView().bot().tree(); // start wizard from .git TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)) .getNode(Constants.DOT_GIT).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("ImportProjectsCommand")); shell = bot.shell(wizardTitle); selected = shell.bot().tree().selection(); wizardNodeText = selected.get(0, 0); // wizard directory should be .git assertEquals(Constants.DOT_GIT, wizardNodeText); shell.bot().button(IDialogConstants.NEXT_LABEL).click(); shell.bot().label("Import Projects"); // wait for import projects page assertEquals(0, shell.bot().tree().getAllItems().length); shell.bot().button(IDialogConstants.BACK_LABEL).click(); // go to project with .project shell.bot().tree().getAllItems()[0].getNode(PROJ1).select(); // next is 1 shell.bot().button(IDialogConstants.NEXT_LABEL).click(); bot.button(UIText.WizardProjectsImportPage_deselectAll).click(); assertEquals(1, shell.bot().tree().getAllItems().length); assertTrue( !shell.bot().button(IDialogConstants.FINISH_LABEL).isEnabled()); shell.bot().button(UIText.WizardProjectsImportPage_selectAll).click(); assertTrue( shell.bot().button(IDialogConstants.FINISH_LABEL).isEnabled()); shell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(Conditions.shellCloses(shell)); assertProjectExistence(PROJ1, true); assertProjectIsShared(PROJ1, true); } private static void removeSmartImportWizardToForceGitImportWizardUsage() throws Exception { final String smartImportWizardId = "org.eclipse.e4.ui.importer.wizard"; AbstractExtensionWizardRegistry wizardRegistry = (AbstractExtensionWizardRegistry) PlatformUI .getWorkbench().getImportWizardRegistry(); IWizardCategory[] categories = PlatformUI.getWorkbench() .getImportWizardRegistry().getRootCategory().getCategories(); for (IWizardDescriptor wizard : getAllWizards(categories)) { if (wizard.getId().equals(smartImportWizardId)) { WorkbenchWizardElement wizardElement = (WorkbenchWizardElement) wizard; wizardRegistry.removeExtension( wizardElement.getConfigurationElement() .getDeclaringExtension(), new Object[] { wizardElement }); return; } } } private static IWizardDescriptor[] getAllWizards( IWizardCategory[] categories) { List<IWizardDescriptor> results = new ArrayList<>(); for (IWizardCategory wizardCategory : categories) { results.addAll(Arrays.asList(wizardCategory.getWizards())); results.addAll(Arrays .asList(getAllWizards(wizardCategory.getCategories()))); } return results.toArray(new IWizardDescriptor[0]); } @Test public void testImportWizardGeneralProject() throws Exception { removeSmartImportWizardToForceGitImportWizardUsage(); deleteAllProjects(); assertProjectExistence(PROJ2, false); SWTBotTree tree = getOrOpenView().bot().tree(); String wizardTitle = NLS.bind( UIText.GitCreateProjectViaWizardWizard_WizardTitle, repositoryFile.getPath()); // start wizard from PROJ2 TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)) .getNode(PROJ2).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("ImportProjectsCommand")); SWTBotShell shell = bot.shell(wizardTitle); shell = bot.shell(wizardTitle); // try import existing project first bot.radio(UIText.GitSelectWizardPage_ImportExistingButton).click(); TableCollection selected = shell.bot().tree().selection(); String wizardNode = selected.get(0, 0); // wizard directory should be PROJ2 assertEquals(PROJ2, wizardNode); shell.bot().button(IDialogConstants.NEXT_LABEL).click(); assertWizardDialogMessage(shell.bot(), " " + UIText.GitProjectsImportPage_NoProjectsMessage); assertEquals(0, shell.bot().tree().getAllItems().length); shell.bot().button(IDialogConstants.BACK_LABEL).click(); // import as general shell.bot().radio(UIText.GitSelectWizardPage_ImportAsGeneralButton) .click(); shell.bot().button(IDialogConstants.NEXT_LABEL).click(); assertEquals(PROJ2, shell.bot() .textWithLabel( UIText.GitCreateGeneralProjectPage_ProjectNameLabel) .getText()); // switch to a sub directory and see if this is used shell.bot().button(IDialogConstants.BACK_LABEL).click(); SWTBotTreeItem item = TestUtil .expandAndWait(shell.bot().tree().getAllItems()[0]); TestUtil.expandAndWait(item.getNode(PROJ2)).getNode(FOLDER).select(); shell.bot().button(IDialogConstants.NEXT_LABEL).click(); String name = shell.bot() .textWithLabel( UIText.GitCreateGeneralProjectPage_ProjectNameLabel) .getText(); assertEquals(FOLDER, name); shell.bot().button(IDialogConstants.BACK_LABEL).click(); // switch back to the root directory TestUtil.expandAndWait(shell.bot().tree().getAllItems()[0]) .getNode(PROJ2).select(); shell.bot().button(IDialogConstants.NEXT_LABEL).click(); assertEquals(PROJ2, shell.bot() .textWithLabel( UIText.GitCreateGeneralProjectPage_ProjectNameLabel) .getText()); shell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(Conditions.shellCloses(shell)); assertProjectExistence(PROJ2, true); assertProjectIsShared(PROJ2, true); } @Test public void testImportWizardGeneralProjectWithWorkingSet() throws Exception { removeSmartImportWizardToForceGitImportWizardUsage(); deleteAllProjects(); assertProjectExistence(PROJ1, false); String workingSetName = "myWorkingSet"; removeWorkingSet(workingSetName); SWTBotTree tree = getOrOpenView().bot().tree(); String wizardTitle = NLS.bind( UIText.GitCreateProjectViaWizardWizard_WizardTitle, repositoryFile.getPath()); // start wizard from PROJ1 TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)) .getNode(PROJ1).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("ImportProjectsCommand")); SWTBotShell shell = bot.shell(wizardTitle); shell = bot.shell(wizardTitle); // try import existing project first bot.radio(UIText.GitSelectWizardPage_ImportExistingButton).click(); SWTBotButton button = shell.bot().button(IDialogConstants.NEXT_LABEL); // Set focus on the next button. If this is not done, Wizard Framework // restores // the focus to the "Import as &General Project" radio button. Setting // the focus on // the radio button selects the button and causes the test to fail. // See also SWTBot Bug 337465 button.setFocus(); button.click(); assertWizardDialogMessage(shell.bot(), UIText.WizardProjectsImportPage_ImportProjectsDescription); shell.bot().tree().getAllItems()[0].check(); // add to working set shell.bot().checkBox("Add project to working sets").select(); // create new working set shell.bot().button("Select...").click(); SWTBotShell workingSetDialog = bot.shell("Select Working Sets"); workingSetDialog.bot().button("New...").click(); SWTBotShell newDialog = bot.shell("New Working Set"); newDialog.bot().table().select("Java"); newDialog.bot().button(IDialogConstants.NEXT_LABEL).click(); newDialog.bot().text(0).setText(workingSetName); newDialog.bot().button(IDialogConstants.FINISH_LABEL).click(); workingSetDialog.bot().table().getTableItem(workingSetName).check(); workingSetDialog.bot().button(IDialogConstants.OK_LABEL).click(); shell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(Conditions.shellCloses(shell)); assertProjectExistence(PROJ1, true); assertProjectInWorkingSet(workingSetName, PROJ1); assertProjectIsShared(PROJ1, true); removeWorkingSet(workingSetName); } private void assertProjectInWorkingSet(String workingSetName, String projectName) { IWorkingSetManager workingSetManager = PlatformUI.getWorkbench() .getWorkingSetManager(); IWorkingSet workingSet = workingSetManager .getWorkingSet(workingSetName); IAdaptable[] elements = workingSet.getElements(); assertEquals("Wrong number of projects in working set", 1, elements.length); IProject project = Adapters.adapt(elements[0], IProject.class); assertEquals("Wrong project in working set", projectName, project.getName()); } private void removeWorkingSet(String name) { IWorkingSetManager workingSetManager = PlatformUI.getWorkbench() .getWorkingSetManager(); IWorkingSet workingSet = workingSetManager.getWorkingSet(name); if (workingSet != null) workingSetManager.removeWorkingSet(workingSet); } private void assertProjectIsShared(String projectName, boolean shouldBeShared) { IProject project = ResourcesPlugin.getWorkspace().getRoot() .getProject(projectName); RepositoryMapping mapping = RepositoryMapping.getMapping(project); if (shouldBeShared) { assertNotNull(mapping); assertNotNull(mapping.getRepository()); } else assertNull(mapping); } @Test public void testLinkWithSelectionNavigator() throws Exception { deleteAllProjects(); shareProjects(repositoryFile); SWTBotTree tree = getOrOpenView().bot().tree(); myRepoViewUtil.getRootItem(tree, repositoryFile).select(); // the selection should be root assertTrue(tree.selection().get(0, 0).contains(REPO1)); SWTBotTree projectExplorerTree = TestUtil.getExplorerTree(); getProjectItem(projectExplorerTree, PROJ1).select(); // the selection should be still be root assertTrue(tree.selection().get(0, 0).contains(REPO1)); // activate the link with selection toggleLinkWithSelection(); // the selection should be project assertTrue(tree.selection().get(0, 0).equals(PROJ1)); } /** * Link with editor, both ways * * @throws Exception */ @Test public void testLinkWithSelectionEditor() throws Exception { deleteAllProjects(); shareProjects(repositoryFile); SWTBotTree tree = getOrOpenView().bot().tree(); myRepoViewUtil.getRootItem(tree, repositoryFile).select(); // the selection should be root assertTrue(tree.selection().get(0, 0).startsWith(REPO1)); SWTBotView view = TestUtil.showExplorerView(); SWTBotTree projectExplorerTree = view.bot().tree(); SWTBotTreeItem item = TestUtil .expandAndWait(getProjectItem(projectExplorerTree, PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)).getNode(FILE1); view.show(); item.doubleClick(); item = TestUtil .expandAndWait(getProjectItem(projectExplorerTree, PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)).getNode(FILE2); view.show(); item.doubleClick(); // now we should have two editors // the selection should be still be root assertTrue(tree.selection().get(0, 0).startsWith(REPO1)); // activate the link with selection toggleLinkWithSelection(); bot.editorByTitle(FILE2).show(); // the selection should have changed to the latest editor TestUtil.waitUntilTreeHasSelectedNodeWithText(bot, tree, FILE2, 10000); bot.editorByTitle(FILE1).show(); // selection should have changed TestUtil.waitUntilTreeHasSelectedNodeWithText(bot, tree, FILE1, 10000); // deactivate the link with editor toggleLinkWithSelection(); bot.editorByTitle(FILE2).show(); // the selection should be still be test.txt TestUtil.waitUntilTreeHasSelectedNodeWithText(bot, tree, FILE1, 10000); bot.editorByTitle(FILE1).show(); item = TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)); item = TestUtil.expandAndWait(item.getNode(PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)); item.getNode(FILE2).select(); // the editor should still be test.txt assertEquals(FILE1, bot.activeEditor().getTitle()); // activate again toggleLinkWithSelection(); item = TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)); item = TestUtil.expandAndWait(item.getNode(PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)); item.getNode(FILE2).select(); TestUtil.waitUntilEditorIsActive(bot, bot.editorByTitle(FILE2), 10000); item = TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)); item = TestUtil.expandAndWait(item.getNode(PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)); item.getNode(FILE1).select(); TestUtil.waitUntilEditorIsActive(bot, bot.editorByTitle(FILE1), 10000); // deactivate the link with editor toggleLinkWithSelection(); item = TestUtil.expandAndWait( myRepoViewUtil.getWorkdirItem(tree, repositoryFile)); item = TestUtil.expandAndWait(item.getNode(PROJ1)); item = TestUtil.expandAndWait(item.getNode(FOLDER)); item.getNode(FILE2).select(); TestUtil.waitUntilEditorIsActive(bot, bot.editorByTitle(FILE1), 10000); } @Test public void testDeleteSingleBranch() throws Exception { // expand first level SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); // create a branch (no checkout) SWTBotTreeItem localBranchesItem = TestUtil.expandAndWait( myRepoViewUtil.getLocalBranchesItem(tree, repositoryFile)); SWTBotTreeItem masterNode = localBranchesItem.getNode("master"); masterNode.select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("RepoViewCreateBranch.label")); SWTBotShell createBranchShell = bot .shell(UIText.CreateBranchWizard_NewBranchTitle); createBranchShell.bot().textWithId("BranchName").setText("abc"); createBranchShell.bot().checkBox(UIText.CreateBranchPage_CheckoutButton) .deselect(); createBranchShell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(shellCloses(createBranchShell), 10000); refreshAndWait(); // delete branch // lookup node again. Widget might have changed due to refresh localBranchesItem = TestUtil.expandAndWait( myRepoViewUtil.getLocalBranchesItem(tree, repositoryFile)); localBranchesItem.getNode("abc").select(); ContextMenuHelper.clickContextMenuSync(tree, myUtil.getPluginLocalizedValue("RepoViewDeleteBranch.label")); refreshAndWait(); SWTBotTreeItem[] items = myRepoViewUtil .getLocalBranchesItem(tree, repositoryFile).getItems(); assertEquals("Wrong number of branches", 2, items.length); assertEquals("master", items[0].getText()); assertEquals("stable", items[1].getText()); } @Test public void testDeleteBranchMultiple() throws Exception { // expand first level SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); // open a branch (checkout) SWTBotTreeItem localBranchesItem = TestUtil.expandAndWait( myRepoViewUtil.getLocalBranchesItem(tree, repositoryFile)); SWTBotTreeItem masterNode = localBranchesItem.getNode("master"); // create first branch (abc) masterNode.select(); ContextMenuHelper.clickContextMenu(tree, "Create Branch..."); SWTBotShell createBranchShell = bot .shell(UIText.CreateBranchWizard_NewBranchTitle); createBranchShell.bot().textWithId("BranchName").setText("abc"); createBranchShell.bot().checkBox(UIText.CreateBranchPage_CheckoutButton) .deselect(); createBranchShell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(shellCloses(createBranchShell), 10000); refreshAndWait(); // create second branch (123) ContextMenuHelper.clickContextMenu(tree, "Create Branch..."); createBranchShell = bot.shell(UIText.CreateBranchWizard_NewBranchTitle); SWTBotText bn = createBranchShell.bot().textWithId("BranchName"); bn.setText("123"); createBranchShell.bot().checkBox(UIText.CreateBranchPage_CheckoutButton) .deselect(); createBranchShell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(shellCloses(createBranchShell), 10000); refreshAndWait(); localBranchesItem = TestUtil.expandAndWait( myRepoViewUtil.getLocalBranchesItem(tree, repositoryFile)); // delete both localBranchesItem.select("abc", "123"); ContextMenuHelper.clickContextMenuSync(tree, myUtil.getPluginLocalizedValue("RepoViewDeleteBranch.label")); refreshAndWait(); SWTBotTreeItem[] items = myRepoViewUtil .getLocalBranchesItem(tree, repositoryFile).getItems(); assertEquals("Wrong number of branches", 2, items.length); assertEquals("master", items[0].getText()); assertEquals("stable", items[1].getText()); } @Test public void testDeleteFileInProject() throws Exception { SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); IProject project1 = ResourcesPlugin.getWorkspace().getRoot() .getProject(PROJ1); // Make sure that the refresh doesn't happen on delete and cause a // timeout project1.refreshLocal(IResource.DEPTH_INFINITE, null); SWTBotTreeItem folder = findWorkdirNode(tree, PROJ1, FOLDER); folder.getNode(FILE1).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("RepoViewDeleteFile.label")); SWTBotShell confirm = bot.shell("Delete Resources"); confirm.bot().button(IDialogConstants.OK_LABEL).click(); bot.waitUntil(shellCloses(confirm)); TestUtil.joinJobs(JobFamilies.REPO_VIEW_REFRESH); folder = findWorkdirNode(tree, PROJ1, FOLDER); assertThat(folder.getNodes(), not(hasItem(FILE1))); assertThat(folder.getNodes(), hasItem(FILE2)); } @Test public void testDeleteFileNotInProject() throws Exception { // PROJ2 is still a valid Eclipse project at that point, even though the // .project file wasn't committed. Close it. ResourcesPlugin.getWorkspace().getRoot().getProject(PROJ2).close(null); SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); SWTBotTreeItem folder = findWorkdirNode(tree, PROJ2, FOLDER); int n = folder.getNodes().size(); folder.getNode(FILE1).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("RepoViewDeleteFile.label")); SWTBotShell confirm = bot .shell(UIText.DeletePathsOperationUI_confirmActionTitle); confirm.bot().button(UIText.DeletePathsOperationUI_ButtonOK).click(); bot.waitUntil(shellCloses(confirm)); bot.waitUntil(new DefaultCondition() { @Override public boolean test() throws Exception { SWTBotTreeItem item = findWorkdirNode(tree, PROJ2, FOLDER); return item.getNodes().size() == n - 1; } @Override public String getFailureMessage() { return "File deletion not reflected in repo view tree within timout"; } }, 20000); folder = findWorkdirNode(tree, PROJ2, FOLDER); assertThat(folder.getNodes(), not(hasItem(FILE1))); assertThat(folder.getNodes(), hasItem(FILE2)); } @Test public void testStashDeleteCreate() throws Exception { Repository repo = lookupRepository(repositoryFile); IFile file = touch("Something"); new StashCreateOperation(repo, "First stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); touch("Something else"); new StashCreateOperation(repo, "Second stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); touch("Something else again"); new StashCreateOperation(repo, "Third stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); SWTBotTreeItem item = myRepoViewUtil.getStashesItem(tree, repositoryFile); item = TestUtil.expandAndWait(item); assertEquals("Unexpected number of stashed commits", 3, item.getItems().length); item.getNode(0).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("StashDropCommand.label")); SWTBotShell confirm = bot.shell(UIText.StashDropCommand_confirmTitle); confirm.bot().button(UIText.StashDropCommand_buttonDelete).click(); bot.waitUntil(shellCloses(confirm)); TestUtil.joinJobs(JobFamilies.STASH); TestUtil.joinJobs(JobFamilies.REPO_VIEW_REFRESH); touch("Something different"); tree.getAllItems()[0].select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("StashesMenu.label"), UIText.StashesMenu_StashChangesActionText); confirm = bot.shell(UIText.StashCreateCommand_titleEnterCommitMessage); confirm.bot().button(UIText.StashCreateCommand_ButtonOK).click(); bot.waitUntil(shellCloses(confirm)); TestUtil.joinJobs(JobFamilies.STASH); TestUtil.joinJobs(JobFamilies.REPO_VIEW_REFRESH); item = myRepoViewUtil.getStashesItem(tree, repositoryFile); assertStashes(item.getItems(), 3); } @Test public void testStashDeleteMultiple() throws Exception { Repository repo = lookupRepository(repositoryFile); IFile file = touch("Something"); new StashCreateOperation(repo, "First stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); touch("Something else"); new StashCreateOperation(repo, "Second stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); touch("Something else again"); new StashCreateOperation(repo, "Third stash").execute(null); file.refreshLocal(IResource.DEPTH_ZERO, null); SWTBotTree tree = getOrOpenView().bot().tree(); refreshAndWait(); SWTBotTreeItem item = myRepoViewUtil.getStashesItem(tree, repositoryFile); item = TestUtil.expandAndWait(item); assertEquals("Unexpected number of stashed commits", 3, item.getItems().length); item.select(1, 2); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("StashDropCommand.label")); SWTBotShell confirm = bot.shell(UIText.StashDropCommand_confirmTitle); confirm.bot().button(UIText.StashDropCommand_buttonDelete).click(); bot.waitUntil(shellCloses(confirm)); TestUtil.joinJobs(JobFamilies.STASH); TestUtil.joinJobs(JobFamilies.REPO_VIEW_REFRESH); item = myRepoViewUtil.getStashesItem(tree, repositoryFile); assertStashes(item.getItems(), 1, "Third stash"); } private void assertStashes(SWTBotTreeItem[] children, int expectedSize, String... decorations) throws Exception { assertEquals("Expected " + expectedSize + " children", expectedSize, children.length); if (decorations != null && decorations.length > 0) { TestUtil.waitForDecorations(); } int[] indices = new int[expectedSize]; int[] expectedIndices = new int[expectedSize]; for (int i = 0; i < indices.length; i++) { indices[i] = -1; expectedIndices[i] = i; } children[0].display.syncExec(() -> { int j = 0; for (SWTBotTreeItem child : children) { Object data = child.widget.getData(); if (data instanceof StashedCommitNode) { indices[j++] = ((StashedCommitNode) data).getIndex(); } } }); assertArrayEquals("Unexpected stash indices", expectedIndices, indices); for (int i = 0; i < children.length; i++) { String text = children[i].getText(); assertTrue("Stash " + i + " has wrong label: " + text, text.startsWith("stash@{" + i + "}")); if (decorations != null && i < decorations.length) { String deco = decorations[i]; if (deco != null) { assertTrue("Label should contain '" + deco + "': " + text, text.contains(deco)); } } } } private void toggleLinkWithSelection() throws Exception { getOrOpenView().toolbarButton( myUtil.getPluginLocalizedValue( "RepoViewLinkWithSelection.tooltip")) .click(); } private SWTBotTreeItem findWorkdirNode(SWTBotTree tree, String... nodes) throws Exception { SWTBotTreeItem item = myRepoViewUtil.getWorkdirItem(tree, repositoryFile); for (String node : nodes) { item = TestUtil.expandAndWait(item).getNode(node); } return item.expand(); } }