/*******************************************************************************
* Copyright (c) 2005, 2009 committers of openArchitectureWare 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:
* committers of openArchitectureWare - initial API and implementation
*******************************************************************************/
package org.eclipse.xtend.expression.ast;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.internal.xtend.expression.ast.Expression;
import org.eclipse.internal.xtend.xtend.parser.ParseFacade;
import org.eclipse.xtend.expression.EvaluationException;
import org.eclipse.xtend.expression.ExecutionContext;
import org.eclipse.xtend.expression.ExecutionContextImpl;
import org.eclipse.xtend.expression.Type1;
import org.eclipse.xtend.expression.Variable;
import org.eclipse.xtend.type.impl.java.JavaMetaModel;
import org.eclipse.xtend.type.impl.java.beans.JavaBeansStrategy;
/**
* @author Sven Efftinge (http://www.efftinge.de)
* @author Arno Haase
*/
public class EvaluationTest extends TestCase {
private ExecutionContextImpl ec;
@Override
protected void setUp() {
ec = new ExecutionContextImpl();
ec.registerMetaModel (new JavaMetaModel("asdf", new JavaBeansStrategy()));
}
private Object eval (String expression) {
final Object oldResult = evalOld (expression);
//final Object newResult = evalNew (expression);
// checkEquals (oldResult, newResult);
setUp (); // re-init ec
return oldResult;
}
private Object evalOld (String expression) {
final Expression expr = ParseFacade.expression(expression);
return expr.evaluate (ec);
}
// private Object evalNew (String expression) {
// final Map<String, Object> newLocalVars = new HashMap<String, Object> ();
// for (String vn: ec.getVisibleVariables().keySet())
// newLocalVars.put (vn, ec.getVisibleVariables().get(vn).getValue());
//
// final Map<String, Object> newGlobalVars = new HashMap<String, Object> ();
// for (String vn: ec.getGlobalVariables().keySet())
// newGlobalVars.put (vn, ec.getGlobalVariables().get(vn).getValue());
//
// return XtendBackendFacade.evaluateExpression (expression, ec.getMetaModels(), newLocalVars, newGlobalVars);
// }
// be lenient about type equality - the new backend is more consistent at converting types than the old runtime is...
private void checkEquals (Object o1, Object o2) {
if (o1 == null) {
assertTrue (o2 == null);
return;
}
if (o1 instanceof Double && o2 instanceof Double) {
assertEquals ((Double) o1, (Double) o2, .0000001);
return;
}
if (o1 instanceof Number && o2 instanceof Number) {
assertEquals (((Number) o1).longValue(), ((Number) o2).longValue());
return;
}
if (o1 instanceof CharSequence && o2 instanceof CharSequence) {
assertEquals (o1.toString(), o2.toString());
return;
}
assertEquals (o1, o2);
}
private Object eval (String expression, String localVarName, Object localVarValue) {
ec = (ExecutionContextImpl) ec.cloneWithVariable (new Variable (localVarName, localVarValue));
return eval (expression);
}
public final void testSimple() {
final Object result = eval ("true == null");
assertFalse(((Boolean) result).booleanValue());
}
public final void testStaticPropertyCall() {
final Object result = eval ("org::eclipse::xtend::expression::Type1::TYPE1_OBJECT_OBJECT");
assertEquals(Type1.TYPE1_OBJECT_OBJECT, result);
}
@SuppressWarnings("unchecked")
public final void testCollectionLiteral1() {
assertEquals(Arrays.asList("hallo"), eval ("{\"hallo\"}"));
assertEquals(Arrays.asList(new BigInteger("3")), eval ("{3}"));
assertEquals (Arrays.asList("hallo", new BigInteger("3")), eval ("{\"hallo\",3}"));
}
public final void testFeatureCall() {
final Object result = eval ("test", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().getTest(), result);
}
public final void testFeatureCall1() {
final Object result = eval ("this.test", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().getTest(), result);
}
public final void testOperationCall1() {
final Object result = eval ("myOperation()", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().myOperation(), result);
}
public final void testOperationCall2() {
final Object result = eval ("myOperation(\"Test\")", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().myOperation("Test"), result);
}
public final void testOperationCall3() {
final Object result = eval ("this.myOperation()", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().myOperation(), result);
}
public final void testOperationCall4() {
final Object result = eval ("this.myOperation(\"Test\")", ExecutionContext.IMPLICIT_VARIABLE, new AType ());
assertEquals(new AType().myOperation("Test"), result);
}
public final void testArithmetic() {
assertEquals(new BigInteger("11"), eval ("4 * 2 + 3"));
assertEquals(new BigInteger("11"), eval ("3 + 4 * 2"));
assertEquals(new BigInteger("9"), eval ("4 * 2 + 3 / 3"));
assertEquals(new BigInteger("4"), eval ("4 * 2 - (9 / 2)"));
assertEquals(new Double(11), eval ("3 + 4.0 * 2"));
assertEquals(new Double(11), eval ("4.0 * 2 + 3"));
assertEquals(new Double(9), eval ("4 * 2 + 3 / 3.0"));
assertEquals(new BigInteger("2"), eval ("5 / 2"));
assertEquals(new Double(2.5), eval ("5 / 2.0"));
}
public final void testStringConcatenation() {
assertEquals("test34", eval ("\"test\" + 3 + 4"));
}
public final void testNullReference() {
assertEquals(null, eval ("nullRef + \"test\" + 3 + 4", "nullRef", null));
assertNull(eval ("this.unknownMember", "this", null));
}
// public final void testTypeLiteral1() {
// assertEquals (ec.getStringType(), evalOld ("String"));
// assertEquals (StringType.INSTANCE, evalNew ("String"));
//
// assertTrue (evalOld ("String.getProperty('length')") instanceof Property);
// assertTrue (evalNew ("String.getProperty('length')") instanceof org.eclipse.xtend.backend.common.Property);
//
// assertEquals (AType.TEST, eval (getATypeName() + "::TEST"));
// }
// private String getATypeName() {
// return AType.class.getName().replaceAll("\\.", SyntaxConstants.NS_DELIM);
// }
public final void testPath1() {
assertEquals (Arrays.asList("A", "B", "C"), eval ("{'a','b','c'}.toUpperCase()"));
assertEquals(new Long(3), eval ("{'a','b','c'}.size"));
assertEquals (Arrays.asList (1L, 2L, 1L), eval ("{'a','b2','c'}.toUpperCase().length"));
}
public final void testPath4() {
final List<?> result = (List<?>) eval ("{'a,b2,c','a,b,c','a,b,c'}.split(',').length");
assertEquals(9, result.size());
assertEquals(new Long(1), result.get(0));
assertEquals(new Long(2), result.get(1));
assertEquals(new Long(1), result.get(2));
}
public final void testNestedCollExpr() {
final List<Object> list = new ArrayList<Object>();
list.add("123");
list.add("1234");
list.add("12345");
list.add(new Long(3));
list.add(new Long(4));
final String expr = "col.typeSelect(String).forAll (e|col.typeSelect(Integer).exists(a | a == e.length))";
assertEquals(Boolean.FALSE, eval (expr, "col", list));
list.add(new Long(5));
assertEquals(Boolean.TRUE, eval (expr, "col", list));
}
public final void testTypeSelectWithNull() {
assertEquals(new Long(1), eval ("{null, 'test'}.typeSelect(String).size"));
}
public final void testGlobalVar() {
ec = new ExecutionContextImpl (Collections.singletonMap ("horst", new Variable("horst", "TEST")));
assertEquals("TEST", eval ("GLOBALVAR horst"));
}
public final void testLet() {
assertEquals("a,b,c", eval ("let x = {'a,b2,c','a,b,c','1,2,3'} : x.get(1)"));
assertEquals(Arrays.asList("1", "2", "3"), eval ("let x = {} : x.add('1') -> x.add('2') -> x.add('3') -> x"));
}
public final void testCollectShortcut1() {
assertEquals(Arrays.asList("A", "B", "C"), eval ("{'a','b','c'}.toUpperCase()"));
assertEquals(Arrays.asList(1L, 1L, 1L), eval ("{'a','b','c'}.length"));
assertEquals(Collections.emptyList(), eval ("{}.toUpperCase()"));
assertEquals (Collections.emptyList(), eval ("{}.length"));
}
public final void testCollectShortcut5() {
assertEquals ("String", eval ("String.name", ExecutionContext.IMPLICIT_VARIABLE, new ArrayList<Object>()));
}
public final void testConstruction() {
assertEquals(new AType (), eval ("new org::eclipse::xtend::expression::ast::AType"));
try {
eval ("new Unkown");
fail();
} catch (final EvaluationException ee) {
// expected
}
}
public void testSortBy() throws Exception {
assertEquals(Arrays.asList("AA", "BBB", "X"), eval ("{'X','AA','BBB'}.sortBy(e|e)"));
assertEquals(Arrays.asList("X", "AA", "BBB"), eval ("{'X','AA','BBB'}.sortBy(e|e.length)"));
}
public void testIfExpression() throws Exception {
assertEquals(true, eval ("if true then true else 'stuff'"));
assertEquals("stuff", eval ("if false then false else 'stuff'"));
assertEquals("stuff", eval ("if false then false else if true then 'stuff' else null "));
assertEquals(null, eval ("if false then false else if false then 'stuff' "));
}
public void testCollectShortCutWithFeatureCalls() throws Exception {
assertEquals (Arrays.asList ("test"), eval ("x.list.list.strings.toLowerCase()", "x", Collections.singletonList (new TestType ())));
assertEquals (Arrays.asList ("test"), eval ("x.list().list().strings().toLowerCase()", "x", Collections.singletonList (new TestType ())));
assertEquals (Arrays.asList ("test"), eval ("x.list.list().list.strings().toLowerCase()", "x", Collections.singletonList (new TestType ())));
}
public void testCollectOnNull() throws Exception {
assertNull(eval("null.collect(e|e.size)"));
}
public void testEvaluationOrderOfOperands() throws Exception {
ec = (ExecutionContextImpl) ec.cloneWithVariable (new Variable ("x", new Cls()));
checkEquals ("12", evalOld ("x.asString() + x.asString()"));
ec = (ExecutionContextImpl) ec.cloneWithVariable (new Variable ("x", new Cls()));
// checkEquals ("12", evalNew ("x.asString() + x.asString()"));
}
public static class Cls {
int c = 1;
public String asString() {
return ""+c++;
}
}
}