blob: a9b6bb3c778f89a61b0bf0376f7e8e1ad7d1c200 [file] [log] [blame]
/**
* Copyright (c) 2012, 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
* Stefan Dirix - update priority value for UML merger
*/
package org.eclipse.emf.compare.uml2.tests;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Iterators.all;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.emf.common.EMFPlugin;
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.AttributeChange;
import org.eclipse.emf.compare.ComparePackage;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.EMFCompare;
import org.eclipse.emf.compare.EMFCompare.Builder;
import org.eclipse.emf.compare.ReferenceChange;
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.postprocessor.IPostProcessor;
import org.eclipse.emf.compare.postprocessor.PostProcessorDescriptorRegistryImpl;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.tests.postprocess.data.TestPostProcessor;
import org.eclipse.emf.compare.uml2.internal.StereotypedElementChange;
import org.eclipse.emf.compare.uml2.internal.UMLDiff;
import org.eclipse.emf.compare.uml2.internal.merge.OpaqueElementBodyChangeMerger;
import org.eclipse.emf.compare.uml2.internal.merge.UMLMerger;
import org.eclipse.emf.compare.uml2.internal.merge.UMLReferenceChangeMerger;
import org.eclipse.emf.compare.uml2.internal.postprocessor.OpaqueElementBodyChangePostProcessor;
import org.eclipse.emf.compare.uml2.internal.postprocessor.UMLPostProcessor;
import org.eclipse.emf.compare.uml2.profile.test.uml2comparetestprofile.UML2CompareTestProfilePackage;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.internal.resource.UMLResourceFactoryImpl;
import org.junit.After;
import org.junit.Before;
/**
* @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
*/
@SuppressWarnings("nls")
public abstract class AbstractUMLTest {
protected EMFCompare emfCompare;
private IMerger.Registry mergerRegistry;
/**
* Each sublass of AbstractUMLTest have to call this method in a @BeforeClass annotated method. This allow
* each test to customize its context.
*/
public static void fillRegistries() {
if (!EMFPlugin.IS_ECLIPSE_RUNNING) {
EPackage.Registry.INSTANCE.put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE);
EPackage.Registry.INSTANCE.put(ComparePackage.eNS_URI, ComparePackage.eINSTANCE);
EPackage.Registry.INSTANCE.put(UMLPackage.eNS_URI, UMLPackage.eINSTANCE);
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore",
new EcoreResourceFactoryImpl());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("uml", //$NON-NLS-1$
new UMLResourceFactoryImpl());
}
}
/**
* Each sublass of AbstractUMLTest have to call this method in a @BeforeClass annotated method. This allow
* each test to safely delete its context.
*/
public static void resetRegistries() {
if (!EMFPlugin.IS_ECLIPSE_RUNNING) {
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().remove("uml");
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().remove("ecore");
EPackage.Registry.INSTANCE.remove(UML2CompareTestProfilePackage.eNS_URI);
EPackage.Registry.INSTANCE.remove(ComparePackage.eNS_URI);
EPackage.Registry.INSTANCE.remove(EcorePackage.eNS_URI);
}
}
@Before
public void before() {
Builder builder = EMFCompare.builder();
// post-processor and merger registry is not filled in runtime (org.eclipse.emf.compare.rcp not
// loaded)
final IPostProcessor.Descriptor.Registry<String> postProcessorRegistry = new PostProcessorDescriptorRegistryImpl<String>();
registerPostProcessors(postProcessorRegistry);
builder.setPostProcessorRegistry(postProcessorRegistry);
mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
final IMerger umlMerger = new UMLMerger();
final IMerger umlReferenceChangeMerger = new UMLReferenceChangeMerger();
final IMerger opaqueElementBodyChangeMerger = new OpaqueElementBodyChangeMerger();
umlMerger.setRanking(20);
umlReferenceChangeMerger.setRanking(25);
opaqueElementBodyChangeMerger.setRanking(25);
mergerRegistry.add(umlMerger);
mergerRegistry.add(umlReferenceChangeMerger);
mergerRegistry.add(opaqueElementBodyChangeMerger);
emfCompare = builder.build();
}
/**
* Used to register new post processors.
*
* @param postProcessorRegistry
*/
protected void registerPostProcessors(
final IPostProcessor.Descriptor.Registry<String> postProcessorRegistry) {
postProcessorRegistry.put(UMLPostProcessor.class.getName(),
new TestPostProcessor.TestPostProcessorDescriptor(Pattern
.compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null,
new UMLPostProcessor(), 20));
postProcessorRegistry.put(OpaqueElementBodyChangePostProcessor.class.getName(),
new TestPostProcessor.TestPostProcessorDescriptor(Pattern
.compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null,
new OpaqueElementBodyChangePostProcessor(), 25));
}
@After
public void cleanup() {
for (ResourceSet set : getInput().getSets()) {
for (Resource res : set.getResources()) {
res.unload();
}
set.getResources().clear();
}
getInput().getSets().clear();
}
protected EMFCompare getCompare() {
return emfCompare;
}
protected Comparison compare(Notifier left, Notifier right) {
return compare(left, right, null);
}
protected Comparison compare(Notifier left, Notifier right, Notifier origin) {
IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
return getCompare().compare(scope);
}
protected IMerger.Registry getMergerRegistry() {
return mergerRegistry;
}
protected enum TestKind {
ADD, DELETE;
}
protected static int count(List<Diff> differences, Predicate<Object> p) {
int count = 0;
final Iterator<Diff> result = Iterators.filter(differences.iterator(), p);
while (result.hasNext()) {
count++;
result.next();
}
return count;
}
public static Predicate<? super Diff> onRealFeature(final EStructuralFeature feature) {
return new Predicate<Diff>() {
public boolean apply(Diff input) {
final EStructuralFeature affectedFeature;
if (input instanceof AttributeChange) {
affectedFeature = ((AttributeChange)input).getAttribute();
} else if (input instanceof ReferenceChange) {
affectedFeature = ((ReferenceChange)input).getReference();
} else {
return false;
}
return feature == affectedFeature;
}
};
}
public static Predicate<? super Diff> isChangeAdd() {
return new Predicate<Diff>() {
public boolean apply(Diff input) {
if (input instanceof ReferenceChange) {
return ReferenceUtil.getAsList(input.getMatch().getLeft(),
((ReferenceChange)input).getReference()).contains(
((ReferenceChange)input).getValue());
} else if (input instanceof AttributeChange) {
return ReferenceUtil.getAsList(input.getMatch().getLeft(),
((AttributeChange)input).getAttribute()).contains(
((AttributeChange)input).getValue());
}
return false;
}
};
}
protected static Predicate<Diff> discriminantInstanceOf(final EClass clazz) {
return new Predicate<Diff>() {
public boolean apply(Diff input) {
return input instanceof UMLDiff && clazz.isInstance(((UMLDiff)input).getDiscriminant());
}
};
}
protected abstract AbstractUMLInputData getInput();
protected void testMergeLeftToRight(Notifier left, Notifier right, Notifier origin) {
testMergeLeftToRight(left, right, origin, false);
}
protected void testMergeRightToLeft(Notifier left, Notifier right, Notifier origin) {
testMergeRightToLeft(left, right, origin, false);
}
protected void testMergeLeftToRight(Notifier left, Notifier right, Notifier origin, boolean pseudoAllowed) {
final IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
final Comparison comparisonBefore = getCompare().compare(scope);
EList<Diff> differencesBefore = comparisonBefore.getDifferences();
final IBatchMerger merger = new BatchMerger(mergerRegistry);
merger.copyAllLeftToRight(differencesBefore, new BasicMonitor());
final Comparison comparisonAfter = getCompare().compare(scope);
EList<Diff> differencesAfter = comparisonAfter.getDifferences();
final boolean diffs;
if (pseudoAllowed) {
diffs = all(differencesAfter.iterator(), hasConflict(ConflictKind.PSEUDO));
} else {
diffs = differencesAfter.isEmpty();
}
assertTrue("Comparison#getDifferences() must be empty after copyAllLeftToRight", diffs);
}
protected void testMergeRightToLeft(Notifier left, Notifier right, Notifier origin, boolean pseudoAllowed) {
final IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
final Comparison comparisonBefore = getCompare().compare(scope);
EList<Diff> differencesBefore = comparisonBefore.getDifferences();
final IBatchMerger merger = new BatchMerger(mergerRegistry);
merger.copyAllRightToLeft(differencesBefore, new BasicMonitor());
final Comparison comparisonAfter = getCompare().compare(scope);
EList<Diff> differencesAfter = comparisonAfter.getDifferences();
final boolean diffs;
if (pseudoAllowed) {
diffs = all(differencesAfter.iterator(), hasConflict(ConflictKind.PSEUDO));
} else {
diffs = differencesAfter.isEmpty();
}
assertTrue("Comparison#getDifferences() must be empty after copyAllRightToLeft", diffs);
}
protected void testIntersections(Comparison comparison) {
for (Diff diff : comparison.getDifferences()) {
int realRefinesSize = Iterables.size(Iterables.filter(diff.getRefines(),
not(instanceOf(StereotypedElementChange.class))));
assertFalse("Wrong number of refines (without StereotypedElementChange) on" + diff,
realRefinesSize > 1);
int stereotypedElementChangeRefines = Iterables.size(Iterables.filter(diff.getRefines(),
instanceOf(StereotypedElementChange.class)));
assertFalse("Wrong number of refines (of type StereotypedElementChange) on " + diff,
stereotypedElementChangeRefines > 1);
}
}
}