Skip to content

Content of file SwitchToMenuTest.java

/******************************************************************************
 *  Copyright (c) 2014, 2019 Tasktop Technologies 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:
 *    Tomasz Zarna (Tasktop) - initial API and implementation
 *    Simon Muschel <smuschel@gmx.de - Bug 451087
 *****************************************************************************/
package org.eclipse.egit.ui.internal.actions;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.common.LocalRepositoryTestCase;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.test.ContextMenuHelper;
import org.eclipse.egit.ui.test.TestUtil;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
import org.eclipse.ui.ISources;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import org.junit.Before;
import org.junit.Test;

public class SwitchToMenuTest extends LocalRepositoryTestCase {

	private static final String TEAM_LABEL = util
			.getPluginLocalizedValue("TeamMenu.label");

	private static final String SWITCH_TO_LABEL_MULTIPLE = util
			.getPluginLocalizedValue("SwitchToMenuMultiple.label");

	private SwitchToMenu switchToMenu;

	private IHandlerService handlerService;

	@Before
	public void setUp() throws Exception {
		switchToMenu = new SwitchToMenu();
		handlerService = mock(IHandlerService.class);
		IServiceLocator serviceLocator = mock(IServiceLocator.class);
		when(serviceLocator.getService(IHandlerService.class))
				.thenReturn(handlerService);
		switchToMenu.initialize(serviceLocator);
	}

	@Test
	public void emptySelection() {
		mockSelection(new EmptySelection());

		MenuItem[] items = fillMenu();

		assertEquals(0, items.length);
	}

	@Test
	public void selectionNotAdaptableToRepository() {
		mockSelection(new StructuredSelection(new Object()));

		MenuItem[] items = fillMenu();

		assertEquals(0, items.length);
	}

	@Test
	public void selectionWithProj1() throws Exception {
		createProjectAndCommitToRepository();
		selectionWithProj1Common();
	}

	@Test
	public void selectionWithProj1AndReflog() throws Exception {
		File gitDir = createProjectAndCommitToRepository();

		// create additional reflog entries
		try (Git git = new Git(lookupRepository(gitDir))) {
			git.checkout().setName("stable").call();
			git.checkout().setName("master").call();
		}

		selectionWithProj1Common();

		// delete reflog again to not confuse other tests
		assertTrue(new File(gitDir, Constants.LOGS + "/" + Constants.HEAD)
				.delete());
	}

	@Test
	public void selectionWithCorruptedReflog() throws Exception {
		File gitDir = createProjectAndCommitToRepository();

		// create additional reflog entries
		try (Git git = new Git(lookupRepository(gitDir))) {
			git.checkout().setName("stable").call();
			git.checkout().setName("master").call();
		}

		// Corrupt the reflog
		File reflog = new File(gitDir, Constants.LOGS + "/" + Constants.HEAD);
		List<String> lines = Files.readAllLines(reflog.toPath());
		assertTrue("Expected some lines in the reflog", lines.size() > 1);
		lines.add(1,
				"INTENTIONALLY CORRUPTED REFLOG. Just some text that definitely shouldn't be in a reflog.");
		Files.write(reflog.toPath(), lines);

		selectionWithProj1Common();

		assertTrue(reflog.delete());
	}

