| /******************************************************************************* |
| * 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()); |
| } |
| } |
| |
| } |