blob: f738fec83ec2bc2069fc4c4263286cba16fc574d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM - Initial API and implementation
* Zeligsoft - Bug 242236
*******************************************************************************/
package org.eclipse.ocl.uml.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.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
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.expressions.OCLExpression;
import org.eclipse.ocl.uml.OCL;
import org.eclipse.ocl.uml.OperationCallExp;
import org.eclipse.ocl.uml.TypeType;
import org.eclipse.ocl.uml.UMLEnvironment;
import org.eclipse.ocl.uml.UMLEnvironmentFactory;
import org.eclipse.ocl.uml.UMLPackage;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
/**
* 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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"self.nestingPackage");
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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"self.nestedPackage->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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"self.nestedPackage->collect(ownedType->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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"let subs : Collection(Package) = self.nestedPackage 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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"self.ownedType->forAll(c | " +
"c.oclIsKindOf(Class) implies Class.allInstances()->includes(c.oclAsType(Class)))");
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<Classifier> expr = parseExpression(
getMetaclass("Package"),
"self.nestedPackage->collect(" +
"Tuple{pkg = name, size = ownedType->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<Classifier> 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() {
OCLExpression<Classifier> 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(getMetaclass("Package"));
Operation oper = null;
try {
oper = helper.defineOperation(
"getUniqueClassifierNames() : Set(String) = " +
"self.ownedType->collect(name)->asSet()");
assertSame(oper,
ocl.getEnvironment().getTypeResolver().resolveAdditionalOperation(
getMetaclass("Package"), oper));
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
OCLExpression<Classifier> expr = parseExpression(
getMetaclass("Package"),
"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(
ocl.getEnvironment().getFactory(),
ocl.getEnvironment().getTypeResolver().getResource());
Operation newOper = newOCL.getEnvironment().getTypeResolver().resolveAdditionalOperation(
getMetaclass("Package"), oper);
assertNotSame(oper, newOper);
}
/**
* Tests the serialization of an expression referencing an additional property.
*/
public void test_additionalPropertySerialization() {
helper.setContext(getMetaclass("Package"));
Property prop = null;
try {
prop = helper.defineAttribute(
"uniqueClassifierNames : Set(String) = " +
"self.ownedType->collect(name)->asSet()");
assertSame(prop,
ocl.getEnvironment().getTypeResolver().resolveAdditionalAttribute(
getMetaclass("Package"), prop));
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
OCLExpression<Classifier> expr = parseExpression(
getMetaclass("Package"),
"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(
ocl.getEnvironment().getFactory(),
ocl.getEnvironment().getTypeResolver().getResource());
Property newProp = newOCL.getEnvironment().getTypeResolver().resolveAdditionalAttribute(
getMetaclass("Package"), prop);
assertNotSame(prop, newProp);
}
/**
* Tests the serialization of TypeTypes.
*/
public void test_typeTypeSerialization_183494() {
OCLExpression<Classifier> expr = parseExpression(
getMetaclass("Package"),
"Package.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(getMetaclass("Package"), typeType.getReferredType());
}
/**
* Tests that the OclType constant is not serialized.
*/
public void test_OclType_serialization_226455() {
TypeResolver<Classifier, Operation, Property> resolver = ocl
.getEnvironment().getTypeResolver();
Classifier 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(
getMetaclass("Package"),
"self.ownedType->any(oclIsKindOf(Class))");
Resource res = ocl.getEnvironment().getTypeResolver().getResource();
Package typesPackage = null;
for (EObject next : res.getContents()) {
if ((next instanceof Package)
&& "types".equals(((Package) next).getName())) {
typesPackage = (Package) next;
break;
}
}
assertNotNull(typesPackage);
assertEquals(1, typesPackage.getOwnedTypes().size());
Classifier first = (Classifier) typesPackage.getOwnedTypes().get(0);
assertTrue(first instanceof TypeType);
assertSame(getMetaclass("Class"), ((TypeType) first).getReferredType());
}
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(UMLPackage.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(UMLPackage.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 + "#//uml/OCLExpression"));
assertTrue(serialForm.contains(UMLPackage.eNS_URI + "#//OCLExpression"));
}
//
// Framework methods
//
@Override
protected void setUp() {
//FIXME: Need to use extrinsic IDs because lookup fails on hierarchical
// name-based fragments
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(); // among other things, creates our resource set
resourceSet.getResources().add(res);
}
@Override
protected OCL createOCL() {
UMLEnvironmentFactory factory = new UMLEnvironmentFactory(resourceSet);
UMLEnvironment environment = (UMLEnvironment) factory.loadEnvironment(res);
return OCL.newInstance(environment);
}
protected OCLExpression<Classifier> parseExpression(
Classifier context, String expr) {
helper.setContext(context);
OCLExpression<Classifier> 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<Classifier> 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());
}
}
}
}