/*******************************************************************************
* Copyright (c) 2014 EclipseSource Muenchen GmbH 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:
* Philip Langer - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.compare.tests.merge;
import static org.eclipse.emf.compare.DifferenceSource.LEFT;
import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.notify.Notifier;
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.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.EMFCompare;
import org.eclipse.emf.compare.merge.BatchMerger;
import org.eclipse.emf.compare.merge.IBatchMerger;
import org.eclipse.emf.compare.merge.IMerger;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.tests.merge.data.ThreeWayMergeInputData;
import org.eclipse.emf.compare.tests.nodes.NodesPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.junit.Test;
/**
* Tests three-way comparison of {@link NodesPackage nodes models} and subsequent merging using the
* {@link BatchMerger}.
*
* @author Philip Langer <planger@eclipsesource.com>
*/
public class ThreeWayBatchMergingTest {
final private ThreeWayMergeInputData input = new ThreeWayMergeInputData();
final private IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
final private IBatchMerger merger = new BatchMerger(mergerRegistry);
/**
* Tests a scenario in which a model element is moved from one container into another, whereas the
* original container's type does not provide the containment reference that is used as the target of the
* move. This lead to an NPE (cf. bug #446739). In this test, the move is applied on the left-hand side.
*
* @throws IOException
* if {@link ThreeWayMergeInputData} fails to load the test models.
*/
@Test
public void mergingMoveToDifferentContainmentFeatureLeft() throws IOException {
final Resource origin = input.getMoveToDifferentContainmentFeatureOrigin();
final Resource left = input.getMoveToDifferentContainmentFeatureMove();
final Resource right = input.getMoveToDifferentContainmentFeatureUnchanged();
assertUnchanged(new DefaultComparisonScope(left, right, origin), RIGHT);
batchMergeAndAssertEquality(new DefaultComparisonScope(left, right, origin), LEFT);
}
/**
* Tests a scenario in which a model element is moved from one container into another, whereas the
* original container's type does not provide the containment reference that is used as the target of the
* move. This lead to an NPE (cf. bug #446739). In this test, the move is applied on the right-hand side.
*
* @throws IOException
* if {@link ThreeWayMergeInputData} fails to load the test models.
*/
@Test
public void mergingMoveToDifferentContainmentFeatureRight() throws IOException {
final Resource origin = input.getMoveToDifferentContainmentFeatureOrigin();
final Resource left = input.getMoveToDifferentContainmentFeatureUnchanged();
final Resource right = input.getMoveToDifferentContainmentFeatureMove();
assertUnchanged(new DefaultComparisonScope(left, right, origin), LEFT);
batchMergeAndAssertEquality(new DefaultComparisonScope(left, right, origin), RIGHT);
}
private void assertUnchanged(IComparisonScope scope, DifferenceSource side) {
final Notifier supposeUnchanged;
if (LEFT.equals(side)) {
supposeUnchanged = scope.getLeft();
} else {
supposeUnchanged = scope.getRight();
}
final IComparisonScope scopeForAssert = createTwoWayScopeWithOrigin(scope, supposeUnchanged);
EList<Diff> diffsForAssertion = compare(scopeForAssert).getDifferences();
assertEquals(0, diffsForAssertion.size());
}
private IComparisonScope createTwoWayScopeWithOrigin(IComparisonScope scope, final Notifier notifier) {
return new DefaultComparisonScope(scope.getOrigin(), notifier, null);
}
private void batchMergeAndAssertEquality(IComparisonScope scope, DifferenceSource side) {
batchMerge(scope, side);
assertEqualityOfLeftAndRight(scope);
}
private void batchMerge(IComparisonScope scope, DifferenceSource side) {
Comparison comparison = compare(scope);
final EList<Diff> differences = comparison.getDifferences();
if (LEFT.equals(side)) {
final List<Diff> leftDiffs = filterDiffs(differences, LEFT, false);
merger.copyAllLeftToRight(leftDiffs, new BasicMonitor());
} else {
final List<Diff> rightDiffs = filterDiffs(differences, RIGHT, false);
merger.copyAllRightToLeft(rightDiffs, new BasicMonitor());
}
}
private Comparison compare(IComparisonScope scope) {
return EMFCompare.builder().build().compare(scope);
}
private List<Diff> filterDiffs(List<Diff> diffs, DifferenceSource source, boolean filterConflicting) {
List<Diff> filteredDiffs = new ArrayList<Diff>();
for (Diff diff : diffs) {
if (source.equals(diff.getSource()) && (!isConflicting(diff) || !filterConflicting)) {
filteredDiffs.add(diff);
}
}
return filteredDiffs;
}
private boolean isConflicting(Diff diff) {
return diff.getConflict() != null && ConflictKind.REAL.equals(diff.getConflict().getKind());
}
private void assertEqualityOfLeftAndRight(IComparisonScope scope) {
final Notifier left = scope.getLeft();
final Notifier right = scope.getRight();
final IComparisonScope assertScope = new DefaultComparisonScope(left, right, null);
final Comparison assertComparison = compare(assertScope);
final EList<Diff> assertDiffs = assertComparison.getDifferences();
assertTrue(assertDiffs.isEmpty());
}
}