blob: e4af7d616d214c39c124e02402cf38cfb8e1256b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 Obeo.
* 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
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.actions;
import static org.eclipse.emf.compare.DifferenceState.DISCARDED;
import static org.eclipse.emf.compare.DifferenceState.MERGED;
import static org.eclipse.emf.compare.internal.merge.MergeMode.ACCEPT;
import static org.eclipse.emf.compare.internal.merge.MergeMode.REJECT;
import static org.eclipse.emf.compare.internal.merge.MergeMode.getMergeMode;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Conflict;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.EMFCompare;
import org.eclipse.emf.compare.ide.ui.internal.structuremergeviewer.actions.MergeRunnableImpl;
import org.eclipse.emf.compare.internal.merge.MergeDataImpl;
import org.eclipse.emf.compare.merge.BatchMerger;
import org.eclipse.emf.compare.merge.IMerger;
import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.tests.framework.AbstractInputData;
import org.eclipse.emf.compare.tests.nodes.Node;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.junit.Before;
import org.junit.Test;
/**
* This test is related to the bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=434827">434827</a>
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
@SuppressWarnings("restriction")
public class TestBug434828 {
private IMerger.Registry mergerRegistry;
private DefaultComparisonScope scope;
private Diff deletedNodeDeletionDiff;
private Diff holdingRefDeletionDiff;
private Diff refChangeDiff;
/**
* Set up the model comparison with the following use case:
* <p>
* The 3 models loaded are:
* <ul>
* <li>Origin which contains 3 nodes structured like this:
*
* <pre>
* Root - DeletedNode - ReferencedNode
* \ - HoldingReferenceNode
* </pre>
*
* </li>
* <li>Left that has an extra eopposite reference between "HoldingReference" and "ReferencedNode"</li>
* <li>Right in which "DeletedNode" has been deleted"</li>
* </ul>
* </p>
*
* @throws IOException
*/
@Before
public void setUp() throws IOException {
Bug434828InputData inputData = new Bug434828InputData();
final Resource left = inputData.getResource("left.nodes"); //$NON-NLS-1$
final Resource right = inputData.getResource("right.nodes"); //$NON-NLS-1$
final Resource origin = inputData.getResource("origin.nodes"); //$NON-NLS-1$
scope = new DefaultComparisonScope(left, right, origin);
final Comparison comparison = EMFCompare.builder().build().compare(scope);
// Add a IMergeData to handle status decorations on Diffs
comparison.eAdapters().add(new MergeDataImpl(true, false));
mergerRegistry = EMFCompareRCPPlugin.getDefault().getMergerRegistry();
// Keeps tracks of the differences to test.
EList<Conflict> conflicts = comparison.getConflicts();
assertEquals(1, conflicts.size());
Conflict conflict = conflicts.get(0);
// Get the left diff of the conflict: change of eopposite reference
EList<Diff> leftConflicts = conflict.getLeftDifferences();
assertEquals(2, leftConflicts.size());
refChangeDiff = leftConflicts.get(0);// Both difference are equivalent.
// Get the right diff of the conflict; deletion of "ReferencedNode"
EList<Diff> rightConflicts = conflict.getRightDifferences();
assertEquals(1, rightConflicts.size());
holdingRefDeletionDiff = rightConflicts.get(0);
// Get the required by diff of the right conflict
EList<Diff> rightRequiredBy = holdingRefDeletionDiff.getRequiredBy();
assertEquals(1, rightRequiredBy.size());
deletedNodeDeletionDiff = rightRequiredBy.get(0);
}
/**
* In the resulting comparison model we have:
* <ul>
* <li>Two equivalent differences which are the reference changes between "HoldingReference" and
* "ReferencedNode"</li>
* <li>One deletion difference (deletion of "HoldingDeletedNode") that requires a another deletion
* difference (deletion of "RefencedNode")</li>
* <ul>
* This test aims to check that accepting one of the two equivalent differences should reject the deletion
* of "ReferencedNode", and doesn't modify the state of "HoldingDeletedNode".
*/
@Test
public void testAcceptConflictDiffWithConflictingDiffWithRequiredBy() {
MergeRunnableImpl mergeRunnable = new MergeRunnableImpl(true, false, ACCEPT);
mergeRunnable.merge(Collections.singletonList(refChangeDiff), false, mergerRegistry);
assertEquals(MERGED, refChangeDiff.getState());
assertEquals(ACCEPT, getMergeMode(refChangeDiff, true, false));
assertEquals(DISCARDED, holdingRefDeletionDiff.getState());
assertEquals(REJECT, getMergeMode(holdingRefDeletionDiff, true, false));
assertEquals(DISCARDED, deletedNodeDeletionDiff.getState());
assertEquals(REJECT, getMergeMode(deletedNodeDeletionDiff, true, false));
// TODO The optimal way is to have the deletedNodeDeletionDiff unresolved
// Assert.assertEquals(DifferenceState.UNRESOLVED, deletedNodeDeletionDiff.getState());
// Checks that the content of the left resource is correct.
Resource leftResource = (Resource)scope.getLeft();
EList<EObject> content = leftResource.getContents();
assertEquals(1, content.size());
Node root = (Node)content.get(0);
EList<Node> children = root.getContainmentRef1();
// Checks that "HoldingDeletedNode" is in the model.
assertEquals(2, children.size());
Node firstChildren = children.get(0);
// Checks that "ReferencedNode" is in the model.
assertEquals(1, firstChildren.getContainmentRef1().size());
}
/**
* Same test described above but this time the merge is done programmatically.
*/
@Test
public void testAcceptConflictDiffWithConflictingDiffWithRequiredByProg() {
new BatchMerger(mergerRegistry).copyAllLeftToRight(Arrays.asList(refChangeDiff), new BasicMonitor());
assertEquals(MERGED, refChangeDiff.getState());
assertEquals(DISCARDED, holdingRefDeletionDiff.getState());
assertEquals(DISCARDED, deletedNodeDeletionDiff.getState());
// Checks that the content of the right resource is correct.
Resource leftResource = (Resource)scope.getLeft();
EList<EObject> content = leftResource.getContents();
assertEquals(1, content.size());
Node root = (Node)content.get(0);
EList<Node> children = root.getContainmentRef1();
// Checks that "DeletedNode" is in the model.
assertEquals(2, children.size());
Node firstChildren = children.get(0);
// Checks that "ReferencedNode" is in the model.
assertEquals(1, firstChildren.getContainmentRef1().size());
}
/**
* Input data for this bug.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
public class Bug434828InputData extends AbstractInputData {
private static final String PATH_PREFIX = "data/_434828/"; //$NON-NLS-1$
public Resource getResource(String resourceName) throws IOException {
StringBuilder resourceURL = new StringBuilder(PATH_PREFIX);
resourceURL.append(resourceName);
return loadFromClassLoader(resourceURL.toString());
}
}
}