| /******************************************************************************* |
| * Copyright (c) 2005, 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.uml.tests; |
| |
| import java.util.Collections; |
| import java.util.Iterator; |
| |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.ocl.expressions.OCLExpression; |
| import org.eclipse.ocl.expressions.PropertyCallExp; |
| import org.eclipse.ocl.expressions.TypeExp; |
| import org.eclipse.uml2.uml.Class; |
| import org.eclipse.uml2.uml.Classifier; |
| import org.eclipse.uml2.uml.Property; |
| |
| |
| /** |
| * Tests support for operation constraints (pre/post/body). |
| * |
| * @author Christian W. Damus (cdamus) |
| */ |
| @SuppressWarnings("nls") |
| public class InvariantConstraintsTest extends AbstractTestSuite { |
| |
| /** |
| * Tests a very simple invariant, with a package and classifier context |
| * not using any "self" variable. |
| */ |
| public void test_simpleInvariant() { |
| parseConstraint( |
| "package ocltest context Fruit " + |
| "inv: color <> Color::black " + |
| "endpackage"); |
| } |
| |
| /** |
| * Tests a very simple invariant, with a package and classifier context |
| * using the "self" variable. |
| */ |
| public void test_simpleInvariantWithSelf() { |
| parseConstraint( |
| "package ocltest context Fruit " + |
| "inv: self.color <> Color::black " + |
| "endpackage"); |
| } |
| |
| /** |
| * Test a let expression. |
| */ |
| public void test_simpleInvariantWithLet() { |
| parseConstraint( |
| "package ocltest context Fruit " + |
| "inv: let myColor : Color = self.color in myColor <> Color::black " + |
| "endpackage"); |
| } |
| |
| /** |
| * Tests that local variables correctly hide attributes of the context |
| * classifier. |
| */ |
| public void test_variablesHidingAttributes() { |
| parseConstraint( |
| "package ocltest context Fruit " + |
| "inv: let color : Boolean = (not self.color.oclIsUndefined()) in " + |
| " color implies self.color <> Color::black " + |
| "endpackage"); |
| } |
| |
| /** |
| * Tests that when a property name coincides with a type name, we correctly |
| * distinguish references to the type from references to the property. |
| */ |
| public void test_propertyNameCoincidesWithTypeName_140347() { |
| expectModified = true; |
| Property myFruit = apple.createOwnedAttribute( |
| "Fruit", fruit); |
| |
| try { |
| OCLExpression<Classifier> expr = parseConstraint( |
| "package ocltest context Apple " + |
| "inv: self.Fruit <> self implies self.Fruit.oclIsKindOf(Fruit) " + |
| "endpackage"); |
| |
| int propertyCalls = 0; |
| int typeCalls = 0; |
| for (Iterator<?> iter = EcoreUtil.getAllContents(Collections.singleton(expr)); iter.hasNext();) { |
| Object next = iter.next(); |
| if (next instanceof PropertyCallExp<?, ?>) { |
| @SuppressWarnings("unchecked") |
| PropertyCallExp<Classifier, Property> pc = |
| (PropertyCallExp<Classifier, Property>) next; |
| |
| if ("Fruit".equals(pc.getReferredProperty().getName())) { |
| propertyCalls++; |
| } |
| } else if (next instanceof TypeExp<?>) { |
| @SuppressWarnings("unchecked") |
| TypeExp<Classifier> te = (TypeExp<Classifier>) next; |
| |
| if ("Fruit".equals(te.getReferredType().getName())) { |
| typeCalls++; |
| } |
| } |
| } |
| |
| assertEquals("property calls", 2, propertyCalls); |
| assertEquals("type calls", 1, typeCalls); |
| } finally { |
| apple.getOwnedAttributes().remove(myFruit); |
| } |
| } |
| |
| /** |
| * Tests that type conformance accounts for interface realizations. |
| */ |
| public void test_interfaceRealization() { |
| // this constraint tests the Environment.getRelationship() method |
| // for conformance of classifiers with implemented interfaces. |
| // Note that it is necessary to cast in order to |
| // access features of the interface because they are not inherited |
| // in UML |
| parseConstraint( |
| "package ocltest context Fruit " + |
| "inv only_tasty_fruit: self.oclAsType(Edible).isTasty implies " + |
| " Edible.allInstances()->excluding(self)->forAll(e | not e.isTasty) " + |
| "endpackage"); |
| } |
| |
| /** |
| * Tests resolution of qualified classifier names for nested classifiers. |
| */ |
| public void test_nestedClassifiers() { |
| expectModified = true; |
| Class seed = (Class) apple.createNestedClassifier("Seed", uml.getClass_()); |
| seed.createOwnedAttribute("fruit", apple); |
| |
| try { |
| // try different usages of the qualified class name |
| parseConstraint( |
| "package ocltest context Fruit" + |
| " inv: Apple::Seed.allInstances()->forAll(fruit.color <> Color::black)" + |
| " endpackage"); |
| |
| parseConstraint( |
| "package ocltest context Apple::Seed" + |
| " inv: not fruit.oclIsUndefined()" + |
| " endpackage"); |
| |
| parseConstraint( |
| "context ocltest::Apple::Seed" + |
| " inv: fruit.color <> Color::black"); |
| |
| parseDef( |
| "package ocltest context Apple::Seed" + |
| " def: getColor() : Color = fruit.color" + |
| " endpackage"); |
| |
| parseConstraint( |
| "package ocltest context Apple::Seed::getColor() : Color" + |
| " pre: not fruit.oclIsUndefined()" + |
| " endpackage"); |
| } finally { |
| seed.destroy(); |
| } |
| } |
| } |