/*******************************************************************************
* 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);
}
}
}