/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.cdk.templatecompiler.parser.el.test;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.richfaces.cdk.templatecompiler.statements.HelperMethod.EMPTINESS_CHECK;
import static org.richfaces.cdk.templatecompiler.statements.HelperMethod.EQUALS_CHECK;
import static org.richfaces.cdk.templatecompiler.statements.HelperMethod.TO_BOOLEAN_CONVERSION;
import static org.richfaces.cdk.templatecompiler.statements.HelperMethod.TO_STRING_CONVERSION;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.richfaces.cdk.As;
import org.richfaces.cdk.CdkClassLoader;
import org.richfaces.cdk.CdkTestBase;
import org.richfaces.cdk.CdkTestRunner;
import org.richfaces.cdk.Logger;
import org.richfaces.cdk.Mock;
import org.richfaces.cdk.MockController;
import org.richfaces.cdk.templatecompiler.ELParser;
import org.richfaces.cdk.templatecompiler.builder.model.Variables;
import org.richfaces.cdk.templatecompiler.el.ELParserImpl;
import org.richfaces.cdk.templatecompiler.el.ParsingException;
import org.richfaces.cdk.templatecompiler.el.types.ELType;
import org.richfaces.cdk.templatecompiler.el.types.TypesFactory;
import org.richfaces.cdk.templatecompiler.el.types.TypesFactoryImpl;
import org.richfaces.cdk.templatecompiler.statements.HelperMethod;
import org.richfaces.cdk.templatecompiler.statements.TypedTemplateStatement;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Binder;
import com.google.inject.Inject;
@RunWith(CdkTestRunner.class)
public class ELParserTest extends CdkTestBase {
@Inject
@As(ELParserImpl.class)
private ELParser parser;
@Mock
private Logger log;
@Inject
@As(TypesFactoryImpl.class)
private TypesFactory typesFactory;
@Inject
private MockController controller;
@Override
public void configure(Binder binder) {
super.configure(binder);
binder.bind(CdkClassLoader.class).toInstance(createClassLoader());
}
private TypedTemplateStatement parseExpression(String expression) throws ParsingException {
return parseExpression(expression, Object.class);
}
private TypedTemplateStatement parseExpression(String expression, String expected, HelperMethod... requiredMethods)
throws ParsingException {
return parseExpression(expression, Object.class, expected, requiredMethods);
}
private TypedTemplateStatement parseExpression(String expression, String expected, Class<?> expectedType,
HelperMethod... requiredMethods) throws ParsingException {
return parseExpression(expression, Object.class, expected, expectedType, requiredMethods);
}
private TypedTemplateStatement parseExpression(String expression, Class<?> returnType, String expected,
Class<?> expectedType, HelperMethod... requiredMethods) throws ParsingException {
TypedTemplateStatement statement = parseExpression(expression, returnType, expected, requiredMethods);
assertEquals(expectedType.getName(), statement.getType().getRawName());
return statement;
}
private TypedTemplateStatement parseExpression(String expression, Class<?> returnType, String expected,
HelperMethod... requiredMethods) throws ParsingException {
controller.replay();
TypedTemplateStatement parseExpression = parseExpression(expression, returnType);
controller.verify();
assertEquals(expected, parseExpression.getCode());
for (HelperMethod helperMethod : requiredMethods) {
assertTrue("Expect helper method " + helperMethod.getName(),
Iterables.contains(parseExpression.getRequiredMethods(), helperMethod));
}
for (HelperMethod helperMethod : parseExpression.getRequiredMethods()) {
assertTrue("Unexpected helper method " + helperMethod.getName(),
Iterables.contains(ImmutableSet.copyOf(requiredMethods), helperMethod));
}
return parseExpression;
}
private TypedTemplateStatement parseExpression(String expression, Class<?> returnType) throws ParsingException {
final Map<String, ELType> contextMap = new HashMap<String, ELType>();
Variables variables = new Variables() {
@Override
public ELType getVariable(String name) throws ParsingException {
return contextMap.get(name);
}
@Override
public boolean isDefined(String name) throws ParsingException {
return contextMap.containsKey(name);
}
@Override
public ELType setVariable(String name, ELType type) throws ParsingException {
return contextMap.put(name, type);
}
};
contextMap.put("action", this.getType(org.richfaces.cdk.templatecompiler.parser.el.test.Bean.class));
contextMap.put("clientId", this.getType(String.class));
contextMap.put("test", this.getType(boolean.class));
contextMap.put("otherTest", this.getType(boolean.class));
contextMap.put("this", this.getType(Object.class));
contextMap.put("super", this.getType(Object.class));
contextMap.put("objectVar", this.getType(Object.class));
return parser.parse(expression, variables, this.getType(returnType));
}
private ELType getType(Class<?> returnType) {
return typesFactory.getType(returnType);
}
@Test
public void testAnd() throws Exception {
parseExpression("#{test and otherTest}", "(test && otherTest)");
}
@Test
public void testAnd1() throws Exception {
parseExpression("#{otherTest && test}", "(otherTest && test)");
// assertEquals(Boolean.TYPE, visitor.getExpressionType().getRawType());
}
@Test
public void testAnd2() throws Exception {
parseExpression("#{action and otherTest}", "(convertToBoolean(action) && otherTest)", TO_BOOLEAN_CONVERSION);
}
@Test
public void testAnd3() throws Exception {
parseExpression("#{test && action}", "(test && convertToBoolean(action))", TO_BOOLEAN_CONVERSION);
// assertEquals(Boolean.TYPE, visitor.getExpressionType().getRawType());
}
@Test
public void testBooleanReturnType() throws Exception {
parseExpression("#{clientId}", Boolean.TYPE, "convertToBoolean(clientId)", Boolean.TYPE, TO_BOOLEAN_CONVERSION);
}
@Test
public void testBooleanReturnType1() throws Exception {
parseExpression("#{test}", Boolean.TYPE, "test", Boolean.TYPE);
}
@Test
public void testChoice() throws Exception {
parseExpression("#{test ? 2 : 3}", Object.class, "(test ? 2 : 3)", Integer.TYPE);
}
@Test
public void testChoice1() throws Exception {
parseExpression("#{test ? null : 'string'}", Object.class, "(test ? null : \"string\")", String.class);
}
@Test
public void testChoice2() throws Exception {
parseExpression("#{action ? null : 'string'}", Object.class, "(convertToBoolean(action) ? null : \"string\")",
TO_BOOLEAN_CONVERSION);
}
@Test
public void testDiv() throws Exception {
parseExpression("#{1/2}", "(1 / 2)", Integer.TYPE);
}
@Test
public void testEmpty() throws Exception {
parseExpression("#{empty action.array}", "isEmpty(action.getArray())", Boolean.TYPE, EMPTINESS_CHECK);
}
@Test
public void testEmptyString() throws Exception {
parseExpression("", "\"\"", String.class);
}
@Test
public void testEquals() throws Exception {
parseExpression("#{1 eq 2}", "(1 == 2)", Boolean.TYPE);
}
@Test
public void testEquals1() throws Exception {
parseExpression("#{3 == 2}", "(3 == 2)", Boolean.TYPE);
}
@Test
public void testEquals2() throws Exception {
parseExpression("#{action == 2}", "isEqual(action,2)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testEquals3() throws Exception {
parseExpression("#{2 eq action}", "isEqual(2,action)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testEquals4() throws Exception {
parseExpression("#{action == clientId}", "isEqual(action,clientId)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testEquals5() throws Exception {
parseExpression("#{action eq clientId}", "isEqual(action,clientId)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testEquals6() throws Exception {
parseExpression("#{action eq null}", "(action == null)", Boolean.TYPE);
}
@Test
public void testEquals7() throws Exception {
parseExpression("#{2 == null}", "isEqual(2,null)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testFalse() throws Exception {
parseExpression("#{false}", "false", Boolean.TYPE);
}
@Test
public void testFloat() throws Exception {
parseExpression("#{5.0}", "Double.valueOf(5.0)", Double.TYPE);
}
@Test
public void testFloat1() throws Exception {
parseExpression("#{5.012e+34}", "Double.valueOf(5.012e+34)", Double.TYPE);
}
@Test
public void testFunction() throws Exception {
parseExpression("#{super:getType()}", "super.getType()");
}
@Test
public void testGreatThen() throws Exception {
parseExpression("#{1 gt 2}", "(1 > 2)", Boolean.TYPE);
}
@Test
public void testGreatThen1() throws Exception {
parseExpression("#{3 > 2}", "(3 > 2)", Boolean.TYPE);
}
@Test
public void testGreatThenEquals() throws Exception {
parseExpression("#{1 ge 2}", "(1 >= 2)", Boolean.TYPE);
}
@Test
public void testGreatThenEquals1() throws Exception {
parseExpression("#{3 >= 2}", "(3 >= 2)", Boolean.TYPE);
}
@Test
public void testIdentifier() throws Exception {
parseExpression("#{clientId}", "clientId", String.class);
}
@Test
public void testInteger() throws Exception {
parseExpression("#{152}", "152", Integer.TYPE);
}
@Test
public void testLessThen() throws Exception {
parseExpression("#{1 lt 2}", "(1 < 2)", Boolean.TYPE);
}
@Test
public void testLessThen1() throws Exception {
parseExpression("#{3 < 2}", "(3 < 2)", Boolean.TYPE);
}
@Test
public void testLessThenEquals() throws Exception {
parseExpression("#{1 le 2}", "(1 <= 2)", Boolean.TYPE);
}
@Test
public void testLessThenEquals1() throws Exception {
parseExpression("#{3 <= 2}", "(3 <= 2)", Boolean.TYPE);
}
@Test
public void testLiteral() throws Exception {
parseExpression("clientId", "\"clientId\"", String.class);
}
@Test
public void testLiteralWithDeferred() throws Exception {
parseExpression("#{1}#{2}", "convertToString(1) + convertToString(2)", String.class, HelperMethod.TO_STRING_CONVERSION);
}
@Test
public void testLiteralWithDeferred1() throws Exception {
parseExpression("abs #{getType()}", "\"abs \" + convertToString(this.getType())", String.class, TO_STRING_CONVERSION);
}
@Test
public void testLiteralWithDeferred2() throws Exception {
parseExpression("#{getType()} abs ", "convertToString(this.getType()) + \" abs \"", String.class, TO_STRING_CONVERSION);
}
@Test
public void testMethod() throws Exception {
parseExpression("#{action.readOnly}", "action.isReadOnly()", Boolean.TYPE);
}
@Test
public void testMethodReturnArray() throws Exception {
parseExpression("#{action.array}", "action.getArray()"/* , UIComponent[].class */);
}
@Test
public void testMethodReturnArrayElement() throws Exception {
parseExpression("#{action.array[0]}", "action.getArray()[0]", UIComponent.class);
}
@Test
public void testMethodReturnList() throws Exception {
TypedTemplateStatement statement = parseExpression("#{action.components}", "action.getComponents()", List.class);
ELType variableType = statement.getType();
assertEquals(List.class.getName(), variableType.getRawName());
assertEquals(UIComponent.class.getName(), variableType.getContainerType().getRawName());
}
@Test
public void testMethodReturnListElement() throws Exception {
parseExpression("#{action.components[0]}", "action.getComponents().get(0)", UIComponent.class);
}
@Test
public void testMethodReturnListElement2() throws Exception {
parseExpression("#{action.components[0].rendered}", "action.getComponents().get(0).isRendered()", Boolean.TYPE);
}
// @Test
// public void testMethodReturnMapElement1() throws Exception {
// assertEquals("action.getFacets().get(\"header\")", resolveExpression("#{action.facets.header}"));
// }
@Test
public void testMethodReturnMap() throws Exception {
TypedTemplateStatement statement = parseExpression("#{action.facets}", "action.getFacets()", Map.class);
ELType variableType = statement.getType();
assertEquals(Map.class.getName(), variableType.getRawName());
assertEquals(UIComponent.class.getName(), variableType.getContainerType().getRawName());
}
@Test
public void testMethodReturnMap1() throws Exception {
parseExpression("#{action.rawMap}", "action.getRawMap()", Map.class);
}
@Test
public void testMethodReturnMapElement() throws Exception {
parseExpression("#{action.getFacet('header')}", "action.getFacet(\"header\")", UIComponent.class);
}
@Test
public void testMethodReturnMapElement1() throws Exception {
parseExpression("#{action.facets['header']}", "action.getFacets().get(\"header\")", UIComponent.class);
}
@Test
public void testMethodReturnMapElement2() throws Exception {
parseExpression("#{action.rawMap['something']}", "action.getRawMap().get(\"something\")", Object.class);
}
@Test
public void testMethodReturnMapElement3() throws Exception {
parseExpression("#{action.facets.toString()}", "action.getFacets().toString()", String.class);
}
@Test
public void testMethodReturnMapElement4() throws Exception {
// assertEquals("action.getFacet(\"header\").isRendered()",
// resolveExpression("#{action.getFacet('header').rendered}"));
parseExpression("#{action.facets['header'].rendered}", "action.getFacets().get(\"header\").isRendered()", Boolean.TYPE);
}
@Test
public void testMethodWithParam() throws Exception {
parseExpression("#{getType(action.array[0].rendered, action.readOnly, true)}",
"this.getType(action.getArray()[0].isRendered(),action.isReadOnly(),true)");
}
@Test
public void testMethodWithParam1() throws Exception {
parseExpression("#{action.count(123)}", "action.count(123)", Integer.class);
}
@Test
public void testMethodWithParam2() throws Exception {
parseExpression("#{action.count(clientId)}", "action.count(clientId)", Object.class);
}
@Test
public void testMinus() throws Exception {
parseExpression("#{1-2}", "(1 - 2)", Integer.TYPE);
}
@Test
public void testMod() throws Exception {
parseExpression("#{1%2}", "(1 % 2)", Integer.TYPE);
}
@Test
public void testMult() throws Exception {
parseExpression("#{1*2}", "(1 * 2)", Integer.TYPE);
}
@Test
public void testNegative() throws Exception {
parseExpression("#{-5}", "-5", Integer.TYPE);
}
@Test
public void testNegativeFloat() throws Exception {
parseExpression("#{-5.0}", "-Double.valueOf(5.0)", Double.TYPE);
}
@Test
public void testNestedMethod() throws Exception {
parseExpression("#{action.testBean2.string}", "action.getTestBean2().getString()", String.class);
}
@Test
public void testNonExistingMethod() throws Exception {
parseExpression("#{action.doSomething(clientId, 123)}", "action.doSomething(clientId,123)", Object.class);
}
@Test
public void testNot() throws Exception {
parseExpression("#{not test}", "(!test)", Boolean.TYPE);
}
@Test
public void testNot1() throws Exception {
parseExpression("#{!otherTest}", "(!otherTest)", Boolean.TYPE);
}
@Test
public void testNot2() throws Exception {
parseExpression("#{!action}", "(!convertToBoolean(action))", Boolean.TYPE, TO_BOOLEAN_CONVERSION);
}
@Test
public void testNotEqual() throws Exception {
parseExpression("#{1 ne 3}", "(1 != 3)", Boolean.TYPE);
}
@Test
public void testNotEqual1() throws Exception {
parseExpression("#{2 != 3}", "(2 != 3)", Boolean.TYPE);
}
@Test
public void testNotEqual2() throws Exception {
parseExpression("#{action != 2}", "!isEqual(action,2)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testNotEqual3() throws Exception {
parseExpression("#{2 ne action}", "!isEqual(2,action)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testNotEqual4() throws Exception {
parseExpression("#{action != clientId}", "!isEqual(action,clientId)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testNotEqual5() throws Exception {
parseExpression("#{action ne clientId}", "!isEqual(action,clientId)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testNotEqual6() throws Exception {
parseExpression("#{action ne null}", "(action != null)", Boolean.TYPE);
}
@Test
public void testNotEqual7() throws Exception {
parseExpression("#{2 != null}", "!isEqual(2,null)", Boolean.TYPE, EQUALS_CHECK);
}
@Test
public void testNull() throws Exception {
TypedTemplateStatement statement = parseExpression("#{null}", "null");
assertTrue(statement.getType().isNullType());
}
@Test
public void testOr() throws Exception {
parseExpression("#{test or otherTest}", "(test || otherTest)", Boolean.TYPE);
}
@Test
public void testOr1() throws Exception {
parseExpression("#{otherTest || test}", "(otherTest || test)", Boolean.TYPE);
}
@Test
public void testOr2() throws Exception {
parseExpression("#{action or otherTest}", "(convertToBoolean(action) || otherTest)", Boolean.TYPE,
TO_BOOLEAN_CONVERSION);
}
@Test
public void testOr3() throws Exception {
parseExpression("#{test || action}", "(test || convertToBoolean(action))", Boolean.TYPE, TO_BOOLEAN_CONVERSION);
}
@Test
public void testPlus() throws Exception {
// TODO: tests involving double values
parseExpression("#{1+2}", "(1 + 2)", Integer.TYPE);
}
@Test
public void testString() throws Exception {
parseExpression("#{\"nabc\"}", "\"nabc\"", String.class);
}
@Test
public void testString1() throws Exception {
parseExpression("#{'nabc'}", "\"nabc\"", String.class);
}
@Test
public void testString2() throws Exception {
parseExpression("#{'\tabc'}", "\"\\tabc\"", String.class);
}
@Test
public void testString3() throws Exception {
parseExpression("#{'/nabc'}", "\"/nabc\"", String.class);
}
@Test
public void testString4() throws Exception {
parseExpression("#{'na\"bc'}", "\"na\\\"bc\"", String.class);
}
@Test
public void testString5() throws Exception {
parseExpression("#{'na\\\\bc'}", "\"na\\\\bc\"", String.class);
}
@Test
public void testStringReturnType() throws Exception {
parseExpression("#{clientId}", String.class, "clientId", String.class);
}
@Test
public void testStringReturnType1() throws Exception {
parseExpression("#{test}", String.class, "convertToString(test)", String.class, TO_STRING_CONVERSION);
}
@Test
public void testThisFunction() throws Exception {
parseExpression("#{getType()}", "this.getType()");
}
@Test
public void testThisFunction1() throws Exception {
parseExpression("#{this.getType()}", "this.getType()");
}
@Test
public void testTrue() throws Exception {
parseExpression("#{true}", "true", Boolean.TYPE);
}
@Test
public void testVariableFunction() throws Exception {
parseExpression("#{objectVar.getType()}", "objectVar.getType()");
}
@Test(/* expected = ParsingException.class */)
public void testWrongExpression() throws Exception {
log.warn((CharSequence) anyObject());
expectLastCall();
parseExpression("#{bean.property}", "bean.getProperty()");
}
@Test
public void testWrongExpression2() throws Exception {
parseExpression("#{action.property}", "action.getProperty()", Object.class);
}
@Test
public void testLiteralExpression() throws Exception {
controller.replay();
TypedTemplateStatement parseExpression = parseExpression("Literal", Object.class);
controller.verify();
assertTrue(parseExpression.isLiteral());
assertEquals("\"Literal\"", parseExpression.getCode());
assertEquals(String.class.getName(), parseExpression.getType().getRawName());
}
@Test
public void testToScriptArgs() throws Exception {
TypedTemplateStatement parseExpression = parseExpression("#{toScriptArgs(clientId, bean)}");
assertTrue(Iterables.contains(parseExpression.getRequiredMethods(), HelperMethod.TO_SCRIPT_ARGS));
assertEquals("toScriptArgs(clientId,bean)", parseExpression.getCode());
}
}