blob: 2490340c4f1998bd4dc0c7c7751d5f0d6fe182ff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2015, 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 - Bugs 243526, 248869, 259740, 259818
* Axel Uhl (SAP AG) - Bug 342644
*******************************************************************************/
package org.eclipse.ocl.ecore.tests;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EClassImpl;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.ocl.OCLInput;
import org.eclipse.ocl.ecore.BagType;
import org.eclipse.ocl.ecore.CollectionType;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.ocl.ecore.OCL;
import org.eclipse.ocl.ecore.OrderedSetType;
import org.eclipse.ocl.ecore.SequenceType;
import org.eclipse.ocl.ecore.SetType;
import org.eclipse.ocl.ecore.TupleType;
import org.eclipse.ocl.expressions.BooleanLiteralExp;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.expressions.LetExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.expressions.VariableExp;
import org.eclipse.ocl.util.Bag;
import org.eclipse.ocl.util.CollectionUtil;
import org.eclipse.ocl.util.Tuple;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.UMLReflection;
import junit.framework.AssertionFailedError;
/**
* Regression tests for specific RATLC defects.
*
* @author Christian W. Damus (cdamus)
*/
@SuppressWarnings("nls")
public class RegressionTest
extends AbstractTestSuite {
/**
* Tests the "..." escape syntax for reserved words. Regression test for
* RATLC00527506.
*/
public void test_quoteReservedWords_RATLC00527506() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("MyType");
epackage.getEClassifiers().add(eclass);
// "context" is an OCL reserved word
EAttribute eattr = EcoreFactory.eINSTANCE.createEAttribute();
eattr.setName("context");
eattr.setEType(EcorePackage.eINSTANCE.getEString());
eclass.getEStructuralFeatures().add(eattr);
parseConstraint(
"package mypkg context MyType " +
"inv: self.\"context\"->notEmpty() " +
"endpackage");
}
/**
* Tests the "..." escape syntax for whitespace. Regression test for
* RATLC00527509.
*/
public void test_quoteWhitespace_RATLC00527509() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("MyType");
epackage.getEClassifiers().add(eclass);
EAttribute eattr = EcoreFactory.eINSTANCE.createEAttribute();
eattr.setName("an attribute");
eattr.setEType(EcorePackage.eINSTANCE.getEString());
eclass.getEStructuralFeatures().add(eattr);
parseConstraint(
"package mypkg context MyType " +
"inv: self.\"an attribute\"->notEmpty() " +
"endpackage");
}
/**
* Tests the \" escape syntax for double-quotes. Regression test for
* RATLC00527509.
*/
public void test_quoteQuote_RATLC00527509() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("MyType");
epackage.getEClassifiers().add(eclass);
EAttribute eattr = EcoreFactory.eINSTANCE.createEAttribute();
eattr.setName("an\"attribute");
eattr.setEType(EcorePackage.eINSTANCE.getEString());
eclass.getEStructuralFeatures().add(eattr);
// try first to parse within surrounding double-quotes
parseConstraint(
"package mypkg context MyType " +
"inv: self.\"an\\\"attribute\"->notEmpty() " +
"endpackage");
AssertionFailedError err = null;
try {
// also try to parse without the surrounding double-quotes.
// This is not allowed
parseConstraint(
"package ecore context EClass " +
"inv: self.an\\\"attribute->notEmpty() " +
"endpackage");
} catch (AssertionFailedError e) {
// success
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Should not have parsed.", err);
}
/**
* Tests the support for international characters. Regression test for
* RATLC01080816.
*/
public void test_internationalCharacters_RATLC01080816() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName("MyType");
epackage.getEClassifiers().add(eclass);
EAttribute eattr = EcoreFactory.eINSTANCE.createEAttribute();
// try some extended latin, cyrillic, and arabic
eattr.setName("\u0160\u01d6\u0429\u0639");
eattr.setEType(EcorePackage.eINSTANCE.getEString());
eclass.getEStructuralFeatures().add(eattr);
// try these characters in the attribute name and string literal
parseConstraint(
"package mypkg context MyType " +
"inv: self.\u0160\u01d6\u0429\u0639 <> '\u0160\u01d6\u0429\u0639' " +
"endpackage");
}
/**
* Tests support for oclIsKindOf() and oclAsType() to cast between
* classifiers that are not related, but where their subtypes may be
* conformant.
*/
public void test_oclIsKindOf_RATLC01087664() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
// create three classes. A and B are unrelated, but C extends
// both. Therefore, it is possible to cast a variable of type
// A to type B where the run-time type is C
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
epackage.getEClassifiers().add(a);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
epackage.getEClassifiers().add(b);
EClass c = EcoreFactory.eINSTANCE.createEClass();
c.setName("C");
epackage.getEClassifiers().add(c);
c.getESuperTypes().add(a);
c.getESuperTypes().add(b);
EAttribute attrA = EcoreFactory.eINSTANCE.createEAttribute();
attrA.setName("a");
attrA.setEType(EcorePackage.eINSTANCE.getEBoolean());
a.getEStructuralFeatures().add(attrA);
EAttribute attrB = EcoreFactory.eINSTANCE.createEAttribute();
attrB.setName("b");
attrB.setEType(EcorePackage.eINSTANCE.getEBoolean());
b.getEStructuralFeatures().add(attrB);
OCLExpression<EClassifier> constraint = parseConstraint(
"package mypkg context A " +
"inv: self.oclIsKindOf(B) implies (self.oclAsType(B).b <> self.a) " +
"endpackage");
EObject eobj = epackage.getEFactoryInstance().create(c);
eobj.eSet(attrA, Boolean.TRUE);
eobj.eSet(attrB, Boolean.TRUE);
assertFalse("Should have failed the check", check(constraint, eobj));
eobj.eSet(attrB, Boolean.FALSE);
assertTrue("Should not have failed the check", check(constraint, eobj));
}
/**
* Tests support for short-circuiting AND operator.
*/
public void test_shortcircuitAnd_RATLC00536528() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
epackage.getEClassifiers().add(a);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
epackage.getEClassifiers().add(b);
b.getESuperTypes().add(a);
EAttribute attrA = EcoreFactory.eINSTANCE.createEAttribute();
attrA.setName("a");
attrA.setEType(EcorePackage.eINSTANCE.getEBoolean());
a.getEStructuralFeatures().add(attrA);
EAttribute attrB = EcoreFactory.eINSTANCE.createEAttribute();
attrB.setName("b");
attrB.setEType(EcorePackage.eINSTANCE.getEBoolean());
b.getEStructuralFeatures().add(attrB);
try {
OCLExpression<EClassifier> constraint = parseConstraint(
"package mypkg context A " +
"inv: self.oclIsKindOf(B) and self.oclAsType(B).b " +
"endpackage");
// create an A
EObject eobj = epackage.getEFactoryInstance().create(a);
eobj.eSet(attrA, Boolean.TRUE);
// this would fail with an NPE on the access to '.b' when
// 'self.oclAsType(B)' evaluates to null, if we didn't short-circuit
assertFalse("Should have failed the check", check(constraint, eobj));
// create a B this time
eobj = epackage.getEFactoryInstance().create(b);
eobj.eSet(attrA, Boolean.TRUE);
eobj.eSet(attrB, Boolean.TRUE);
assertTrue("Should not have failed the check", check(constraint, eobj));
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
/**
* Tests support for short-circuiting OR operator.
*/
public void test_shortcircuitOr_RATLC00536528() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
epackage.getEClassifiers().add(a);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
epackage.getEClassifiers().add(b);
b.getESuperTypes().add(a);
EAttribute attrA = EcoreFactory.eINSTANCE.createEAttribute();
attrA.setName("a");
attrA.setEType(EcorePackage.eINSTANCE.getEBoolean());
a.getEStructuralFeatures().add(attrA);
EAttribute attrB = EcoreFactory.eINSTANCE.createEAttribute();
attrB.setName("b");
attrB.setEType(EcorePackage.eINSTANCE.getEBoolean());
b.getEStructuralFeatures().add(attrB);
try {
OCLExpression<EClassifier> constraint = parseConstraint(
"package mypkg context A " +
"inv: (not self.oclIsKindOf(B)) or self.oclAsType(B).b " +
"endpackage");
// create an A
EObject eobj = epackage.getEFactoryInstance().create(a);
eobj.eSet(attrA, Boolean.TRUE);
// this would fail with an NPE on the access to '.b' when
// 'self.oclAsType(B)' evaluates to null, if we didn't short-circuit
assertTrue("Should not have failed the check", check(constraint, eobj));
// create a B this time
eobj = epackage.getEFactoryInstance().create(b);
eobj.eSet(attrA, Boolean.TRUE);
eobj.eSet(attrB, Boolean.TRUE);
assertTrue("Should not have failed the check", check(constraint, eobj));
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
/**
* Tests support for short-circuiting IMPLIES operator.
*/
public void test_shortcircuitImplies_RATLC00536528() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
epackage.getEClassifiers().add(a);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
epackage.getEClassifiers().add(b);
b.getESuperTypes().add(a);
EAttribute attrA = EcoreFactory.eINSTANCE.createEAttribute();
attrA.setName("a");
attrA.setEType(EcorePackage.eINSTANCE.getEBoolean());
a.getEStructuralFeatures().add(attrA);
EAttribute attrB = EcoreFactory.eINSTANCE.createEAttribute();
attrB.setName("b");
attrB.setEType(EcorePackage.eINSTANCE.getEBoolean());
b.getEStructuralFeatures().add(attrB);
try {
OCLExpression<EClassifier> constraint = parseConstraint(
"package mypkg context A " +
"inv: self.oclIsKindOf(B) implies self.oclAsType(B).b " +
"endpackage ");
// create an A
EObject eobj = epackage.getEFactoryInstance().create(a);
eobj.eSet(attrA, Boolean.TRUE);
// this would fail with an NPE on the access to '.b' when
// 'self.oclAsType(B)' evaluates to null, if we didn't short-circuit
assertTrue("Should not have failed the check", check(constraint, eobj));
// create a B this time
eobj = epackage.getEFactoryInstance().create(b);
eobj.eSet(attrA, Boolean.TRUE);
eobj.eSet(attrB, Boolean.FALSE);
assertFalse("Should have failed the check", check(constraint, eobj));
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
/**
* Tests that we correctly parse the <tt>oclIsNew</tt> operation in
* invariant constraints, but that validation reports a suitable error.
*/
public void test_oclIsNew_invariant_RATLC00529981() {
OCLExpression<EClassifier> constraint = parseConstraintUnvalidated(
"package ocltest context Fruit " +
"inv: color.oclIsNew() " +
"endpackage");
AssertionFailedError err = null;
try {
validate(constraint);
} catch (AssertionFailedError e) {
// success
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Should not have succeeded in validating illegal oclIsNew", err);
}
/**
* Tests that we correctly parse the <tt>oclIsNew</tt> operation in
* precondition constraints, but that validation reports a suitable error.
*/
public void test_oclIsNew_precondition_RATLC00529981() {
OCLExpression<EClassifier> constraint = parseConstraintUnvalidated(
"package ocltest context Fruit::ripen(c : Color) : Boolean " +
"pre: c.oclIsNew() implies c <> Color::black " +
"endpackage");
AssertionFailedError err = null;
try {
validate(constraint);
} catch (AssertionFailedError e) {
// success
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Should not have succeeded in validating illegal oclIsNew", err);
}
/**
* Tests that we correctly parse the <tt>oclIsNew</tt> operation in
* postcondition constraints, and that validation reports no errors.
*/
public void test_oclIsNew_postcondition_RATLC00529981() {
parseConstraint(
"package ocltest context Fruit::ripen(c : Color) : Boolean " +
"post: color.oclIsNew() implies color <> Color::black " +
"endpackage");
}
/**
* Tests that we correctly parse and evaluate the <tt>toLower</tt> operation
* on OCL string values.
*/
public void test_toLower_RATLC00529981() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context Fruit " +
"inv: 'AlPHaBet'.toLower() " +
"endpackage");
Object value = evaluate(expr);
assertEquals("alphabet", value);
}
/**
* Tests that we correctly parse and evaluate the <tt>toUpper</tt> operation
* on OCL string values.
*/
public void test_toUpper_RATLC00529981() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context Fruit " +
"inv: 'AlPHaBet'.toUpper() " +
"endpackage");
Object value = evaluate(expr);
assertEquals("ALPHABET", value);
}
/**
* Tests that references that have multiplicity, are unique, and
* are ordered are rendered as OCL sets.
*/
public void test_referenceMultiplicity_orderedSet_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.orderedSet" +
" endpackage");
// check that the result type is an ordered set type
assertTrue(
"Not an ordered set type",
expr.getType() instanceof OrderedSetType);
}
/**
* Tests that references that have multiplicity, are unique, and
* are unordered are rendered as OCL sets.
*/
public void test_referenceMultiplicity_set_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.set" +
" endpackage");
// check that the result type is a set type
assertTrue(
"Not a set type",
(expr.getType() instanceof SetType)
&& !(expr.getType() instanceof OrderedSetType));
}
/**
* Tests that references that have multiplicity, are non-unique, and
* are ordered are rendered as OCL sequences.
*/
public void test_referenceMultiplicity_sequence_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.sequence" +
" endpackage");
// check that the result type is a sequence set type
assertTrue(
"Not a sequence type",
expr.getType() instanceof SequenceType);
}
/**
* Tests that references that have multiplicity, are non-unique, and
* are unordered are rendered as OCL bags.
*/
public void test_referenceMultiplicity_bag_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.bag" +
" endpackage");
// check that the result type is a bag set type
assertTrue(
"Not a bag type",
expr.getType() instanceof BagType);
}
/**
* Tests that operation parameters that have multiplicity, are unique, and
* are ordered are rendered as OCL sets.
*/
public void test_parameterMultiplicity_orderedSet_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processOrderedSet(self.orderedSet)" +
" endpackage");
// now also check that the result type is an ordered set type
assertTrue(
"Not an ordered set type",
expr.getType() instanceof OrderedSetType);
}
/**
* Tests that operation parameters that have multiplicity, are unique, and
* are unordered are rendered as OCL sets.
*/
public void test_parameterMultiplicity_set_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processSet(self.set)" +
" endpackage");
// now also check that the result type is a set type
assertTrue(
"Not a set type",
(expr.getType() instanceof SetType)
&& !(expr.getType() instanceof OrderedSetType));
}
/**
* Tests that operation parameters that have multiplicity, are non-unique, and
* are ordered are rendered as OCL sequences.
*/
public void test_parameterMultiplicity_sequence_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processSequence(self.sequence)" +
" endpackage");
// now also check that the result type is a sequence type
assertTrue(
"Not a sequence type",
expr.getType() instanceof SequenceType);
}
/**
* Tests that operation parameters that have multiplicity, are non-unique, and
* are unordered are rendered as OCL bags.
*/
public void test_parameterMultiplicity_bag_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processBag(self.bag)" +
" endpackage");
// now also check that the result type is a bag type
assertTrue(
"Not a bag type",
expr.getType() instanceof BagType);
}
/**
* Tests that operations that have multiplicity, are unique, and
* are ordered are rendered as OCL sets.
*/
public void test_operationMultiplicity_orderedSet_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processOrderedSet(self.processOrderedSet(self.orderedSet))" +
" endpackage");
// now also check that the result type is an ordered set type
assertTrue(
"Not an ordered set type",
expr.getType() instanceof OrderedSetType);
}
/**
* Tests that operations that have multiplicity, are unique, and
* are unordered are rendered as OCL sets.
*/
public void test_operationMultiplicity_set_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processSet(self.processSet(self.set))" +
" endpackage");
// now also check that the result type is a set type
assertTrue(
"Not a set type",
(expr.getType() instanceof SetType)
&& !(expr.getType() instanceof OrderedSetType));
}
/**
* Tests that operations that have multiplicity, are non-unique, and
* are ordered are rendered as OCL sequences.
*/
public void test_operationMultiplicity_sequence_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processSequence(self.processSequence(self.sequence))" +
" endpackage");
// now also check that the result type is a sequence type
assertTrue(
"Not a sequence type",
expr.getType() instanceof SequenceType);
}
/**
* Tests that operations that have multiplicity, are non-unique, and
* are unordered are rendered as OCL bags.
*/
public void test_operationMultiplicity_bag_RATLC00538035() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context FruitUtil " +
"inv: self.processBag(self.processBag(self.bag))" +
" endpackage");
// now also check that the result type is a bag type
assertTrue(
"Not a bag type",
expr.getType() instanceof BagType);
}
/**
* Tests that the operation context parsing matches ordered set types
* correctly in the parameters, result type, and body expression type.
*/
public void test_operationContext_orderedSet_RATLC00538035() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context " +
"FruitUtil::processOrderedSet(x : Fruit) : Fruit " +
"body: result = x" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
// this should work
parse(
"package ocltest context " +
"FruitUtil::processOrderedSet(x : OrderedSet(Fruit)) : OrderedSet(Fruit) " +
"body: result = x" +
" endpackage");
}
/**
* Tests that the operation context parsing matches set types
* correctly in the parameters, result type, and body expression type.
*/
public void test_operationContext_set_RATLC00538035() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context " +
"FruitUtil::processSet(x : Fruit) : Fruit " +
"body: result = x" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
// this should work
parse(
"package ocltest context " +
"FruitUtil::processSet(x : Set(Fruit)) : Set(Fruit) " +
"body: result = x" +
" endpackage");
}
/**
* Tests that the operation context parsing matches sequence types
* correctly in the parameters, result type, and body expression type.
*/
public void test_operationContext_sequence_RATLC00538035() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context " +
"FruitUtil::processSequence(x : Fruit) : Fruit " +
"body: result = x" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
// this should work
parse(
"package ocltest context " +
"FruitUtil::processSequence(x : Sequence(Fruit)) : Sequence(Fruit) " +
"body: result = x" +
" endpackage");
}
/**
* Tests that the operation context parsing matches bag types
* correctly in the parameters, result type, and body expression type.
*/
public void test_operationContext_bag_RATLC00538035() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context " +
"FruitUtil::processBag(x : Fruit) : Fruit " +
"body: result = x" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
// this should work
parse(
"package ocltest context " +
"FruitUtil::processBag(x : Bag(Fruit)) : Bag(Fruit) " +
"body: result = x" +
" endpackage");
}
/**
* Regression test to check that <code>allInstances()</code> works as
* expected on enumerations.
*/
public void test_allInstances_enumeration_RATLC00538079() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: Color.allInstances() " +
" endpackage"));
Set<EEnumLiteral> expected = new java.util.HashSet<EEnumLiteral>(
color.getELiterals());
assertEquals(expected, result);
}
/**
* Regression test to check that <code>allInstances()</code> works as
* expected on the <code>OclVoid</code> type.
*/
public void test_allInstances_voidType_RATLC00538079() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: OclVoid.allInstances() " +
" endpackage"));
Set<Object> expected = new java.util.HashSet<Object>();
expected.add(null);
assertEquals(expected, result);
}
public void test_bagIterationWithNullOccurrences() {
Bag<Object> bag = CollectionUtil.createNewBag();
bag.add(3);
bag.add(null);
bag.add(4);
bag.add(null);
bag.add("test");
assertEquals(2, bag.count(null));
Iterator<Object> i = bag.iterator();
int nullCount = 0;
while (i.hasNext()) {
if (i.next() == null) {
nullCount++;
}
}
assertEquals(2, nullCount);
Bag<Object> bagWithSingleNull = CollectionUtil.createNewBag();
bagWithSingleNull.add(null);
assertEquals(1, bagWithSingleNull.count(null));
assertTrue(bagWithSingleNull.iterator().hasNext());
assertNull(bagWithSingleNull.iterator().next());
i = bagWithSingleNull.iterator();
i.next();
assertFalse(i.hasNext());
}
/**
* Regression test to check that <code>allInstances()</code> works as
* expected on primitive types.
*/
public void test_allInstances_primitive_RATLC00538079() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: ecore::EMap.allInstances() " +
" endpackage"));
assertEquals(Collections.EMPTY_SET, result);
}
/**
* Regression test for the problem of extra closing parentheses allowing
* garbage expressions to appear to parse correctly. This test tests
* the core parser.
*/
public void test_closingParentheses_core() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context Fruit " +
"inv: self)garbage " +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
}
/**
* Regression test for the problem of extra closing parentheses allowing
* garbage expressions to appear to parse correctly. This test tests
* the OCL helper.
*/
public void test_closingParentheses_helper() {
helper.setContext(fruit);
try {
// this should not work
helper.createInvariant("self)garbage");
fail("Parse should have failed");
} catch (Exception e) {
// success
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
}
/**
* Regression test for the problem of extra closing parentheses allowing
* garbage expressions to appear to parse correctly. This test tests
* the OCL helper with a precondition instead of an invariant.
*/
public void test_closingParentheses_helper_precondition() {
helper.setOperationContext(fruit, fruit_ripen);
try {
// this should not work
helper.createPrecondition("self)garbage");
fail("Parse should have failed");
} catch (Exception e) {
// success
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
}
public void test_operationBodyBoolean_116251() {
AssertionFailedError err = null;
// this should work
parseConstraint(
"package ocltest context " +
"FruitUtil::processBag(x : Bag(Fruit)) : Bag(Fruit) " +
"body: result = x->asSet()->asBag()" +
" endpackage");
// as should this
parseConstraint(
"package ocltest context " +
"FruitUtil::processBag(x : Bag(Fruit)) : Bag(Fruit) " +
"body: x->asSet()->asBag() = result" +
" endpackage");
// and this (allow any number of lets to wrap the expression)
parseConstraint(
"package ocltest context " +
"FruitUtil::processBag(x : Bag(Fruit)) : Bag(Fruit) " +
"body: let set : Set(Fruit) = x->asSet() in" +
" let bag : Bag(Fruit) = set->asBag() in" +
" result = bag" +
" endpackage");
// this should not work, however, because it has the result in the
// body expression part of the constraint
err = null;
try {
parseConstraint(
"package ocltest context " +
"FruitUtil::processBag(x : Bag(Fruit)) : Bag(Fruit) " +
"body: result = result->asSet()->union(x)->asBag()" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
}
public void test_ifWithNullConditionMustBeInvalid_342644() {
EObject apple = fruitFactory.create(this.apple);
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: let b:Boolean=null in (if b then 1 else 2 endif).oclIsInvalid()" +
" endpackage"), apple);
// oclIsInvalid() on an invalid variable value results in TRUE
assertEquals(Boolean.TRUE, result);
}
/**
* When resolving unqualified property calls in an inner scope (such as in a loop
* expression), the OCL language specification requires that the lookup of the
* implicit target of the property call start with the innermost iterator variable
* (whether explicitly or implicitly defined) and work outwards until it finds a
* match).
*/
public void test_innerScopeFeatureResolution_bugzilla113355() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
// Library1
// - Library2
// - Writer1
// - Writer2
EClass libraryClass = EcoreFactory.eINSTANCE.createEClass();
libraryClass.setName("Library");
epackage.getEClassifiers().add(libraryClass);
EClass writerClass = EcoreFactory.eINSTANCE.createEClass();
writerClass.setName("Writer");
epackage.getEClassifiers().add(writerClass);
EReference branchesRef = EcoreFactory.eINSTANCE.createEReference();
branchesRef.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
branchesRef.setName("branches");
branchesRef.setEType(libraryClass);
EReference writersRef = EcoreFactory.eINSTANCE.createEReference();
writersRef.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
writersRef.setName("writers");
writersRef.setEType(writerClass);
EAttribute writerName = EcoreFactory.eINSTANCE.createEAttribute();
writerName.setName("name");
writerName.setEType(EcorePackage.eINSTANCE.getEString());
libraryClass.getEStructuralFeatures().add(branchesRef);
libraryClass.getEStructuralFeatures().add(writersRef);
writerClass.getEStructuralFeatures().add(writerName);
EFactory efactory = epackage.getEFactoryInstance();
// create our test instance
EObject library1 = efactory.create(libraryClass);
EObject library2 = efactory.create(libraryClass);
EObject writer1 = efactory.create(writerClass);
EObject writer2 = efactory.create(writerClass);
writer1.eSet(writerName, "Joe");
writer2.eSet(writerName, "Jane");
EList<EObject> branches = new BasicEList<EObject>();
branches.add(library2);
EList<EObject> writers = new BasicEList<EObject>();
writers.add(writer1);
writers.add(writer2);
library1.eSet(branchesRef, branches);
library2.eSet(writersRef, writers);
// parse expression
try {
OCLExpression<EClassifier> expr = parse(
"package mypkg context Library " +
"inv: branches->collect(writers->collect(w : Writer | w))->flatten()" +
"endpackage");
@SuppressWarnings("unchecked")
List<EObject> result = (List<EObject>)evaluate(expr, library1);
assertTrue(result.size() == 2);
assertTrue(result.get(0).eGet(writerName).equals("Joe"));
assertTrue(result.get(1).eGet(writerName).equals("Jane"));
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
/**
* Tests the collection product() operation.
*/
public void test_product_126336() {
helper.setContext(EcorePackage.Literals.ESTRING);
Set<Tuple<EOperation, EStructuralFeature>> product = null;
try {
OCLExpression<EClassifier> expr = helper.createQuery(
"Set{'foo', 'bar'}->product(Sequence{1, 2, 3})");
EClassifier resultType = expr.getType();
assertTrue(resultType instanceof CollectionType);
EClassifier elementType = ((CollectionType) resultType).getElementType();
assertTrue(elementType instanceof TupleType);
TupleType tupleType = (TupleType) elementType;
assertEquals(2, tupleType.getEAttributes().size());
@SuppressWarnings("unchecked")
Set<Tuple<EOperation, EStructuralFeature>> evalResult =
(Set<Tuple<EOperation, EStructuralFeature>>) ocl.evaluate("", expr);
product = evalResult;
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
assertNotNull(product);
// got as many product tuples as required (2 x 3)
assertEquals(6, product.size());
Map<String, Set<Integer>> expectedTuples =
new java.util.HashMap<String, Set<Integer>>();
Set<Integer> values = new java.util.HashSet<Integer>();
values.add(1);
values.add(2);
values.add(3);
expectedTuples.put("foo", new java.util.HashSet<Integer>(values));
expectedTuples.put("bar", new java.util.HashSet<Integer>(values));
for (Tuple<EOperation, EStructuralFeature> tuple : product) {
values = expectedTuples.get(tuple.getValue("first"));
// every "first" value must hit
assertNotNull(values);
// every "second" must remove a different mapping
assertTrue(values.remove(tuple.getValue("second")));
}
}
/**
* Test that the conversion of an expression to string and re-parsing works
* as expected. Use the particular iteration expression described in the
* referenced bugzilla.
*/
public void test_iterationToString_126454() {
EPackage fakePkg = EcoreFactory.eINSTANCE.createEPackage();
fakePkg.setName("fake");
EClass fake = EcoreFactory.eINSTANCE.createEClass();
fake.setName("Fake");
fakePkg.getEClassifiers().add(fake);
EAttribute eattr = EcoreFactory.eINSTANCE.createEAttribute();
eattr.setName("e");
eattr.setEType(EcorePackage.Literals.EINT);
eattr.setUpperBound(1); // not a collection
fake.getEStructuralFeatures().add(eattr);
EObject aFake = fakePkg.getEFactoryInstance().create(fake);
aFake.eSet(eattr, Integer.valueOf(7));
helper.setContext(fake);
try {
OCLExpression<EClassifier> expr = helper.createQuery("self.e->sum()");
// convert to string and re-parse
String toStringResult = expr.toString();
expr = helper.createQuery(toStringResult);
assertEquals(aFake.eGet(eattr), ocl.evaluate(aFake, expr));
} catch (Exception exc) {
fail("Failed to parse or evaluate: " + exc.getLocalizedMessage());
}
}
/**
* Test the OclVoid literal 'null'.
*/
public void test_null() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclIsTypeOf(OclVoid) " +
" endpackage"));
assertEquals(Boolean.TRUE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclIsUndefined() " +
" endpackage"));
assertEquals(Boolean.TRUE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclIsInvalid() " +
" endpackage"));
assertEquals(Boolean.FALSE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclAsType(Integer) " +
" endpackage"));
assertNull(result);
}
/**
* Test the OclInvalid type and its literal 'invalid'.
*/
public void test_oclInvalid() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: invalid.oclIsTypeOf(OclInvalid) " +
" endpackage"));
assertEquals(Boolean.TRUE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: invalid.oclIsUndefined() " +
" endpackage"));
assertEquals(Boolean.TRUE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: invalid.oclIsInvalid() " +
" endpackage"));
assertEquals(Boolean.TRUE, result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: invalid.oclAsType(Integer) " +
" endpackage"));
assertInvalid(result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclAsType(Apple).color " +
" endpackage"));
// feature calls on null result in invalid
assertInvalid(result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclAsType(Apple).stem " +
" endpackage"));
// feature calls on null result in invalid
assertInvalid(result);
result = evaluate(parse(
"package ocltest context Fruit " +
"inv: null.oclAsType(Apple).preferredLabel('foo') " +
" endpackage"));
// feature calls on null result in invalid
assertInvalid(result);
}
public void test_oclInvalidInIterateAccumulator_342644() {
EObject apple = fruitFactory.create(this.apple);
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: self->iterate(i; acc:Integer='123a'.toInteger() | if acc.oclIsInvalid() then 0 else acc+1 endif)" +
" endpackage"), apple);
// oclIsInvalid() on an invalid variable value results in TRUE
assertEquals(0, result);
}
public void test_oclIsInvalidOnInvalidLetVariable_342644() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: let a:Integer = '123a'.toInteger() in a.oclIsInvalid() " +
" endpackage"));
// oclIsInvalid() on an invalid variable value results in TRUE
assertEquals(Boolean.TRUE, result);
}
public void test_oclIsInvalidOnInvalidOperationResult_342561() {
Object result = evaluate(parse(
"package ocltest context Fruit " +
"inv: '123a'.toInteger().oclIsInvalid() " +
" endpackage"));
// oclIsInvalid() on an invalid OperationCallExp results in TRUE
assertEquals(Boolean.TRUE, result);
}
/**
* Tests that we report an error on failing to find an operation matching
* a call. Moreover, the error is in parsing, not in validating.
*/
public void test_operationNotFound() {
AssertionFailedError err = null;
// this should not work (failure in parse, not validation)
try {
parseUnvalidated(
"package ocltest context FruitUtil " +
"inv: self.processOrderedSet(1) = 0 " +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
}
/**
* Tests that matching operations finds the first match, but that
* casting via oclAsType() can direct the parser to the best match.
*/
@SuppressWarnings("unchecked")
public void test_operationSignatureMatching() {
EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
pkg.getEClassifiers().add(a);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
pkg.getEClassifiers().add(b);
EClass c = EcoreFactory.eINSTANCE.createEClass();
c.setName("C");
c.getESuperTypes().add(b);
pkg.getEClassifiers().add(c);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setEType(b);
ref.setName("b");
a.getEStructuralFeatures().add(ref);
ref = EcoreFactory.eINSTANCE.createEReference();
ref.setEType(c);
ref.setName("c");
a.getEStructuralFeatures().add(ref);
EOperation foo1 = EcoreFactory.eINSTANCE.createEOperation();
foo1.setName("foo");
foo1.setEType(EcorePackage.Literals.EBOOLEAN);
EParameter param = EcoreFactory.eINSTANCE.createEParameter();
param.setEType(c);
foo1.getEParameters().add(param);
a.getEOperations().add(foo1);
EOperation foo2 = EcoreFactory.eINSTANCE.createEOperation();
foo2.setName("foo");
foo2.setEType(EcorePackage.Literals.EBOOLEAN);
param = EcoreFactory.eINSTANCE.createEParameter();
param.setEType(b);
foo2.getEParameters().add(param);
a.getEOperations().add(foo2);
helper.setContext(a);
try {
OCLExpression<EClassifier> expr = helper.createQuery("self.foo(c)");
assertTrue(expr instanceof OperationCallExp<?, ?>);
OperationCallExp<EClassifier, EOperation> oc =
(OperationCallExp<EClassifier, EOperation>) expr;
// foo1's parameter type is c
assertSame(foo1, oc.getReferredOperation());
expr = helper.createQuery("self.foo(b)");
assertTrue(expr instanceof OperationCallExp<?, ?>);
oc = (OperationCallExp<EClassifier, EOperation>) expr;
// we matched foo1 because it was the first operation matching b
// (we skipped the foo having parameter type c)
assertSame(foo2, oc.getReferredOperation());
expr = helper.createQuery("self.foo(b.oclAsType(C))");
assertTrue(expr instanceof OperationCallExp<?, ?>);
oc = (OperationCallExp<EClassifier, EOperation>) expr;
// coerced the arg to type C to find the correct foo
assertSame(foo1, oc.getReferredOperation());
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Tests that looking up an operation call on an implicit source works
* and fails gracefully when it doesn't. Test the case where the implicit
* source is not self.
*/
public void test_operationImplicitSource() {
AssertionFailedError err = null;
// this should not work
try {
parse(
"package ocltest context Fruit " +
"inv: Apple.allInstances()->collect(preferredLabel())" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
// this should work
parse(
"package ocltest context Fruit " +
"inv: Apple.allInstances()->collect(preferredLabel('foo'))" +
" endpackage");
// and this
parse(
"package ocltest context Apple " +
"inv: preferredLabel('foo')" +
" endpackage");
}
/**
* Tests resolution of nested packages where the root package has a
* namespace prefix that differs from the name (in particular, by being
* some dot-separated root name).
*/
public void test_nestedPackages_129769() {
EPackage rootPackage = EcoreFactory.eINSTANCE.createEPackage();
rootPackage.setName("foo");
rootPackage.setNsPrefix("a.b.c.foo");
rootPackage.setNsURI("http:///foo.ecore");
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
rootPackage.getEClassifiers().add(a);
EPackage nestedPackage = EcoreFactory.eINSTANCE.createEPackage();
nestedPackage.setName("bar");
nestedPackage.setNsPrefix("a.b.c.foo.bar");
nestedPackage.setNsURI("http:///foo/bar.ecore");
rootPackage.getESubpackages().add(nestedPackage);
EClass b = EcoreFactory.eINSTANCE.createEClass();
b.setName("B");
nestedPackage.getEClassifiers().add(b);
EPackage.Registry reg = new EPackageRegistryImpl(resourceSet.getPackageRegistry());
reg.put(rootPackage.getNsURI(), rootPackage);
reg.put(nestedPackage.getNsURI(), nestedPackage);
EcoreEnvironmentFactory ef = new EcoreEnvironmentFactory(reg);
ocl.dispose();
ocl = OCL.newInstance(ef);
helper = ocl.createOCLHelper();
helper.setContext(b);
try {
// look up by name
helper.createInvariant("not self.oclIsKindOf(foo::A)");
// for compatibility, NS prefix also works
helper.createInvariant("not self.oclIsKindOf(a::b::c::foo::A)");
helper.setContext(a);
// look-up relative to context package
helper.createInvariant("not self.oclIsKindOf(bar::B)");
// absolute look-up by name
helper.createInvariant("not self.oclIsKindOf(foo::bar::B)");
// and by NS prefix
helper.createInvariant("not self.oclIsKindOf(a::b::c::foo::bar::B)");
} catch (Exception e) {
fail("Parse failed: " + e.getLocalizedMessage());
}
}
/**
* Tests that EClassifier sameness is tested using equality rather than
* identity, on the understanding that usually EClasses implement equality
* as identity, except for clients such as Bugzilla 126145.
*/
@SuppressWarnings("deprecation")
public void test_typeEquality_126145() {
class EqualsEClass extends EClassImpl {
private int key;
EqualsEClass(int key) {
this.key = key;
}
@Override
public boolean equals(Object o) {
return (o instanceof EqualsEClass)
&& (key == ((EqualsEClass) o).key);
}
}
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("foo");
EClass a = new EqualsEClass(1);
a.setName("A");
epackage.getEClassifiers().add(a);
EClass b = new EqualsEClass(1); // same key as a, so b.equals(a)
b.setName("B");
epackage.getEClassifiers().add(b);
EClass c = new EqualsEClass(2);
c.setName("C");
epackage.getEClassifiers().add(b);
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("a");
ref.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
ref.setOrdered(false);
ref.setUnique(true);
ref.setEType(a);
c.getEStructuralFeatures().add(ref);
ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName("b");
ref.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
ref.setOrdered(false);
ref.setUnique(true);
ref.setEType(b);
c.getEStructuralFeatures().add(ref);
helper.setContext(c);
OCLExpression<EClassifier> expr = null;
try {
expr = helper.createQuery("a->union(b)");
} catch (Exception e) {
fail("Parse failed: " + e.getLocalizedMessage());
}
assertNotNull(expr);
EClassifier type = expr.getType();
assertTrue(type instanceof CollectionType);
type = ((CollectionType) type).getElementType();
// verify that the common supertype is a/b, which are considered by
// OCL to be the same type
assertEquals(a, type);
assertEquals(b, type);
EcoreEnvironment env = (EcoreEnvironment) ocl.getEnvironment();
assertEquals(UMLReflection.SAME_TYPE, TypeUtil.getRelationship(env, a, b));
assertEquals(UMLReflection.SAME_TYPE, TypeUtil.getRelationship(env, b, a));
try {
assertEquals(a, TypeUtil.commonSuperType(env, a, b));
assertEquals(b, TypeUtil.commonSuperType(env, a, b));
assertEquals(a, TypeUtil.commonSuperType(env, b, a));
assertEquals(b, TypeUtil.commonSuperType(env, b, a));
} catch (Exception e) {
fail("No common super type: " + e.getLocalizedMessage());
}
}
/**
* Tests referencing an element in an enclosing package using an unqualified name.
*
* <ul>
* <li>EPackage level1<ul>
* <li>EEnum Enum1<ul>
* <li>EEnumLiteral Enum1Literal1</li></ul></li>
* <li>EPackage level2<ul>
* <li>EClass Class1<ul>
* <li>EAttribute attr1 : Enum1</li></ul></li></ul></li></ul></li>
* </ul>
* <pre>
* context: Class1
* expression: attr1 = Enum1::Enum1Literal1
* </pre>
*/
public void test_enclosingPackage_unqualifiedName() {
EPackage level1 = EcoreFactory.eINSTANCE.createEPackage();
level1.setName("level1");
EPackage level2 = EcoreFactory.eINSTANCE.createEPackage();
level2.setName("level2");
level1.getESubpackages().add(level2);
EEnum enum1 = EcoreFactory.eINSTANCE.createEEnum();
enum1.setName("Enum1");
EEnumLiteral enum1Literal1 = EcoreFactory.eINSTANCE.createEEnumLiteral();
enum1Literal1.setName("Enum1Literal1");
enum1.getELiterals().add(enum1Literal1);
EClass class1 = EcoreFactory.eINSTANCE.createEClass();
class1.setName("Class1");
EAttribute attr1 = EcoreFactory.eINSTANCE.createEAttribute();
attr1.setName("attr1");
attr1.setEType(enum1);
class1.getEStructuralFeatures().add(attr1);
level1.getEClassifiers().add(enum1);
level2.getEClassifiers().add(class1);
helper.setContext(class1);
try {
helper.createInvariant("attr1 = Enum1::Enum1Literal1");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
/**
* The Hebrew (Israel) locale on SuSe Linux likes to use character 0xB4
* (acute accent) as a single quotation mark. Should also, then, support
* the back-quote (grave accent), as well.
*/
public void test_hebrew_singleQuote_135321() {
// checkForUTF8Encoding();
parse(
// English locale style
"package ocltest context Apple " +
"inv: preferredLabel('foo')" +
" endpackage");
/* parse( FIXME Bug 291310 rewrite for OCL 2.3 and reintroduce when build is UTF-8.
// SuSe Linux in Hebrew Local
"package ocltest context Apple " +
"inv: preferredLabel(´foo´)" +
" endpackage");
parse(
// I've seen this before (esp. in text export from MS Word)
"package ocltest context Apple " +
"inv: preferredLabel(`foo´)" +
" endpackage"); */
}
/**
* Test that we don't get a <code>null</code> string from an OCL expression
* that contains a reference to a variable that has no name.
*/
public void test_nullVariableName_143386() {
org.eclipse.ocl.ecore.Variable var =
(org.eclipse.ocl.ecore.Variable) oclFactory.<EClassifier, EParameter>createVariable();
assertEquals("\"<null>\"", var.toString());
VariableExp<EClassifier, EParameter> exp =
oclFactory.createVariableExp();
exp.setReferredVariable(var);
assertEquals("\"<null>\"", exp.toString());
var.setName("foo");
assertEquals("foo", var.toString());
assertEquals("foo", exp.toString());
var.setEType(getOCLStandardLibrary().getString());
assertEquals("foo : String", var.toString());
assertEquals("foo", exp.toString());
}
/**
* Regression test for the case of Let expression declaring multiple
* variables that is well-formed.
*/
@SuppressWarnings("unchecked")
public void test_letWithMultipleVariables_bug164503() {
OCLExpression<EClassifier> expr = parse(
"package ocltest context Fruit " +
" inv: let s : String = '', i : Set(Integer) = Set{1}, n : UnlimitedNatural = * in true" +
" endpackage");
// verify the structure of the nested let expression
// first level let is the String variable
assertTrue(expr instanceof LetExp<?, ?>);
LetExp<EClassifier, ?> letExp = (LetExp<EClassifier, ?>) expr;
Variable<EClassifier, ?> var = letExp.getVariable();
assertEquals("s", var.getName());
assertSame(getOCLStandardLibrary().getString(), var.getType());
// second level is the Set(Integer)
assertTrue(letExp.getIn() instanceof LetExp<?, ?>);
letExp = (LetExp<EClassifier, ?>) letExp.getIn();
var = letExp.getVariable();
assertEquals("i", var.getName());
assertTrue(var.getType() instanceof SetType);
// third level is the UnlimitedNatural
assertTrue(letExp.getIn() instanceof LetExp<?, ?>);
letExp = (LetExp<EClassifier, ?>) letExp.getIn();
var = letExp.getVariable();
assertEquals("n", var.getName());
assertSame(getOCLStandardLibrary().getUnlimitedNatural(), var.getType());
// now we have a real "in"
assertTrue(letExp.getIn() instanceof BooleanLiteralExp<?>);
}
/**
* Regression test for the case of Let expression declaring multiple
* variables that is ill-formed, that we don't fail parsing with a runtime
* exception.
*/
public void test_letWithMultipleVariables_illFormed_bug164503() {
try {
parse(
"package ocltest context Fruit " +
" inv: let s : String = '', i : Set(Integer) in true" +
" endpackage");
fail("Should have failed to parse or validate");
} catch (AssertionFailedError e) {
// success
debugPrintln("Got the expected exception: " + e.getLocalizedMessage());
} catch (Exception e) {
fail("Parse failed with run-time exception: " + e.getLocalizedMessage());
}
}
/**
* Tests that, where a path name includes two or more components
* having the same name, the PathNameCS does not remove duplicates.
*/
public void test_repeatedNamesInPath_176308() {
EPackage rootpkg = EcoreFactory.eINSTANCE.createEPackage();
rootpkg.setName("rootpkg");
EPackage first = EcoreFactory.eINSTANCE.createEPackage();
first.setName("repeated");
EPackage second = EcoreFactory.eINSTANCE.createEPackage();
second.setName("repeated");
rootpkg.getESubpackages().add(first);
first.getESubpackages().add(second);
EEnum enum1 = EcoreFactory.eINSTANCE.createEEnum();
enum1.setName("Enum1");
EEnumLiteral enum1Literal1 = EcoreFactory.eINSTANCE.createEEnumLiteral();
enum1Literal1.setName("Enum1Literal1");
enum1.getELiterals().add(enum1Literal1);
second.getEClassifiers().add(enum1);
EClass dummy = EcoreFactory.eINSTANCE.createEClass();
dummy.setName("Dummy");
rootpkg.getEClassifiers().add(dummy);
EAttribute attr1 = EcoreFactory.eINSTANCE.createEAttribute();
attr1.setName("attr1");
attr1.setEType(enum1);
dummy.getEStructuralFeatures().add(attr1);
helper.setContext(dummy);
try {
// should not attempt to look up "repeated::Enum1"
helper.createInvariant(
"attr1 = repeated::repeated::Enum1::Enum1Literal1");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Tests that dollar signs are supported in string literals and in
* element names.
*/
public void test_dollarSignInStrings_163542() {
EPackage rootpkg = EcoreFactory.eINSTANCE.createEPackage();
rootpkg.setName("rootpkg");
rootpkg.setNsURI("http:///rootpkg.ecore");
EClass superclass = EcoreFactory.eINSTANCE.createEClass();
superclass.setName("Superclass");
EClass subclass = EcoreFactory.eINSTANCE.createEClass();
subclass.setName("Sub$Class");
subclass.getESuperTypes().add(superclass);
rootpkg.getEClassifiers().add(superclass);
rootpkg.getEClassifiers().add(subclass);
EAttribute attr1 = EcoreFactory.eINSTANCE.createEAttribute();
attr1.setName("attr$1");
attr1.setEType(EcorePackage.Literals.ESTRING);
superclass.getEStructuralFeatures().add(attr1);
resourceSet.getPackageRegistry().put(rootpkg.getNsURI(), rootpkg);
try {
// parse dollar sign in comments, element names, and string literals
ocl.parse(new OCLInput(
"package rootpkg context Superclass\n" +
"-- this comment has a $ in it\n" +
"inv: attr$1 = 'dollar$sign' implies self.oclIsKindOf(Sub$Class)\n" +
"endpackage"));
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Tests that we don't get NPEs from getting the names of collection types
* that do not (yet) have element types.
*/
public void test_nameOfCollectionTypeWithoutElementType() {
org.eclipse.ocl.types.CollectionType<?, ?> collType = oclFactory.createCollectionType(
CollectionKind.BAG_LITERAL, null);
collType.getName();
}
/**
* Ensure that variable expressions' names are set as they were in the
* 1.1 release.
*/
public void test_variableExpName_243526() {
OCLExpression<EClassifier> constraint = parseConstraintUnvalidated(
"package ocltest context Fruit::ripen(c : Color) : Boolean " +
"pre: c.oclIsUndefined() implies Fruit.allInstances()->forAll(color <> self.color) " +
"endpackage");
for (Iterator<EObject> iter = constraint.eAllContents(); iter.hasNext();) {
EObject next = iter.next();
if (next instanceof VariableExp<?, ?>) {
VariableExp<?, ?> ve = (VariableExp<?, ?>) next;
assertNotNull(ve.getReferredVariable());
assertEquals(ve.getReferredVariable().getName(), ve.getName());
}
}
}
/**
* Ensures that we can reference the UnlimitedNatural type by name.
*/
public void test_refToUnlimitedNaturalType_259740() {
parse(
"package ocltest context Apple " +
"inv: let u : UnlimitedNatural = * in u.abs()" +
" endpackage");
parse(
"package ocltest context Apple " +
"inv: let i : Integer = -1 in not i.oclIsKindOf(UnlimitedNatural)" +
" endpackage");
}
/**
* Tests that a package declaration for an unresolved package fails to
* parse (as it should).
*/
public void test_nullPackageEnvironment_259818() {
try {
parse(
"package NOSUCHPACKAGE context ocltest::Fruit " +
" inv: true" +
" endpackage");
fail("Should have failed to parse or validate");
} catch (AssertionFailedError e) {
// success
debugPrintln("Got the expected exception: " + e.getLocalizedMessage());
} catch (Exception e) {
fail("Parse failed with run-time exception: " + e.getLocalizedMessage());
}
}
/**
* Tests support for Properties with OclVoid, Collection(OclVoid) type..
*/
public void test_voidCollections_463441() {
EPackage epackage = EcoreFactory.eINSTANCE.createEPackage();
epackage.setName("MyPackage");
epackage.setNsPrefix("mypkg");
epackage.setNsURI("http:///mypkg.ecore");
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass a = EcoreFactory.eINSTANCE.createEClass();
a.setName("A");
epackage.getEClassifiers().add(a);
EClassifier voidType = ocl.getEnvironment().getOCLStandardLibrary().getOclVoid();
EAttribute attrA = EcoreFactory.eINSTANCE.createEAttribute();
attrA.setName("void");
attrA.setEType(voidType);
a.getEStructuralFeatures().add(attrA);
EAttribute attrB = EcoreFactory.eINSTANCE.createEAttribute();
attrB.setName("voids");
attrB.setEType(voidType);
attrB.setUpperBound(-1);
a.getEStructuralFeatures().add(attrB);
try {
OCLExpression<EClassifier> constraint = parseConstraint(
"package mypkg context A " +
"inv: self.voids = OrderedSet{} " +
"endpackage");
// create an A
EObject eobj = epackage.getEFactoryInstance().create(a);
assertTrue("Should not have failed the check", check(constraint, eobj));
constraint = parseConstraint(
"package mypkg context A " +
"inv: self.voids = Set{} " +
"endpackage");
assertFalse("Should have failed the check", check(constraint, eobj)); // Check that we are checking
constraint = parseConstraint(
"package mypkg context A " +
"inv: self.void = null " +
"endpackage");
assertTrue("Should have failed the check", check(constraint, eobj));
@SuppressWarnings("unchecked")List<Object> voids = (List<Object>) eobj.eGet(attrB);
voids.add(null);
constraint = parseConstraint(
"package mypkg context A " +
"inv: self.voids = OrderedSet{null} " +
"endpackage");
assertTrue("Should have failed the check", check(constraint, eobj)); // Check that we are checking
} catch (Exception e) {
fail("Failed to parse or evaluate: " + e.getLocalizedMessage());
}
}
}