blob: 4f882a02c6a5a5a731284130cac37a1dc433ecec [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 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 251808
*******************************************************************************/
package org.eclipse.ocl.uml.tests;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.ocl.AmbiguousLookupException;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.LookupException;
import org.eclipse.ocl.OCLInput;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.expressions.AssociationClassCallExp;
import org.eclipse.ocl.expressions.FeatureCallExp;
import org.eclipse.ocl.expressions.LoopExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.helper.Choice;
import org.eclipse.ocl.helper.ChoiceKind;
import org.eclipse.ocl.helper.ConstraintKind;
import org.eclipse.ocl.lpg.BasicEnvironment;
import org.eclipse.ocl.lpg.ProblemHandler;
import org.eclipse.ocl.options.ParsingOptions;
import org.eclipse.ocl.options.ProblemOption;
import org.eclipse.ocl.uml.CollectionType;
import org.eclipse.ocl.uml.options.UMLParsingOptions;
import org.eclipse.ocl.util.OCLUtil;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.AssociationClass;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.LiteralNull;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.util.UMLUtil;
import junit.framework.AssertionFailedError;
/**
* Tests for association navigation.
*
* @author Christian W. Damus (cdamus)
*/
@SuppressWarnings("nls")
public class AssociationTest
extends AbstractTestSuite {
Resource instanceResource;
Package instancePackage;
/**
* Tests support for association end qualifiers.
*/
public void test_qualifiers_associationEnd_RATLC00538077() {
InstanceSpecification aForest = instantiate(instancePackage, forest);
InstanceSpecification aTree = instantiate(instancePackage, tree);
InstanceSpecification anotherTree = instantiate(instancePackage, tree);
Collection<InstanceSpecification> trees =
new java.util.HashSet<InstanceSpecification>();
trees.add(aTree);
trees.add(anotherTree);
link(instancePackage,
aForest, forest_trees,
new Object[] {"foo", 3},
aTree, a_forest_tree_forest,
a_forest_tree);
link(instancePackage,
aForest, forest_trees,
new Object[] {"bar", 2},
anotherTree, a_forest_tree_forest,
a_forest_tree);
// allowed to specify no qualifiers
OCLExpression<Classifier> expr = parse(
"package ocltest context Forest " +
"inv: self.trees->asSet()" +
" endpackage");
Object result = evaluate(expr, aForest);
assertEquals(trees, result);
// allowed to specify both qualifiers
expr = parse(
"package ocltest context Forest " +
"inv: self.trees['bar', 2]" +
" endpackage");
result = evaluate(expr, aForest);
assertSame(anotherTree, result);
AssertionFailedError err = null;
try {
// must specify both qualifiers or none
parse(
"package ocltest context Forest " +
"inv: not self.trees['foo'].apples->isEmpty()" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
try {
// qualifiers must conform
parse(
"package ocltest context Forest " +
"inv: not self.trees[3, 'foo'].apples->isEmpty()" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
try {
// too many qualifiers
parse(
"package ocltest context Forest " +
"inv: not self.trees['foo', 3, 'bar'].apples->isEmpty()" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
}
/**
* Tests support for association class navigation.
*/
public void test_associationClass_RATLC00538077() {
InstanceSpecification aTree = instantiate(instancePackage, tree);
InstanceSpecification anApple = instantiate(instancePackage, apple);
setValue(anApple, fruit_color, color_red);
InstanceSpecification anotherApple = instantiate(instancePackage, apple);
setValue(anotherApple, fruit_color, color_green);
InstanceSpecification aStem = link(instancePackage,
aTree, tree_apples,
anApple, apple_tree,
stem);
setValue(aStem, stem_length, 3);
InstanceSpecification anotherStem = link(instancePackage,
aTree, tree_apples,
anotherApple, apple_tree,
stem);
setValue(anotherStem, stem_length, 2);
// navigate the association end as usual
OCLExpression<Classifier> expr = parse(
"package ocltest context Tree " +
"inv: self.apples->forAll(a : Apple | a.color <> Color::black)" +
" endpackage");
assertTrue(check(expr, aTree));
setValue(anotherApple, fruit_color, color_black);
assertFalse(check(expr, aTree));
// navigate to the association class, itself
expr = parse(
"package ocltest context Tree " +
"inv: self.stem->forAll(s : Stem | s.length > 0)" +
" endpackage");
assertTrue(check(expr, aTree));
setValue(anotherStem, stem_length, 0);
assertFalse(check(expr, aTree));
}
/**
* Tests support for association class navigation in a scalar (multiplicity
* upper bound is 1) direction.
*/
public void test_associationClass_scalar_182193() {
InstanceSpecification aTree = instantiate(instancePackage, tree);
setValue(aTree, tree_height, 30);
InstanceSpecification anApple = instantiate(instancePackage, apple);
setValue(anApple, fruit_color, color_red);
InstanceSpecification anotherApple = instantiate(instancePackage, apple);
setValue(anotherApple, fruit_color, color_green);
InstanceSpecification aStem = link(instancePackage,
aTree, tree_apples,
anApple, apple_tree,
stem);
setValue(aStem, stem_length, 3);
InstanceSpecification anotherStem = link(instancePackage,
aTree, tree_apples,
anotherApple, apple_tree,
stem);
setValue(anotherStem, stem_length, 2);
// navigate the association end as usual
OCLExpression<Classifier> expr = parse(
"package ocltest context Apple " +
"inv: self.tree.height > 20" +
" endpackage");
assertTrue(check(expr, anApple));
setValue(aTree, tree_height, 20);
assertFalse(check(expr, anApple));
// navigate to the association class, itself
expr = parse(
"package ocltest context Apple " +
"inv: self.stem.length > 0" +
" endpackage");
assertTrue(check(expr, anApple));
setValue(anotherStem, stem_length, 0);
assertFalse(check(expr, anotherApple));
}
/**
* Tests support for association class navigation qualifiers.
*/
public void test_associationClass_qualifiers_RATLC00538077() {
InstanceSpecification aTree = instantiate(instancePackage, tree);
InstanceSpecification anApple = instantiate(instancePackage, apple);
setValue(anApple, fruit_color, color_red);
InstanceSpecification anotherApple = instantiate(instancePackage, apple);
setValue(anotherApple, fruit_color, color_green);
InstanceSpecification aStem = link(instancePackage,
aTree, tree_apples,
anApple, apple_tree,
stem);
setValue(aStem, stem_length, 3);
InstanceSpecification anotherStem = link(instancePackage,
aTree, tree_apples,
anotherApple, apple_tree,
stem);
setValue(anotherStem, stem_length, 2);
// navigate to the association class using the optional qualifier
OCLExpression<Classifier> expr = parse(
"package ocltest context Tree " +
"inv: self.stem[apples]->forAll(s : Stem | s.length > 0)" +
" endpackage");
assertTrue(check(expr, aTree));
AssertionFailedError err = null;
try {
// cannot use role name "tree" as a qualifier
parse(
"package ocltest context Tree " +
"inv: self.stem[tree]->forAll(s : Stem | s.length > 0)" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
try {
// cannot use other expressions as qualifiers
parse(
"package ocltest context Tree " +
"inv: self.stem[3]->forAll(s : Stem | s.length > 0)" +
" endpackage");
} catch (AssertionFailedError e) {
// this is expected (success case)
err = e;
debugPrintln("Got expected error: " + e.getLocalizedMessage());
}
assertNotNull("Parse should have failed", err);
try {
// only one qualifier is allowed
parse(
"package ocltest context Tree " +
"inv: self.stem[apples, apples]->forAll(s : Stem | s.length > 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 support for association class navigation in the case of a
* reflexive association.
*/
public void test_associationClass_reflexive_RATLC00538077() {
expectModified = true;
// set up a reflexive association class for this test case
AssociationClass ac = (AssociationClass) fruitPackage.createOwnedType("AC",
uml.getAssociationClass());
Property x = ac.createOwnedAttribute("x",
getUMLInteger());
Property parent = tree.createOwnedAttribute("parent",
tree);
parent.setLower(0);
parent.setIsUnique(true);
parent.setIsOrdered(false);
Property children = tree.createOwnedAttribute("children",
tree);
children.setLower(0);
children.setUpper(LiteralUnlimitedNatural.UNLIMITED);
children.setIsUnique(true);
children.setIsOrdered(false);
parent.setAssociation(ac);
children.setAssociation(ac);
// create some instances
InstanceSpecification aTree = instantiate(instancePackage, tree);
InstanceSpecification aChild = instantiate(instancePackage, tree);
InstanceSpecification anotherChild = instantiate(instancePackage, tree);
InstanceSpecification aLink = link(instancePackage,
aTree, children,
aChild, parent,
ac);
setValue(aLink, x, 3);
InstanceSpecification anotherLink = link(instancePackage,
aTree, children,
anotherChild, parent,
ac);
setValue(anotherLink, x, 2);
// navigate the association end as usual
OCLExpression<Classifier> expr = parse(
"package ocltest context Tree " +
"inv: self.children->forAll(t : Tree | t.apples->isEmpty())" +
" endpackage");
assertTrue(check(expr, aTree));
link(instancePackage,
anotherChild, tree_apples,
instantiate(instancePackage, apple), apple_tree,
null);
assertFalse(check(expr, aTree));
// navigate to the association class, itself, using the role qualifier
expr = parse(
"package ocltest context Tree " +
"inv: self.aC[children]->forAll(ac : AC | ac.x > 0)" +
" endpackage");
assertTrue(check(expr, aTree));
setValue(anotherLink, x, 0);
assertFalse(check(expr, aTree));
// this direction is a scalar reference
expr = parse(
"package ocltest context Tree " +
"inv: self.aC[parent].x > 0" +
" endpackage");
assertTrue(check(expr, aChild));
assertFalse(check(expr, anotherChild));
AssertionFailedError err = null;
try {
// ambiguous navigation to association class
parse(
"package ocltest context Tree " +
"inv: self.aC->forAll(ac : AC | ac.x > 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 support for navigation from association class to its ends.
*/
public void test_navigateFromAssociationClass_RATLC00538077() {
InstanceSpecification aTree = instantiate(instancePackage, tree);
setValue(aTree, tree_height, 20);
InstanceSpecification anApple = instantiate(instancePackage, apple);
setValue(anApple, fruit_color, color_red);
InstanceSpecification anotherApple = instantiate(instancePackage, apple);
setValue(anotherApple, fruit_color, color_black);
InstanceSpecification aStem = link(instancePackage,
aTree, tree_apples,
anApple, apple_tree,
stem);
setValue(aStem, stem_length, 3);
InstanceSpecification anotherStem = link(instancePackage,
aTree, tree_apples,
anotherApple, apple_tree,
stem);
setValue(anotherStem, stem_length, 0);
// navigate the association end. This end is multiplicity 1..1 by
// definition
OCLExpression<Classifier> expr = parse(
"package ocltest context Stem " +
"inv: self.apples.color <> Color::black" +
" endpackage");
assertTrue(check(expr, aStem));
assertFalse(check(expr, anotherStem));
// this end, too, is 1..1
expr = parse(
"package ocltest context Stem " +
"inv: self.tree.height > 20" +
" endpackage");
assertFalse(check(expr, aStem));
assertFalse(check(expr, anotherStem));
setValue(aTree, tree_height, 30);
assertTrue(check(expr, aStem));
assertTrue(check(expr, anotherStem));
// I have my own attributes, too
expr = parse(
"package ocltest context Stem " +
"inv: self.length > 0" +
" endpackage");
assertTrue(check(expr, aStem));
assertFalse(check(expr, anotherStem));
}
/**
* Tests that content-assist suggests association class navigation.
*/
public void test_associationClass_contentAssist_RATLC00538077() {
helper.setContext(tree);
try {
List<Choice> choices = helper.getSyntaxHelp(
ConstraintKind.INVARIANT, "self.");
assertNotNull(choices);
// regular reference feature
assertChoice(choices, ChoiceKind.PROPERTY, "apples");
// association class navigation
assertChoice(choices, ChoiceKind.ASSOCIATION_CLASS, "stem");
} catch (Exception e) {
fail("Parse failed: " + e.getLocalizedMessage());
}
}
/**
* Tests the retention of location information for property names referenced
* by association end call expressions for association classes.
*/
public void test_propertyPositions_associationClassEndCall() {
final String exprString =
"self.apples->notEmpty()";
OCLExpression<Classifier> constraint = createQuery(tree, exprString);
OperationCallExp<Classifier, Operation> notEmptyExp = LocationInformationTest.asOperationCall(
constraint);
FeatureCallExp<Classifier> mpcExp = LocationInformationTest.asFeatureCall(
notEmptyExp.getSource());
LocationInformationTest.assertPropertyLocation(mpcExp,
exprString.indexOf("apples"),
exprString.indexOf("->"));
}
/**
* Tests the retention of location information for property names referenced
* by association class call expressions.
*/
public void test_propertyPositions_associationClassCall() {
final String exprString =
"self.stem[apples]->notEmpty()";
OCLExpression<Classifier> constraint = createQuery(tree, exprString);
OperationCallExp<Classifier, Operation> notEmptyExp = LocationInformationTest.asOperationCall(
constraint);
FeatureCallExp<Classifier> mpcExp = LocationInformationTest.asFeatureCall(
notEmptyExp.getSource());
LocationInformationTest.assertPropertyLocation(mpcExp,
exprString.indexOf("stem"),
exprString.indexOf("["));
}
/**
* Tests the retention of location information for property names referenced
* by association class call expressions, where the source is a collection
* (so that there is an implicit collect node).
*/
public void test_propertyPositions_associationClassCall_implicitCollect() {
final String exprString =
"Tree.allInstances().stem[apples]->notEmpty()";
OCLExpression<Classifier> constraint = createQuery(tree, exprString);
OperationCallExp<Classifier, Operation> notEmptyExp = LocationInformationTest.asOperationCall(
constraint);
// the OCL is implicitly ->collect(stem[apples])->notEmpty()
LoopExp<Classifier, Parameter> loopExp = LocationInformationTest.asLoop(
notEmptyExp.getSource());
FeatureCallExp<Classifier> mpcExp = LocationInformationTest.asFeatureCall(
loopExp.getBody());
LocationInformationTest.assertPropertyLocation(mpcExp,
exprString.indexOf("stem"),
exprString.indexOf("["));
}
/**
* Tests the retention of location information for property names referenced
* as qualifiers of association class call expressions.
*/
public void test_propertyPositions_associationClassQualified() {
final String exprString =
"self.stem[apples]->notEmpty()";
OCLExpression<Classifier> constraint = createQuery(tree, exprString);
OperationCallExp<Classifier, Operation> notEmptyExp = LocationInformationTest.asOperationCall(
constraint);
AssociationClassCallExp<Classifier, Property> accExp =
LocationInformationTest.asAssociationClassCall(notEmptyExp.getSource());
List<OCLExpression<Classifier>> qualifiers = accExp.getQualifier();
assertEquals(1, qualifiers.size());
OCLExpression<Classifier> qualifier = qualifiers.get(0);
LocationInformationTest.assertLocation(qualifier,
exprString.indexOf("apples"),
exprString.indexOf("]->"));
}
/**
* Tests the retention of location information for property names referenced
* as qualifiers of association class call expressions, where the source
* is a collection (so that there is an implicit collect node).
*/
public void test_propertyPositions_associationClassQualified_implicitCollect() {
final String exprString =
"Tree.allInstances().stem[apples]->notEmpty()";
OCLExpression<Classifier> constraint = createQuery(tree, exprString);
OperationCallExp<Classifier, Operation> notEmptyExp = LocationInformationTest.asOperationCall(
constraint);
// the OCL is implicitly ->collect(stem[apples])->notEmpty()
LoopExp<Classifier, Parameter> loopExp = LocationInformationTest.asLoop(
notEmptyExp.getSource());
AssociationClassCallExp<Classifier, Property> accExp = LocationInformationTest.asAssociationClassCall(
loopExp.getBody());
List<OCLExpression<Classifier>> qualifiers = accExp.getQualifier();
assertEquals(1, qualifiers.size());
OCLExpression<Classifier> qualifier = qualifiers.get(0);
LocationInformationTest.assertLocation(qualifier,
exprString.indexOf("apples"),
exprString.indexOf("]->"));
}
/**
* Tests that navigation through association ends does not throw NPE
* in case that at least one end in the navigation path
* (except for the last) is undefined.
*/
public void test_associationNullContext_bugzilla121614() {
// Employee class
Class employee = instancePackage.createOwnedClass("Employee", false);
// manager reference
employee.createOwnedAttribute("manager", employee);
// create our test instance
InstanceSpecification emp1 = instantiate(instancePackage, employee);
// parse & evaluate expression
OCLExpression<Classifier> expr = parse(
"package instances context Employee " +
"inv: self.manager.manager" +
" endpackage");
Object result = evaluate(expr, emp1);
assertInvalid(result);
}
/**
* Tests that the result of qualifying an association navigation is a
* scalar value (not a collection).
*/
public void test_qualifiedAssociation_scalar_133435() {
// unqualified navigation
OCLExpression<Classifier> expr = parse(
"package ocltest context Forest " +
"inv: self.trees" +
" endpackage");
assertTrue(expr.getType() instanceof CollectionType);
CollectionType collType = (CollectionType) expr.getType();
assertSame(tree, collType.getElementType());
// qualified navigation
expr = parse(
"package ocltest context Forest " +
"inv: self.trees['foo', 3]" +
" endpackage");
assertSame(tree, expr.getType());
}
public void test_nonNavigableAttribute() {
OCLExpression<Classifier> expr = parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
EPackage epackage = UMLUtil.convertToEcore(fruitPackage, null)
.iterator().next();
EFactory factory = epackage.getEFactoryInstance();
// create a resource to provide the context of instance searches
Resource res = new ResourceImpl(URI.createURI("test://foo"));
res.eAdapters().add(new ECrossReferenceAdapter());
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
try {
EClass eTree = (EClass) epackage.getEClassifier("Tree");
EClass eForest = (EClass) epackage.getEClassifier("Forest");
EStructuralFeature eTrees = eForest.getEStructuralFeature("trees");
EObject aForest = factory.create(eForest);
res.getContents().add(aForest);
@SuppressWarnings("unchecked")
EList<EObject> trees = (EList<EObject>) aForest.eGet(eTrees);
EObject aTree = factory.create(eTree);
res.getContents().add(aTree);
trees.add(aTree);
EObject anotherTree = factory.create(eTree);
res.getContents().add(anotherTree);
trees.add(anotherTree);
aTree = factory.create(eTree);
res.getContents().add(aTree);
trees.add(aTree);
assertTrue(check(expr, anotherTree));
} finally {
res.unload();
}
}
public void test_nonNavigableAttribute_instanceSpecification() {
OCLExpression<Classifier> expr = parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
InstanceSpecification aForest = instantiate(instancePackage, forest);
InstanceSpecification aTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, aTree);
InstanceSpecification anotherTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, anotherTree);
aTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, aTree);
assertTrue(check(expr, anotherTree));
}
public void test_unnamedAttribute_194245() {
expectModified = true;
Property tree_forest = forest_trees.getOtherEnd();
assertNotNull(tree_forest);
assertNotNull(tree_forest.getName());
tree_forest.setName(null); // unnamed end
// create a resource to provide the context of instance searches
Resource res = new ResourceImpl(URI.createURI("test://foo"));
res.eAdapters().add(new ECrossReferenceAdapter());
OCLExpression<Classifier> expr = parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
EPackage epackage = UMLUtil.convertToEcore(fruitPackage, null)
.iterator().next();
EFactory factory = epackage.getEFactoryInstance();
resourceSet.getPackageRegistry().put(epackage.getNsURI(), epackage);
EClass eTree = (EClass) epackage.getEClassifier("Tree");
EClass eForest = (EClass) epackage.getEClassifier("Forest");
EStructuralFeature eTrees = eForest.getEStructuralFeature("trees");
EObject aForest = factory.create(eForest);
res.getContents().add(aForest);
@SuppressWarnings("unchecked")
EList<EObject> trees = (EList<EObject>) aForest.eGet(eTrees);
EObject aTree = factory.create(eTree);
res.getContents().add(aTree);
trees.add(aTree);
EObject anotherTree = factory.create(eTree);
res.getContents().add(anotherTree);
trees.add(anotherTree);
aTree = factory.create(eTree);
res.getContents().add(aTree);
trees.add(aTree);
assertTrue(check(expr, anotherTree));
}
public void test_unnamedAttribute_instanceSpecification_194245() {
expectModified = true;
Property tree_forest = forest_trees.getOtherEnd();
assertNotNull(tree_forest);
assertNotNull(tree_forest.getName());
tree_forest.setName(null); // unnamed end
OCLExpression<Classifier> expr = parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
InstanceSpecification aForest = instantiate(instancePackage, forest);
InstanceSpecification aTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, aTree);
InstanceSpecification anotherTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, anotherTree);
aTree = instantiate(instancePackage, tree);
addValue(aForest, forest_trees, aTree);
assertTrue(check(expr, anotherTree));
}
public void test_associationEndAmbiguity_nonNavigable_194245() {
expectModified = true;
// create a duplicate end
forest.createAssociation(
true, AggregationKind.SHARED_LITERAL, "someTrees", 0, -1, tree,
false, AggregationKind.SHARED_LITERAL, "forest", 0, 1);
BasicEnvironment benv = OCLUtil.getAdapter(ocl.getEnvironment(),
BasicEnvironment.class);
benv.setOption(ProblemOption.AMBIGUOUS_ASSOCIATION_ENDS,
ProblemHandler.Severity.WARNING);
parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
Diagnostic diag = ocl.getProblems();
assertNotNull(diag);
assertEquals(Diagnostic.WARNING, diag.getSeverity());
debugPrintln("Got expected warning: " + diag.getMessage());
}
public void test_associationEndAmbiguity_unnamed_194245() {
expectModified = true;
Property tree_forest = forest_trees.getOtherEnd();
assertNotNull(tree_forest);
assertNotNull(tree_forest.getName());
tree_forest.setName(null); // unnamed end
// create a duplicate end
forest.createAssociation(
true, AggregationKind.SHARED_LITERAL, "someTrees", 0, -1, tree,
false, AggregationKind.SHARED_LITERAL, null, 0, 1); // unnamed
BasicEnvironment benv = OCLUtil.getAdapter(ocl.getEnvironment(),
BasicEnvironment.class);
benv.setOption(ProblemOption.AMBIGUOUS_ASSOCIATION_ENDS,
ProblemHandler.Severity.WARNING);
parseConstraint("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage");
Diagnostic diag = ocl.getProblems();
assertNotNull(diag);
assertEquals(Diagnostic.WARNING, diag.getSeverity());
debugPrintln("Got expected warning: " + diag.getMessage());
}
public void test_associationEndAmbiguity_errorSeverity_194245() {
expectModified = true;
// create a duplicate end
forest.createAssociation(
true, AggregationKind.SHARED_LITERAL, "someTrees", 0, -1, tree,
false, AggregationKind.SHARED_LITERAL, "forest", 0, 1);
try {
ocl.parse(new OCLInput("package ocltest context Tree " +
"inv: forest.trees->includes(self)" +
" endpackage"));
fail("Should not have parsed");
} catch (ParserException e) {
// success
debugPrintln("Got expected exception: " + e.getLocalizedMessage());
}
}
public void test_nonNavigableAttribute_inheritedAssociation_194245() {
OCLExpression<Classifier> expr = parseConstraint(
"package UML context LiteralNull " +
"inv: not owningProperty.type.oclIsUndefined()" +
" endpackage");
Package pkg = UMLFactory.eINSTANCE.createPackage();
pkg.setName("pkg");
Class a = pkg.createOwnedClass("A", false);
Property foo = a.createOwnedAttribute("foo", null);
LiteralNull nullVal = (LiteralNull) foo.createDefaultValue(null, null,
UMLPackage.Literals.LITERAL_NULL);
assertFalse(check(expr, nullVal));
foo.setType(a);
assertTrue(check(expr, nullVal));
}
public void test_unnamedAttribute_inheritedAssociation_194245() {
OCLExpression<Classifier> expr = parseConstraint(
"package UML context Class " +
"inv: instanceSpecification.classifier->excluding(self)->isEmpty()" +
" endpackage");
Package pkg = UMLFactory.eINSTANCE.createPackage();
pkg.setName("pkg");
Class a = pkg.createOwnedClass("A", false);
Class b = pkg.createOwnedClass("B", false);
InstanceSpecification instance = (InstanceSpecification) pkg.createPackagedElement(
"anA", UMLPackage.Literals.INSTANCE_SPECIFICATION);
instance.getClassifiers().add(a);
assertTrue(check(expr, a));
instance = (InstanceSpecification) pkg.createPackagedElement(
"anotherA", UMLPackage.Literals.INSTANCE_SPECIFICATION);
instance.getClassifiers().add(a);
assertTrue(check(expr, a));
instance.getClassifiers().add(b); // violate the constraint
assertFalse(check(expr, a));
}
/**
* Tests support for navigation from association to its ends.
*/
public void test_navigateFromAssociation() {
// set the option to consider all Assocations as OCL association-classes
ParsingOptions.setOption(ocl.getEnvironment(), UMLParsingOptions.ASSOCIATION_CLASS_TYPE,
Association.class);
InstanceSpecification aForest = instantiate(instancePackage, forest);
setValue(aForest, forest_area, 1000);
InstanceSpecification aTree = instantiate(instancePackage, tree);
setValue(aTree, tree_height, 2);
InstanceSpecification anotherTree = instantiate(instancePackage, tree);
setValue(anotherTree, tree_height, 0);
InstanceSpecification aLink = link(instancePackage,
aForest, forest_trees,
aTree, forest_trees.getOtherEnd(),
forest_trees.getAssociation());
InstanceSpecification anotherLink = link(instancePackage,
aForest, forest_trees,
anotherTree, forest_trees.getOtherEnd(),
forest_trees.getAssociation());
// navigate the association end. This end is multiplicity 1..1 by
// definition
OCLExpression<Classifier> expr = parse(
"package ocltest context A_Forest_Tree " +
"inv: self.trees.height > 0" +
" endpackage");
assertTrue(check(expr, aLink));
assertFalse(check(expr, anotherLink));
// this end, too, is 1..1
expr = parse(
"package ocltest context A_Forest_Tree " +
"inv: self.forest.area > 1000" +
" endpackage");
assertFalse(check(expr, aLink));
assertFalse(check(expr, anotherLink));
setValue(aForest, forest_area, 1050);
assertTrue(check(expr, aLink));
assertTrue(check(expr, anotherLink));
}
/**
* Tests that reference to uml::Class::general does not resolve to anything,
* not the Classifier::general attribute (because it is redefined as
* Class::superType) nor the bogus association end Generalization::general.
*/
@SuppressWarnings("unchecked")
public void test_classGeneralResolvesToNothing_251808() {
try {
assertNull(
"Should not find redefined property Classifier::general",
OCLUtil.getAdapter(ocl.getEnvironment(),
Environment.Lookup.class).tryLookupProperty(
getMetaclass("Class"), "general"));
} catch (AmbiguousLookupException e) {
fail("Should not be an ambiguous look-up");
} catch (LookupException e) {
fail("Should not be a look-up exception");
}
// this should parse OK, though
parseConstraint("package UML context Class " +
"inv: self.oclAsType(Classifier).general->isEmpty()" +
" endpackage");
}
//
// Fixture methods
//
@Override
protected void setUp() {
super.setUp();
instanceResource = resourceSet.createResource(
URI.createFileURI("/tmp/instances.uml"));
instancePackage = umlf.createPackage();
instancePackage.setName("instances");
instanceResource.getContents().add(instancePackage);
}
}