blob: 1dc0a406fe727c81d40fb83d16810a3a41375db3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 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
*******************************************************************************/
package org.eclipse.ocl.ecore.tests;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
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.EParameter;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.OCLInput;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.ExpressionInOCL;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.utilities.UMLReflection;
/**
* Tests support for parsing OCL documents.
*
* @author Christian W. Damus (cdamus)
*/
@SuppressWarnings("nls")
public class OCLDocumentTest extends AbstractTestSuite {
Map<String, Constraint> constraints;
public void test_multipleInvariants() {
Constraint notBlack = getConstraint("not_black");
Constraint notFoo = getConstraint("not_foo");
assertMatchingContextVariables(fruit, notBlack);
assertMatchingContextVariables(fruit, notFoo);
EObject anApple = fruitFactory.create(apple);
anApple.eSet(fruit_color, color_black);
anApple.eSet(apple_label, "Foo");
// this constraint actually uses the derivation of the Fruit::name
// property, defined in the Apple context :-)
assertFalse(ocl.check(anApple, notFoo));
assertFalse(ocl.check(anApple, notBlack));
anApple.eSet(fruit_color, color_red);
anApple.eSet(apple_label, "Bar");
assertTrue(ocl.check(anApple, notFoo));
assertTrue(ocl.check(anApple, notBlack));
}
public void test_multipleDefExpressions() {
assertMatchingContextVariables(fruit, getConstraint("property_helper"));
assertMatchingContextVariables(fruit, getConstraint("operation_helper"));
EObject anApple = fruitFactory.create(apple);
anApple.eSet(fruit_color, color_black);
anApple.eSet(apple_label, "Foo");
EObject anotherApple = fruitFactory.create(apple);
anotherApple.eSet(fruit_color, color_red);
anotherApple.eSet(apple_label, "Bar");
Set<EObject> apples = new java.util.HashSet<EObject>();
apples.add(anApple);
apples.add(anotherApple);
Map<EClass, Set<EObject>> extentMap = new java.util.HashMap<EClass, Set<EObject>>();
extentMap.put(apple, apples);
extentMap.put(fruit, apples);
ocl.setExtentMap(extentMap);
helper = ocl.createOCLHelper();
helper.setContext(apple);
try {
// test the additional property
Object value = evaluate(helper, anApple, "self.otherFruits");
assertEquals(Collections.singleton(anotherApple), value);
// test the additional operation
value = evaluate(helper, anotherApple, "self.getOtherFruits(false)");
assertEquals(Collections.singleton(anApple), value);
} catch (ParserException e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
public void test_multipleInvariantsAndDefExpressions() {
Constraint notBlack = getConstraint("not_black1");
Constraint notFoo = getConstraint("not_foo1");
assertMatchingContextVariables(fruit, notBlack);
assertMatchingContextVariables(fruit, notFoo);
assertMatchingContextVariables(fruit, getConstraint("property_helper"));
assertMatchingContextVariables(fruit, getConstraint("operation_helper"));
EObject anApple = fruitFactory.create(apple);
anApple.eSet(fruit_color, color_black);
anApple.eSet(apple_label, "Foo");
// this constraint actually uses the derivation of the Fruit::name
// property, defined in the Apple context :-)
assertFalse(ocl.check(anApple, notFoo));
assertFalse(ocl.check(anApple, notBlack));
anApple.eSet(fruit_color, color_red);
anApple.eSet(apple_label, "Bar");
assertTrue(ocl.check(anApple, notFoo));
assertTrue(ocl.check(anApple, notBlack));
anApple.eSet(fruit_color, color_black);
anApple.eSet(apple_label, "Foo");
EObject anotherApple = fruitFactory.create(apple);
anotherApple.eSet(fruit_color, color_red);
anotherApple.eSet(apple_label, "Bar");
Set<EObject> apples = new java.util.HashSet<EObject>();
apples.add(anApple);
apples.add(anotherApple);
Map<EClass, Set<EObject>> extentMap = new java.util.HashMap<EClass, Set<EObject>>();
extentMap.put(apple, apples);
extentMap.put(fruit, apples);
ocl.setExtentMap(extentMap);
helper = ocl.createOCLHelper();
helper.setContext(apple);
try {
// test the additional property
Object value = evaluate(helper, anApple, "self.otherFruits1");
assertEquals(Collections.singleton(anotherApple), value);
// test the additional operation
value = evaluate(helper, anotherApple, "self.getOtherFruits1(false)");
assertEquals(Collections.singleton(anApple), value);
} catch (ParserException e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
public void test_multipleMixedOperationConstraints() {
Constraint textNotNull = getConstraint("text_not_null");
Constraint textNotLabel = getConstraint("text_not_label");
Constraint computeLabel = getConstraint("compute_label");
Constraint labelIsChanged = getConstraint("label_is_changed");
Constraint labelIsSet = getConstraint("label_is_set");
assertEquals(1, textNotNull.getConstrainedElements().size());
EOperation oper = (EOperation) textNotNull.getConstrainedElements().get(0);
assertNotNull(oper);
assertEquals(UMLReflection.PRECONDITION, textNotNull.getStereotype());
assertNotNull(textNotNull.getSpecification().getBodyExpression());
assertMatchingContextVariables(oper, textNotNull);
assertEquals(1, textNotLabel.getConstrainedElements().size());
assertSame(oper, textNotLabel.getConstrainedElements().get(0));
assertEquals(UMLReflection.PRECONDITION, textNotLabel.getStereotype());
assertNotNull(textNotLabel.getSpecification().getBodyExpression());
assertMatchingContextVariables(oper, textNotLabel);
assertEquals(1, computeLabel.getConstrainedElements().size());
assertSame(oper, computeLabel.getConstrainedElements().get(0));
assertEquals(UMLReflection.BODY, computeLabel.getStereotype());
assertNotNull(computeLabel.getSpecification().getBodyExpression());
assertMatchingContextVariables(oper, computeLabel);
assertEquals(1, labelIsChanged.getConstrainedElements().size());
assertSame(oper, labelIsChanged.getConstrainedElements().get(0));
assertEquals(UMLReflection.POSTCONDITION, labelIsChanged.getStereotype());
assertNotNull(labelIsChanged.getSpecification().getBodyExpression());
assertMatchingContextVariables(oper, labelIsChanged);
assertEquals(1, labelIsSet.getConstrainedElements().size());
assertSame(oper, labelIsSet.getConstrainedElements().get(0));
assertEquals(UMLReflection.POSTCONDITION, labelIsSet.getStereotype());
assertNotNull(labelIsSet.getSpecification().getBodyExpression());
assertMatchingContextVariables(oper, labelIsSet);
}
public void test_initAndDerConstraints() {
helper.setContext(apple);
try {
EObject anApple = fruitFactory.create(apple);
anApple.eSet(apple_label, "Foo");
assertEquals("Foo", evaluate(helper, anApple, "self.name"));
anApple.eUnset(apple_label);
assertEquals("", evaluate(helper, anApple, "self.name"));
} catch (ParserException e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
/**
* Tests that we get a proper ParserException from parsing an operation
* context declaration that is missing the classifier (qualified) name.
*/
public void test_operationContextWithoutClassifierName_182286() {
try {
ocl.parse(new OCLInput(
"context label(s : String) : \n" +
" pre: true"
));
} catch (ParserException e) {
// success
debugPrintln("Got expected exception: " + e.getLocalizedMessage());
} catch (RuntimeException e) {
fail("Got runtime exception: " + e.getLocalizedMessage());
}
}
/**
* Tests that a constraint can reference an operation defined in a package
* context earlier in the OCL document.
*/
public void test_dependenciesOnDefExpressions_packageContext_176109() {
try {
ocl.parse(new OCLInput(
"package ecore context EClassifier \n" +
"def: isHappy() : Boolean = true \n" +
"endpackage \n" +
"package ecore context ETypedElement \n" +
"inv: eType <> null implies eType.isHappy() \n" +
"endpackage \n"
));
} catch (ParserException e) {
fail("Should not have failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Tests that a constraint can reference an operation defined in a classifier
* context earlier in the OCL document.
*/
public void test_dependenciesOnDefExpressions_classifierContext_176109() {
try {
ocl.parse(new OCLInput(
"package ecore \n" +
"context EClassifier \n" +
"def: isHappy() : Boolean = true \n" +
"context ETypedElement \n" +
"inv: eType <> null implies eType.isHappy() \n" +
"endpackage \n"
));
} catch (ParserException e) {
fail("Should not have failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Tests that a constraint can reference an operation defined ahead of it in
* the same classifier context.
*/
public void test_dependenciesOnDefExpressions_withinClassifierContext_176109() {
try {
ocl.parse(new OCLInput(
"package ecore \n" +
"context EClassifier \n" +
"def: isHappy() : Boolean = true \n" +
"inv: self.isHappy() \n" +
"endpackage \n"
));
} catch (ParserException e) {
fail("Should not have failed to parse: " + e.getLocalizedMessage());
}
}
//
// Framework methods
//
@Override
protected void setUp() {
super.setUp();
constraints = new java.util.HashMap<String, Constraint>();
URI uri = getTestModelURI("/model/test_constraints.ocl");
try {
InputStream is = resourceSet.getURIConverter().createInputStream(uri);
List<Constraint> parsed = ocl.parse(new OCLInput(is));
is.close();
for (Constraint ct : parsed) {
validate(ct);
constraints.put(ct.getName(), ct);
}
} catch (Exception e) {
fail("Failed to parse " + uri + " : " + e.getMessage());
}
}
Constraint getConstraint(String name) {
Constraint result = constraints.get(name);
assertNotNull("Did not find constraint " + name, result);
return result;
}
void assertMatchingContextVariables(EClassifier context, Constraint constraint) {
ExpressionInOCL spec = (ExpressionInOCL) constraint.getSpecification();
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
Variable<EClassifier, EParameter> selfVar = spec.getContextVariable();
assertNotNull(selfVar);
assertEquals(Environment.SELF_VARIABLE_NAME, selfVar.getName());
assertEquals(selfVar.getType(), env.getUMLReflection().getOCLType(context));
}
void assertMatchingContextVariables(EOperation operation, Constraint constraint) {
ExpressionInOCL spec = (ExpressionInOCL) constraint.getSpecification();
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
if (operation.getEContainingClass() != null) {
Variable<EClassifier, EParameter> selfVar = spec.getContextVariable();
assertNotNull(selfVar);
assertEquals(Environment.SELF_VARIABLE_NAME, selfVar.getName());
assertEquals(selfVar.getType(), env.getUMLReflection().getOCLType(operation.getEContainingClass()));
}
if ((operation.getEType() != null)
&& !UMLReflection.PRECONDITION.equals(constraint.getStereotype())) {
Variable<EClassifier, EParameter> resultVar = spec.getResultVariable();
assertNotNull(resultVar);
assertEquals(Environment.RESULT_VARIABLE_NAME, resultVar.getName());
assertEquals(resultVar.getType(), env.getUMLReflection().getOCLType(operation));
}
EList<EParameter> parms = operation.getEParameters();
EList<Variable<EClassifier, EParameter>> vars = spec.getParameterVariable();
assertEquals(parms.size(), vars.size());
for (int i = 0; i < parms.size(); i++) {
Variable<EClassifier, EParameter> var = vars.get(i);
EParameter parm = parms.get(i);
assertEquals(var.getType(), env.getUMLReflection().getOCLType(parm));
}
}
}