/******************************************************************************* * Copyright (c) 2007, 2009 IBM Corporation 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 *******************************************************************************/ package org.eclipse.ocl.ecore.tests; import java.io.InputStream; import java.net.URL; 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 System.out.println("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 { URL url = new URL(uri.toString()); InputStream is = url.openStream(); 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)); } } }