| /******************************************************************************* |
| * Copyright (c) 2006, 2018 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 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 238050 |
| *******************************************************************************/ |
| |
| package org.eclipse.ocl.ecore.tests; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.Set; |
| |
| 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.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.ocl.OCLInput; |
| import org.eclipse.ocl.ParserException; |
| import org.eclipse.ocl.ecore.Constraint; |
| import org.eclipse.ocl.ecore.OCL; |
| import org.eclipse.ocl.expressions.OCLExpression; |
| import org.eclipse.ocl.helper.Choice; |
| import org.eclipse.ocl.helper.ChoiceKind; |
| import org.eclipse.ocl.helper.ConstraintKind; |
| import org.eclipse.ocl.internal.l10n.OCLMessages; |
| import org.eclipse.ocl.options.ParsingOptions; |
| import org.eclipse.ocl.types.SetType; |
| import org.eclipse.ocl.util.TypeUtil; |
| import org.eclipse.ocl.utilities.UMLReflection; |
| |
| /** |
| * Tests for def expressions (additional properties and operations). |
| * |
| * @author Christian W. Damus (cdamus) |
| */ |
| @SuppressWarnings("nls") |
| public class DefExpressionTest |
| extends AbstractTestSuite { |
| |
| /** |
| * Tests the parsing the def expression for an operation from raw text. |
| */ |
| public void test_defExpression_raw_operation() { |
| try { |
| OCLExpression<EClassifier> expr = parseDef( |
| "package ocltest context Fruit " + |
| "def: bestColor(c : Color) : Color = if self.color = Color::black then c else self.color endif" + |
| " endpackage"); |
| |
| Constraint constraint = (Constraint) expr.eContainer().eContainer(); |
| assertNotNull(constraint); |
| |
| assertEquals(UMLReflection.DEFINITION, constraint.getStereotype()); |
| |
| assertSame(color, expr.getType()); |
| |
| expr = parse( |
| "package ocltest context Fruit " + |
| "inv: bestColor(Color::red) = Color::red" + |
| " endpackage"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| anApple.eSet(fruit_color, color_black); |
| |
| assertTrue(ocl.check(anApple, expr)); |
| |
| anApple.eSet(fruit_color, color_green); |
| |
| assertFalse(ocl.check(anApple, expr)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the parsing the def expression for an operation using the helper. |
| */ |
| public void test_defExpression_helper_operation() { |
| helper.setContext(fruit); |
| |
| try { |
| helper.defineOperation( |
| "bestColor(c : Color) : Color = " + |
| "if self.color = Color::black then c else self.color endif"); |
| |
| Constraint expr = helper.createInvariant( |
| "bestColor(Color::red) = Color::red"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| anApple.eSet(fruit_color, color_black); |
| |
| assertTrue(ocl.check(anApple, expr)); |
| |
| anApple.eSet(fruit_color, color_green); |
| |
| assertFalse(ocl.check(anApple, expr)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the parsing the def expression for an attribute from raw text. |
| */ |
| public void test_defExpression_raw_attribute() { |
| try { |
| OCLExpression<EClassifier> expr = parseDef( |
| "package ocltest context Apple " + |
| "def: fallen : Boolean = stem.oclIsUndefined()" + |
| " endpackage"); |
| |
| Constraint constraint = (Constraint) expr.eContainer().eContainer(); |
| assertNotNull(constraint); |
| |
| assertEquals(UMLReflection.DEFINITION, constraint.getStereotype()); |
| |
| assertSame(getOCLStandardLibrary().getBoolean(), expr.getType()); |
| |
| expr = parse( |
| "package ocltest context Apple " + |
| "inv: not fallen" + |
| " endpackage"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| anApple.eSet(apple_stem, fruitFactory.create(stem)); |
| |
| assertTrue(ocl.check(anApple, expr)); |
| |
| anApple.eSet(apple_stem, null); |
| |
| assertFalse(ocl.check(anApple, expr)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the parsing the def expression for an attribute using the helper. |
| */ |
| public void test_defExpression_helper_attribute() { |
| helper.setContext(apple); |
| |
| try { |
| helper.defineAttribute( |
| "fallen : Boolean = " + |
| "stem.oclIsUndefined()"); |
| |
| Constraint expr = helper.createInvariant("not fallen"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| anApple.eSet(apple_stem, fruitFactory.create(stem)); |
| |
| assertTrue(ocl.check(anApple, expr)); |
| |
| anApple.eSet(apple_stem, null); |
| |
| assertFalse(ocl.check(anApple, expr)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the parsing the def expression for a reference from raw text. |
| */ |
| public void test_defExpression_raw_reference() { |
| try { |
| OCLExpression<EClassifier> expr = parseDef( |
| "package ocltest context Apple " + |
| "def: otherApples : Set(Apple) = Apple.allInstances()->excluding(self)" + |
| " endpackage"); |
| |
| Constraint constraint = (Constraint) expr.eContainer().eContainer(); |
| assertNotNull(constraint); |
| |
| assertEquals(UMLReflection.DEFINITION, constraint.getStereotype()); |
| |
| assertTrue(expr.getType() instanceof SetType<?, ?>); |
| assertSame( |
| ((org.eclipse.ocl.ecore.SetType) expr.getType()).getElementType(), |
| apple); |
| |
| expr = parse( |
| "package ocltest context Apple " + |
| "inv: self.otherApples" + |
| " endpackage"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| EObject anotherApple = fruitFactory.create(apple); |
| Map<EClass, Set<EObject>> extentMap = new java.util.HashMap<EClass, Set<EObject>>(); |
| Set<EObject> allApples = new java.util.HashSet<EObject>(); |
| allApples.add(anApple); |
| allApples.add(anotherApple); |
| extentMap.put(apple, allApples); |
| ocl.setExtentMap(extentMap); |
| |
| Object otherApples = ocl.evaluate(anApple, expr); |
| |
| assertEquals(Collections.singleton(anotherApple), otherApples); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_defExpression_inheritance_operation() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| helper.defineOperation( |
| "allParents() : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.oclAsType(EClass)->closure(eSuperTypes) else Set{} endif"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery("self.allParents()"); |
| |
| Object allParents = ocl.evaluate(apple, expr); |
| assertTrue(allParents instanceof Set<?>); |
| assertTrue(((Set<?>) allParents).contains(fruit)); |
| |
| allParents = ocl.evaluate(color, expr); |
| assertTrue(allParents instanceof Set<?>); |
| assertTrue(((Set<?>) allParents).isEmpty()); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_defExpression_inheritance_attribute() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| helper.defineAttribute( |
| "allParents : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.oclAsType(EClass)->closure(eSuperTypes) else Set{} endif"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery("self.allParents"); |
| |
| Object allParents = ocl.evaluate(apple, expr); |
| assertTrue(allParents instanceof Set<?>); |
| assertTrue(((Set<?>) allParents).contains(fruit)); |
| |
| allParents = ocl.evaluate(color, expr); |
| assertTrue(allParents instanceof Set<?>); |
| assertTrue(((Set<?>) allParents).isEmpty()); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the parsing the def expression for static attributes and operations. |
| */ |
| public void test_defExpression_static() { |
| try { |
| ParsingOptions.setOption(ocl.getEnvironment(), ParsingOptions.SUPPORT_STATIC_FEATURES, true); |
| try { |
| ocl.parse(new OCLInput("package ocltest context Fruit " + |
| "def: bestColor1() : Color = null " + |
| "static def: bestColor2() : Color = null " + |
| "def: goodColor1 : Color = null " + |
| "static def: goodColor2 : Color = null " + |
| "endpackage")); |
| fail("Should have failed to parse the unimplemented static"); |
| } catch (ParserException e) { |
| // success! |
| assertEquals(OCLMessages.UnimplementedStatic_ERROR_, e.getMessage()); |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| |
| ParsingOptions.setOption(ocl.getEnvironment(), ParsingOptions.SUPPORT_STATIC_FEATURES, false); |
| try { |
| ocl.parse(new OCLInput("package ocltest context Fruit " + |
| "def: bestColor3() : Color = null " + |
| "static def: bestColor4() : Color = null " + |
| "endpackage")); |
| fail("Should have failed to parse the unsupported static"); |
| } catch (ParserException e) { |
| // success! |
| assertEquals(OCLMessages.UnsupportedStatic_ERROR_, e.getMessage()); |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_malformedDefExpression_attribute() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| // non-conformant expression type |
| helper.defineAttribute( |
| "allParents : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.name else '' endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // missing type declaration |
| helper.defineAttribute( |
| "myName = " + |
| "if self.oclIsKindOf(EClass) then self.name else '' endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_malformedDefExpression_operation() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| // non-conformant expression type |
| helper.defineOperation( |
| "allParents() : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.name else '' endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // missing type declaration |
| helper.defineOperation( |
| "bestName(s : String) = " + |
| "if self.oclIsKindOf(EClass) then self.name else s endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // missing type declaration in parameter |
| helper.defineOperation( |
| "bestName(s) : String = " + |
| "if self.oclIsKindOf(EClass) then self.name else s endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_duplicateDefinition_attribute() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| // same name and type as existing property |
| helper.defineAttribute( |
| "name : String = " + |
| "if self.oclIsKindOf(EClass) then 'foo' else '' endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // same name but different type |
| helper.defineAttribute( |
| "eAnnotations : Set(String) = " + |
| "Set{'a', 'b', 'c'}"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_duplicateDefinition_operation() { |
| helper.setContext(apple); |
| |
| try { |
| // same signature as existing operation (note different param name) |
| helper.defineOperation( |
| "preferredLabel(s : String) : String = " + |
| "if self.oclIsKindOf(EClass) then 'foo' else s endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // same signature as existing operation (note different return type) |
| helper.defineOperation( |
| "preferredLabel(s : String) : Integer = " + |
| "if self.oclIsKindOf(EClass) then 0 else s.size() endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // same name but different signature is OK |
| helper.defineOperation( |
| "preferredLabel(text : Integer) : String = " + |
| "if text > 0 then 'foo' else 'bar' endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_undefine_property_152018() { |
| helper.setContext(EcorePackage.Literals.ECLASS); |
| |
| EStructuralFeature property = null; |
| |
| try { |
| // define some additional property |
| property = helper.defineAttribute( |
| "other : EClass = " + |
| "if eSuperTypes->notEmpty() then eSuperTypes->first() else null endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| |
| assertNotNull(property); |
| |
| // now, undefine this property |
| ocl.getEnvironment().undefine(property); |
| |
| assertNull(property.eContainer()); |
| assertNull(property.eResource()); |
| |
| try { |
| // try to define this property again. We should succeed |
| property = helper.defineAttribute( |
| "other : EClass = " + |
| "if eSuperTypes->notEmpty() then eSuperTypes->first() else null endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_undefine_operation_152018() { |
| helper.setContext(EcorePackage.Literals.ECLASS); |
| |
| EOperation operation = null; |
| |
| try { |
| // define some additional property |
| operation = helper.defineOperation( |
| "other(x : Integer) : EClass = " + |
| "if eSuperTypes->notEmpty() then eSuperTypes->at(x) else null endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| |
| assertNotNull(operation); |
| |
| // now, undefine this operation |
| ocl.getEnvironment().undefine(operation); |
| |
| assertNull(operation.eContainer()); |
| assertNull(operation.eResource()); |
| |
| try { |
| // try to define this property again. We should succeed |
| operation = helper.defineOperation( |
| "other(x : Integer) : EClass = " + |
| "if eSuperTypes->size() >= x then eSuperTypes->at(x) else null endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_recursive_property_152018() { |
| helper.setContext(EcorePackage.Literals.ECLASS); |
| |
| EStructuralFeature property = null; |
| |
| try { |
| // first, attempt a definition with an invalid body |
| property = helper.defineAttribute( |
| "friend : EClass = " + |
| "if eSuperTypes->notEmpty() then ePackage else self endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // now, attempt a correct definition. This should not find that |
| // 'other' is already defined, because it should have been |
| // undefined when we failed to parse, above |
| property = helper.defineAttribute( |
| "friend : EClass = " + |
| "if eSuperTypes->notEmpty() then eSuperTypes->first().friend else self endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| |
| assertNotNull(property); |
| |
| try { |
| // now, attempt to use this additional property |
| helper.createInvariant( |
| "not friend.oclIsUndefined() implies friend = self"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_recursive_operation_152018() { |
| helper.setContext(EcorePackage.Literals.ECLASS); |
| |
| EOperation operation = null; |
| |
| try { |
| // first, attempt a definition with an invalid body |
| operation = helper.defineOperation( |
| "friend(x : Integer) : EClass = " + |
| "if eSuperTypes->size() >= x then ePackage else self endif"); |
| |
| fail("Should not have parsed"); |
| } catch (Exception e) { |
| // success |
| debugPrintln("Got expected error: " + e.getLocalizedMessage()); |
| } |
| |
| try { |
| // now, attempt a correct definition. This should not find that |
| // 'other' is already defined, because it should have been |
| // undefined when we failed to parse, above |
| operation = helper.defineOperation( |
| "friend(x : Integer) : EClass = " + |
| "if eSuperTypes->size() >= x then eSuperTypes->at(x).friend(x) else self endif"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| |
| assertNotNull(operation); |
| |
| try { |
| // now, attempt to use this additional property |
| helper.createInvariant( |
| "not friend(1).oclIsUndefined() implies friend(1) = self"); |
| } catch (Exception e) { |
| fail("Failed to parse: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_defExpression_completion_operation() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| helper.defineOperation( |
| "allParents() : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.oclAsType(EClass)->closure(eSuperTypes) else Set{} endif"); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.OPERATION, "allParents"); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| public void test_defExpression_completion_attribute() { |
| helper.setContext(EcorePackage.Literals.ECLASSIFIER); |
| |
| try { |
| helper.defineAttribute( |
| "allParents : Set(EClassifier) = " + |
| "if self.oclIsKindOf(EClass) then self.oclAsType(EClass)->closure(eSuperTypes) else Set{} endif"); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.PROPERTY, "allParents"); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the definition of additional attributes on the metamodel's |
| * representation of a primitive type for which OCL has a counterpart. |
| */ |
| public void test_defAttributeOnPrimitiveType_172782() { |
| // context is the Ecore metamodel's EString data type |
| helper.setContext(EcorePackage.Literals.ESTRING); |
| |
| try { |
| EStructuralFeature feature = helper.defineAttribute( |
| "reverse : String = " + |
| "Sequence{1..size()}->sortedBy(i | -i)->iterate(i; s : String = '' |" + |
| " s.concat(self.substring(i, i)))"); |
| |
| // the other representation of 'String' |
| helper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.PROPERTY, "reverse"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery( |
| "self.reverse"); |
| |
| assertEquals( |
| "ablE was i ere I saw elbA", |
| ocl.evaluate("Able was I ere i saw Elba", expr)); |
| |
| // verify that TypeUtil produces the correct result |
| assertTrue(TypeUtil.getAttributes(ocl.getEnvironment(), ocl.getEnvironment().getOCLStandardLibrary().getString()) |
| .contains(feature)); |
| assertTrue(TypeUtil.getAttributes(ocl.getEnvironment(), EcorePackage.Literals.ESTRING) |
| .contains(feature)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // now, make sure that this definition was local to the OCL that |
| // parsed it (that it is not shared via the standard library package) |
| OCL localOCL = OCL.newInstance(); |
| OCL.Helper localHelper = localOCL.createOCLHelper(); |
| localHelper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| Collection<Choice> choices = localHelper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertNotChoice(choices, ChoiceKind.PROPERTY, "reverse"); |
| |
| localHelper.createQuery("self.reverse"); |
| |
| fail("Should have failed to parse the undefined attribute"); |
| } catch (ParserException e) { |
| // success! |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the definition of additional operations on the metamodel's |
| * representation of a primitive type for which OCL has a counterpart. |
| */ |
| public void test_defOperationOnPrimitiveType_172782() { |
| // context is the Ecore metamodel's EString data type |
| helper.setContext(EcorePackage.Literals.ESTRING); |
| |
| try { |
| EOperation feature = helper.defineOperation( |
| "reversed() : String = " + |
| "Sequence{1..size()}->sortedBy(i | -i)->iterate(i; s : String = '' |" + |
| " s.concat(self.substring(i, i)))"); |
| |
| // the other representation of 'String' |
| helper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.OPERATION, "reversed"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery( |
| "self.reversed()"); |
| |
| assertEquals( |
| "ablE was i ere I saw elbA", |
| ocl.evaluate("Able was I ere i saw Elba", expr)); |
| |
| // verify that TypeUtil produces the correct result |
| assertTrue(TypeUtil.getOperations(ocl.getEnvironment(), ocl.getEnvironment().getOCLStandardLibrary().getString()) |
| .contains(feature)); |
| assertTrue(TypeUtil.getOperations(ocl.getEnvironment(), EcorePackage.Literals.ESTRING) |
| .contains(feature)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // now, make sure that this definition was local to the OCL that |
| // parsed it (that it is not shared via the standard library package) |
| OCL localOCL = OCL.newInstance(); |
| OCL.Helper localHelper = localOCL.createOCLHelper(); |
| localHelper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| Collection<Choice> choices = localHelper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertNotChoice(choices, ChoiceKind.OPERATION, "reversed"); |
| |
| localHelper.createQuery("self.reversed()"); |
| |
| fail("Should have failed to parse the undefined operation"); |
| } catch (ParserException e) { |
| // success! |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the definition of additional attributes on an OCL pre-defined type. |
| */ |
| public void test_defAttributeOnPredefinedType_172782() { |
| // context is the predefined OCL String type |
| helper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| EStructuralFeature feature = helper.defineAttribute( |
| "reverse : String = " + |
| "Sequence{1..size()}->sortedBy(i | -i)->iterate(i; s : String = '' |" + |
| " s.concat(self.substring(i, i)))"); |
| |
| // the other representation of 'String' |
| helper.setContext(EcorePackage.Literals.ESTRING); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.PROPERTY, "reverse"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery( |
| "self.reverse"); |
| |
| assertEquals( |
| "ablE was i ere I saw elbA", |
| ocl.evaluate("Able was I ere i saw Elba", expr)); |
| |
| // verify that TypeUtil produces the correct result |
| assertTrue(TypeUtil.getAttributes(ocl.getEnvironment(), ocl.getEnvironment().getOCLStandardLibrary().getString()) |
| .contains(feature)); |
| assertTrue(TypeUtil.getAttributes(ocl.getEnvironment(), EcorePackage.Literals.ESTRING) |
| .contains(feature)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // now, make sure that this definition was local to the OCL that |
| // parsed it (that it is not shared via the standard library package) |
| OCL localOCL = OCL.newInstance(); |
| OCL.Helper localHelper = localOCL.createOCLHelper(); |
| localHelper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| Collection<Choice> choices = localHelper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertNotChoice(choices, ChoiceKind.PROPERTY, "reverse"); |
| |
| localHelper.createQuery("self.reverse"); |
| |
| fail("Should have failed to parse the undefined attribute"); |
| } catch (ParserException e) { |
| // success! |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests the definition of additional operations on an OCL pre-defined type. |
| */ |
| public void test_defOperationOnPredefinedType_172782() { |
| // context is the predefined OCL String type |
| helper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| EOperation feature = helper.defineOperation( |
| "reversed() : String = " + |
| "Sequence{1..size()}->sortedBy(i | -i)->iterate(i; s : String = '' |" + |
| " s.concat(self.substring(i, i)))"); |
| |
| // the other representation of 'String' |
| helper.setContext(EcorePackage.Literals.ESTRING); |
| |
| Collection<Choice> choices = helper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertChoice(choices, ChoiceKind.OPERATION, "reversed"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery( |
| "self.reversed()"); |
| |
| assertEquals( |
| "ablE was i ere I saw elbA", |
| ocl.evaluate("Able was I ere i saw Elba", expr)); |
| |
| // verify that TypeUtil produces the correct result |
| assertTrue(TypeUtil.getOperations(ocl.getEnvironment(), ocl.getEnvironment().getOCLStandardLibrary().getString()) |
| .contains(feature)); |
| assertTrue(TypeUtil.getOperations(ocl.getEnvironment(), EcorePackage.Literals.ESTRING) |
| .contains(feature)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // now, make sure that this definition was local to the OCL that |
| // parsed it (that it is not shared via the standard library package) |
| OCL localOCL = OCL.newInstance(); |
| OCL.Helper localHelper = localOCL.createOCLHelper(); |
| localHelper.setContext(ocl.getEnvironment().getOCLStandardLibrary().getString()); |
| |
| try { |
| Collection<Choice> choices = localHelper.getSyntaxHelp( |
| ConstraintKind.INVARIANT, "self."); |
| |
| assertNotChoice(choices, ChoiceKind.OPERATION, "reversed"); |
| |
| localHelper.createQuery("self.reversed()"); |
| |
| fail("Should have failed to parse the undefined operation"); |
| } catch (ParserException e) { |
| // success! |
| debugPrintln("Got the expected exception: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests that the {@link UMLReflection} API provides the correct owner of an |
| * additional operation. |
| */ |
| public void test_defExpression_operation_owner() { |
| helper.setContext(fruit); |
| |
| try { |
| EOperation o = helper.defineOperation( |
| "bestColor(c : Color) : Color = " + |
| "if self.color = Color::black then c else self.color endif"); |
| |
| UMLReflection<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, ?> uml = |
| ocl.getEnvironment().getUMLReflection(); |
| |
| // sanity check |
| assertSame(fruit, uml.getOwningClassifier(fruit_ripen)); |
| |
| // check the owner of the additional operation |
| assertSame(fruit, uml.getOwningClassifier(o)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests that the {@link UMLReflection} API provides the correct owner of an |
| * additional attribute. |
| */ |
| public void test_defExpression_attribute_owner() { |
| helper.setContext(fruit); |
| |
| try { |
| EStructuralFeature p = helper.defineAttribute( |
| "isBlack : Boolean = " + |
| "color = Color::black"); |
| |
| UMLReflection<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, ?> uml = |
| ocl.getEnvironment().getUMLReflection(); |
| |
| // sanity check |
| assertSame(fruit, uml.getOwningClassifier(fruit_color)); |
| |
| // check the owner of the additional operation |
| assertSame(fruit, uml.getOwningClassifier(p)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests that when we define additional operations on the <code>OclAny</code> |
| * type, they can be invoked on user model types. |
| */ |
| public void test_def_operation_OclAny_192892() { |
| // define an operation on OclAny |
| helper.setContext(getOCLStandardLibrary().getOclAny()); |
| |
| try { |
| helper.defineOperation("isBlack() : Boolean = true"); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // switch to context of a user model classifier |
| helper.setContext(fruit); |
| |
| try { |
| EObject instance = fruitFactory.create(apple); |
| assertTrue(check(helper, instance, "self.isBlack()")); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests that when we define additional attributes on the <code>OclAny</code> |
| * type, they can be invoked on user model types. |
| */ |
| public void test_def_attribute_OclAny_192892() { |
| // define an operation on OclAny |
| helper.setContext(getOCLStandardLibrary().getOclAny()); |
| |
| try { |
| helper.defineAttribute("isBlack : Boolean = true"); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| |
| // switch to context of a user model classifier |
| helper.setContext(fruit); |
| |
| try { |
| EObject instance = fruitFactory.create(apple); |
| assertTrue(check(helper, instance, "self.isBlack")); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| |
| /** |
| * Tests def expression for an operations with multiple parameters of |
| * the same type. |
| */ |
| public void test_defExpression_operation_similarParams_238050() { |
| helper.setContext(fruit); |
| |
| try { |
| helper.defineOperation( |
| "displayName(first : String, last : String) : String = " + |
| "if self.color = Color::red then first else last endif"); |
| |
| OCLExpression<EClassifier> expr = helper.createQuery( |
| "self.displayName('Roger', 'Bacon')"); |
| |
| EObject anApple = fruitFactory.create(apple); |
| anApple.eSet(fruit_color, color_black); |
| |
| assertEquals("Bacon", ocl.evaluate(anApple, expr)); |
| |
| anApple.eSet(fruit_color, color_red); |
| |
| assertEquals("Roger", ocl.evaluate(anApple, expr)); |
| } catch (Exception e) { |
| fail("Failed to parse or evaluate: " + e.getLocalizedMessage()); |
| } |
| } |
| } |