blob: c7fff5d57a693247ea347b9058ada2e5284e093b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 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
*
* Contributors:
* Obeo - initial API and implementation
* Philip Langer - extract super class AbstractGitLogicalModelTest
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.unit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.eclipse.core.resources.IFile;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jgit.api.Status;
import org.junit.Test;
@SuppressWarnings("nls")
public class GitLogicalMergeTest extends AbstractGitLogicalModelTest {
/**
* Sets up the repository so that there are three commits affecting a single file.
* <ul>
* <li>initial commit : A single file "file1" contains a package P1 which contains the classes C1 and C2.
* </li>
* <li>master commit : delete C2</li>
* <li>branch commit : make C2 a super-class of C1</li>
* </ul>
* <p>
* This is both a textual and a logical conflict. We expect both kind of merges to mark the file as
* conflicting, but textual merging should corrupt the model with its conflict markers whereas logical
* merge will leave it untouched.
* </p>
*/
private void setUp001() throws Exception {
// We don't need the second resource here
file2.delete();
resource2 = null;
final EPackage root = createPackage(null, "P1");
createClass(root, "C1");
EClass class2 = createClass(root, "C2");
resource1.getContents().add(root);
save(resource1);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root.getEClassifiers().remove(class2);
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1);
final EClass class1 = (EClass)findObject(resource1, "C1");
class2 = (EClass)findObject(resource1, "C2");
class1.getESuperTypes().add(class2);
save(resource1);
repository.addAndCommit(project, "branch-commit", file1);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// We expect one conflict, with one single diff on each side
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 1, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting a single file.
* <ul>
* <li>initial commit : A single file "file1" contains a package P1 which contains the classes C1 and C2.
* </li>
* <li>master commit : rename C1 into C10</li>
* <li>branch commit : make C2 a super-class of C1</li>
* </ul>
* <p>
* This is a textual conflict, but there are no logical conflict. We expect the textual merge to mark the
* file as conflicting, corrupting the model with its markers, but the logical merge should pass without
* issues.
* </p>
*
* @throws Exception
*/
private void setUp002() throws Exception {
// We don't need the second resource here
file2.delete();
resource2 = null;
final EPackage root = createPackage(null, "P1");
EClass class1 = createClass(root, "C1");
createClass(root, "C2");
resource1.getContents().add(root);
save(resource1);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
class1.setName("C10");
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1);
class1 = (EClass)findObject(resource1, "C1");
final EClass class2 = (EClass)findObject(resource1, "C2");
class1.getESuperTypes().add(class2);
save(resource1);
repository.addAndCommit(project, "branch-commit", file1);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// One diff on each side, no conflicts
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 0, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting a single file.
* <ul>
* <li>initial commit : A single file "file1" contains a package P1 which contains the classes C1 and C2.
* </li>
* <li>master commit : delete C2</li>
* <li>branch commit : delete C2</li>
* </ul>
* <p>
* This is a pseudo conflict at both logical and textual level, which can thus be automatically merged in
* both cases.
* </p>
*
* @throws Exception
*/
private void setUp003() throws Exception {
// We don't need the second resource here
file2.delete();
resource2 = null;
final EPackage root = createPackage(null, "P1");
createClass(root, "C1");
EClass class2 = createClass(root, "C2");
resource1.getContents().add(root);
save(resource1);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root.getEClassifiers().remove(class2);
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1);
class2 = (EClass)findObject(resource1, "C2");
class2.getEPackage().getEClassifiers().remove(class2);
save(resource1);
repository.addAndCommit(project, "branch-commit", file1);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// One diff on each side, one pseudo conflict
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 1, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting two files with no links between them
* (not part of a single logical model).
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4.</li>
* <li>master commit : delete C2</li>
* <li>branch commit : make C2 a super-class of C1, delete C4</li>
* </ul>
* <p>
* This constitutes a conflict in file1, whereas the merge of file2 should end successfully.
* </p>
*
* @throws Exception
*/
private void setUp004() throws Exception {
final EPackage root1 = createPackage(null, "P1");
createClass(root1, "C1");
EClass class2 = createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root1.getEClassifiers().remove(class2);
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
final EClass class1 = (EClass)findObject(resource1, "C1");
class2 = (EClass)findObject(resource1, "C2");
final EClass class4 = (EClass)findObject(resource2, "C4");
class1.getESuperTypes().add(class2);
class4.getEPackage().getEClassifiers().remove(class4);
save(resource1, resource2);
repository.addAndCommit(project, "branch-commit", file1, file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// One diff on each side, one conflict
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 1, 1, 1);
// one diff from the right
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 0, 0, 1);
}
/**
* Sets up the repository so that there are three commits affecting two files with no links between them
* (not part of a single logical model).
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4.</li>
* <li>master commit : delete C2, delete C4</li>
* <li>branch commit : make C2 a super-class of C1, make C4 a super-class of C3</li>
* </ul>
* <p>
* This constitutes a conflict in both files for both kind of merge (textual or logical).
* </p>
*
* @throws Exception
*/
private void setUp005() throws Exception {
final EPackage root1 = createPackage(null, "P1");
createClass(root1, "C1");
EClass class2 = createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
createClass(root2, "C3");
EClass class4 = createClass(root2, "C4");
resource2.getContents().add(root2);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root1.getEClassifiers().remove(class2);
root2.getEClassifiers().remove(class4);
save(resource1, resource2);
repository.addAndCommit(project, "master-commit", file1, file2);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
final EClass class1 = (EClass)findObject(resource1, "C1");
class2 = (EClass)findObject(resource1, "C2");
final EClass class3 = (EClass)findObject(resource2, "C3");
class4 = (EClass)findObject(resource2, "C4");
class1.getESuperTypes().add(class2);
class3.getESuperTypes().add(class4);
save(resource1, resource2);
repository.addAndCommit(project, "branch-commit", file1, file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// One diff on each side, one conflict
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 1, 1, 1);
// likewise
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 1, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting two files with no links between them
* (not part of a single logical model).
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4.</li>
* <li>master commit : renamed C1 into C10, rename C3 into C30</li>
* <li>branch commit : make C2 a super-class of C1, make C4 a super-class of C3</li>
* </ul>
* <p>
* This is a textual conflict in both files, but there are no logical conflicts. Textual merge will
* corrupt both models on top of being unable to finish the merge, logical merge will end successfully.
* </p>
*
* @throws Exception
*/
private void setUp006() throws Exception {
final EPackage root1 = createPackage(null, "P1");
EClass class1 = createClass(root1, "C1");
createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
EClass class3 = createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
class1.setName("C10");
class3.setName("C30");
save(resource1, resource2);
repository.addAndCommit(project, "master-commit", file1, file2);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
class1 = (EClass)findObject(resource1, "C1");
final EClass class2 = (EClass)findObject(resource1, "C2");
class3 = (EClass)findObject(resource2, "C3");
final EClass class4 = (EClass)findObject(resource2, "C4");
class1.getESuperTypes().add(class2);
class3.getESuperTypes().add(class4);
save(resource1, resource2);
repository.addAndCommit(project, "branch-commit", file1, file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
// One diff on each side, no conflict
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 0, 1, 1);
// likewise
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 0, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting two interlinked files (part of the
* same logical model). The files won't be part of the same logical model initially, the link will be
* created in one of the commits we'll merge.
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4.</li>
* <li>master commit : delete C3</li>
* <li>branch commit : make C3 a super-class of C1</li>
* </ul>
* <p>
* There is no textual conflict in these changes, so a textual merge will end successfully, corrupting the
* model by breaking the links between them. However, logical merging will see the conflict and should
* mark both files as conflicting, without touching either of them.
* </p>
* <p>
* This case also presents the particularity of having a "single file" locally (file1 is not linked to
* file2) whereas the model is comprised of two files in the right. This will allow us to make sure that
* we are able to resolve the logical model in such cases.
* </p>
*
* @throws Exception
*/
private void setUp007() throws Exception {
final EPackage root1 = createPackage(null, "P1");
createClass(root1, "C1");
createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
EClass class3 = createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root2.getEClassifiers().remove(class3);
save(resource2);
repository.addAndCommit(project, "master-commit", file2);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
final EClass class1 = (EClass)findObject(resource1, "C1");
class3 = (EClass)findObject(resource2, "C3");
class1.getESuperTypes().add(class3);
save(resource1);
repository.addAndCommit(project, "branch-commit", file1);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
/*
* The files are unrelated locally, but they are part of the same logical model on the remote. We
* expect EMF Compare to detect that when starting from file1 (as the remote file1 references the
* remote file2), but not when starting from file2 (since in such a case, we have no way to discover
* the cross reference).
*/
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 1, 1, 1);
compareADirectionAndCheck(iFile2, MASTER, BRANCH, 0, 1, 0);
compareADirectionAndCheck(iFile2, BRANCH, MASTER, 1, 1, 1);
repository.checkoutBranch(MASTER);
}
/**
* See {@link #setUp007()} for the description of this use case, except that we reverse the changes made
* to file1 and file2 so that the "leaf" of the logical model is found before its root in the tree, making
* sure that this case will not fail to merge properly.
*
* @see #setUp007()
* @throws Exception
*/
private void setUp007_reverse() throws Exception {
final EPackage root1 = createPackage(null, "P1");
EClass class1 = createClass(root1, "C1");
createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
root1.getEClassifiers().remove(class1);
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
final EClass class3 = (EClass)findObject(resource2, "C3");
class1 = (EClass)findObject(resource1, "C1");
class3.getESuperTypes().add(class1);
save(resource2);
repository.addAndCommit(project, "branch-commit", file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
/*
* The files are unrelated locally, but they are part of the same logical model on the remote. We
* expect EMF Compare to detect that when starting from file2 (as the remote file2 references the
* remote file1), but not when starting from file1 (since in such a case, we have no way to discover
* the cross reference).
*/
compareADirectionAndCheck(iFile1, MASTER, BRANCH, 0, 1, 0);
compareADirectionAndCheck(iFile1, BRANCH, MASTER, 1, 1, 1);
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 1, 1, 1);
}
/**
* Sets up the repository so that there are three commits affecting two interlinked files (part of the
* same logical model). The files will be linked together as a single logical model in all three sides of
* the comparison.
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4. C3 is a super-type of C1, linking the two files together.</li>
* <li>master commit : renamed C1 into C10</li>
* <li>branch commit : replace C3 by C4 as a super-class of C1, rename C4 into C40</li>
* </ul>
* <p>
* There is a textual conflict in the first file, none in the second. We expect the textual merge to
* corrupt the model with its textual conflict markers. There are no logical conflicts, so logical merging
* should end successfully.
* </p>
*
* @throws Exception
*/
private void setUp008() throws Exception {
final EPackage root1 = createPackage(null, "P1");
EClass class1 = createClass(root1, "C1");
createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
EClass class3 = createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
class1.getESuperTypes().add(class3);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
class1.setName("C10");
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
class1 = (EClass)findObject(resource1, "C1");
final EClass class4 = (EClass)findObject(resource2, "C4");
class1.getESuperTypes().clear();
class1.getESuperTypes().add(class4);
class4.setName("C40");
save(resource1, resource2);
repository.addAndCommit(project, "branch-commit", file1, file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 0, 1, 3);
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 0, 1, 3);
}
/**
* Sets up the repository so that there are three commits affecting two interlinked files (part of the
* same logical model).
* <ul>
* <li>initial commit : "file1" contains package P1 and classes C1 and C2. "file2" contains P2 containing
* C3 and C4.</li>
* <li>master commit : renamed C1 into C10</li>
* <li>branch commit : renamed C4 into C40</li>
* </ul>
* <p>
* There is no conflict with these changes, neither textual nor logical.
* </p>
*
* @throws Exception
*/
private void setUp009() throws Exception {
final EPackage root1 = createPackage(null, "P1");
final EClass class1 = createClass(root1, "C1");
createClass(root1, "C2");
resource1.getContents().add(root1);
final EPackage root2 = createPackage(null, "P2");
final EClass class3 = createClass(root2, "C3");
createClass(root2, "C4");
resource2.getContents().add(root2);
class1.getESuperTypes().add(class3);
save(resource1, resource2);
repository.addAllAndCommit("initial-commit");
// Branch, but stay on master
repository.createBranch(MASTER, BRANCH);
class1.setName("C10");
save(resource1);
repository.addAndCommit(project, "master-commit", file1);
repository.checkoutBranch(BRANCH);
reload(resource1, resource2);
final EClass class4 = (EClass)findObject(resource2, "C4");
class4.setName("C40");
save(resource2);
repository.addAndCommit(project, "branch-commit", file2);
repository.checkoutBranch(MASTER);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
compareBothDirectionsAndCheck(iFile1, MASTER, BRANCH, 0, 1, 1);
compareBothDirectionsAndCheck(iFile2, MASTER, BRANCH, 0, 1, 1);
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp001, and B - the textual merge ends up corrupting the models.
*/
@Test
public void merge001_text() throws Exception {
setUp001();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
}
/*
* Try and merge logically. There is a conflict, but contrarily to merge001_textual, we expect the model
* not to be corrupted by this attempt.
*/
@Test
public void merge001_logical() throws Exception {
setUp001();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
// Make sure we're still in the configuration we had on master
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
assertNotNull(findObject(resource1, "C1"));
assertNull(findObject(resource1, "C2"));
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp002, and B - the textual merge ends up corrupting the model with a false
* conflict.
*/
@Test
public void merge002_text() throws Exception {
setUp002();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
}
/*
* Try and merge logically. The merge should end without issues, without being affected by the textual
* conflict.
*/
@Test
public void merge002_logical() throws Exception {
setUp002();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
// Make sure that the merge actually changed the model
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C10");
final EClass class2 = (EClass)findObject(resource1, "C2");
assertNotNull(pack);
assertNotNull(class1);
assertNotNull(class2);
assertTrue(class1.getESuperTypes().contains(class2));
assertEquals(2, pack.getEClassifiers().size());
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp003, and B - the textual merge manages to auto-merge the pseudo-conflict
* without corrupting the model.
*/
@Test
public void merge003_text() throws Exception {
setUp003();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C1");
assertNotNull(pack);
assertNotNull(class1);
assertEquals(1, pack.getEClassifiers().size());
}
/*
* Try and merge logically. The merge should end successfully, auto-merging the pseudo-conflict as needed.
*/
@Test
public void merge003_logical() throws Exception {
setUp003();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C1");
assertNotNull(pack);
assertNotNull(class1);
assertEquals(1, pack.getEClassifiers().size());
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp004, and B - the textual merge corrupts the model in which there was a
* conflict.
*/
@Test
public void merge004_text() throws Exception {
setUp004();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertFalse(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack = (EPackage)findObject(resource2, "P2");
final EClass class3 = (EClass)findObject(resource2, "C3");
assertNotNull(pack);
assertNotNull(class3);
assertEquals(1, pack.getEClassifiers().size());
}
/*
* Try and merge logically. The merge should leave file1 as conflicting, leaving it untouched as compared
* to master. file2 should be properly merged.
*/
@Test
public void merge004_logical() throws Exception {
setUp004();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertFalse(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
assertNotNull(findObject(resource1, "C1"));
assertNull(findObject(resource1, "C2"));
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack = (EPackage)findObject(resource2, "P2");
final EClass class3 = (EClass)findObject(resource2, "C3");
assertNotNull(pack);
assertNotNull(class3);
assertEquals(1, pack.getEClassifiers().size());
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp005, and B - the textual merge corrupts the two models.
*/
@Test
public void merge005_text() throws Exception {
setUp005();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
try {
reload(resource2);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
}
/*
* Try and merge logically. both files should be marked as conflicting, untouched as compared to master.
*/
@Test
public void merge005_logical() throws Exception {
setUp005();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
assertNotNull(findObject(resource1, "C1"));
assertNull(findObject(resource1, "C2"));
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
assertNotNull(findObject(resource2, "C3"));
assertNull(findObject(resource2, "C4"));
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp006, and B - the textual merge ends up corrupting the models with false
* conflicts.
*/
@Test
public void merge006_text() throws Exception {
setUp006();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
try {
reload(resource2);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
}
/*
* Try and merge logically. The merge should end without issues, without being affected by the textual
* conflicts.
*/
@Test
public void merge006_logical() throws Exception {
setUp006();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
// Make sure that the merge actually changed the models
reload(resource1, resource2);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack1 = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C10");
final EClass class2 = (EClass)findObject(resource1, "C2");
assertNotNull(pack1);
assertNotNull(class1);
assertNotNull(class2);
assertTrue(class1.getESuperTypes().contains(class2));
assertEquals(2, pack1.getEClassifiers().size());
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack2 = (EPackage)findObject(resource2, "P2");
final EClass class3 = (EClass)findObject(resource2, "C30");
final EClass class4 = (EClass)findObject(resource2, "C4");
assertNotNull(pack2);
assertNotNull(class3);
assertNotNull(class4);
assertTrue(class3.getESuperTypes().contains(class4));
assertEquals(2, pack2.getEClassifiers().size());
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp007, and B - the textual merge ends up corrupting the logical model even
* though it says the merge ends successfully.
*/
@Test
public void merge007_text() throws Exception {
setUp007();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
unload(resource1, resource2);
// This one has a broken reference towards C3
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
final EClass class1 = (EClass)findObject(resource1, "C1");
final EClass superType = class1.getESuperTypes().get(0);
// the super type (what was "class C3") is a proxy
assertTrue(superType.eIsProxy());
// even though its resource has been loaded in the resource set
final Resource res2 = resource1.getResourceSet().getResource(resource2.getURI(), false);
assertNotNull(res2);
// and it is unresolveable
assertSame(superType, EcoreUtil.resolve(superType, resource1.getResourceSet()));
// But the second should be fine
reload(resource2);
final EPackage pack2 = (EPackage)findObject(resource2, "P2");
final EClass class4 = (EClass)findObject(resource2, "C4");
assertNotNull(pack2);
assertNotNull(class4);
assertEquals(1, pack2.getEClassifiers().size());
}
/*
* Try and merge logically. There is a logical conflict, so we expect both files to remain untouched and
* the conflict marked.
*/
@Test
public void merge007_logical() throws Exception {
setUp007();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
final EClass class1 = (EClass)findObject(resource1, "C1");
assertNotNull(class1);
assertTrue(class1.getESuperTypes().isEmpty());
assertNotNull(findObject(resource1, "C2"));
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
assertNull(findObject(resource2, "C3"));
assertNotNull(findObject(resource2, "C4"));
}
/* This should have the reverse effect as merge007_textual. */
@Test
public void merge007_reverse_text() throws Exception {
setUp007_reverse();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
unload(resource1, resource2);
// This one should be fine
reload(resource1);
final EPackage pack1 = (EPackage)findObject(resource1, "P1");
final EClass class2 = (EClass)findObject(resource1, "C2");
assertNotNull(pack1);
assertNotNull(class2);
assertEquals(1, pack1.getEClassifiers().size());
// But the second one has a broken references towards C1
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
final EClass class3 = (EClass)findObject(resource2, "C3");
final EClass superType = class3.getESuperTypes().get(0);
// the super type (what was "class C1") is a proxy
assertTrue(superType.eIsProxy());
// even though its resource has been loaded in the resource set
final Resource res1 = resource2.getResourceSet().getResource(resource1.getURI(), false);
assertNotNull(res1);
// and it is unresolveable
assertSame(superType, EcoreUtil.resolve(superType, resource2.getResourceSet()));
}
/* This should have the exact same effect as merge007_logical. */
@Test
public void merge007_reverse_logical() throws Exception {
setUp007_reverse();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file2)));
unload(resource1, resource2);
reload(resource1);
assertTrue(resource1.getErrors().isEmpty());
assertNull(findObject(resource1, "C1"));
assertNotNull(findObject(resource1, "C2"));
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
final EClass class3 = (EClass)findObject(resource2, "C3");
assertNotNull(class3);
assertTrue(class3.getESuperTypes().isEmpty());
assertNotNull(findObject(resource2, "C4"));
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp008, and B - the textual merge ends up corrupting the logical model even
* though it says the merge ends successfully.
*/
@Test
public void merge008_text() throws Exception {
setUp008();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertTrue(status.hasUncommittedChanges());
assertTrue(status.getConflicting().contains(repository.getRepoRelativePath(file1)));
unload(resource1, resource2);
try {
reload(resource1);
fail();
} catch (IOException e) {
// expected behavior : the file has been corrupted by the textual merge
}
// This file has been merged, so we should find C40 in it.
reload(resource2);
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack2 = (EPackage)findObject(resource2, "P2");
assertNotNull(findObject(resource2, "C3"));
assertNotNull(findObject(resource2, "C40"));
assertEquals(2, pack2.getEClassifiers().size());
}
/*
* Try and merge logically. There is no logical conflict, so the merge should end successfully.
*/
@Test
public void merge008_logical() throws Exception {
setUp008();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
reload(resource1, resource2);
assertTrue(resource1.getErrors().isEmpty());
final EClass class1 = (EClass)findObject(resource1, "C10");
assertNotNull(class1);
assertNotNull(findObject(resource1, "C2"));
assertTrue(resource2.getErrors().isEmpty());
final EClass class4 = (EClass)findObject(resource2, "C40");
assertNotNull(findObject(resource2, "C3"));
assertNotNull(class4);
assertTrue(class1.getESuperTypes().contains(class4));
assertEquals(1, class1.getESuperTypes().size());
}
/*
* Try and merge textually. This has no relation with EMF Compare, but it does check that : A - the models
* were properly created by setUp009, and B - the textual merge wouldn't have corrupted the model in this
* case.
*/
@Test
public void merge009_text() throws Exception {
setUp009();
repository.mergeTextual(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
reload(resource1, resource2);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack1 = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C10");
assertNotNull(class1);
assertNotNull(findObject(resource1, "C2"));
assertEquals(2, pack1.getEClassifiers().size());
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack2 = (EPackage)findObject(resource2, "P2");
final EClass class3 = (EClass)findObject(resource2, "C3");
assertNotNull(class3);
assertNotNull(findObject(resource2, "C40"));
assertEquals(2, pack2.getEClassifiers().size());
assertTrue(class1.getESuperTypes().contains(class3));
assertEquals(1, class1.getESuperTypes().size());
}
/*
* Try and merge logically. There is no logical conflict, so the merge should end successfully.
*/
@Test
public void merge009_logical() throws Exception {
setUp009();
repository.mergeLogical(BRANCH);
final Status status = repository.status();
assertFalse(status.hasUncommittedChanges());
assertTrue(status.getConflicting().isEmpty());
reload(resource1, resource2);
assertTrue(resource1.getErrors().isEmpty());
final EPackage pack1 = (EPackage)findObject(resource1, "P1");
final EClass class1 = (EClass)findObject(resource1, "C10");
assertNotNull(class1);
assertNotNull(findObject(resource1, "C2"));
assertEquals(2, pack1.getEClassifiers().size());
assertTrue(resource2.getErrors().isEmpty());
final EPackage pack2 = (EPackage)findObject(resource2, "P2");
final EClass class3 = (EClass)findObject(resource2, "C3");
assertNotNull(class3);
assertNotNull(findObject(resource2, "C40"));
assertEquals(2, pack2.getEClassifiers().size());
assertTrue(class1.getESuperTypes().contains(class3));
assertEquals(1, class1.getESuperTypes().size());
}
private void compareADirectionAndCheck(IFile file, String source, String destination,
int expectedConflicts, int diffsInSource, int diffsInDestination) throws Exception {
repository.checkoutBranch(source);
Comparison compareResult = compare(source, destination, file);
assertEquals(expectedConflicts, compareResult.getConflicts().size());
assertDiffCount(compareResult.getDifferences(), diffsInSource, diffsInDestination);
}
}