/*******************************************************************************
* Copyright (c) 2005, 2007 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.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import junit.framework.TestCase;
import org.eclipse.internal.xtend.expression.ast.ChainExpression;
import org.eclipse.internal.xtend.expression.ast.Expression;
import org.eclipse.internal.xtend.expression.ast.Identifier;
import org.eclipse.internal.xtend.expression.ast.SwitchExpression;
import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
import org.eclipse.internal.xtend.xtend.ast.ExtensionFile;
import org.eclipse.internal.xtend.xtend.ast.ExtensionImportStatement;
import org.eclipse.internal.xtend.xtend.parser.ParseFacade;
import org.eclipse.xtend.expression.AnalysationIssue;
import org.eclipse.xtend.expression.ExecutionContext;
import org.eclipse.xtend.expression.ExecutionContextImpl;
import org.eclipse.xtend.expression.Resource;
import org.eclipse.xtend.expression.Type1;
import org.eclipse.xtend.expression.Type2;
import org.eclipse.xtend.expression.Variable;
import org.eclipse.xtend.type.impl.java.JavaMetaModel;
import org.eclipse.xtend.type.impl.java.beans.JavaBeansStrategy;
import org.eclipse.xtend.typesystem.Callable;
import org.eclipse.xtend.typesystem.ParameterizedType;
import org.eclipse.xtend.typesystem.Property;
import org.eclipse.xtend.typesystem.Type;
/**
* @author Sven Efftinge (http://www.efftinge.de)
* @author Arno Haase
*/
public class AnalyzationTest extends TestCase {
private Set<AnalysationIssue> issues;
private ExecutionContextImpl ec;
@Override
protected void setUp() throws Exception {
ec = new ExecutionContextImpl();
ec
.registerMetaModel(new JavaMetaModel("asdf",
new JavaBeansStrategy()));
issues = new HashSet<AnalysationIssue>();
}
private Expression parse(final String expression) {
return ParseFacade.expression(expression);
}
private void dumpIssues() {
for (final Iterator<AnalysationIssue> iter = issues.iterator(); iter
.hasNext();) {
final AnalysationIssue element = iter.next();
System.out.println(element.getType().toString() + " - "
+ element.getMessage());
}
}
public final void testEquals() {
final Expression expr = parse("true == null");
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getBooleanType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testStaticPropertyCall() {
final Expression expr = parse("org::eclipse::xtend::expression::Type1::TYPE1_OBJECT_OBJECT");
final Type result = expr.analyze(ec, issues);
assertTrue(issues.toString(), issues.isEmpty());
assertNotNull("Static property not resolved. ", result);
dumpIssues();
assertEquals(ec.getStringType(), result);
}
public final void testCollectionLiteral1() {
final Expression expr = parse("{\"hallo\"}");
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getListType(ec.getStringType()), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testCollectionLiteral3() {
final Expression expr = parse("{3}");
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getListType(ec.getIntegerType()), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testCollectionLiteral2() {
final Expression expr = parse("{\"hallo\",3}");
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getListType(ec.getObjectType()), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testFeatureCall() {
final Expression expr = parse("test");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertTrue(issues.toString(), issues.isEmpty());
assertEquals(ec.getStringType(), result);
}
public final void testFeatureCall1() {
final Expression expr = parse("this.test");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getStringType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testOperationCall1() {
final Expression expr = parse("myOperation()");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getStringType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testOperationCall2() {
final Expression expr = parse("myOperation(\"Test\")");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getIntegerType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testOperationCall3() {
final Expression expr = parse("this.myOperation()");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getStringType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testOperationCall4() {
final Expression expr = parse("this.myOperation(\"Test\")");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(ec.getIntegerType(), result);
assertTrue(issues.toString(), issues.isEmpty());
}
public final void testSwitchExpr() {
final SwitchExpression expr = (SwitchExpression) parse("switch (3) { case \"Test\" : true default : false }");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(1, issues.size());
assertEquals(ec.getBooleanType(), result);
}
public final void testSwitchExpr1() {
final SwitchExpression expr = (SwitchExpression) parse("switch (\"Horst\") { case \"Test\" : true default : 3 }");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getObjectType(), result);
}
public final void testSwitchExpr2() {
final SwitchExpression expr = (SwitchExpression) parse("switch { case \"Test\"==null : true default : false }");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getBooleanType(), result);
}
public final void testChainExpr() {
final ChainExpression expr = (ChainExpression) parse("switch { case \"Test\"==null : true default : false } -> 3");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getIntegerType(), result);
}
public final void testChainExpr1() {
final ChainExpression expr = (ChainExpression) parse("true -> List -> 3 -> \"Test\"");
ec = (ExecutionContextImpl) ec.cloneWithVariable(new Variable(
ExecutionContext.IMPLICIT_VARIABLE, ec
.getTypeForName(getATypeName())));
final Type result = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getStringType(), result);
}
public final void testTypeLiteral1() {
assertEquals(ec.getTypeType(), parse("String").analyze(ec,
new HashSet<AnalysationIssue>()));
}
public final void testTypeLiteral2() {
final Expression e = parse("String.getOperation('length',(List[xpand2::Type]){})");
assertEquals(ec.getOperationType(), e.analyze(ec,
new HashSet<AnalysationIssue>()));
}
public final void testTypeLiteral3() {
final Expression e = parse(getATypeName() + "::TEST");
assertEquals(ec.getStringType(), e.analyze(ec,
new HashSet<AnalysationIssue>()));
}
private String getATypeName() {
return AType.class.getName()
.replaceAll("\\.", SyntaxConstants.NS_DELIM);
}
public final void testSelect() {
final Expression expr = parse("String.allProperties.select(element.name=='length').toList().get(0)");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getPropertyType(), t);
}
public final void testTypeSelect() {
final Expression expr = parse("{3.4,3}.typeSelect(Integer)");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getIntegerType()), t);
}
public final void testPath1() {
final Expression expr = parse("{'a','b','c'}.toUpperCase()");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getStringType()), t);
}
public final void testPath2() {
final Expression expr = parse("{'a','b','c'}.size");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getIntegerType(), t);
}
public final void testPath3() {
final Expression expr = parse("{'a','b','c'}.toUpperCase().length");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getIntegerType()), t);
}
public final void testPath4() {
final Expression expr = parse("{'a,b,c','a,b,c','a,b,c'}.split(',').length");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getIntegerType()), t);
}
public final void testImplies() {
final Expression expr = parse("true implies false");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getBooleanType(), t);
}
public final void testImplies1() {
final Expression expr = parse("true implies null");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(1, issues.size());
assertEquals(ec.getBooleanType(), t);
}
public final void testLet1() {
final Expression expr = parse("let x = true : x");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getBooleanType(), t);
}
public final void testLet2() {
final Expression expr = parse("let x = true : 'test'+x");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getStringType(), t);
}
public final void testLet3() {
final Expression expr = parse("let x = stuff : true");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(1, issues.size());
assertNull(t);
}
public final void testCast1() {
final Expression expr = parse("(List[String]) {}");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getStringType()), t);
}
public final void testCast2() {
final Expression expr = parse("(Collection[String]) {}");
final Type t = expr.analyze(ec, issues);
dumpIssues();
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getStringType()), t);
}
public final void testConstruction() {
Expression expr = parse("new String");
Type t = expr.analyze(ec, issues);
assertEquals(0, issues.size());
assertEquals(ec.getStringType(), t);
expr = parse("new Unknown");
t = expr.analyze(ec, issues);
assertEquals(1, issues.size());
assertNull(t);
}
public void testSelectFirst() throws Exception {
Expression expr = parse("{'test','holla'}.selectFirst(e|e=='honk')");
Type t = expr.analyze(ec, issues);
assertEquals(0, issues.size());
assertEquals(ec.getStringType(), t);
}
public void testSortBy() throws Exception {
Expression expr = parse("{'test','holla'}.sortBy(e|e)");
Type t = expr.analyze(ec, issues);
assertEquals(0, issues.size());
assertEquals(ec.getListType(ec.getStringType()), t);
}
/**
* Import of an non-existent extension must lead to an error
*/
@SuppressWarnings("unchecked")
public void testBug174611() throws Exception {
// create the lists to initialize an ExtensionFile instance
// create an erraneous AbstractExtension Import
List<ExtensionImportStatement> importStatements = new ArrayList<ExtensionImportStatement>();
importStatements.add(new ExtensionImportStatement(new Identifier(
"nonsense_import"), false));
ExtensionFile extensionFile = new ExtensionFile(Collections.EMPTY_LIST,
importStatements, Collections.EMPTY_LIST,
Collections.EMPTY_LIST, Collections.EMPTY_LIST);
extensionFile.analyze(ec, issues);
assertEquals(1, issues.size());
}
public void testCollectShortCutWithFeatureCalls() throws Exception {
Expression e = parse("x.list.list.strings.toLowerCase()");
TestMetaModel mm = new TestMetaModel();
ec.registerMetaModel(mm);
ExecutionContext ctx = ec.cloneWithVariable(new Variable("x",
ec.getCollectionType(mm.singleType)));
Type rt = e.analyze(ctx, issues);
assertTrue(issues.toString(), issues.isEmpty());
assertTrue(rt instanceof ParameterizedType);
assertEquals(ec.getStringType(),
((ParameterizedType) rt).getInnerType());
}
public void testCollectShortCutWithOperationCalls() throws Exception {
Expression e = parse("x.list().list().strings().toLowerCase()");
TestMetaModel mm = new TestMetaModel();
ec.registerMetaModel(mm);
ExecutionContext ctx = ec.cloneWithVariable(new Variable("x",
ec.getCollectionType(mm.singleType)));
Type rt = e.analyze(ctx, issues);
assertTrue(issues.toString(), issues.isEmpty());
assertTrue(rt instanceof ParameterizedType);
assertEquals(ec.getStringType(),
((ParameterizedType) rt).getInnerType());
}
public void testCollectShortCutWithExtensionCalls() throws Exception {
Expression e = parse("x.listExtension().listExtension().strings().toLowerCase()");
final TestMetaModel mm = new TestMetaModel();
ec = new ExecutionContextImpl();
ec.registerMetaModel(mm);
ec = (ExecutionContextImpl) ec.cloneWithResource(new Resource(){
public String getFullyQualifiedName() {
return null;
}
public String[] getImportedExtensions() {
return new String[]{"org::eclipse::xtend::expression::ast::TestExtensions"};
}
public String[] getImportedNamespaces() {
return null;
}
public void setFullyQualifiedName(String fqn) {
}});
ExecutionContext ctx = ec.cloneWithVariable(new Variable("x",
ec.getCollectionType(mm.singleType)));
Type rt = e.analyze(ctx, issues);
System.out.println(issues);
assertTrue(issues.toString(), issues.isEmpty());
assertTrue(rt instanceof ParameterizedType);
assertEquals(ec.getStringType(),
((ParameterizedType) rt).getInnerType());
}
public void testCollectShortCutWithMixedCalls() throws Exception {
Expression e = parse("x.list.list().list.strings().toLowerCase()");
TestMetaModel mm = new TestMetaModel();
ec.registerMetaModel(mm);
ExecutionContext ctx = ec.cloneWithVariable(new Variable("x",
ec.getCollectionType(mm.singleType)));
Type rt = e.analyze(ctx, issues);
assertTrue(issues.toString(), issues.isEmpty());
assertTrue(rt instanceof ParameterizedType);
assertEquals(ec.getStringType(),
((ParameterizedType) rt).getInnerType());
}
public void testGetAllFeatures() throws Exception {
Type1 type2 = new Type2();
Type type = ec.getType(type2);
Set<? extends Callable> allFeatures = type.getAllFeatures();
boolean matched =false;
for (Callable callable : allFeatures) {
if (callable instanceof Property) {
Property p = (Property) callable;
if (p.getName().equals("test")) {
assertEquals(type,p.getOwner());
matched = true;
}
}
}
assertTrue("no property 'test' found",matched);
}
}