blob: 10be259814faaaac96048f41929083f6989d8aa3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2018 IBM Corporation 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 248869
* Borland - Bug 242880
* E.D.Willink - Bug 295166
* Adolfo Sanchez-Barbudo Herrera (Open Canarias) - Bug 333032
*******************************************************************************/
package org.eclipse.ocl.ecore.tests;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
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.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
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.ecore.SendSignalAction;
import org.eclipse.ocl.helper.Choice;
import org.eclipse.ocl.helper.ChoiceKind;
import org.eclipse.ocl.helper.ConstraintKind;
import org.eclipse.ocl.helper.OCLHelper;
import org.eclipse.ocl.options.ParsingOptions;
/**
* Tests the {@link ExpressionsUtil} class.
*
* @author Christian Vogt (cvogt)
*/
@SuppressWarnings("nls")
public class EcoreEnvironmentTest
extends AbstractTestSuite {
/**
* Tests the default EcoreEnvironment which uses the global package registry.
*/
public void test_globalEPackageRegistry_lookup() {
// add a context which we won't use
helper.setContext(EcorePackage.eINSTANCE.getEClassifier());
final String EXPRESSION = "ocltest::Color::";
// choices should be returned
List<Choice> choices = helper.getSyntaxHelp(ConstraintKind.INVARIANT, EXPRESSION);
assertNotNull(choices);
assertFalse(choices.isEmpty());
assertChoice(choices, ChoiceKind.ENUMERATION_LITERAL, "green");
// remove the package from the global registry
resourceSet.getPackageRegistry().remove(fruitPackage.getNsURI());
// registry no longer contains the fruit package
// no choices should be returned
choices = helper.getSyntaxHelp(ConstraintKind.INVARIANT, EXPRESSION);
assertNotNull(choices);
assertTrue(choices.isEmpty());
}
/**
* Tests the use of a custom package registry with the EcoreEnvironment.
*/
public void test_customEPackageRegistry_lookup() {
EPackage.Registry registry = new EPackageRegistryImpl();
ocl.dispose();
ocl = OCL.newInstance(new EcoreEnvironmentFactory(registry));
OCLHelper<EClassifier, EOperation, EStructuralFeature, Constraint> helper =
ocl.createOCLHelper();
// add a context which we won't use
helper.setContext(EcorePackage.eINSTANCE.getEClassifier());
final String EXPRESSION = "ocltest::Color::";
// registry is empty, no choices should be returned
List<Choice> choices = helper.getSyntaxHelp(ConstraintKind.INVARIANT, EXPRESSION);
assertNotNull(choices);
assertTrue(choices.isEmpty());
// add the fruit package to the registry
registry.put(fruitPackage.getNsURI(), fruitPackage);
// choices should now be returned
choices = helper.getSyntaxHelp(ConstraintKind.INVARIANT, EXPRESSION);
assertNotNull(choices);
assertFalse(choices.isEmpty());
assertChoice(choices, ChoiceKind.ENUMERATION_LITERAL, "green");
}
public void test_evaluationEnvironment_getType_178901() {
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject>
evalEnv = ocl.getEvaluationEnvironment();
assertSame(EcorePackage.Literals.EPACKAGE, evalEnv.getType(fruitPackage));
assertSame(EcorePackage.Literals.ECLASS, evalEnv.getType(fruit));
assertSame(EcorePackage.Literals.ERESOURCE_SET, evalEnv.getType(new ResourceSetImpl()));
assertSame(getOCLStandardLibrary().getString(), evalEnv.getType("foo"));
assertSame(getOCLStandardLibrary().getOclAny(), evalEnv.getType(this));
}
/**
* Tests extensibility of the OCL Ecore environment.
*/
public void test_extensibility_156360() {
ocl.dispose();
OCL ocl = OCL.newInstance(new MyEnvironmentFactory());
OCL.Helper helper = ocl.createOCLHelper();
helper.setContext(EcorePackage.Literals.ESTRING);
Constraint constraint = null;
try { // Double \ for Java and Double \ again for OCL String Literal
constraint = helper.createInvariant(
"self.regexMatch('\\\\d{3}-\\\\d{3}-\\\\d{3}') <> null");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
assertTrue(ocl.check("123-456-789", constraint));
assertFalse(ocl.check("123-4567-890", constraint));
assertFalse(ocl.check("123-abc-456", constraint));
}
/**
* Tests extensibility of the OCL Ecore environment, that the particular
* scenario also works with backslash escaping, such that the Java operation
* implementation gets the expected string values.
*/
public void test_extensibility_156360_with_backslash_escaping() {
OCL ocl = OCL.newInstance(new MyEnvironmentFactory());
OCL.Helper helper = ocl.createOCLHelper();
helper.setContext(EcorePackage.Literals.ESTRING);
Constraint constraint = null;
Boolean oldBackslashProcessingEnabled = ParsingOptions.getValue(ocl
.getEnvironment(), ParsingOptions.USE_BACKSLASH_ESCAPE_PROCESSING);
ParsingOptions.setOption(ocl.getEnvironment(),
ParsingOptions.USE_BACKSLASH_ESCAPE_PROCESSING, true);
try {
constraint = helper
.createInvariant("self.regexMatch('\\\\d{3}-\\\\d{3}-\\\\d{3}') <> null");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
} finally {
ParsingOptions.setOption(ocl.getEnvironment(),
ParsingOptions.USE_BACKSLASH_ESCAPE_PROCESSING,
oldBackslashProcessingEnabled);
}
assertTrue(ocl.check("123-456-789", constraint));
assertFalse(ocl.check("123-4567-890", constraint));
assertFalse(ocl.check("123-abc-456", constraint));
}
class MyEnvironment extends EcoreEnvironment {
EOperation regexMatch;
// this constructor is used to initialize the root environment
MyEnvironment(EcoreEnvironmentFactory factory) {
super(factory, null);
defineCustomOperations();
}
// this constructor is used to initialize child environments
MyEnvironment(MyEnvironment parent) {
super(parent);
// get the parent's custom operations
regexMatch = parent.regexMatch;
}
// use the AbstractEnvironment's mechanism for defining "additional operations"
// to add our custom operation to OCL's String primitive type
private void defineCustomOperations() {
// pattern-matching operation
regexMatch = EcoreFactory.eINSTANCE.createEOperation();
regexMatch.setName("regexMatch");
regexMatch.setEType(getOCLStandardLibrary().getString());
EParameter parm = EcoreFactory.eINSTANCE.createEParameter();
parm.setName("pattern");
parm.setEType(getOCLStandardLibrary().getString());
regexMatch.getEParameters().add(parm);
// annotate it so that we will recognize it in the evaluation environment
EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
annotation.setSource("MyEnvironment");
regexMatch.getEAnnotations().add(annotation);
// define it as an additional operation on OCL String
addHelperOperation(getOCLStandardLibrary().getString(), regexMatch);
}
}
class MyEvaluationEnvironment extends EcoreEvaluationEnvironment {
MyEvaluationEnvironment(MyEnvironmentFactory factory) {
super(factory);
}
MyEvaluationEnvironment(
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent) {
super(parent);
}
@Override
public Object callOperation(EOperation operation, int opcode, Object source, Object[] args) {
if (operation.getEAnnotation("MyEnvironment") == null) {
// not our custom regex operation
return super.callOperation(operation, opcode, source, args);
}
if ("regexMatch".equals(operation.getName())) {
Pattern pattern = Pattern.compile((String) args[0]);
Matcher matcher = pattern.matcher((String) source);
return matcher.matches()? matcher.group() : null;
}
throw new UnsupportedOperationException(); // unknown operation
}
}
class MyEnvironmentFactory extends EcoreEnvironmentFactory {
@Override
public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject>
createEnvironment() {
MyEnvironment result = new MyEnvironment(this);
return result;
}
@Override
public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject>
createEnvironment(Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> parent) {
if (!(parent instanceof MyEnvironment)) {
throw new IllegalArgumentException(
"Parent environment must be my environment: " + parent);
}
MyEnvironment result = new MyEnvironment((MyEnvironment) parent);
return result;
}
@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);
}
}
}