Skip to content

Content of file GitSubscriberMergeContextTest.java

/*******************************************************************************
 * Copyright (C) 2011, 2012 Benjamin Muskalla <benjamin.muskalla@tasktop.com>
 * 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
 *******************************************************************************/
package org.eclipse.egit.core.synchronize;

import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.util.LinkedHashSet;
import java.util.Set;

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.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.GitCorePreferences;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.core.test.TestRepository;
import org.eclipse.egit.core.test.TestUtils;
import org.eclipse.egit.core.test.models.ModelTestCase;
import org.eclipse.egit.core.test.models.SampleResourceMapping;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.mapping.IMergeContext;
import org.eclipse.team.core.mapping.IMergeStatus;
import org.eclipse.team.core.mapping.IResourceMappingMerger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class GitSubscriberMergeContextTest extends ModelTestCase {

	private static final String MASTER = Constants.R_HEADS + Constants.MASTER;

	private static final String BRANCH = Constants.R_HEADS + "branch";

	private Repository repo;

	private IProject iProject;

	private TestRepository testRepo;

	@Override
	@Before
	public void setUp() throws Exception {
		super.setUp();

		iProject = project.project;
		testRepo = new TestRepository(gitDir);
		testRepo.connect(iProject);
		repo = RepositoryMapping.getMapping(iProject).getRepository();

		// make initial commit
		try (Git git = new Git(repo)) {
			git.commit().setAuthor("JUnit", "junit@jgit.org")
					.setMessage("Initial commit").call();
		}
	}

	@After
	public void clearGitResources() throws Exception {
		testRepo.disconnect(iProject);
		testRepo.dispose();
		repo = null;
		super.tearDown();
	}

	@Test
	public void markAsMerged() throws Exception {
		String fileName = "src/Main.java";
		File file = testRepo.createFile(iProject, fileName);
		testRepo.appendContentAndCommit(iProject, file, "class Main {}",
				"some file");
		testRepo.addToIndex(iProject.getFile(".classpath"));
		testRepo.addToIndex(iProject.getFile(".project"));
		testRepo.commit("project files");

		IFile workspaceFile = testRepo.getIFile(iProject, file);

		testRepo.appendFileContent(file, "some changes");
		Status status = status(repo);
		assertEquals(0, status.getAdded().size());
		assertEquals(1, status.getModified().size());
		String repoRelativePath = testRepo.getRepoRelativePath(workspaceFile
				.getLocation().toPortableString());
		assertTrue(status.getModified().contains(repoRelativePath));

		iProject.refreshLocal(IResource.DEPTH_INFINITE,
				new NullProgressMonitor());

		IMergeContext mergeContext = prepareContext(repo, workspaceFile, HEAD,
				HEAD);
		IDiff node = mergeContext.getDiffTree().getDiff(workspaceFile);
		assertNotNull(node);
		// First of all, "markAsMerged" is not supposed to have any effect on a
		// folder.
		// Second, it should only be used on IDiff obtained from the context,
		// not created for the occasion.
		mergeContext.markAsMerged(node, true, null);

		status = status(repo);
		assertEquals(1, status.getChanged().size());
		assertEquals(0, status.getModified().size());
		assertTrue(status.getChanged().contains(repoRelativePath));
	}

	@Test
	public void mergeNoConflict() throws Exception {
		String fileName = "src/Main.java";
		File file = testRepo.createFile(iProject, fileName);
		final String initialContent = "class Main {}\n";
		testRepo.appendContentAndCommit(iProject, file, initialContent,
				"some file");
		testRepo.addToIndex(iProject.getFile(".classpath"));
		testRepo.addToIndex(iProject.getFile(".project"));
		testRepo.commit("project files");

		IFile workspaceFile = testRepo.getIFile(iProject, file);
		String repoRelativePath = testRepo.getRepoRelativePath(workspaceFile
				.getLocation().toPortableString());

		testRepo.createAndCheckoutBranch(MASTER, BRANCH);

		final String branchChanges = "branch changes\n";
		setContentsAndCommit(testRepo, workspaceFile, branchChanges
				+ initialContent, "branch commit");

		testRepo.checkoutBranch(MASTER);

		final String masterChanges = "some changes\n";
		setContentsAndCommit(testRepo, workspaceFile, initialContent
				+ masterChanges, "master commit");
		iProject.refreshLocal(IResource.DEPTH_INFINITE,
				new NullProgressMonitor());
		// end setup

		IMergeContext mergeContext = prepareContext(repo, workspaceFile,
				MASTER, BRANCH);
		IDiff node = mergeContext.getDiffTree().getDiff(workspaceFile);
		assertNotNull(node);

		IStatus mergeStatus = mergeContext.merge(node, false,
				new NullProgressMonitor());
		assertEquals(IStatus.OK, mergeStatus.getSeverity());
		assertContentEquals(workspaceFile, branchChanges + initialContent
				+ masterChanges);

		Status status = status(repo);
		assertEquals(1, status.getChanged().size());
		assertEquals(0, status.getModified().size());
		assertTrue(status.getChanged().contains(repoRelativePath));
	}

	@Test
	public void mergeModelNoConflict() throws Exception {
		File file1 = testRepo.createFile(iProject, "file1."
				+ SAMPLE_FILE_EXTENSION);
		File file2 = testRepo.createFile(iProject, "file2."
				+ SAMPLE_FILE_EXTENSION);

		String initialContent1 = "some content for the first file";
		String initialContent2 = "some content for the second file";
		testRepo.appendContentAndCommit(iProject, file1, initialContent1,
				"first file - initial commit");
		testRepo.appendContentAndCommit(iProject, file2, initialContent2,
				"second file - initial commit");

		IFile iFile1 = testRepo.getIFile(iProject, file1);
		IFile iFile2 = testRepo.getIFile(iProject, file2);
		String repoRelativePath1 = testRepo.getRepoRelativePath(iFile1
				.getLocation().toPortableString());
		String repoRelativePath2 = testRepo.getRepoRelativePath(iFile2
				.getLocation().toPortableString());

		testRepo.createAndCheckoutBranch(MASTER, BRANCH);

		final String branchChanges = "branch changes\n";
		setContentsAndCommit(testRepo, iFile1, branchChanges + initialContent1,
				"branch commit");
		setContentsAndCommit(testRepo, iFile2, branchChanges + initialContent2,
				"branch commit");

		testRepo.checkoutBranch(MASTER);

		final String masterChanges = "some changes\n";
		setContentsAndCommit(testRepo, iFile1, initialContent1 + masterChanges,
				"master commit");
		setContentsAndCommit(testRepo, iFile2, initialContent2 + masterChanges,
				"master commit");
		iProject.refreshLocal(IResource.DEPTH_INFINITE,
				new NullProgressMonitor());
		// end setup

		IMergeContext mergeContext = prepareModelContext(repo, iFile1, MASTER,
				BRANCH);
		IDiff node = mergeContext.getDiffTree().getDiff(iFile1);
		assertNotNull(node);
		node = mergeContext.getDiffTree().getDiff(iFile2);
		assertNotNull(node);

		IResourceMappingMerger merger = createMerger();
		IStatus mergeStatus = merger.merge(mergeContext,
				new NullProgressMonitor());
		assertEquals(IStatus.OK, mergeStatus.getSeverity());
		assertContentEquals(iFile1, branchChanges + initialContent1
				+ masterChanges);
		assertContentEquals(iFile2, branchChanges + initialContent2
				+ masterChanges);

		Status status = status(repo);
		assertEquals(2, status.getChanged().size());
		assertEquals(0, status.getModified().size());
		assertTrue(status.getChanged().contains(repoRelativePath1));
		assertTrue(status.getChanged().contains(repoRelativePath2));
	}

	@Test
	public void mergeWithConflict() throws Exception {
		String fileName = "src/Main.java";
		File file = testRepo.createFile(iProject, fileName);
		final String initialContent = "class Main {}\n";
		testRepo.appendContentAndCommit(iProject, file, initialContent,
				"some file");
		testRepo.addToIndex(iProject.getFile(".classpath"));
		testRepo.addToIndex(iProject.getFile(".project"));
		testRepo.commit("project files");

		IFile workspaceFile = testRepo.getIFile(iProject, file);
		String repoRelativePath = testRepo.getRepoRelativePath(workspaceFile
				.getLocation().toPortableString());

		testRepo.createAndCheckoutBranch(MASTER, BRANCH);

		final String branchChanges = "branch changes\n";
		setContentsAndCommit(testRepo, workspaceFile, initialContent
				+ branchChanges, "branch commit");

		testRepo.checkoutBranch(MASTER);

		final String masterChanges = "some changes\n";
		setContentsAndCommit(testRepo, workspaceFile, initialContent
				+ masterChanges, "master commit");
		iProject.refreshLocal(IResource.DEPTH_INFINITE,
				new NullProgressMonitor());
		// end setup

		IMergeContext mergeContext = prepareContext(repo, workspaceFile,
				MASTER,
				BRANCH);
		IDiff node = mergeContext.getDiffTree().getDiff(workspaceFile);
		assertNotNull(node);

		IStatus mergeStatus = mergeContext.merge(node, false,
				new NullProgressMonitor());
		assertEquals(IStatus.ERROR, mergeStatus.getSeverity());
		assertContentEquals(workspaceFile, initialContent + masterChanges);

		Status status = status(repo);
		assertEquals(0, status.getChanged().size());
		assertEquals(0, status.getModified().size());
		assertFalse(status.getChanged().contains(repoRelativePath));
	}

	@Test
	public void mergeModelWithConflict() throws Exception {
		File file1 = testRepo.createFile(iProject, "file1."
				+ SAMPLE_FILE_EXTENSION);
		File file2 = testRepo.createFile(iProject, "file2."
				+ SAMPLE_FILE_EXTENSION);

		String initialContent1 = "some content for the first file";
		String initialContent2 = "some content for the second file";
		testRepo.appendContentAndCommit(iProject, file1, initialContent1,
				"first file - initial commit");
		testRepo.appendContentAndCommit(iProject, file2, initialContent2,
				"second file - initial commit");

		IFile iFile1 = testRepo.getIFile(iProject, file1);
		IFile iFile2 = testRepo.getIFile(iProject, file2);

		testRepo.createAndCheckoutBranch(MASTER, BRANCH);

		final String branchChanges = "branch changes\n";
		setContentsAndCommit(testRepo, iFile1, initialContent1 + branchChanges,
				"branch commit");
		setContentsAndCommit(testRepo, iFile2, initialContent2 + branchChanges,
				"branch commit");

		testRepo.checkoutBranch(MASTER);

		final String masterChanges = "some changes\n";
		setContentsAndCommit(testRepo, iFile1, initialContent1 + masterChanges,
				"master commit");
		setContentsAndCommit(testRepo, iFile2, initialContent2 + masterChanges,
				"master commit");
		iProject.refreshLocal(IResource.DEPTH_INFINITE,
				new NullProgressMonitor());
		// end setup

		IMergeContext mergeContext = prepareModelContext(repo, iFile1, MASTER,
				BRANCH);
		IDiff node = mergeContext.getDiffTree().getDiff(iFile1);
		assertNotNull(node);
		node = mergeContext.getDiffTree().getDiff(iFile2);
		assertNotNull(node);

		IResourceMappingMerger merger = createMerger();
		IStatus mergeStatus = merger.merge(mergeContext,
				new NullProgressMonitor());
		assertEquals(IStatus.ERROR, mergeStatus.getSeverity());

		assertTrue(mergeStatus instanceof IMergeStatus);
Assertion of type org.eclipse.team.core.mapping.IMergeStatus in org.eclipse.egit.core.synchronize.GitSubscriberMergeContextTest.mergeModelWithConflict() at GitSubscriberMergeContextTest.java:[line 333] may hide useful information about why a cast may have failed.
no message found
assertEquals(2, ((IMergeStatus) mergeStatus).getConflictingMappings().length); Set<IFile> conflictingFiles = new LinkedHashSet<>(); for (ResourceMapping conflictingMapping : ((IMergeStatus) mergeStatus) .getConflictingMappings()) { assertTrue(conflictingMapping instanceof SampleResourceMapping && conflictingMapping.getModelObject() instanceof IFile); conflictingFiles.add((IFile) conflictingMapping.getModelObject()); } assertTrue(conflictingFiles.contains(iFile1)); assertTrue(conflictingFiles.contains(iFile2)); assertContentEquals(iFile1, initialContent1 + masterChanges); assertContentEquals(iFile2, initialContent2 + masterChanges); Status status = status(repo); assertEquals(0, status.getChanged().size()); assertEquals(0, status.getModified().size()); } @Test public void mergeModelWithDeletedFileNoConflict() throws Exception { IEclipsePreferences p = InstanceScope.INSTANCE .getNode(Activator.PLUGIN_ID); p.putBoolean(GitCorePreferences.core_autoStageDeletion, true); File file1 = testRepo.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); File file2 = testRepo.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); String initialContent1 = "some content for the first file"; String initialContent2 = "some content for the second file"; testRepo.appendContentAndCommit(iProject, file1, initialContent1, "first file - initial commit"); testRepo.appendContentAndCommit(iProject, file2, initialContent2, "second file - initial commit"); IFile iFile1 = testRepo.getIFile(iProject, file1); IFile iFile2 = testRepo.getIFile(iProject, file2); String repoRelativePath1 = testRepo.getRepoRelativePath(iFile1 .getLocation().toPortableString()); String repoRelativePath2 = testRepo.getRepoRelativePath(iFile2 .getLocation().toPortableString()); testRepo.createAndCheckoutBranch(MASTER, BRANCH); final String branchChanges = "branch changes\n"; setContentsAndCommit(testRepo, iFile1, branchChanges + initialContent1, "branch commit"); iFile2.delete(true, new NullProgressMonitor()); TestUtils.waitForJobs(500, 5000, null); assertFalse(iFile2.exists()); testRepo.addAndCommit(iProject, file2, "branch commit - deleted file2." + SAMPLE_FILE_EXTENSION); testRepo.checkoutBranch(MASTER); iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); TestUtils.waitForJobs(500, 5000, null); if (!iFile2.exists()) { // Debug output to track down sporadically failing test System.out.println(iFile2 + " is synchronized? " + Boolean .toString(iFile2.isSynchronized(IResource.DEPTH_ZERO))); System.out.println(TestUtils.dumpThreads()); System.out.println("***** WARNING: IFile reported as not existing"); System.out.println(iProject + " is open? " + Boolean.toString(iProject.isOpen())); System.out.println(file2.getPath() + " exists? " + Boolean.toString(file2.exists())); System.out.println(iFile2 + " exists now? " + Boolean.toString(iFile2.exists())); iFile2 = iProject.getFile(iFile2.getName()); System.out.println(iFile2 + " exists now? " + Boolean.toString(iFile2.exists())); fail(iFile2 + " reported not to exist"); } assertTrue(iFile2.exists()); final String masterChanges = "some changes\n"; setContentsAndCommit(testRepo, iFile1, initialContent1 + masterChanges, "master commit"); iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup TestUtils.waitForJobs(500, 5000, null); IMergeContext mergeContext = prepareModelContext(repo, iFile1, MASTER, BRANCH); IDiff node = mergeContext.getDiffTree().getDiff(iFile1); assertNotNull(node); node = mergeContext.getDiffTree().getDiff(iFile2); assertNotNull(node); IResourceMappingMerger merger = createMerger(); IStatus mergeStatus = merger.merge(mergeContext, new NullProgressMonitor()); assertEquals(IStatus.OK, mergeStatus.getSeverity()); assertContentEquals(iFile1, branchChanges + initialContent1 + masterChanges); assertFalse(iFile2.exists()); Status status = status(repo); assertEquals(1, status.getChanged().size()); assertEquals(1, status.getRemoved().size()); assertEquals(0, status.getModified().size()); assertTrue(status.getChanged().contains(repoRelativePath1)); assertTrue(status.getRemoved().contains(repoRelativePath2)); } }