/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.standard;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionException;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.junit.Assert.*;
/**
* @author Andy Clement
* @author Juergen Hoeller
*/
public class SpelParserTests {
@Test
public void theMostBasic() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2");
assertNotNull(expr);
assertNotNull(expr.getAST());
assertEquals(2, expr.getValue());
assertEquals(Integer.class, expr.getValueType());
assertEquals(2, expr.getAST().getValue(null));
}
@Test
public void valueType() {
SpelExpressionParser parser = new SpelExpressionParser();
EvaluationContext ctx = new StandardEvaluationContext();
Class<?> c = parser.parseRaw("2").getValueType();
assertEquals(Integer.class, c);
c = parser.parseRaw("12").getValueType(ctx);
assertEquals(Integer.class, c);
c = parser.parseRaw("null").getValueType();
assertNull(c);
c = parser.parseRaw("null").getValueType(ctx);
assertNull(c);
Object o = parser.parseRaw("null").getValue(ctx, Integer.class);
assertNull(o);
}
@Test
public void whitespace() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2 + 3");
assertEquals(5, expr.getValue());
expr = parser.parseRaw("2 + 3");
assertEquals(5, expr.getValue());
expr = parser.parseRaw("2\n+\t3");
assertEquals(5, expr.getValue());
expr = parser.parseRaw("2\r\n+\t3");
assertEquals(5, expr.getValue());
}
@Test
public void arithmeticPlus1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+2");
assertNotNull(expr);
assertNotNull(expr.getAST());
assertEquals(4, expr.getValue());
}
@Test
public void arithmeticPlus2() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("37+41");
assertEquals(78, expr.getValue());
}
@Test
public void arithmeticMultiply1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3");
assertNotNull(expr);
assertNotNull(expr.getAST());
// printAst(expr.getAST(),0);
assertEquals(6, expr.getValue());
}
@Test
public void arithmeticPrecedence1() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2*3+5");
assertEquals(11, expr.getValue());
}
@Test
public void generalExpressions() {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.MISSING_CONSTRUCTOR_ARGS, spe.getMessageCode());
assertEquals(10, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3,");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS, spe.getMessageCode());
assertEquals(10, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(3");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS, spe.getMessageCode());
assertEquals(10, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("new String(");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS, spe.getMessageCode());
assertEquals(10, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("\"abc");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING, spe.getMessageCode());
assertEquals(0, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw("'abc");
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(SpelMessage.NON_TERMINATING_QUOTED_STRING, spe.getMessageCode());
assertEquals(0, spe.getPosition());
assertTrue(ex.getMessage().contains(ex.getExpressionString()));
}
}
@Test
public void arithmeticPrecedence2() {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw("2+3*5");
assertEquals(17, expr.getValue());
}
@Test
public void arithmeticPrecedence3() {
SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2");
assertEquals(8, expr.getValue());
}
@Test
public void arithmeticPrecedence4() {
SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3");
assertEquals(8, expr.getValue());
}
@Test
public void arithmeticPrecedence5() {
SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2");
assertEquals(7, expr.getValue());
}
@Test
public void arithmeticPrecedence6() {
SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2");
assertEquals(10, expr.getValue());
}
@Test
public void booleanOperators() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false and false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and (true or false)");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true and true or false");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!true");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!(false or true)");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
}
@Test
public void booleanOperators_symbolic_spr9614() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false && false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true && (true || false)");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true && true || false");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!true");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!(false || true)");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
}
@Test
public void stringLiterals() {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");
assertEquals("howdy", expr.getValue());
expr = new SpelExpressionParser().parseRaw("'hello '' world'");
assertEquals("hello ' world", expr.getValue());
}
@Test
public void stringLiterals2() {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)");
assertEquals("ho", expr.getValue());
}
@Test
public void testStringLiterals_DoubleQuotes_spr9620() {
SpelExpression expr = new SpelExpressionParser().parseRaw("\"double quote: \"\".\"");
assertEquals("double quote: \".", expr.getValue());
expr = new SpelExpressionParser().parseRaw("\"hello \"\" world\"");
assertEquals("hello \" world", expr.getValue());
}
@Test
public void testStringLiterals_DoubleQuotes_spr9620_2() {
try {
new SpelExpressionParser().parseRaw("\"double quote: \\\"\\\".\"");
fail("Should have failed");
}
catch (SpelParseException spe) {
assertEquals(17, spe.getPosition());
assertEquals(SpelMessage.UNEXPECTED_ESCAPE_CHAR, spe.getMessageCode());
}
}
@Test
public void positionalInformation() {
SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false");
SpelNode rootAst = expr.getAST();
OpOr operatorOr = (OpOr) rootAst;
OpAnd operatorAnd = (OpAnd) operatorOr.getLeftOperand();
SpelNode rightOrOperand = operatorOr.getRightOperand();
// check position for final 'false'
assertEquals(17, rightOrOperand.getStartPosition());
assertEquals(22, rightOrOperand.getEndPosition());
// check position for first 'true'
assertEquals(0, operatorAnd.getLeftOperand().getStartPosition());
assertEquals(4, operatorAnd.getLeftOperand().getEndPosition());
// check position for second 'true'
assertEquals(9, operatorAnd.getRightOperand().getStartPosition());
assertEquals(13, operatorAnd.getRightOperand().getEndPosition());
// check position for OperatorAnd
assertEquals(5, operatorAnd.getStartPosition());
assertEquals(8, operatorAnd.getEndPosition());
// check position for OperatorOr
assertEquals(14, operatorOr.getStartPosition());
assertEquals(16, operatorOr.getEndPosition());
}
@Test
public void tokenKind() {
TokenKind tk = TokenKind.NOT;
assertFalse(tk.hasPayload());
assertEquals("NOT(!)", tk.toString());
tk = TokenKind.MINUS;
assertFalse(tk.hasPayload());
assertEquals("MINUS(-)", tk.toString());
tk = TokenKind.LITERAL_STRING;
assertEquals("LITERAL_STRING", tk.toString());
assertTrue(tk.hasPayload());
}
@Test
public void token() {
Token token = new Token(TokenKind.NOT, 0, 3);
assertEquals(TokenKind.NOT, token.kind);
assertEquals(0, token.startPos);
assertEquals(3, token.endPos);
assertEquals("[NOT(!)](0,3)", token.toString());
token = new Token(TokenKind.LITERAL_STRING, "abc".toCharArray(), 0, 3);
assertEquals(TokenKind.LITERAL_STRING, token.kind);
assertEquals(0, token.startPos);
assertEquals(3, token.endPos);
assertEquals("[LITERAL_STRING:abc](0,3)", token.toString());
}
@Test
public void exceptions() {
ExpressionException exprEx = new ExpressionException("test");
assertEquals("test", exprEx.getSimpleMessage());
assertEquals("test", exprEx.toDetailedString());
assertEquals("test", exprEx.getMessage());
exprEx = new ExpressionException("wibble", "test");
assertEquals("test", exprEx.getSimpleMessage());
assertEquals("Expression [wibble]: test", exprEx.toDetailedString());
assertEquals("Expression [wibble]: test", exprEx.getMessage());
exprEx = new ExpressionException("wibble", 3, "test");
assertEquals("test", exprEx.getSimpleMessage());
assertEquals("Expression [wibble] @3: test", exprEx.toDetailedString());
assertEquals("Expression [wibble] @3: test", exprEx.getMessage());
}
@Test
public void parseMethodsOnNumbers() {
checkNumber("3.14.toString()", "3.14", String.class);
checkNumber("3.toString()", "3", String.class);
}
@Test
public void numerics() {
checkNumber("2", 2, Integer.class);
checkNumber("22", 22, Integer.class);
checkNumber("+22", 22, Integer.class);
checkNumber("-22", -22, Integer.class);
checkNumber("2L", 2L, Long.class);
checkNumber("22l", 22L, Long.class);
checkNumber("0x1", 1, Integer.class);
checkNumber("0x1L", 1L, Long.class);
checkNumber("0xa", 10, Integer.class);
checkNumber("0xAL", 10L, Long.class);
checkNumberError("0x", SpelMessage.NOT_AN_INTEGER);
checkNumberError("0xL", SpelMessage.NOT_A_LONG);
checkNumberError(".324", SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
checkNumberError("3.4L", SpelMessage.REAL_CANNOT_BE_LONG);
checkNumber("3.5f", 3.5f, Float.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1.2e+3", 1.2e3d, Double.class);
checkNumber("1.2e-3", 1.2e-3d, Double.class);
checkNumber("1.2e3", 1.2e3d, Double.class);
checkNumber("1e+3", 1e3d, Double.class);
}
private void checkNumber(String expression, Object value, Class<?> type) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expr = parser.parseRaw(expression);
Object exprVal = expr.getValue();
assertEquals(value, exprVal);
assertEquals(type, exprVal.getClass());
}
catch (Exception ex) {
fail(ex.getMessage());
}
}
private void checkNumberError(String expression, SpelMessage expectedMessage) {
try {
SpelExpressionParser parser = new SpelExpressionParser();
parser.parseRaw(expression);
fail();
}
catch (ParseException ex) {
assertTrue(ex instanceof SpelParseException);
SpelParseException spe = (SpelParseException) ex;
assertEquals(expectedMessage, spe.getMessageCode());
}
}
}