	private void selectionWithProj1Common() {
		IProject project = ResourcesPlugin.getWorkspace().getRoot()
				.getProject(PROJ1);
		mockSelection(new StructuredSelection(project));

		MenuItem[] items = fillMenu();

		assertEquals(7, items.length);
		assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]);
		assertStyleEquals(SWT.SEPARATOR, items[1]);
		assertTextEquals("master", items[2]);
		assertTextEquals("stable", items[3]);
		assertStyleEquals(SWT.SEPARATOR, items[4]);
		assertTextEquals(UIText.SwitchToMenu_CommitMenuLabel, items[5]);
		assertTextEquals(UIText.SwitchToMenu_OtherMenuLabel, items[6]);
	}

	@Test
	public void selectionWithRepositoryHavingOver20Branches() throws Exception {
		Repository repo = lookupRepository(
				createProjectAndCommitToRepository());
		for (int i = 0; i < SwitchToMenu.MAX_NUM_MENU_ENTRIES; i++) {
			createBranch(repo, "refs/heads/change/" + i);
		}
		IProject project = ResourcesPlugin.getWorkspace().getRoot()
				.getProject(PROJ1);
		mockSelection(new StructuredSelection(project));

		MenuItem[] items = fillMenu();

		assertEquals(25, items.length);
		assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]);
		assertStyleEquals(SWT.SEPARATOR, items[1]);
		assertTextEquals("change/0", items[2]);
		assertTextEquals("change/1", items[3]);
		assertTextEquals("change/2", items[4]);
		assertTextEquals("change/3", items[5]);
		assertTextEquals("change/4", items[6]);
		assertTextEquals("change/5", items[7]);
		assertTextEquals("change/6", items[8]);
		assertTextEquals("change/7", items[9]);
		assertTextEquals("change/8", items[10]);
		assertTextEquals("change/9", items[11]);
		assertTextEquals("change/10", items[12]);
		assertTextEquals("change/11", items[13]);
		assertTextEquals("change/12", items[14]);
		assertTextEquals("change/13", items[15]);
		assertTextEquals("change/14", items[16]);
		assertTextEquals("change/15", items[17]);
		assertTextEquals("change/16", items[18]);
		assertTextEquals("change/17", items[19]);
		assertTextEquals("change/18", items[20]);
		assertTextEquals("change/19", items[21]);
		// "master" and "stable" didn't make it
		assertStyleEquals(SWT.SEPARATOR, items[22]);
		assertTextEquals(UIText.SwitchToMenu_CommitMenuLabel, items[23]);
		assertTextEquals(UIText.SwitchToMenu_OtherMenuLabel, items[24]);
	}

	@Test
	public void validateMenuEntriesForMultiSelectionWithMultipleRepositories()
			throws Exception {
		File gitOne = createProjectAndCommitToRepository(REPO1, PROJ1);
		File gitTwo = createProjectAndCommitToRepository(REPO2, PROJ2);

		Repository repoOne = lookupRepository(gitOne);
		Repository repoTwo = lookupRepository(gitTwo);
		for (int i = 0; i < SwitchToMenu.MAX_NUM_MENU_ENTRIES; i++) {
			createBranch(repoOne, "refs/heads/change/" + i);
			createBranch(repoTwo, "refs/heads/change/" + (i + 15));
		}

		mockMultiProjectSelection(PROJ1, PROJ2);

		MenuItem[] items = fillMenu();
		assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]);
		// item[1] is separator
		assertTextEquals("change/15", items[2]);
		assertTextEquals("change/16", items[3]);
		assertTextEquals("change/17", items[4]);
		assertTextEquals("change/18", items[5]);
		assertTextEquals("change/19", items[6]);
		assertTextEquals("master", items[7]);
		assertTextEquals("stable", items[8]);
	}

	@Test
	public void validateBranchSwitchingForForMultiSelectionWithMultipleRepositories()
			throws Exception {

		File gitOne = createProjectAndCommitToRepository(REPO1, PROJ1);
		File gitTwo = createProjectAndCommitToRepository(REPO2, PROJ2);
		Repository repoOne = lookupRepository(gitOne);
		Repository repoTwo = lookupRepository(gitTwo);

		// Set up different branch sources
		try (Git git = new Git(repoOne)) {
			git.checkout().setName("master").call();
		}

		try (Git git = new Git(repoTwo)) {
			git.checkout().setName("stable").call();
		}

		String branchName = "commonBranchAmongRepositories";
		String branchRef = "refs/heads/" + branchName;
		createBranch(repoOne, branchRef);
		createBranch(repoTwo, branchRef);

		assertEquals("master", repoOne.getBranch());
		assertEquals("stable", repoTwo.getBranch());

		// Multi repository Switch To
		SWTBotTree tree = TestUtil.getExplorerTree();
		SWTBotTree select = tree.select(tree.getAllItems());
		ContextMenuHelper.clickContextMenu(select, TEAM_LABEL,
				SWITCH_TO_LABEL_MULTIPLE, branchName);
		TestUtil.joinJobs(JobFamilies.CHECKOUT);

		assertEquals(branchName, repoOne.getBranch());
		assertEquals(branchName, repoTwo.getBranch());
	}

	@Test
	public void multipleSelectionWithMultipleRepositoriesAndNoCommonBranches()
			throws Exception {
		File gitOne = createProjectAndCommitToRepository(REPO1, PROJ1);
		File gitTwo = createProjectAndCommitToRepository(REPO2, PROJ2);

		try (Git git = new Git(lookupRepository(gitOne))) {
			git.checkout().setName("stable").call();
			git.branchDelete().setBranchNames("master").setForce(true).call();
		}

		try (Git git = new Git(lookupRepository(gitTwo))) {
			git.branchDelete().setBranchNames("stable").setForce(true).call();
		}

		mockMultiProjectSelection(PROJ1, PROJ2);

		MenuItem[] items = fillMenu();
		assertTextEquals(UIText.SwitchToMenu_NewBranchMenuLabel, items[0]);
		// item[1] is separator
		assertTextEquals(UIText.SwitchToMenu_NoCommonBranchesFound, items[2]);

		// delete reflog again to not confuse other tests
		new File(gitOne, Constants.LOGS + "/" + Constants.HEAD).delete();
Exceptional return value of java.io.File.delete() ignored in org.eclipse.egit.ui.internal.actions.SwitchToMenuTest.multipleSelectionWithMultipleRepositoriesAndNoCommonBranches()

This method returns a value that is not checked. The return value should be checked since it can indicate an unusual or unexpected function execution. For example, the File.delete() method returns false if the file could not be successfully deleted (rather than throwing an Exception). If you don't check the result, you won't notice if the method invocation signals unexpected behavior by returning an atypical return value.

new File(gitTwo, Constants.LOGS + "/" + Constants.HEAD).delete(); } private void mockSelection(ISelection selection) { EvaluationContext context = new EvaluationContext(null, new Object()); context.addVariable(ISources.ACTIVE_MENU_SELECTION_NAME, selection); when(handlerService.getCurrentState()).thenReturn(context); } private void mockMultiProjectSelection(String... projNames) { List<IProject> projects = new ArrayList<>(); for (String s : projNames) { projects.add( ResourcesPlugin.getWorkspace().getRoot().getProject(s)); } mockSelection(new StructuredSelection(projects)); } private MenuItem[] fillMenu() { final MenuItem[][] items = new MenuItem[1][]; PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { Menu menu = new Menu( new Shell(PlatformUI.getWorkbench().getDisplay())); switchToMenu.fill(menu, 0 /* index */); items[0] = menu.getItems(); } }); return items[0]; } private static class EmptySelection implements ISelection { @Override public boolean isEmpty() { return true; } } private static void assertTextEquals(final String expectedText, final MenuItem item) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { assertEquals(expectedText, item.getText()); } }); } private static void assertStyleEquals(final int expectedStyle, final MenuItem item) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { assertEquals(expectedStyle, item.getStyle()); } }); } }