@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2020 the original author or authors .
* Copyright 2002 - 2023 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 .
@ -18,6 +18,8 @@ package org.springframework.expression.spel.standard;
@@ -18,6 +18,8 @@ package org.springframework.expression.spel.standard;
import java.util.function.Consumer ;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable ;
import org.assertj.core.api.ThrowableAssertAlternative ;
import org.junit.jupiter.api.Test ;
import org.springframework.expression.EvaluationContext ;
@ -31,16 +33,28 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -31,16 +33,28 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType ;
import static org.springframework.expression.spel.SpelMessage.MISSING_CONSTRUCTOR_ARGS ;
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING ;
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_QUOTED_STRING ;
import static org.springframework.expression.spel.SpelMessage.NOT_AN_INTEGER ;
import static org.springframework.expression.spel.SpelMessage.NOT_A_LONG ;
import static org.springframework.expression.spel.SpelMessage.REAL_CANNOT_BE_LONG ;
import static org.springframework.expression.spel.SpelMessage.RUN_OUT_OF_ARGUMENTS ;
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_DATA_AFTER_DOT ;
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_ESCAPE_CHAR ;
/ * *
* @author Andy Clement
* @author Juergen Hoeller
* @author Sam Brannen
* /
class SpelParserTests {
private final SpelExpressionParser parser = new SpelExpressionParser ( ) ;
@Test
void theMostBasic ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2" ) ;
assertThat ( expr ) . isNotNull ( ) ;
assertThat ( expr . getAST ( ) ) . isNotNull ( ) ;
@ -51,7 +65,6 @@ class SpelParserTests {
@@ -51,7 +65,6 @@ class SpelParserTests {
@Test
void valueType ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
EvaluationContext ctx = new StandardEvaluationContext ( ) ;
Class < ? > c = parser . parseRaw ( "2" ) . getValueType ( ) ;
assertThat ( c ) . isEqualTo ( Integer . class ) ;
@ -67,7 +80,6 @@ class SpelParserTests {
@@ -67,7 +80,6 @@ class SpelParserTests {
@Test
void whitespace ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2 + 3" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 5 ) ;
expr = parser . parseRaw ( "2 + 3" ) ;
@ -80,7 +92,6 @@ class SpelParserTests {
@@ -80,7 +92,6 @@ class SpelParserTests {
@Test
void arithmeticPlus1 ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2+2" ) ;
assertThat ( expr ) . isNotNull ( ) ;
assertThat ( expr . getAST ( ) ) . isNotNull ( ) ;
@ -89,14 +100,12 @@ class SpelParserTests {
@@ -89,14 +100,12 @@ class SpelParserTests {
@Test
void arithmeticPlus2 ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "37+41" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 78 ) ;
}
@Test
void arithmeticMultiply1 ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2*3" ) ;
assertThat ( expr ) . isNotNull ( ) ;
assertThat ( expr . getAST ( ) ) . isNotNull ( ) ;
@ -105,162 +114,120 @@ class SpelParserTests {
@@ -105,162 +114,120 @@ class SpelParserTests {
@Test
void arithmeticPrecedence1 ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2*3+5" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 11 ) ;
}
@Test
void generalExpressions ( ) {
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "new String" ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . MISSING_CONSTRUCTOR_ARGS , 10 ) ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "new String(3," ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . RUN_OUT_OF_ARGUMENTS , 10 ) ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "new String(3" ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . RUN_OUT_OF_ARGUMENTS , 10 ) ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "new String(" ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . RUN_OUT_OF_ARGUMENTS , 10 ) ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "\"abc" ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . NON_TERMINATING_DOUBLE_QUOTED_STRING , 0 ) ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
parser . parseRaw ( "'abc" ) ;
} )
. satisfies ( parseExceptionRequirements ( SpelMessage . NON_TERMINATING_QUOTED_STRING , 0 ) ) ;
}
private < E extends SpelParseException > Consumer < E > parseExceptionRequirements (
SpelMessage expectedMessage , int expectedPosition ) {
return ex - > {
assertThat ( ex . getMessageCode ( ) ) . isEqualTo ( expectedMessage ) ;
assertThat ( ex . getPosition ( ) ) . isEqualTo ( expectedPosition ) ;
assertThat ( ex . getMessage ( ) ) . contains ( ex . getExpressionString ( ) ) ;
} ;
void parseExceptions ( ) {
assertParseException ( ( ) - > parser . parseRaw ( "new String" ) , MISSING_CONSTRUCTOR_ARGS , 10 ) ;
assertParseException ( ( ) - > parser . parseRaw ( "new String(3," ) , RUN_OUT_OF_ARGUMENTS , 10 ) ;
assertParseException ( ( ) - > parser . parseRaw ( "new String(3" ) , RUN_OUT_OF_ARGUMENTS , 10 ) ;
assertParseException ( ( ) - > parser . parseRaw ( "new String(" ) , RUN_OUT_OF_ARGUMENTS , 10 ) ;
assertParseException ( ( ) - > parser . parseRaw ( "\"abc" ) , NON_TERMINATING_DOUBLE_QUOTED_STRING , 0 ) ;
assertParseException ( ( ) - > parser . parseRaw ( "'abc" ) , NON_TERMINATING_QUOTED_STRING , 0 ) ;
}
@Test
void arithmeticPrecedence2 ( ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( "2+3*5" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 17 ) ;
}
@Test
void arithmeticPrecedence3 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "3+10/2" ) ;
SpelExpression expr = parser . parseRaw ( "3+10/2" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 8 ) ;
}
@Test
void arithmeticPrecedence4 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "10/2+3" ) ;
SpelExpression expr = parser . parseRaw ( "10/2+3" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 8 ) ;
}
@Test
void arithmeticPrecedence5 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "(4+10)/2" ) ;
SpelExpression expr = parser . parseRaw ( "(4+10)/2" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 7 ) ;
}
@Test
void arithmeticPrecedence6 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "(3+2)*2" ) ;
SpelExpression expr = parser . parseRaw ( "(3+2)*2" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( 10 ) ;
}
@Test
void booleanOperators ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "false and false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "true and (true or false)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "true and true or false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "!true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "!(false or true)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
SpelExpression expr = parser . parseRaw ( "true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "false and false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "true and (true or false)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "true and true or false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "!true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "!(false or true)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
}
@Test
void booleanOperators_symbolic_spr9614 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "false && false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "true && (true || false)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "true && true || false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . TRUE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "!true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "!(false || true)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isEqualTo ( Boolean . FALSE ) ;
SpelExpression expr = parser . parseRaw ( "true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "false && false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "true && (true || false)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "true && true || false" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isTrue ( ) ;
expr = parser . parseRaw ( "!true" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
expr = parser . parseRaw ( "!(false || true)" ) ;
assertThat ( expr . getValue ( Boolean . class ) ) . isFalse ( ) ;
}
@Test
void stringLiterals ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "'howdy'" ) ;
SpelExpression expr = parser . parseRaw ( "'howdy'" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( "howdy" ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "'hello '' world'" ) ;
expr = parser . parseRaw ( "'hello '' world'" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( "hello ' world" ) ;
}
@Test
void stringLiterals2 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "'howdy'.substring(0,2)" ) ;
SpelExpression expr = parser . parseRaw ( "'howdy'.substring(0,2)" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( "ho" ) ;
}
@Test
void testStringLiterals_DoubleQuotes_spr9620 ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "\"double quote: \"\".\"" ) ;
SpelExpression expr = parser . parseRaw ( "\"double quote: \"\".\"" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( "double quote: \"." ) ;
expr = new S pelExpressionP arser( ) . parseRaw ( "\"hello \"\" world\"" ) ;
expr = parser . parseRaw ( "\"hello \"\" world\"" ) ;
assertThat ( expr . getValue ( ) ) . isEqualTo ( "hello \" world" ) ;
}
@Test
void testStringLiterals_DoubleQuotes_spr9620_2 ( ) {
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - >
new SpelExpressionParser ( ) . parseRaw ( "\"double quote: \\\"\\\".\"" ) )
assertParseExceptionThrownBy ( ( ) - > parser . parseRaw ( "\"double quote: \\\"\\\".\"" ) )
. satisfies ( ex - > {
assertThat ( ex . getPosition ( ) ) . isEqualTo ( 17 ) ;
assertThat ( ex . getMessageCode ( ) ) . isEqualTo ( SpelMessage . UNEXPECTED_ESCAPE_CHAR ) ;
assertThat ( ex . getMessageCode ( ) ) . isEqualTo ( UNEXPECTED_ESCAPE_CHAR ) ;
} ) ;
}
@Test
void positionalInformation ( ) {
SpelExpression expr = new S pelExpressionP arser( ) . parseRaw ( "true and true or false" ) ;
SpelExpression expr = parser . parseRaw ( "true and true or false" ) ;
SpelNode rootAst = expr . getAST ( ) ;
OpOr operatorOr = ( OpOr ) rootAst ;
OpAnd operatorAnd = ( OpAnd ) operatorOr . getLeftOperand ( ) ;
@ -355,10 +322,10 @@ class SpelParserTests {
@@ -355,10 +322,10 @@ class SpelParserTests {
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 ) ;
checkNumberError ( "0x" , NOT_AN_INTEGER ) ;
checkNumberError ( "0xL" , NOT_A_LONG ) ;
checkNumberError ( ".324" , UNEXPECTED_DATA_AFTER_DOT ) ;
checkNumberError ( "3.4L" , REAL_CANNOT_BE_LONG ) ;
checkNumber ( "3.5f" , 3 . 5f , Float . class ) ;
checkNumber ( "1.2e3" , 1 . 2e3d , Double . class ) ;
@ -371,7 +338,6 @@ class SpelParserTests {
@@ -371,7 +338,6 @@ class SpelParserTests {
private void checkNumber ( String expression , Object value , Class < ? > type ) {
try {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
SpelExpression expr = parser . parseRaw ( expression ) ;
Object exprVal = expr . getValue ( ) ;
assertThat ( exprVal ) . isEqualTo ( value ) ;
@ -383,9 +349,26 @@ class SpelParserTests {
@@ -383,9 +349,26 @@ class SpelParserTests {
}
private void checkNumberError ( String expression , SpelMessage expectedMessage ) {
SpelExpressionParser parser = new SpelExpressionParser ( ) ;
assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( ( ) - > parser . parseRaw ( expression ) )
assertParseExceptionThrownBy ( ( ) - > parser . parseRaw ( expression ) )
. satisfies ( ex - > assertThat ( ex . getMessageCode ( ) ) . isEqualTo ( expectedMessage ) ) ;
}
private static ThrowableAssertAlternative < SpelParseException > assertParseExceptionThrownBy ( ThrowingCallable throwingCallable ) {
return assertThatExceptionOfType ( SpelParseException . class ) . isThrownBy ( throwingCallable ) ;
}
private static void assertParseException ( ThrowingCallable throwingCallable , SpelMessage expectedMessage , int expectedPosition ) {
assertParseExceptionThrownBy ( throwingCallable )
. satisfies ( parseExceptionRequirements ( expectedMessage , expectedPosition ) ) ;
}
private static < E extends SpelParseException > Consumer < E > parseExceptionRequirements (
SpelMessage expectedMessage , int expectedPosition ) {
return ex - > {
assertThat ( ex . getMessageCode ( ) ) . isEqualTo ( expectedMessage ) ;
assertThat ( ex . getPosition ( ) ) . isEqualTo ( expectedPosition ) ;
assertThat ( ex . getMessage ( ) ) . contains ( ex . getExpressionString ( ) ) ;
} ;
}
}