/******************************************************************************* * Copyright (c) 2010, 2016 SAP AG 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: * Mathias Kinzler (SAP AG) - initial implementation * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 499482 *******************************************************************************/ package org.eclipse.egit.ui.view.repositories; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.text.MessageFormat; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.commands.State; import org.eclipse.egit.core.RepositoryUtil; import org.eclipse.egit.core.op.BranchOperation; import org.eclipse.egit.core.op.CloneOperation; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.internal.CommonUtils; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator; import org.eclipse.egit.ui.internal.repository.tree.command.ToggleBranchHierarchyCommand; import org.eclipse.egit.ui.test.ContextMenuHelper; import org.eclipse.egit.ui.test.TestUtil; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.events.ConfigChangedEvent; import org.eclipse.jgit.events.ConfigChangedListener; import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.transport.URIish; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; import org.eclipse.swtbot.swt.finder.SWTBot; import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; import org.eclipse.swtbot.swt.finder.waits.Conditions; 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.PlatformUI; import org.eclipse.ui.commands.ICommandService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * SWTBot Tests for the Git Repositories View (mainly branch operations) */ @RunWith(SWTBotJunit4ClassRunner.class) public class GitRepositoriesViewBranchHandlingTest extends GitRepositoriesViewTestBase { private File repositoryFile; private File remoteRepositoryFile; private File clonedRepositoryFile; @Before public void setUp() throws Exception { clearView(); setVerboseBranchMode(false); repositoryFile = createProjectAndCommitToRepository(); remoteRepositoryFile = createRemoteRepository(repositoryFile); // now let's clone the remote repository final URIish uri = new URIish(remoteRepositoryFile.getPath()); final File workdir = new File(getTestDirectory(), "Cloned"); CloneOperation op = new CloneOperation(uri, true, null, workdir, "refs/heads/master", "origin", 0); op.run(null); clonedRepositoryFile = new File(workdir, Constants.DOT_GIT); RepositoryUtil repositoryUtil = Activator.getDefault() .getRepositoryUtil(); repositoryUtil.addConfiguredRepository(repositoryFile); repositoryUtil.addConfiguredRepository(remoteRepositoryFile); repositoryUtil.addConfiguredRepository(clonedRepositoryFile); } @Test public void testCreateCheckoutDeleteLocalBranch() throws Exception { final SWTBotView view = getOrOpenView(); SWTBotTreeItem localItem = myRepoViewUtil.getLocalBranchesItem(view .bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 1, localItem.getNodes().size()); assertEquals("master", localItem.getNodes().get(0)); localItem.getNode(0).select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil .getPluginLocalizedValue("CreateBranchCommand")); SWTBotShell createPage = bot .shell(UIText.CreateBranchWizard_NewBranchTitle); createPage.activate(); // getting text with label doesn't work createPage.bot().textWithId("BranchName").setText("newLocal"); createPage.bot().checkBox(UIText.CreateBranchPage_CheckoutButton) .deselect(); createPage.bot().button(IDialogConstants.FINISH_LABEL).click(); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 2, localItem.getNodes().size()); localItem.getNode(0).select(); assertCheckoutNotAvailable(view); localItem.getNode(1).select(); ContextMenuHelper.clickContextMenuSync(view.bot().tree(), myUtil .getPluginLocalizedValue("CheckoutCommand")); TestUtil.joinJobs(JobFamilies.CHECKOUT); assertCheckoutNotAvailable(view); localItem.getNode(0).select(); ContextMenuHelper.clickContextMenuSync(view.bot().tree(), myUtil .getPluginLocalizedValue("CheckoutCommand")); TestUtil.joinJobs(JobFamilies.CHECKOUT); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); localItem.getNode(1).select(); ContextMenuHelper.clickContextMenuSync(view.bot().tree(), myUtil .getPluginLocalizedValue("RepoViewDeleteBranch.label")); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 1, localItem.getNodes().size()); } private void assertCheckoutNotAvailable(final SWTBotView view) { assertFalse("Checkout context menu item should not exist", ContextMenuHelper.contextMenuItemExists(view.bot().tree(), myUtil.getPluginLocalizedValue("CheckoutCommand"))); } @Test public void testCreateDeleteLocalBranchWithUnmerged() throws Exception { final SWTBotView view = getOrOpenView(); SWTBotTreeItem localItem = myRepoViewUtil.getLocalBranchesItem(view .bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 1, localItem.getNodes().size()); assertEquals("master", localItem.getNodes().get(0)); localItem.getNode(0).select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil .getPluginLocalizedValue("CreateBranchCommand")); SWTBotShell createPage = bot .shell(UIText.CreateBranchWizard_NewBranchTitle); createPage.activate(); // getting text with label doesn't work createPage.bot().textWithId("BranchName").setText("newLocal"); createPage.bot().checkBox(UIText.CreateBranchPage_CheckoutButton) .select(); createPage.bot().button(IDialogConstants.FINISH_LABEL).click(); TestUtil.joinJobs(JobFamilies.CHECKOUT); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 2, localItem.getNodes().size()); touchAndSubmit("Some more changes"); localItem.getNode(1).select(); assertCheckoutNotAvailable(view); localItem.getNode(0).select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil .getPluginLocalizedValue("CheckoutCommand")); TestUtil.joinJobs(JobFamilies.CHECKOUT); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); localItem.getNode(1).select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil .getPluginLocalizedValue("RepoViewDeleteBranch.label")); SWTBotShell confirmPopup = bot .shell(UIText.UnmergedBranchDialog_Title); confirmPopup.activate(); confirmPopup.bot().button(IDialogConstants.OK_LABEL).click(); refreshAndWait(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), repositoryFile); TestUtil.expandAndWait(localItem); assertEquals("Wrong number of children", 1, localItem.getNodes().size()); } @Test public void testClonedRepository() throws Exception { SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = TestUtil.expandAndWait(myRepoViewUtil .getLocalBranchesItem(tree, clonedRepositoryFile)); List<String> children = item.getNodes(); assertEquals("Wrong number of local children", 1, children.size()); item = TestUtil.expandAndWait(myRepoViewUtil.getRemoteBranchesItem(tree, clonedRepositoryFile)); children = item.getNodes(); assertEquals("Wrong number of children", 2, children.size()); assertTrue("Missing remote branch", children.contains("origin/master")); assertTrue("Missing remote branch", children.contains("origin/stable")); item.getNode("origin/stable").select(); ContextMenuHelper.clickContextMenu(tree, myUtil .getPluginLocalizedValue("CreateBranchCommand")); SWTBotShell shell = bot.shell(UIText.CreateBranchWizard_NewBranchTitle); shell.activate(); assertEquals("stable", shell.bot().textWithId("BranchName").getText()); shell.bot().button(IDialogConstants.FINISH_LABEL).click(); bot.waitUntil(Conditions.shellCloses(shell)); refreshAndWait(); item = TestUtil.expandAndWait(myRepoViewUtil.getLocalBranchesItem(tree, clonedRepositoryFile)); children = item.getNodes(); assertEquals("Wrong number of local children", 2, children.size()); } @Test public void testCheckoutRemote() throws Exception { Repository repo = lookupRepository(clonedRepositoryFile); BranchOperation bop = new BranchOperation(repo, "refs/heads/master"); bop.execute(null); assertEquals("master", repo.getBranch()); SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = myRepoViewUtil.getLocalBranchesItem(tree, clonedRepositoryFile).expand(); touchAndSubmit(null); refreshAndWait(); item = TestUtil.expandAndWait(myRepoViewUtil.getRemoteBranchesItem(tree, clonedRepositoryFile)); List<String> children = item.getNodes(); assertEquals("Wrong number of remote children", 2, children.size()); item.getNode("origin/stable").select(); ContextMenuHelper.clickContextMenuSync(tree, myUtil.getPluginLocalizedValue("CheckoutCommand")); TestUtil.joinJobs(JobFamilies.CHECKOUT); refreshAndWait(); GitLightweightDecorator.refresh(); assertTrue("Branch should not be symbolic", ObjectId.isId(lookupRepository(clonedRepositoryFile) .getBranch())); // now let's try to create a local branch from the remote one item = myRepoViewUtil.getRemoteBranchesItem(tree, clonedRepositoryFile); TestUtil.expandAndWait(item).getNode("origin/stable").select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("CreateBranchCommand")); SWTBotShell createPage = bot .shell(UIText.CreateBranchWizard_NewBranchTitle); createPage.activate(); assertEquals("Wrong suggested branch name", "stable", createPage.bot() .textWithId("BranchName").getText()); createPage.close(); // checkout master again item = myRepoViewUtil.getLocalBranchesItem(tree, clonedRepositoryFile); TestUtil.expandAndWait(item).getNode("master").select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("CheckoutCommand")); TestUtil.joinJobs(JobFamilies.CHECKOUT); refreshAndWait(); } @Test public void testRenameBranch() throws Exception { SWTBotTree tree = getOrOpenView().bot().tree(); SWTBotTreeItem item = TestUtil.expandAndWait(myRepoViewUtil .getLocalBranchesItem(tree, clonedRepositoryFile)); item.getNode("master").select(); ContextMenuHelper.clickContextMenu(tree, myUtil .getPluginLocalizedValue("RepoViewRenameBranch.label")); refreshAndWait(); SWTBotShell renameDialog = bot .shell(UIText.BranchRenameDialog_WindowTitle); SWTBotText newBranchNameText = renameDialog.bot().textWithLabel(UIText.BranchRenameDialog_NewNameLabel); newBranchNameText.setText("invalid~name"); renameDialog.bot().text(" " + // the text is now in the error message, and the MessageAreaDialog seems to add a space NLS.bind(UIText.ValidationUtils_InvalidRefNameMessage, "refs/heads/invalid~name")); assertFalse(renameDialog.bot().button(IDialogConstants.OK_LABEL) .isEnabled()); newBranchNameText.setText("newmaster"); renameDialog.bot().button(IDialogConstants.OK_LABEL).click(); refreshAndWait(); item = TestUtil.expandAndWait(myRepoViewUtil.getLocalBranchesItem(tree, clonedRepositoryFile)); assertEquals("newmaster", item.getNode(0).select().getText()); ContextMenuHelper.clickContextMenu(tree, myUtil .getPluginLocalizedValue("RepoViewRenameBranch.label")); refreshAndWait(); renameDialog = bot.shell(UIText.BranchRenameDialog_WindowTitle); newBranchNameText = renameDialog.bot().text(0); newBranchNameText.setText("master"); renameDialog.bot().button(IDialogConstants.OK_LABEL).click(); refreshAndWait(); item = TestUtil.expandAndWait(myRepoViewUtil.getLocalBranchesItem(tree, clonedRepositoryFile)); assertEquals("master", item.getNode(0).select().getText()); } @Test public void testMergeOnRepo() throws Exception { SWTBotTree tree = getOrOpenView().bot().tree(); myRepoViewUtil.getRootItem(tree, clonedRepositoryFile).select(); ContextMenuHelper.clickContextMenu(tree, myUtil .getPluginLocalizedValue("RepoViewMerge.label")); String title = NLS.bind( UIText.MergeTargetSelectionDialog_TitleMergeWithBranch, FileRepositoryBuilder.create(clonedRepositoryFile).getBranch()); SWTBotShell mergeDialog = bot.shell(title); // TODO do some merge here mergeDialog.close(); } @Test public void testRebaseDialogOnRepo() throws Exception { ICommandService srv = CommonUtils.getService(PlatformUI.getWorkbench(), ICommandService.class); State commandState = srv.getCommand(ToggleBranchHierarchyCommand.ID) .getState(ToggleBranchHierarchyCommand.TOGGLE_STATE); Boolean isHierarchical = (Boolean) commandState.getValue(); commandState.setValue(Boolean.TRUE); try { SWTBotTree tree = getOrOpenView().bot().tree(); myRepoViewUtil.getRootItem(tree, clonedRepositoryFile).select(); ContextMenuHelper.clickContextMenu(tree, myUtil.getPluginLocalizedValue("RebaseCommand.label2")); String title = MessageFormat.format( UIText.RebaseTargetSelectionDialog_RebaseTitleWithBranch, FileRepositoryBuilder.create(clonedRepositoryFile) .getBranch()); SWTBotShell targetSelectionDialog = bot.shell(title); SWTBot dialogBot = targetSelectionDialog.bot(); SWTBotTree dialogTree = dialogBot.tree(); assertEquals("Should have a node selected", 1, dialogTree.selectionCount()); String[] result = { null }; PlatformUI.getWorkbench().getDisplay().syncExec(() -> { TreeItem[] selected = dialogTree.widget.getSelection(); result[0] = selected[0].getText(); }); assertTrue("master node should be selected", result[0] != null && result[0].contains("master")); targetSelectionDialog.close(); } finally { commandState.setValue(isHierarchical); } } @Test public void testBranchConfiguration() throws Exception { Repository repo = lookupRepository(clonedRepositoryFile); try (Git git = new Git(repo)) { git.branchCreate().setName("configTest") .setStartPoint("refs/remotes/origin/master") .setUpstreamMode(SetupUpstreamMode.TRACK).call(); } BranchRebaseMode rebase = repo.getConfig().getEnum( BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "configTest", ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE); assertEquals(BranchRebaseMode.NONE, rebase); SWTBotView view = getOrOpenView(); SWTBotTreeItem localItem = myRepoViewUtil.getLocalBranchesItem(view .bot().tree(), clonedRepositoryFile); TestUtil.expandAndWait(localItem).getNode("configTest").select(); ContextMenuHelper.clickContextMenuSync(view.bot().tree(), myUtil.getPluginLocalizedValue("ShowIn"), "Properties"); SWTBotView propsView = bot.viewById(IPageLayout.ID_PROP_SHEET); SWTBotTreeItem rootItem = propsView .bot() .tree() .getTreeItem( UIText.BranchPropertySource_UpstreamConfigurationCategory); SWTBotTreeItem rebaseItem = TestUtil.expandAndWait(rootItem) .getNode(UIText.BranchPropertySource_RebaseDescriptor); assertEquals(UIText.BranchPropertySource_ValueNotSet, rebaseItem.cell(1)); SWTBotTreeItem remoteItem = rootItem .getNode(UIText.BranchPropertySource_RemoteDescriptor); assertEquals("origin", remoteItem.cell(1)); SWTBotTreeItem upstreamItem = rootItem .getNode(UIText.BranchPropertySource_UpstreamBranchDescriptor); assertEquals("refs/heads/master", upstreamItem.cell(1)); view = getOrOpenView(); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), clonedRepositoryFile); TestUtil.expandAndWait(localItem).getNode("configTest").select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil.getPluginLocalizedValue("ConfigurBranchCommand.label")); SWTBotShell configureBranchDialog = bot .shell(UIText.BranchConfigurationDialog_BranchConfigurationTitle); assertEquals(MessageFormat.format( UIText.BranchConfigurationDialog_EditBranchConfigMessage, "configTest"), configureBranchDialog.bot().text().getText()); assertEquals( "refs/heads/master", configureBranchDialog .bot() .comboBoxWithLabel( UIText.BranchConfigurationDialog_UpstreamBranchLabel) .getText()); assertEquals( "origin", configureBranchDialog .bot() .comboBoxWithLabel( UIText.BranchConfigurationDialog_RemoteLabel) .getText()); assertEquals(UIText.BranchRebaseMode_None, configureBranchDialog.bot() .comboBoxWithLabel( UIText.BranchRebaseModeCombo_RebaseModeLabel) .getText()); configureBranchDialog.bot() .comboBoxWithLabel( UIText.BranchRebaseModeCombo_RebaseModeLabel) .setSelection(0); // add a listener to wait for the configuration changed event final AtomicBoolean changed = new AtomicBoolean(); ConfigChangedListener listener = new ConfigChangedListener() { @Override public void onConfigChanged(ConfigChangedEvent event) { changed.set(true); } }; ListenerHandle handle = repo.getConfig().addChangeListener(listener); // only now click ok configureBranchDialog.bot().button("OK").click(); // cleanup behind ourselves handle.remove(); if (!changed.get()) fail("We should have received a config change event"); refreshAndWait(); // Repo view updates itself after config change. rebase = repo.getConfig().getEnum(BranchRebaseMode.values(), ConfigConstants.CONFIG_BRANCH_SECTION, "configTest", ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE); assertEquals(BranchRebaseMode.REBASE, rebase); localItem = myRepoViewUtil.getLocalBranchesItem(view.bot().tree(), clonedRepositoryFile); TestUtil.expandAndWait(localItem).getNode("configTest").select(); ContextMenuHelper.clickContextMenu(view.bot().tree(), myUtil.getPluginLocalizedValue("ShowIn"), "Properties"); propsView = bot.viewById(IPageLayout.ID_PROP_SHEET); rootItem = propsView .bot() .tree() .getTreeItem( UIText.BranchPropertySource_UpstreamConfigurationCategory); rebaseItem = TestUtil.expandAndWait(rootItem) .getNode(UIText.BranchPropertySource_RebaseDescriptor); assertEquals("true", rebaseItem.cell(1)); } }