/******************************************************************************* * Copyright (C) 2015 Obeo 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 *******************************************************************************/ package org.eclipse.emf.compare.ide.ui.tests.merge; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.NullProgressMonitor; 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.emf.compare.ide.ui.tests.models.ModelTestCase; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.IndexDiff.StageState; import org.eclipse.jgit.lib.Repository; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * This test requires two extensions which are registered in fragment.xml: * <ol> * <li><code>org.eclipse.core.resources.modelProviders</code>: SampleModelProvider provides logical models for * <code>*.sample</code> files and the</li> * <li><code>org.eclipse.core.runtime.adapters</code>: SampleModelProvider adapts to IResourceMappingMerger * </li> * </ol> * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> * @author <a href="mailto:laurent.delaigue@obeo.fr">Laurent Delaigue</a> */ @SuppressWarnings("restriction") // @RunWith(EMFCompareGitTestRunner.class) public class StrategyRecursiveModelTest extends ModelTestCase { protected static final String MASTER = Constants.R_HEADS + Constants.MASTER; protected static final String BRANCH = Constants.R_HEADS + "branch"; //$NON-NLS-1$ protected static final String INITIAL_CONTENT_FILE1 = "some content for the first file"; //$NON-NLS-1$ protected static final String INITIAL_CONTENT_FILE2 = "some content for the second file"; //$NON-NLS-1$ // The Team merger uses this when merging, regardless of what exists in the // file protected static final String SYSTEM_EOL = System.getProperty("line.separator"); //$NON-NLS-1$ protected static final String BRANCH_CHANGE = "branch changes" + SYSTEM_EOL; //$NON-NLS-1$ protected static final String MASTER_CHANGE = "master changes" + SYSTEM_EOL; //$NON-NLS-1$ protected Repository repo; protected IProject iProject; @Override @Before public void setUp() throws Exception { super.setUp(); iProject = project.getProject(); repo = RepositoryMapping.getMapping(iProject).getRepository(); // make initial commit Git git = new Git(repo); try { git.commit().setAuthor("JUnit", "junit@jgit.org").setMessage("Initial commit").call(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } finally { git.close(); } // Select strategy recursive as preferred strategy InstanceScope.INSTANCE.getNode(Activator.getPluginId()) .put(GitCorePreferences.core_preferredMergeStrategy, "model recursive"); //$NON-NLS-1$ } @After public void clearGitResources() throws Exception { repository.disconnect(iProject); repo = null; super.tearDown(); } // /** // * This test will initialize a repository with two branches with a few changes each, then try to merge // the // * branch into master. // * <p> // * The repository will contain two files, file1.sample and file2.sample, both being in the same // container // * and thus considered to be components of a single logical model by the SampleModelProvider. // * </p> // * <p> // * file1 will be modified on both master and the branch, these changes being considered as an // * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the // * SampleResourceMappingMerger. file2 will only be modified on the branch : it will be deleted. // * </p> // * <p> // * We expect the merge to end successfully, ending with a repository that has no uncommited change. // * </p> // * // * @throws Exception // */ // @Merge(localBranch = "master", remoteBranch = "branch") // @Input("data/strategyRecursiveModel/deletedRemoteNoConflict.zip") // public void mergeModelWithDeletedRemoteNoConflict(Status status, Repository repository, // List<IProject> projects) throws Exception { // IProject project = projects.get(0); // IFile iFile1 = project.getFile("file1.sample"); // IFile iFile2 = project.getFile("file2.sample"); // // assertFalse(status.hasUncommittedChanges()); // assertTrue(status.getConflicting().isEmpty()); // // assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); // assertFalse(iFile2.exists()); // } // // /** // * This test will initialize a repository with two branches with a few changes each, then try to merge // the // * branch into master. // * <p> // * The repository will contain two files, file1.sample and file2.sample, both being in the same // container // * and thus considered to be components of a single logical model by the SampleModelProvider. // * </p> // * <p> // * file1 will be modified on both master and the branch, these changes being considered as an // * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the // * SampleResourceMappingMerger. file2 will only be modified on master where it will be deleted. // * </p> // * <p> // * We expect the merge to end successfully, ending with a repository that has no uncommited change. // * </p> // * // * @throws Exception // */ // @Merge(localBranch = "master", remoteBranch = "branch") // @Input("data/strategyRecursiveModel/deletedLocalNoConflict.zip") // public void mergeModelWithDeletedLocalNoConflict(Status status, Repository repository, // List<IProject> projects) throws Exception { // IProject project = projects.get(0); // IFile iFile1 = project.getFile("file1.sample"); // IFile iFile2 = project.getFile("file2.sample"); // assertFalse(status.hasUncommittedChanges()); // assertTrue(status.getConflicting().isEmpty()); // // assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); // assertFalse(iFile2.exists()); // } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be deleted on both master and the branch. This is a * pseudo-conflict and should thus be automatically merged. * </p> * <p> * We expect the merge to end successfully, ending with a repository that has no uncommited change. * </p> * * @throws Exception */ @Test public void mergeModelWithPseudoConflictDeletion() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); IFile iFile2 = repository.getIFile(iProject, file2); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "branch commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "master commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertFalse(status.hasUncommittedChanges()); assertTrue(status.getConflicting().isEmpty()); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertFalse(iFile2.exists()); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch in such a way that it will be an unresolveable * conflict for both JGit and the model merger. file2 will be deleted from the branch. * </p> * <p> * The merge must end in a conflict. The SampleResourceMappingMerger pre-merges what can be, so file2 will * be deleted from the working tree while file1 will be left untouched. file2 will be added to the index, * but file 1 will be marked as a conflict. * </p> * * @throws Exception */ @Test public void mergeModelWithDeletedRemoteModelConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "branch commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1, "master commit"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertFalse(status.getConflicting().isEmpty()); assertTrue(status.getConflicting().contains(repoRelativePath1)); assertTrue(status.getRemoved().contains(repoRelativePath2)); assertContentEquals(iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1); assertFalse(iFile2.exists()); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_MODIFIED, map.get(repoRelativePath1)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch in such a way that it will be an unresolveable * conflict for both JGit and the model merger. file2 will be deleted from master. * </p> * <p> * The merge must end in a conflict. Since file2 has been deleted locally and has not been changed on the * remote, it will not be seen as a part of the logical model (it won't even be part of the merge * operation). Thus, file1 will be marked as a conflict, untouched as compared to its previous (master) * state, and file2 will not be part of the index. * </p> * * @throws Exception */ @Test public void mergeModelWithDeletedLocalModelConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1, "master commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "master commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertFalse(status.getConflicting().isEmpty()); assertTrue(status.getConflicting().contains(repoRelativePath1)); assertFalse(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1); assertFalse(iFile2.exists()); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_MODIFIED, map.get(repoRelativePath1)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be deleted from the branch, but modified on master. * </p> * <p> * The merge will end in conflict, file1 being pre-merged since it does not present a conflict, and file2 * should remain in its "master" state. file1 will have been added to the index, but file2 will be marked * as conflicting. * </p> * * @throws Exception */ @Test public void mergeModelWithDeletedRemoteFileConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "branch commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit - file1"); //$NON-NLS-1$ setContentsAndCommit(repository, iFile2, INITIAL_CONTENT_FILE2 + MASTER_CHANGE, "master commit - file2"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertTrue(status.getChanged().contains(repoRelativePath1)); assertTrue(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2 + MASTER_CHANGE); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.DELETED_BY_THEM, map.get(repoRelativePath2)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be deleted from master, but modified on the branch. * </p> * <p> * The merge will end in conflict. Since file2 has been deleted locally, it will not be seen as a part of * the logical model. file1 will be pre-merged since it does not present a conflict, and file2 will be * checked out in its "branch" state since we won't detect its logical model. Only file2 will be marked as * a conflict. * </p> * * @throws Exception */ @Test public void mergeModelWithDeletedLocalFileConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ setContentsAndCommit(repository, iFile2, BRANCH_CHANGE + INITIAL_CONTENT_FILE2, "branch commit"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit"); //$NON-NLS-1$ iFile2.delete(true, new NullProgressMonitor()); repository.addAndCommit(iProject, "master commit - deleted file2." + SAMPLE_FILE_EXTENSION, file2); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertFalse(status.getConflicting().contains(repoRelativePath1)); assertTrue(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, BRANCH_CHANGE + INITIAL_CONTENT_FILE2); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.DELETED_BY_US, map.get(repoRelativePath2)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will only exist on the branch since we'll add it there. * </p> * <p> * We expect the merge to end successfully, ending with a repository that has no uncommited change. * </p> * * @throws Exception */ @Test public void mergeModelWithAddedRemoteNoConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit on branch"); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertFalse(status.hasUncommittedChanges()); assertTrue(status.getConflicting().isEmpty()); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be added to master after the branch has diverged. * </p> * <p> * We expect the merge to end successfully, ending with a repository that has no uncommited change. * </p> * * @throws Exception */ @Test public void mergeModelWithAddedLocalNoConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit"); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit on master"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertFalse(status.hasUncommittedChanges()); assertTrue(status.getConflicting().isEmpty()); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be added on both master and the branch with the same content. * This is a pseudo-conflict but the default text merger (TextStorageMerger) cannot handle such cases. * file2 will thus be marked as a conflict. * </p> * <p> * We expect the merge to end successfully, ending with a repository that has no uncommited change. * </p> * * @throws Exception */ @Test public void mergeModelWithPseudoConflictAddition() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit on branch"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit"); //$NON-NLS-1$ file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ iFile2 = repository.getIFile(iProject, file2); repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit on master"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertTrue(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_ADDED, map.get(repoRelativePath2)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch in such a way that it will be an unresolveable * conflict for both JGit and the model merger. file2 will be added to the branch. * </p> * <p> * The merge must end in a conflict. The SampleResourceMappingMerger pre-merges what can be, so file2 will * be added to the working tree while file1 will be left untouched. file2 will be added to the index, but * file 1 will be marked as a conflict. * </p> * * @throws Exception */ @Test public void mergeModelWithAddedRemoteModelConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit - branch"); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1, "master commit"); //$NON-NLS-1$ iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertFalse(status.getConflicting().isEmpty()); assertTrue(status.getConflicting().contains(repoRelativePath1)); assertTrue(status.getAdded().contains(repoRelativePath2)); assertContentEquals(iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_MODIFIED, map.get(repoRelativePath1)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch in such a way that it will be an unresolveable * conflict for both JGit and the model merger. file2 will be added to master. * </p> * <p> * The merge must end in a conflict. file1 will be marked as a conflict, untouched as compared to its * previous (master) state. file2 will also be marked as conflicting, since the default merger doesn't * tell us that "added by us" files are to be made in sync. * </p> * * @throws Exception */ @Test public void mergeModelWithAddedLocalModelConflict() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1, "master commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2, "second file - initial commit"); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertFalse(status.getConflicting().isEmpty()); assertTrue(status.getConflicting().contains(repoRelativePath1)); assertTrue(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, MASTER_CHANGE + INITIAL_CONTENT_FILE1); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2); Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_MODIFIED, map.get(repoRelativePath1)); assertEquals(StageState.ADDED_BY_US, map.get(repoRelativePath2)); } /** * This test will initialize a repository with two branches with a few changes each, then try to merge the * branch into master. * <p> * The repository will contain two files, file1.sample and file2.sample, both being in the same container * and thus considered to be components of a single logical model by the SampleModelProvider. * </p> * <p> * file1 will be modified on both master and the branch, these changes being considered as an * unresolveable conflict by git (and JGit), but considered as an auto-mergeable conflict by the * SampleResourceMappingMerger. file2 will be added to both master and the branch, with distinct content. * </p> * <p> * The merge will end in conflict, file1 being pre-merged since it does not present a conflict, and file2 * should remain in its "master" state. file1 will have been added to the index, but file2 will be marked * as conflicting. * </p> * * @throws Exception */ @Test public void mergeModelWithConflictAddition() throws Exception { File file1 = repository.createFile(iProject, "file1." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ File file2 = repository.createFile(iProject, "file2." + SAMPLE_FILE_EXTENSION); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file1, INITIAL_CONTENT_FILE1, "first file - initial commit"); //$NON-NLS-1$ IFile iFile1 = repository.getIFile(iProject, file1); String repoRelativePath1 = repository.getRepoRelativePath(iFile1.getLocation().toPortableString()); repository.createAndCheckoutBranch(MASTER, BRANCH); setContentsAndCommit(repository, iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1, "branch commit"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2 + "branch", //$NON-NLS-1$ "second file - initial commit - branch"); //$NON-NLS-1$ repository.checkoutBranch(MASTER); setContentsAndCommit(repository, iFile1, INITIAL_CONTENT_FILE1 + MASTER_CHANGE, "master commit - file1"); //$NON-NLS-1$ repository.appendContentAndCommit(iProject, file2, INITIAL_CONTENT_FILE2 + "master", //$NON-NLS-1$ "second file - initial commit - master"); //$NON-NLS-1$ IFile iFile2 = repository.getIFile(iProject, file2); String repoRelativePath2 = repository.getRepoRelativePath(iFile2.getLocation().toPortableString()); iProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // end setup merge(repo, BRANCH); final Status status = status(repo); assertTrue(status.hasUncommittedChanges()); assertTrue(status.getChanged().contains(repoRelativePath1)); assertTrue(status.getConflicting().contains(repoRelativePath2)); assertContentEquals(iFile1, BRANCH_CHANGE + INITIAL_CONTENT_FILE1 + MASTER_CHANGE); assertContentEquals(iFile2, INITIAL_CONTENT_FILE2 + "master"); //$NON-NLS-1$ Map<String, StageState> map = status.getConflictingStageState(); assertEquals(StageState.BOTH_ADDED, map.get(repoRelativePath2)); } }