/******************************************************************************* * Copyright (c) 2008, 2010 Obeo, Zeligsoft Inc., 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: * Obeo - initial API and implementation * Zeligsoft - Bug 243079 (fix test so that it will work) * Adolfo Sanchez-Barbudo Herrera (Open Canarias) - Bug 333032 *******************************************************************************/ package org.eclipse.ocl.ecore.tests; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.ocl.EvaluationEnvironment; import org.eclipse.ocl.ParserException; import org.eclipse.ocl.ecore.EcoreEnvironment; import org.eclipse.ocl.ecore.EcoreEnvironmentFactory; import org.eclipse.ocl.ecore.EcoreEvaluationEnvironment; import org.eclipse.ocl.ecore.OCL; import org.eclipse.ocl.expressions.OCLExpression; import org.eclipse.ocl.helper.OCLHelper; /** * Shows the "operation names collision" bug. When defining a new EOperations * which name is the same as a predefined operation (even if its signature does * not correspond), an opCode is affected to the OperationCallExp and the * evaluation returns <code>null</code> without going through the * EvaluationEnvironment's callOperation method. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ @SuppressWarnings("nls") public class OCLOperationCollisionTest extends AbstractTestSuite { /** * Name of the colliding operation we'll provide as an additional EOperation * on type String. */ private static final String OPERATION_STRING_LAST = "last"; /** Flag to see whether the custom environment was called. */ private boolean enteredMyOperationBody; @Override protected void setUp() { super.setUp(); ((EcoreEnvironment) ocl.getEnvironment()).addHelperOperation(ocl .getEnvironment().getOCLStandardLibrary().getString(), getLastOperation()); } @Override protected OCL createOCL() { return OCL.newInstance(new MyEnvironmentFactory()); } /** * This will simply create an EOperation named "last" with a return type * equal to the primitive OCL "String" type. * * @return The created EOperation. */ public EOperation getLastOperation() { EOperation operation = EcoreFactory.eINSTANCE.createEOperation(); operation.setName(OPERATION_STRING_LAST); operation.setEType(ocl.getEnvironment().getOCLStandardLibrary() .getString()); return operation; } /** * Creates and return a "dummy" ecore model : a single EPackage "package" * containing a single EClass "Class". * * @return the created EPackage. */ public EPackage getDummyModel() { EPackage packaje = EcoreFactory.eINSTANCE.createEPackage(); packaje.setName("package"); EClass clazz = EcoreFactory.eINSTANCE.createEClass(); clazz.setName("Class"); packaje.getEClassifiers().add(clazz); return packaje; } /** * Actual test displaying our collision. * * @throws ParserException * This shouldn't be thrown. */ public void testEvaluation() throws ParserException { OCLHelper<EClassifier, ?, ?, ?> helper = ocl.createOCLHelper(); helper.setContext(EcorePackage.eINSTANCE.getENamedElement()); OCLExpression<EClassifier> expression = helper .createQuery("self.name.last()"); try { ocl.createQuery(expression).evaluate( getDummyModel().getEClassifiers().get(0)); assertTrue( "Evaluation should have gone through MyEvaluationEnvironment#callOperation()", enteredMyOperationBody); } catch (UnsupportedOperationException e) { // expected behavior } } /** * Dummy environment factory. Will allow us to create our own evaluation * environment. */ private class MyEnvironmentFactory extends EcoreEnvironmentFactory { @Override public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> createEvaluationEnvironment() { return new MyEvaluationEnvironment(this); } @Override public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> createEvaluationEnvironment( EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent) { return new MyEvaluationEnvironment(parent); } } /** * Dummy Evaluation environment. Will throw an * {@link UnsupportedOperationException} if its callOperation method is * called on the {@value OPERATION_STRING_LAST} method. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ private class MyEvaluationEnvironment extends EcoreEvaluationEnvironment { /** * Default constructor. */ public MyEvaluationEnvironment(MyEnvironmentFactory factory) { super(factory); } /** * This constructor is needed by the factory. * * @param parent * Parent evaluation environment. */ public MyEvaluationEnvironment( EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent) { super(parent); } @Override public Object callOperation(EOperation operation, int opcode, Object source, Object[] args) { if (OPERATION_STRING_LAST.equals(operation.getName())) { enteredMyOperationBody = true; } return super.callOperation(operation, opcode, source, args); } } }