blob: 1ff7bd1f9449688066799d9cca69c00f67e3f910 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 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 248869
* E.D.Willink - Bug 288040 xor/or/and
*******************************************************************************/
package org.eclipse.ocl.uml.tests;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.SemanticException;
import org.eclipse.ocl.expressions.LetExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.PropertyCallExp;
import org.eclipse.ocl.internal.l10n.OCLMessages;
import org.eclipse.ocl.lpg.ProblemHandler;
import org.eclipse.ocl.options.ParsingOptions;
import org.eclipse.ocl.options.ProblemOption;
import org.eclipse.ocl.util.OCLUtil;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.UMLFactory;
/**
* Operator precedence tests.
*
* @author Christian W. Damus (cwdamus)
*/
@SuppressWarnings("nls")
public class PrecedenceTest
extends AbstractTestSuite {
Resource res;
Package pkg;
Class class1;
/**
* Test that let expressions require parenthesis when embedding them in
* other expressions.
*/
public void test_let() {
helper.setContext(class1);
try {
helper.createInvariant(
"self.base_Property.redefinedProperty->isEmpty() = false implies \n" +
" self.base_Property.redefinedProperty->size() = 1 and\n" +
" let rp : UML::Property =\n" +
" self.base_Property.redefinedProperty->asSequence()->at(1) in \n" +
" self.base_Property.name = rp.name and\n" +
" self.base_Property.type = rp.type");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
helper.setContext(getMetaclass("NamedElement"));
try {
helper.createInvariant(
"namespace.getNamesOfMember(\n" +
" let ne : NamedElement = self in ne)->exists(n |\n" +
" let len : Integer = n.size() in len = 1)");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
/**
* Test that the "in" expression part of a let expression consumes as much
* of the input as possible, so that
* <blockquote><code>let a = ... in a.b</code></blockquote>
* parses as
* <blockquote><code>let a = ... in (a.b)</code></blockquote>
* not as
* <blockquote><code>(let a = ... in a).b</code></blockquote>
*/
@SuppressWarnings("unchecked")
public void test_let_inExpression_182201() {
helper.setContext(getMetaclass("NamedElement"));
OCLExpression<Classifier> expr = null;
try {
expr = helper.createQuery("let ne : NamedElement = self in ne.name");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
assertNotNull(expr);
assertTrue(expr instanceof LetExp<?, ?>); // not a PropertyCallExp
LetExp<Classifier, ?> letExp = (LetExp<Classifier, ?>) expr;
assertTrue(letExp.getIn() instanceof PropertyCallExp<?, ?>);
try {
expr = helper.createQuery(
"let n : String = let ne : NamedElement = self in ne.name in n.size()");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
assertNotNull(expr);
assertTrue(expr instanceof LetExp<?, ?>); // not a PropertyCallExp
letExp = (LetExp<Classifier, ?>) expr;
assertTrue(letExp.getIn() instanceof OperationCallExp<?, ?>);
OperationCallExp<Classifier, Operation> opCall =
(OperationCallExp<Classifier, Operation>) letExp.getIn();
assertEquals("size", opCall.getReferredOperation().getName());
expr = letExp.getVariable().getInitExpression();
assertTrue(expr instanceof LetExp<?, ?>);
letExp = (LetExp<Classifier, ?>) letExp.getVariable().getInitExpression();
assertTrue(letExp.getIn() instanceof PropertyCallExp<?, ?>);
// a different nesting
try {
expr = helper.createQuery(
"let ne : NamedElement = self in let n : String = ne.name in n.size()");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
assertNotNull(expr);
assertTrue(expr instanceof LetExp<?, ?>); // not a PropertyCallExp
letExp = (LetExp<Classifier, ?>) expr;
assertTrue(letExp.getIn() instanceof LetExp<?, ?>);
letExp = (LetExp<Classifier, ?>) letExp.getIn();
assertTrue(letExp.getIn() instanceof OperationCallExp<?, ?>);
OperationCallExp<Classifier, Operation> opCall2 =
(OperationCallExp<Classifier, Operation>) letExp.getIn();
assertEquals("size", opCall2.getReferredOperation().getName());
}
public void test_equality_relational_179249() {
helper.setContext(class1);
try {
// this should parse, because "1 < 2" has higher precedence.
// If it hadn't, then we would fail to parse because
// Integer has no "< Boolean" operation (we would parse this
// expression as "1 < (2 = true)"
helper.createInvariant("1 < 2 = true");
} catch (Exception e) {
fail("Failed to parse: " + e.getLocalizedMessage());
}
}
public void test_or_and_precedence() throws ParserException {
ParsingOptions.setOption(helper.getEnvironment(), ProblemOption.ELEMENT_NAME_QUOTE_ESCAPE, ProblemHandler.Severity.OK);
helper.setContext(class1);
assertTrueWithoutWarning("(true or (false and false)) = true");
assertTrueWithoutWarning("(true or false.\"and\"(false)) = true");
assertTrueWithoutWarning("((true or false) and false) = false");
assertTrueWithoutWarning("(true or false and false) = true");
ParsingOptions.setOption(helper.getEnvironment(), ParsingOptions.WARN_OF_XOR_OR_AND_PRECEDENCE_CHANGE, true);
assertTrueWithoutWarning("(true or (false and false)) = true");
assertTrueWithoutWarning("(true or false.\"and\"(false)) = true");
assertTrueWithoutWarning("((true or false) and false) = false");
//1.x assertTrue(check(helper, class1, "(true or false and false) = false"));
assertTrueWithWarning("(true or false and false) = true", OCLMessages.XorOrAndPrecedence_WARNING);
}
public void test_xor_or_precedence() throws ParserException {
ParsingOptions.setOption(helper.getEnvironment(), ProblemOption.ELEMENT_NAME_QUOTE_ESCAPE, ProblemHandler.Severity.OK);
helper.setContext(class1);
assertTrueWithoutWarning("(true xor (false or false)) = true");
assertTrueWithoutWarning("(true xor false.\"or\"(false)) = true");
assertTrueWithoutWarning("((true xor false) or true) = true");
assertTrueWithoutWarning("(true xor false or true) = false");
ParsingOptions.setOption(helper.getEnvironment(), ParsingOptions.WARN_OF_XOR_OR_AND_PRECEDENCE_CHANGE, true);
assertTrueWithoutWarning("(true xor (false or false)) = true");
assertTrueWithoutWarning("(true xor false.\"or\"(false)) = true");
assertTrueWithoutWarning("((true xor false) or true) = true");
//1.x assertTrue(check(helper, class1, "(true xor false or true) = true"));
assertTrueWithWarning("(true xor false or true) = false", OCLMessages.XorOrAndPrecedence_WARNING);
}
protected void assertTrueWithWarning(String expression, String warning)throws ParserException {
helper.createInvariant(expression);
try {
OCLUtil.checkForErrorsOrWarnings(helper.getEnvironment());
fail("Missing warning: " + warning);
} catch (SemanticException e) {
System.out.println("Got expected warning: " + e.getLocalizedMessage());
assertEquals(warning, e.getMessage());
}
}
protected void assertTrueWithoutWarning(String expression)throws ParserException {
helper.createInvariant(expression);
OCLUtil.checkForErrorsOrWarnings(helper.getEnvironment());
}
//
// Framework methods
//
@Override
protected void setUp() {
super.setUp();
// create a little test model for a Smalltalk-like collection class that
// defines operations corresponding to OCL iterators
res = new ResourceImpl(URI.createURI("foo://uml"));
pkg = UMLFactory.eINSTANCE.createPackage();
pkg.setName("testpkg");
res.getContents().add(pkg);
class1 = pkg.createOwnedClass("Class1", false);
class1.createOwnedAttribute("base_Property", getMetaclass("Property"));
}
}