/*******************************************************************************
* Copyright (c) 2006, 2009 IBM Corporation, Zeligsoft Inc., 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:
* IBM - Initial API and implementation
* Zeligsoft - Bugs 248869, 242236
*******************************************************************************/
package org.eclipse.ocl.ecore.tests;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.TypeResolver;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.ocl.ecore.OCL;
import org.eclipse.ocl.ecore.OperationCallExp;
import org.eclipse.ocl.ecore.TypeType;
import org.eclipse.ocl.expressions.ExpressionsPackage;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.types.TypesPackage;
import org.eclipse.ocl.utilities.UtilitiesPackage;
/**
* Tests for serialization of OCL constraints and expressions.
*
* @author Christian W. Damus (cdamus)
*/
@SuppressWarnings("nls")
public class SerializationTest
extends AbstractTestSuite {
Resource res;
/**
* Tests the serialization of an expression that uses no standard library types.
*/
public void test_basicSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eSuperPackage");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression that uses OCL primitive types.
*/
public void test_primitiveTypeSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eSubpackages->size() > 2");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression that uses collections of
* primitive types.
*/
public void test_primitiveCollectionTypeSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eSubpackages->collect(eClassifiers->size())");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression that uses collections of
* model types. Incidentally tests variable serialization via a let expression.
*/
public void test_modelCollectionTypeSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"let subs : Collection(EPackage) = self.eSubpackages in subs->size() > 2");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression that references model types in
* type expressions.
*/
public void test_typeExpSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eClassifiers->forAll(c | " +
"c.oclIsKindOf(EClass) implies EClass.allInstances()->includes(c.oclAsType(EClass)))");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression containing a tuple literal.
*/
public void test_tupleSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eSubpackages->collect(" +
"Tuple{pkg = name, size = eClassifiers->size()})");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression containing an operation message
* expression.
*/
public void test_operationMessageSerialization() {
OCLExpression<EClassifier> expr = parseExpression(
fruit,
"let msgs : Sequence(OclMessage) = self^^ripen(?) in " +
"msgs->forAll(m | m.hasReturned() implies m.color <> Color::black)");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression containing an operation message
* expression.
*/
public void test_signalMessageSerialization() {
expectModified = true;
ocl.dispose();
ocl = OCL.newInstance(new MessagesTest.MessagingFruitEnvironmentFactory(this),
res);
helper = ocl.createOCLHelper();
OCLExpression<EClassifier> expr = parseExpression(
fruit,
"let msgs : Sequence(OclMessage) = self^^Drop(?, ?) in " +
"msgs->forAll(m | m.delay = 0 implies m.stem.oclIsUndefined())");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
}
/**
* Tests the serialization of an expression referencing an additional operation.
*/
public void test_additionalOperationSerialization() {
helper.setContext(EcorePackage.Literals.EPACKAGE);
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
EOperation eoper = null;
try {
eoper = helper.defineOperation(
"getUniqueClassifierNames() : Set(String) = " +
"self.eClassifiers->collect(name)->asSet()");
assertSame(eoper,
env.getTypeResolver().resolveAdditionalOperation(
EcorePackage.Literals.EPACKAGE, eoper));
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.getUniqueClassifierNames()->size()");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
// verify the loading of an environment from a resource
OCL newOCL = OCL.newInstance(
env.getFactory(),
env.getTypeResolver().getResource());
EOperation newOper = newOCL.getEnvironment().getTypeResolver().resolveAdditionalOperation(
EcorePackage.Literals.EPACKAGE, eoper);
assertNotSame(eoper, newOper);
}
/**
* Tests the serialization of an expression referencing an additional property.
*/
public void test_additionalPropertySerialization() {
helper.setContext(EcorePackage.Literals.EPACKAGE);
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
EStructuralFeature esf = null;
try {
esf = helper.defineAttribute(
"uniqueClassifierNames : Set(String) = " +
"self.eClassifiers->collect(name)->asSet()");
assertSame(esf,
env.getTypeResolver().resolveAdditionalAttribute(
EcorePackage.Literals.EPACKAGE, esf));
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.uniqueClassifierNames->size()");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
// verify the loading of an environment from a resource
OCL newOCL = OCL.newInstance(
env.getFactory(),
env.getTypeResolver().getResource());
EStructuralFeature newSF = newOCL.getEnvironment().getTypeResolver().resolveAdditionalAttribute(
EcorePackage.Literals.EPACKAGE, esf);
assertNotSame(esf, newSF);
}
/**
* Tests the serialization of TypeTypes.
*/
public void test_typeTypeSerialization_183494() {
OCLExpression<EClassifier> expr = parseExpression(
EcorePackage.Literals.EPACKAGE,
"EPackage.allInstances()");
String toStringForm = expr.toString();
String serialForm = serialize(expr);
expr = loadExpression(serialForm);
validate(expr); // ensure that it is structurally valid
assertEquals(toStringForm, expr.toString()); // should "look" the same
assertTrue(expr instanceof OperationCallExp);
expr = ((OperationCallExp) expr).getSource();
assertNotNull(expr);
assertTrue(expr.getType() instanceof TypeType);
TypeType typeType = (TypeType) expr.getType();
assertSame(EcorePackage.Literals.EPACKAGE, typeType.getReferredType());
}
/**
* Tests that the OclType constant is not serialized.
*/
public void test_OclType_serialization_226455() {
TypeResolver<EClassifier, EOperation, EStructuralFeature> resolver = ocl
.getEnvironment().getTypeResolver();
EClassifier oclType = resolver.resolve(getOCLStandardLibrary().getOclType());
assertSame(getOCLStandardLibrary().getOclType(), oclType);
assertTrue(resolver.getResource().getContents().isEmpty());
}
/**
* Tests for appropriate resolution of 'typespec' as in oclIsKindOf() operation.
*/
public void test_typespec_resolution_226455() {
parseExpression(
EcorePackage.Literals.EPACKAGE,
"self.eClassifiers->any(oclIsKindOf(EClass))");
Resource res = ocl.getEnvironment().getTypeResolver().getResource();
EPackage typesPackage = null;
for (EObject next : res.getContents()) {
if ((next instanceof EPackage)
&& "types".equals(((EPackage) next).getName())) {
typesPackage = (EPackage) next;
break;
}
}
assertNotNull(typesPackage);
assertEquals(1, typesPackage.getEClassifiers().size());
EClassifier first = typesPackage.getEClassifiers().get(0);
assertTrue(first instanceof TypeType);
assertSame(EcorePackage.Literals.ECLASS, ((TypeType) first).getReferredType());
}
public void test_referenceToGenericOCLExpressionsPackage_214878() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("foo");
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("Foo");
epackage.getEClassifiers().add(eclass);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("expr");
ref.setEType(ExpressionsPackage.Literals.OCL_EXPRESSION);
eclass.getEStructuralFeatures().add(ref);
String serialForm = serialize(epackage);
epackage = load(serialForm, EPackage.class);
eclass = (EClass) epackage.getEClassifier("Foo");
assertNotNull(eclass);
assertFalse(eclass.eIsProxy());
ref = (EReference) eclass.getEStructuralFeature("expr");
assertNotNull(ref);
assertFalse(ref.eIsProxy());
assertSame(ExpressionsPackage.Literals.OCL_EXPRESSION, ref.getEType());
// correct loading is one thing. but the reference must look
// correct in the serial form, also
assertFalse(serialForm.contains(Environment.OCL_NAMESPACE_URI + "#//expressions/OCLExpression"));
assertTrue(serialForm.contains(ExpressionsPackage.eNS_URI + "#//OCLExpression"));
}
public void test_referenceToGenericOCLTypesPackage_214878() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("foo");
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("Foo");
epackage.getEClassifiers().add(eclass);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("any");
ref.setEType(TypesPackage.Literals.ANY_TYPE);
eclass.getEStructuralFeatures().add(ref);
String serialForm = serialize(epackage);
epackage = load(serialForm, EPackage.class);
eclass = (EClass) epackage.getEClassifier("Foo");
assertNotNull(eclass);
assertFalse(eclass.eIsProxy());
ref = (EReference) eclass.getEStructuralFeature("any");
assertNotNull(ref);
assertFalse(ref.eIsProxy());
assertSame(TypesPackage.Literals.ANY_TYPE, ref.getEType());
// correct loading is one thing. but the reference must look
// correct in the serial form, also
assertFalse(serialForm.contains(Environment.OCL_NAMESPACE_URI + "#//types/AnyType"));
assertTrue(serialForm.contains(TypesPackage.eNS_URI + "#//AnyType"));
}
public void test_referenceToGenericOCLUtilitiesPackage_214878() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("foo");
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("Foo");
epackage.getEClassifiers().add(eclass);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("ast");
ref.setEType(UtilitiesPackage.Literals.AST_NODE);
eclass.getEStructuralFeatures().add(ref);
String serialForm = serialize(epackage);
epackage = load(serialForm, EPackage.class);
eclass = (EClass) epackage.getEClassifier("Foo");
assertNotNull(eclass);
assertFalse(eclass.eIsProxy());
ref = (EReference) eclass.getEStructuralFeature("ast");
assertNotNull(ref);
assertFalse(ref.eIsProxy());
assertSame(UtilitiesPackage.Literals.AST_NODE, ref.getEType());
// correct loading is one thing. but the reference must look
// correct in the serial form, also
assertFalse(serialForm.contains(Environment.OCL_NAMESPACE_URI + "#//utilities/ASTNode"));
assertTrue(serialForm.contains(UtilitiesPackage.eNS_URI + "#//ASTNode"));
}
public void test_referenceToOCLEcoreMetamodel_214878() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("foo");
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("Foo");
epackage.getEClassifiers().add(eclass);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("expr");
ref.setEType(org.eclipse.ocl.ecore.EcorePackage.Literals.OCL_EXPRESSION);
eclass.getEStructuralFeatures().add(ref);
String serialForm = serialize(epackage);
epackage = load(serialForm, EPackage.class);
eclass = (EClass) epackage.getEClassifier("Foo");
assertNotNull(eclass);
assertFalse(eclass.eIsProxy());
ref = (EReference) eclass.getEStructuralFeature("expr");
assertNotNull(ref);
assertFalse(ref.eIsProxy());
assertSame(org.eclipse.ocl.ecore.EcorePackage.Literals.OCL_EXPRESSION, ref.getEType());
// correct loading is one thing. but the reference must look
// correct in the serial form, also
assertFalse(serialForm.contains(Environment.OCL_NAMESPACE_URI + "#//ecore/OCLExpression"));
assertTrue(serialForm.contains(org.eclipse.ocl.ecore.EcorePackage.eNS_URI + "#//OCLExpression"));
}
//
// Framework methods
//
@Override
protected void setUp() {
//FIXME: Need to use extrinsic IDs because lookup fails on hierarchical
// name-based fragments owing to %-encoding of the names in references
res = new XMIResourceImpl() {
@Override
protected boolean useIDs() {
return true;
}
@Override
protected boolean useUUIDs() {
return true;
}
};
res.setURI(URI.createFileURI("/tmp/ocltest.xmi"));
((XMLResource) res).setEncoding("UTF-8");
super.setUp();
resourceSet.getResources().add(res);
}
@Override
protected OCL createOCL() {
// OCL ocl = super.createOCL();
EcoreEnvironmentFactory factory = new EcoreEnvironmentFactory(resourceSet.getPackageRegistry());
EcoreEnvironment environment = (EcoreEnvironment) factory.loadEnvironment(res);
// EcoreEnvironmentFactory factory = ocl.;
// EcoreEnvironment result = new EcoreEnvironment(resourceSet.getPackageRegistry(), res);
// result.setFactory(this);
return OCL.newInstance(environment);
}
protected OCLExpression<EClassifier> parseExpression(
EClassifier context, String expr) {
helper.setContext(context);
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
resourceSet.getResources().add(env.getTypeResolver().getResource());
OCLExpression<EClassifier> result = null;
try {
result = helper.createQuery(expr);
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
assertNotNull(result);
return result;
}
protected String serialize(EObject eobject) {
String result = null;
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
res.getContents().add(eobject);
res.save(output,
Collections.singletonMap(XMLResource.OPTION_SAVE_TYPE_INFORMATION, Boolean.TRUE));
result = output.toString("UTF-8");
} catch (Exception e) {
fail("Exception serializing AST: " + e.getLocalizedMessage());
}
assertNotNull(result);
assertFalse(result.contains("ocl://"));
return result;
}
protected List<EObject> deserialize(String serial) {
List<EObject> result;
try {
ByteArrayInputStream input = new ByteArrayInputStream(serial.getBytes());
res.unload();
res.load(input, Collections.EMPTY_MAP);
// reload the environment
ocl = createOCL();
helper = createHelper();
assertFalse("No contents in serial data", res.getContents().isEmpty());
assertNoProxies(res);
result = res.getContents();
} catch (Exception e) {
fail("Exception deserializing AST: " + e.getLocalizedMessage());
result = Collections.emptyList(); // fail will throw
}
assertNotNull(result);
return result;
}
@SuppressWarnings("unchecked")
protected OCLExpression<EClassifier> loadExpression(String serial) {
return load(serial, OCLExpression.class);
}
protected Constraint loadConstraint(String serial) {
return load(serial, Constraint.class);
}
@SuppressWarnings("unchecked")
protected <T extends EObject> T load(String serial, Class<T> expectedType) {
T result = null;
List<EObject> objects = deserialize(serial);
for (Object next : objects) {
if (expectedType.isInstance(next)) {
result = (T) next;
break;
}
}
assertNotNull("Did not deserialize a " + expectedType.getSimpleName(), result);
return result;
}
protected void assertNoProxies(Resource res) {
for (Iterator<EObject> iter = res.getAllContents(); iter.hasNext();) {
for (EObject xref : iter.next().eCrossReferences()) {
assertFalse("Unresolved reference: " + xref, xref.eIsProxy());
}
}
}
}