package com.sap.ap.metamodel.utils;
import java.util.HashMap;
import junit.framework.TestCase;
import modelmanagement.ModelmanagementFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.ocl.examples.eventmanager.EventFilter;
import org.eclipse.ocl.examples.eventmanager.EventManager;
import org.eclipse.ocl.examples.eventmanager.EventManagerFactory;
import behavioral.actions.ActionsFactory;
import behavioral.actions.Block;
import data.classes.Association;
import data.classes.AssociationEnd;
import data.classes.ClassesFactory;
import data.classes.ClassesPackage;
import data.classes.LinkSetting;
import data.classes.LinkTraversal;
import data.classes.MethodSignature;
import data.classes.Parameter;
import data.classes.SapClass;
import data.classes.TypeAdapter;
import data.classes.util.ClassesValidator;
public class MetamodelTests extends TestCase {
private ResourceSet resourceSet;
private Resource resource;
public void setUp() {
resourceSet = new ResourceSetImpl();
resource = resourceSet.createResource(URI.createURI("http://some_uri.xmi"));
resourceSet.getResources().add(resource);
}
public void tearDown() {
}
public void testMetamodelAvailability() {
EClass typeAdapter = ClassesPackage.eINSTANCE.getTypeAdapter();
assertEquals("TypeAdapter", typeAdapter.getName());
}
public void testLinkRemoveEventUponElementDelete() {
final boolean[] ok = new boolean[1];
final SapClass clazz = ClassesFactory.eINSTANCE.createSapClass();
final TypeAdapter ta = ClassesFactory.eINSTANCE.createTypeAdapter();
resource.getContents().add(clazz);
resource.getContents().add(ta);
EventManager em = EventManagerFactory.eINSTANCE.getEventManagerFor(resourceSet);
EventFilter filter = EventManagerFactory.eINSTANCE.createStructuralFeatureFilter(ClassesPackage.eINSTANCE.getTypeAdapter_To());
em.subscribe(filter, new AdapterImpl() {
public void notifyChanged(Notification event) {
if (event.getEventType() == Notification.SET && event.getNewValue() == null) {
ok[0] = ok[0] || event.getNotifier().equals(ta) &&
event.getOldValue().equals(clazz);
}
}
});
ta.setTo(clazz);
ta.setTo(null);
// If this test fails, check if in the target IDE there is an editor or the Runlet console open;
// this may turn off events during creating a deep copy / snapshot of the object under edit
// which temporarily disables the event handling required / tested here
assertTrue(ok[0]);
}
/**
* Asserts that two types don't just conform based on their signature structures
*/
public void testNoStructuralConformance() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();;
c1.setName("C1");
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
assertFalse("Two classes that don't have an adapter between them must not conform",
c1.conformsTo(c2));
}
/**
* Asserts that two types conform if there is one adapter between them
*/
public void testConformanceWithOneAdapter() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setAdapted(c1);
adapter.setTo(c2);
assertTrue("Classes with no signatures and an adapter between them should conform",
c1.conformsTo(c2));
}
/**
* Asserts that two types conform if there is one adapter between them
*/
public void testConformanceWithSignaturesAndOneAdapter() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
MethodSignature s1 = ClassesFactory.eINSTANCE.createMethodSignature();
s1.setName("someSignature");
c1.getOwnedSignatures().add(s1);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
MethodSignature s2 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("someSignature");
c2.getOwnedSignatures().add(s2);
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setName("FromC1ToC2");
adapter.setAdapted(c1);
adapter.setTo(c2);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter, diagnostics, new HashMap<Object, Object>());
assertTrue("Adapter should be valid", diagnostics.getSeverity() == Diagnostic.OK);
assertTrue("Classes with no signatures and an adapter between them should conform",
c1.conformsTo(c2));
}
/**
* Check that adapter invariants are really enforced
*/
public void testAdapterInvariantsEnforcement() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
MethodSignature s1 = ClassesFactory.eINSTANCE.createMethodSignature();
s1.setName("s1");
c1.getOwnedSignatures().add(s1);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
MethodSignature s2 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("s2");
c2.getOwnedSignatures().add(s2);
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setName("FromC1ToC2");
adapter.setAdapted(c1);
adapter.setTo(c2);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter, diagnostics, new HashMap<Object, Object>());
assertTrue("Adapter should be considered invalid and should violate the IsFullAdaptationToTo constraint",
diagnostics.getSeverity() != Diagnostic.OK &&
diagnostics.getChildren().iterator().next().getMessage().startsWith(
"The 'IsFullAdaptationToTo' constraint is violated")
);
}
/**
* Check that the constraint works that requires an association between two value classes to
* have at least one non-equality-relevant end
*/
public void testDoubleEqualityRelevantValueClassAssociation() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
c1.setValueType(true);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
c2.setValueType(true);
Association a = MetamodelUtils.createAssociation(resourceSet, c1, "c1", 0, 1, true, false, false, false, c2, "c2", 0, 1, true, false, false, false);
a.setName("a");
modelmanagement.Package p = ModelmanagementFactory.eINSTANCE.createPackage();
p.setName("p");
c1.setPackage_(p);
c2.setPackage_(p);
p.getAssociations().add(a);
for (AssociationEnd ae:a.getEnds()) {
ae.setContributesToEquality(true);
}
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(a, diagnostics, new HashMap<Object, Object>());
assertEquals("Expected exactly one constraint violation", 1, diagnostics.getChildren().size());
assertTrue(diagnostics.getChildren().iterator().next().getMessage().startsWith(
"The 'AtMostOneEqualityContributionForTwoValueClasses' constraint is violated"));
}
/**
* Check that no modifying feature of an association end can be exposed if that
* would modify a value
*/
public void testValueImmutability() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1Value");
c1.setValueType(true);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2Entity");
c2.setValueType(false);
Association a = MetamodelUtils.createAssociation(resourceSet, c1, "c1", 0, 1, true, false, false, false, c2, "c2", 0, 1, true, false, false, false);
a.setName("a");
modelmanagement.Package p = ModelmanagementFactory.eINSTANCE.createPackage();
p.setName("p");
c1.setPackage_(p);
c2.setPackage_(p);
p.getAssociations().add(a);
assertEquals("c1", a.getEnds().get(0).getName());
a.getEnds().get(0).setContributesToEquality(true);
// expose eqality-relevant association as getter (required!)
MethodSignature getter = ClassesFactory.eINSTANCE.createMethodSignature();
getter.setName("getC2");
getter.setOutput(a.getEnds().get(1).getType());
LinkTraversal linkTraversal = ClassesFactory.eINSTANCE.createLinkTraversal();
linkTraversal.setEnd(a.getEnds().get(1));
linkTraversal.setImplements_(getter);
c1.getOwnedSignatures().add(getter);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(a, diagnostics, new HashMap<Object, Object>());
assertEquals(Diagnostic.OK, diagnostics.getSeverity());
diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(c1, diagnostics, new HashMap<Object, Object>());
assertEquals(Diagnostic.OK, diagnostics.getSeverity());
diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(c2, diagnostics, new HashMap<Object, Object>());
assertEquals(Diagnostic.OK, diagnostics.getSeverity());
// expose equality-relevant association as setter (illegal!)
MethodSignature setter = ClassesFactory.eINSTANCE.createMethodSignature();
setter.setName("setC2");
LinkSetting linkSetting = ClassesFactory.eINSTANCE.createLinkSetting();
linkSetting.setEnd(a.getEnds().get(1));
linkSetting.setImplements_(setter);
Parameter setterParam = ClassesFactory.eINSTANCE.createParameter();
setterParam.setName("c2Param");
setter.getInput().add(setterParam);
c1.getOwnedSignatures().add(setter);
diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(linkSetting, diagnostics, new HashMap<Object, Object>());
assertEquals(1, diagnostics.getChildren().size());
assertTrue(diagnostics.getChildren().iterator().next().getMessage().startsWith(
"The 'MustNotModifyExtentIfEqualityRelevantForValueClass' constraint is violated"));
}
/**
* Check that adapter invariants are really enforced
*/
public void testEnforcementNoAbstractSignaturesInAdapter() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
MethodSignature s1 = ClassesFactory.eINSTANCE.createMethodSignature();
s1.setName("s1");
c1.getOwnedSignatures().add(s1);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
MethodSignature s2 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("s2");
c2.getOwnedSignatures().add(s2);
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setName("FromC1ToC2");
adapter.setAdapted(c1);
adapter.setTo(c2);
MethodSignature adapterSig = ClassesFactory.eINSTANCE.createMethodSignature();
adapterSig.setName("s2");
adapter.getOwnedSignatures().add(adapterSig);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter, diagnostics, new HashMap<Object, Object>());
assertEquals(1, diagnostics.getChildren().size());
assertTrue(diagnostics.getChildren().iterator().next().getMessage().startsWith("The 'SignaturesCannotBeAbstract' constraint is violated"));
}
/**
* Check that adapter invariants are really enforced
*/
public void testConformanceWithoutSignatureAdaptation() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
MethodSignature s1 = ClassesFactory.eINSTANCE.createMethodSignature();
s1.setName("s1");
c1.getOwnedSignatures().add(s1);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
MethodSignature s2 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("s2");
c2.getOwnedSignatures().add(s2);
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setName("FromC1ToC2");
adapter.setAdapted(c1);
adapter.setTo(c2);
MethodSignature adapterSig = ClassesFactory.eINSTANCE.createMethodSignature();
adapterSig.setName("s2");
Block impl = ActionsFactory.eINSTANCE.createBlock();
impl.setImplements_(adapterSig);
adapter.getOwnedSignatures().add(adapterSig);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter, diagnostics, new HashMap<Object, Object>());
assertEquals("Adapter should be valid", Diagnostic.OK, diagnostics.getSeverity());
assertTrue("Classes with no signatures and an adapter between them should conform",
c1.conformsTo(c2));
}
/**
* Check that adapter invariants are really enforced
*/
public void testConformanceAlongAdapterChain() {
SapClass c1 = ClassesFactory.eINSTANCE.createSapClass();
c1.setName("C1");
MethodSignature s1 = ClassesFactory.eINSTANCE.createMethodSignature();
s1.setName("s1");
c1.getOwnedSignatures().add(s1);
SapClass c2 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C2");
MethodSignature s2 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("s2");
c2.getOwnedSignatures().add(s2);
TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter.setName("FromC1ToC2");
adapter.setAdapted(c1);
adapter.setTo(c2);
MethodSignature adapterSig = ClassesFactory.eINSTANCE.createMethodSignature();
adapterSig.setName("s2");
Block impl = ActionsFactory.eINSTANCE.createBlock();
impl.setImplements_(adapterSig);
adapter.getOwnedSignatures().add(adapterSig);
SapClass c3 = ClassesFactory.eINSTANCE.createSapClass();
c2.setName("C3");
MethodSignature s3 = ClassesFactory.eINSTANCE.createMethodSignature();
s2.setName("s3");
c3.getOwnedSignatures().add(s3);
TypeAdapter adapter2 = ClassesFactory.eINSTANCE.createTypeAdapter();
adapter2.setName("FromC2ToC3");
adapter2.setAdapted(c2);
adapter2.setTo(c3);
MethodSignature adapter2Sig = ClassesFactory.eINSTANCE.createMethodSignature();
adapterSig.setName("s3");
Block impl2 = ActionsFactory.eINSTANCE.createBlock();
impl2.setImplements_(adapter2Sig);
adapter2.getOwnedSignatures().add(adapter2Sig);
BasicDiagnostic diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter, diagnostics, new HashMap<Object, Object>());
assertEquals("Adapter should be valid", Diagnostic.OK, diagnostics.getSeverity());
diagnostics = new BasicDiagnostic();
ClassesValidator.INSTANCE.validate(adapter2, diagnostics, new HashMap<Object, Object>());
assertEquals("Adapter should be valid", Diagnostic.OK, diagnostics.getSeverity());
assertTrue("Classes with no signatures and an adapter between them should conform",
c1.conformsTo(c3));
}
}