From ca13b5cbca078002acaee1d095134644a4efded9 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 25 Apr 2023 13:15:28 +0200 Subject: [PATCH] Polish SpelParserTests and TemplateExpressionParsingTests --- .../spel/TemplateExpressionParsingTests.java | 27 ++- .../spel/standard/SpelParserTests.java | 159 ++++++++---------- 2 files changed, 83 insertions(+), 103 deletions(-) diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java index b1c995128883..937b54e5c08a 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java @@ -40,26 +40,26 @@ class TemplateExpressionParsingTests extends AbstractExpressionTests { static final ParserContext DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT = new TemplateParserContext("${", "}"); + private final SpelExpressionParser parser = new SpelExpressionParser(); + + @Test - void parsingSimpleTemplateExpression01() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void parsingSimpleTemplateExpression01() { Expression expr = parser.parseExpression("hello ${'world'}", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertThat(o.toString()).isEqualTo("hello world"); } @Test - void parsingSimpleTemplateExpression02() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void parsingSimpleTemplateExpression02() { Expression expr = parser.parseExpression("hello ${'to'} you", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertThat(o.toString()).isEqualTo("hello to you"); } @Test - void parsingSimpleTemplateExpression03() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void parsingSimpleTemplateExpression03() { Expression expr = parser.parseExpression("The quick ${'brown'} fox jumped over the ${'lazy'} dog", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); @@ -67,8 +67,7 @@ void parsingSimpleTemplateExpression03() throws Exception { } @Test - void parsingSimpleTemplateExpression04() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void parsingSimpleTemplateExpression04() { Expression expr = parser.parseExpression("${'hello'} world", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertThat(o.toString()).isEqualTo("hello world"); @@ -87,8 +86,7 @@ void parsingSimpleTemplateExpression04() throws Exception { } @Test - void compositeStringExpression() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void compositeStringExpression() { Expression ex = parser.parseExpression("hello ${'world'}", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); assertThat(ex.getValue()).isInstanceOf(String.class).isEqualTo("hello world"); assertThat(ex.getValue(String.class)).isInstanceOf(String.class).isEqualTo("hello world"); @@ -127,8 +125,7 @@ void compositeStringExpression() throws Exception { static class Rooty {} @Test - void nestedExpressions() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); + void nestedExpressions() { // treat the nested ${..} as a part of the expression Expression ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); @@ -158,7 +155,7 @@ void nestedExpressions() throws Exception { } @Test - void clashingWithSuffixes() throws Exception { + void clashingWithSuffixes() { // Just wanting to use the prefix or suffix within the template: Expression ex = parser.parseExpression("hello ${3+4} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT); String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); @@ -174,13 +171,13 @@ void clashingWithSuffixes() throws Exception { } @Test - void parsingNormalExpressionThroughTemplateParser() throws Exception { + void parsingNormalExpressionThroughTemplateParser() { Expression expr = parser.parseExpression("1+2+3"); assertThat(expr.getValue()).isEqualTo(6); } @Test - void errorCases() throws Exception { + void errorCases() { assertThatExceptionOfType(ParseException.class).isThrownBy(() -> parser.parseExpression("hello ${'world'", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT)) .satisfies(pex -> { diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java index d043b5d06af8..dfef1d4b85af 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java @@ -18,6 +18,8 @@ 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 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 @@ void theMostBasic() { @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 @@ void valueType() { @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 @@ void whitespace() { @Test void arithmeticPlus1() { - SpelExpressionParser parser = new SpelExpressionParser(); SpelExpression expr = parser.parseRaw("2+2"); assertThat(expr).isNotNull(); assertThat(expr.getAST()).isNotNull(); @@ -89,14 +100,12 @@ void arithmeticPlus1() { @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 @@ void arithmeticMultiply1() { @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 Consumer 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 SpelExpressionParser().parseRaw("3+10/2"); + SpelExpression expr = parser.parseRaw("3+10/2"); assertThat(expr.getValue()).isEqualTo(8); } @Test void arithmeticPrecedence4() { - SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3"); + SpelExpression expr = parser.parseRaw("10/2+3"); assertThat(expr.getValue()).isEqualTo(8); } @Test void arithmeticPrecedence5() { - SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2"); + SpelExpression expr = parser.parseRaw("(4+10)/2"); assertThat(expr.getValue()).isEqualTo(7); } @Test void arithmeticPrecedence6() { - SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2"); + SpelExpression expr = parser.parseRaw("(3+2)*2"); assertThat(expr.getValue()).isEqualTo(10); } @Test void booleanOperators() { - SpelExpression expr = new SpelExpressionParser().parseRaw("true"); + SpelExpression expr = parser.parseRaw("true"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("false"); + expr = parser.parseRaw("false"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("false and false"); + expr = parser.parseRaw("false and false"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("true and (true or false)"); + expr = parser.parseRaw("true and (true or false)"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("true and true or false"); + expr = parser.parseRaw("true and true or false"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("!true"); + expr = parser.parseRaw("!true"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("!(false or true)"); + expr = parser.parseRaw("!(false or true)"); assertThat(expr.getValue(Boolean.class)).isFalse(); } @Test void booleanOperators_symbolic_spr9614() { - SpelExpression expr = new SpelExpressionParser().parseRaw("true"); + SpelExpression expr = parser.parseRaw("true"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("false"); + expr = parser.parseRaw("false"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("false && false"); + expr = parser.parseRaw("false && false"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("true && (true || false)"); + expr = parser.parseRaw("true && (true || false)"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("true && true || false"); + expr = parser.parseRaw("true && true || false"); assertThat(expr.getValue(Boolean.class)).isTrue(); - expr = new SpelExpressionParser().parseRaw("!true"); + expr = parser.parseRaw("!true"); assertThat(expr.getValue(Boolean.class)).isFalse(); - expr = new SpelExpressionParser().parseRaw("!(false || true)"); + expr = parser.parseRaw("!(false || true)"); assertThat(expr.getValue(Boolean.class)).isFalse(); } @Test void stringLiterals() { - SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'"); + SpelExpression expr = parser.parseRaw("'howdy'"); assertThat(expr.getValue()).isEqualTo("howdy"); - expr = new SpelExpressionParser().parseRaw("'hello '' world'"); + expr = parser.parseRaw("'hello '' world'"); assertThat(expr.getValue()).isEqualTo("hello ' world"); } @Test void stringLiterals2() { - SpelExpression expr = new SpelExpressionParser().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 SpelExpressionParser().parseRaw("\"double quote: \"\".\""); + SpelExpression expr = parser.parseRaw("\"double quote: \"\".\""); assertThat(expr.getValue()).isEqualTo("double quote: \"."); - expr = new SpelExpressionParser().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 SpelExpressionParser().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 @@ void numerics() { 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 @@ void numerics() { 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 @@ private void checkNumber(String expression, Object value, Class type) { } 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 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 Consumer parseExceptionRequirements( + SpelMessage expectedMessage, int expectedPosition) { + return ex -> { + assertThat(ex.getMessageCode()).isEqualTo(expectedMessage); + assertThat(ex.getPosition()).isEqualTo(expectedPosition); + assertThat(ex.getMessage()).contains(ex.getExpressionString()); + }; + } + }