/******************************************************************************* * Copyright (c) 2005, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM - Initial API and implementation * Zeligsoft - Bug 245897, 179990 * Radek Dvorak - Bug 261128 * E.D.Willink - Bug 254919, 298634 *******************************************************************************/ package org.eclipse.ocl.uml.tests; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.ocl.tests.GenericFruitTestSuite; import org.eclipse.ocl.uml.util.OCLUMLUtil; import org.eclipse.uml2.uml.Association; import org.eclipse.uml2.uml.AssociationClass; import org.eclipse.uml2.uml.CallOperationAction; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.DataType; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.EnumerationLiteral; import org.eclipse.uml2.uml.InstanceSpecification; import org.eclipse.uml2.uml.InstanceValue; import org.eclipse.uml2.uml.LiteralBoolean; import org.eclipse.uml2.uml.LiteralInteger; import org.eclipse.uml2.uml.LiteralNull; import org.eclipse.uml2.uml.LiteralString; 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.PrimitiveType; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.SendSignalAction; import org.eclipse.uml2.uml.Slot; import org.eclipse.uml2.uml.State; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLFactory; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.ValueSpecification; import org.eclipse.uml2.uml.util.UMLUtil; /** * Extended test framework for tests using the UML binding and the Fruit meta-model. * * @author Christian W. Damus (cdamus) */ @SuppressWarnings("nls") public abstract class AbstractTestSuite extends GenericFruitTestSuite<EObject, Package, Type, Classifier, Class, DataType, PrimitiveType, Enumeration, Operation, Parameter, Property, Property, Property, EnumerationLiteral, State, CallOperationAction, SendSignalAction, Constraint> { protected static final ExecutorService exec = Executors .newSingleThreadExecutor(); @SuppressWarnings("unused") private static org.eclipse.uml2.types.TypesPackage umltypes = org.eclipse.uml2.types.TypesPackage.eINSTANCE; // FIXME Until BUG 366083 fixed protected static org.eclipse.ocl.uml.UMLPackage ocltypes = org.eclipse.ocl.uml.UMLPackage.eINSTANCE; protected static UMLPackage uml = UMLPackage.eINSTANCE; protected static UMLFactory umlf = uml.getUMLFactory(); protected EPackage fruitEPackage; protected EFactory fruitEFactory; protected Class fruit; protected Operation fruit_ripen; protected Operation fruit_preferredColor; protected Operation fruit_newFruit; protected Operation fruit_setColor; protected Property fruit_color; protected Property fruit_friends; protected Class apple; protected Property apple_label; protected Property apple_tree; protected Property apple_appleFriends; protected Operation apple_labelOper; protected Operation apple_newApple; protected AssociationClass stem; protected Property stem_length; protected Class tree; protected Property tree_apples; protected Property tree_height; protected Enumeration color; protected EnumerationLiteral color_black; protected EnumerationLiteral color_red; protected EnumerationLiteral color_green; protected EnumerationLiteral color_yellow; protected EnumerationLiteral color_orange; protected EnumerationLiteral color_brown; protected EnumerationLiteral color_pink; protected Class forest; protected Property forest_trees; protected Property forest_trees_zoneQualifier; protected Property forest_trees_indexQualifier; protected Property forest_area; protected Association a_forest_tree; protected Property a_forest_tree_forest; protected Class util; protected Property util_orderedSet; protected Property util_set; protected Property util_bag; protected Property util_sequence; protected Operation util_processOrderedSet; protected Operation util_processSet; protected Operation util_processBag; protected Operation util_processSequence; /** * Adds parser-style independent tests to the test suite. * * @param result the suite */ public static void suite(CheckedTestSuite result) { result.createTestSuite(BasicOCLTest.class, "Basic Tests"); result.createTestSuite(EvaluationBooleanOperationTest.class, "Boolean operations Tests"); result.createTestSuite(EvaluationCollectionOperationTest.class, "Collection operations Tests"); result.createTestSuite(EvaluationNumberOperationTest.class, "Numeric operations Tests"); result.createTestSuite(EvaluationOclAnyOperationTest.class, "OclAny operations Tests"); result.createTestSuite(EvaluationStringOperationTest.class, "String operations Tests"); result.createTestSuite(PrimitiveTypesTest.class, "Primitive Type Tests"); result.createTestSuite(ComparisonTest.class, "Comparison/Ordering Tests"); result.createTestSuite(CollectionsTest.class, "Collection Type Tests"); result.createTestSuite(AssociationTest.class, "Association Tests"); result.createTestSuite(IteratorsTest.class, "Iterator Tests"); result.createTestSuite(KeywordsTest.class, "LPG and OCL Keyword Tests"); result.createTestSuite(PrecedenceTest.class, "Operator Precedence Tests"); result.createTestSuite(TuplesTest.class, "Tuple Tests"); result.createTestSuite(StatesTest.class, "State Expression Tests"); result.createTestSuite(MessagesTest.class, "Message Expression Tests"); result.createTestSuite(ProfilesTest.class, "Profile Constraint Tests"); result.createTestSuite(InvariantConstraintsTest.class, "Invariant Constraints"); result.createTestSuite(OperationConstraintsTest.class, "Operation Constraints"); result.createTestSuite(LocationInformationTest.class, "Location Information Tests"); result.createTestSuite(FeatureRedefinitionTest.class, "Feature redefinition tests"); result.createTestSuite(DefExpressionTest.class, "Def Expression Tests"); result.createTestSuite(InitOrDerExpressionTest.class, "Initial and Derivation Expression Tests"); result.createTestSuite(UMLTest.class, "UML-Specific Tests"); result.createTestSuite(OCLDocumentTest.class, "OCL Document Parsing Tests"); result.createTestSuite(UtilitiesTest.class, "OCLUMLUtil Utility Class Tests"); result.createTestSuite(UMLEnvironmentTest.class, "UML Environment Tests"); result.addTestSuite(org.eclipse.ocl.uml.helper.tests.AbstractTestSuite.suite()); result.createTestSuite(RegressionTest.class, "Regression Tests"); result.createTestSuite(ValidationTest.class, "Expression Validation Tests"); result.createTestSuite(TypesValidatorTest.class, "Types Validator Tests"); result.createTestSuite(ExpressionsValidatorTest.class, "Expressions Validator Tests"); result.createTestSuite(SerializationTest.class, "Serialization Tests"); result.createTestSuite(EvaluationHaltedTest.class, "UML Halted Evaluation Tests"); } /** * Adds backtracking tests to the test suite. * * @param result the suite */ public static void suiteBacktracking(CheckedTestSuite result) { result.createTestSuite(ParserBacktrackingTest.class, "Parser Backtracking Tests"); } // // Framework methods // @Override public UMLTestReflection.Static getStaticReflection() { return UMLTestReflection.Static.INSTANCE; } /** * Clean up on behalf of derived tests, alleviating them of the tedious need to avoid * leaks. All loaded resources are unloaded and all fields are nulled, by invoking * tearDown_xxx() if such a method is available, or setting it to null otherwise. * public access must be provided. * * This method is final to force invocation. Provide a tearDown_xxx method to do * some derived action during tearDown. * @Override protected final void tearDown() throws Exception { final Resource resource = fruitPackage.eResource(); final boolean isModified = resource.isModified(); final boolean expectIsModified = expectModified; // // Unload any resources that a test may have loaded. // for (ListIterator<Resource> i = resourceSet.getResources().listIterator(); i.hasNext(); ) { Resource res = i.next(); if (((res == resource) && isModified) || !standardResources.contains(res)) { i.remove(); res.unload(); res.eAdapters().clear(); } } // // Null out any references that a test may have left behind, so that unwanted // objects are not locked into memory. // for (java.lang.Class<?> aClass = getClass(); AbstractTestSuite.class.isAssignableFrom(aClass); aClass = aClass.getSuperclass()) { for (Field field : aClass.getDeclaredFields()) { int modifiers = field.getModifiers(); if (Modifier.isFinal(modifiers)) { } else if (!Modifier.isStatic(modifiers)) { java.lang.Class<?> fieldType = field.getType(); if (Object.class.isAssignableFrom(fieldType)) { String fieldName = field.getName(); try { String tearDownName = "tearDown_" + fieldName; Method method = aClass.getDeclaredMethod(tearDownName); try { method.invoke(this); } catch (Exception e) { // tearDown_xxx must be public fail("Failed to invoke " + getClass().getSimpleName() + "." + tearDownName + " : " + e); } } catch (NoSuchMethodException e) { try { field.set(this, null); } catch (Exception e1) { // xxx without a tearDown_xxx must be public to ensure that leakage can be stopped fail("Failed to set " + getClass().getSimpleName() + "." + fieldName + " to null : " + e1); } } } } else if (aClass != AbstractTestSuite.class) { // Tests may not have statics since they are prone to memory leakage fail("static test variable:" + field); } } } assertTrue(isModified == expectIsModified ); System.out.println("==> Finish " + getName()); } */ @Override protected void tearDownField(Field field) throws IllegalAccessException { field.set(this, null); } @Override protected final void tearDownStatic(java.lang.Class<?> aClass, Field field) { if (aClass != AbstractTestSuite.class) { super.tearDownStatic(aClass, field); } } @Override protected void tearDownUsing(Method method) throws IllegalAccessException, InvocationTargetException { method.invoke(this); } public void tearDown_fruitEPackage() { resourceSet.getPackageRegistry().remove(fruitEPackage.getNsURI()); fruitEPackage = null; } protected final String getStereotype(Constraint constraint) { EList<String> keywords = constraint.getKeywords(); return keywords.isEmpty()? null : keywords.get(0); } protected InstanceSpecification instantiate(Package pkg, Classifier classifier) { InstanceSpecification result = (InstanceSpecification) pkg.createPackagedElement( null, uml.getInstanceSpecification()); if (classifier != null) { result.getClassifiers().add(classifier); } return result; } protected Slot setValue( InstanceSpecification instance, Property property, Object value) { Slot result = null; for (Slot slot : instance.getSlots()) { if (slot.getDefiningFeature() == property) { result = slot; slot.getValues().clear(); break; } } if (result == null) { result = instance.createSlot(); result.setDefiningFeature(property); } if (value instanceof Collection<?>) { for (Object e : (Collection<?>) value) { addValue(result, e); } } else { addValue(result, value); } return result; } protected void clearValue( InstanceSpecification instance, Property property) { for (Slot slot : instance.getSlots()) { if (slot.getDefiningFeature() == property) { instance.getSlots().remove(slot); break; } } } protected Slot addValue( InstanceSpecification instance, Property property, Object value) { Slot result = null; for (Slot slot : instance.getSlots()) { if (slot.getDefiningFeature() == property) { result = slot; break; } } if (result == null) { result = setValue(instance, property, value); } else { addValue(result, value); } return result; } protected ValueSpecification addValue(Slot slot, Object value) { ValueSpecification result; if (value instanceof InstanceSpecification) { InstanceValue valueSpec = (InstanceValue) slot.createValue( null, null, uml.getInstanceValue()); valueSpec.setInstance((InstanceSpecification) value); result = valueSpec; } else if (value instanceof String) { LiteralString valueSpec = (LiteralString) slot.createValue( null, null, uml.getLiteralString()); valueSpec.setValue((String) value); result = valueSpec; } else if (value instanceof Integer) { if (slot.getDefiningFeature().getType() == getUMLUnlimitedNatural()) { LiteralUnlimitedNatural valueSpec = (LiteralUnlimitedNatural) slot.createValue( null, null, uml.getLiteralUnlimitedNatural()); valueSpec.setValue(((Integer) value).intValue()); result = valueSpec; } else { LiteralInteger valueSpec = (LiteralInteger) slot.createValue( null, null, uml.getLiteralInteger()); valueSpec.setValue(((Integer) value).intValue()); result = valueSpec; } } else if (value instanceof Boolean) { LiteralBoolean valueSpec = (LiteralBoolean) slot.createValue( null, null, uml.getLiteralBoolean()); valueSpec.setValue(((Boolean) value).booleanValue()); result = valueSpec; } else if (value == null) { LiteralNull valueSpec = (LiteralNull) slot.createValue( null, null, uml.getLiteralNull()); result = valueSpec; } else { throw new IllegalArgumentException("Unrecognized slot value: " + value); } return result; } protected Object getValue(InstanceSpecification owner, Property property) { for (Slot slot : owner.getSlots()) { if (slot.getDefiningFeature() == property) { EList<ValueSpecification> values = slot.getValues(); if (!property.isMultivalued()) { return values.isEmpty()? null : convert(values.get(0)); } else { EList<Object> result = new BasicEList.FastCompare<Object>(values.size()); for (ValueSpecification value : values) { result.add(convert(value)); } return result; } } } fail("No such property value: " + property.getName()); return null; } protected Object convert(ValueSpecification value) { Object result; if (value instanceof InstanceValue) { result = ((InstanceValue) value).getInstance(); } else if (value instanceof LiteralString) { result = ((LiteralString) value).stringValue(); } else if (value instanceof LiteralInteger) { result = ((LiteralInteger) value).integerValue(); } else if (value instanceof LiteralUnlimitedNatural) { result = ((LiteralUnlimitedNatural) value).integerValue(); } else if (value instanceof LiteralBoolean) { result = ((LiteralBoolean) value).booleanValue(); } else if (value instanceof LiteralNull) { result = null; } else { throw new IllegalArgumentException("Unrecognized slot value: " + value); } return result; } protected InstanceSpecification link( Package pkg, InstanceSpecification instance1, Property end1, InstanceSpecification instance2, Property end2, Association assoc) { InstanceSpecification result = instantiate(pkg, assoc); setValue(result, end1, instance2); if (end1.getOwningAssociation() == null) { addValue(instance1, end1, instance2); } setValue(result, end2, instance1); if (end2.getOwningAssociation() == null) { addValue(instance2, end2, instance1); } return result; } protected InstanceSpecification link( Package pkg, InstanceSpecification instance1, Property end1, Object[] qualifierValues, InstanceSpecification instance2, Property end2, Association assoc) { InstanceSpecification result = link(pkg, instance1, end1, instance2, end2, assoc); List<Property> qualifiers = end1.getQualifiers(); int count = qualifiers.size(); for (int i = 0; i < count; i++) { setValue(result, qualifiers.get(i), qualifierValues[i]); } return result; } protected void unload(EObject eObject) { eObject.eAdapters().clear(); for (Iterator<EObject> iter = eObject.eAllContents(); iter.hasNext();) { iter.next().eAdapters().clear(); } } protected void unload(Collection<? extends EObject> eObjects) { for (EObject eObject : eObjects) { unload(eObject); } } @Override protected void initFruitPackage() { URI uri = getTestModelURI("/model/OCLTest.uml"); Resource res = resourceSet.getResource(uri, true); fruitPackage = (Package) res.getContents().get(0); fruit = (Class) fruitPackage.getOwnedType("Fruit"); fruit_ripen = fruit.getOwnedOperation("ripen", null, null); fruit_preferredColor = fruit.getOwnedOperation("preferredColor", null, null); fruit_newFruit = fruit.getOwnedOperation("newFruit", null, null); fruit_setColor = fruit.getOwnedOperation("setColor", null, null); fruit_color = fruit.getOwnedAttribute("color", null); fruit_friends = fruit.getOwnedAttribute("friends", null); apple = (Class) fruitPackage.getOwnedType("Apple"); apple_label = apple.getOwnedAttribute("label", null); apple_tree = apple.getOwnedAttribute("tree", null); apple_appleFriends = apple.getOwnedAttribute("appleFriends", null); apple_labelOper = apple.getOwnedOperation("label", null, null); apple_newApple = apple.getOwnedOperation("newApple", null, null); stem = (AssociationClass) fruitPackage.getOwnedType("Stem"); stem_length = stem.getOwnedAttribute("length", null); tree = (Class) fruitPackage.getOwnedType("Tree"); tree_apples = tree.getOwnedAttribute("apples", null); tree_height = tree.getOwnedAttribute("height", null); color = (Enumeration) fruitPackage.getOwnedType("Color"); color_black = color.getOwnedLiteral("black"); color_red = color.getOwnedLiteral("red"); color_green = color.getOwnedLiteral("green"); color_yellow = color.getOwnedLiteral("yellow"); color_orange = color.getOwnedLiteral("orange"); color_brown = color.getOwnedLiteral("brown"); color_pink = color.getOwnedLiteral("pink"); forest = (Class) fruitPackage.getOwnedType("Forest"); forest_trees = forest.getOwnedAttribute("trees", null); forest_trees_zoneQualifier = forest_trees.getQualifier("zone", null); forest_trees_indexQualifier = forest_trees.getQualifier("index", null); forest_area = forest.getOwnedAttribute("area", null); a_forest_tree = (Association) fruitPackage.getOwnedType("A_Forest_Tree"); a_forest_tree_forest = a_forest_tree.getOwnedEnd("forest", null); util = (Class) fruitPackage.getOwnedType("FruitUtil"); util_orderedSet = util.getOwnedAttribute("orderedSet", null); util_set = util.getOwnedAttribute("set", null); util_bag = util.getOwnedAttribute("bag", null); util_sequence = util.getOwnedAttribute("sequence", null); util_processOrderedSet = util.getOwnedOperation("processOrderedSet", null, null); util_processSet = util.getOwnedOperation("processSet", null, null); util_processBag = util.getOwnedOperation("processBag", null, null); util_processSequence = util.getOwnedOperation("processSequence", null, null); // convert the Package to Ecore for evaluation on instances fruitEPackage = UMLUtil.convertToEcore(fruitPackage, null).iterator().next(); resourceSet.getPackageRegistry().put(fruitEPackage.getNsURI(), fruitEPackage); fruitEFactory = fruitEPackage.getEFactoryInstance(); res.setTrackingModification(true); assertSame( fruitPackage, OCLUMLUtil.findPackage( Collections.singletonList(fruitPackage.getName()), resourceSet)); } }