From 21f3b964feb440dfcab9b013ed6d0924d929a459 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:28:33 +0200 Subject: [PATCH] Improve SpEL tests for Elvis and Ternary operators --- .../expression/spel/EvaluationTests.java | 62 +++++++------------ .../spel/SpelCompilationCoverageTests.java | 42 +++++++------ 2 files changed, 47 insertions(+), 57 deletions(-) diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java index 920333a2ec6..0398a3464e5 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java @@ -151,12 +151,14 @@ class EvaluationTests extends AbstractExpressionTests { @Test void elvisOperator() { - evaluate("'Andy'?:'Dave'", "Andy", String.class); - evaluate("null?:'Dave'", "Dave", String.class); - evaluate("3?:1", 3, Integer.class); - evaluate("(2*3)?:1*10", 6, Integer.class); - evaluate("null?:2*10", 20, Integer.class); - evaluate("(null?:1)*10", 10, Integer.class); + evaluate("'Andy' ?: 'Dave'", "Andy", String.class); + evaluate("null ?: 'Dave'", "Dave", String.class); + evaluate("3 ?: 1", 3, Integer.class); + evaluate("(2 * 3) ?: 1 * 10", 6, Integer.class); + evaluate("null ?: 2 * 10", 20, Integer.class); + evaluate("(null ?: 1) * 10", 10, Integer.class); + evaluate("3 ?: #var = 5", 3, Integer.class); + evaluate("null ?: #var = 5", 5, Integer.class); } @Test @@ -721,59 +723,41 @@ class EvaluationTests extends AbstractExpressionTests { class TernaryOperatorTests { @Test - void ternaryOperator01() { - evaluate("2>4?1:2", 2, Integer.class); + void ternaryExpressionWithNullConditionType() { + // cannot convert null to boolean + evaluateAndCheckError("null ? 0 : 1", SpelMessage.TYPE_CONVERSION_ERROR); } @Test - void ternaryOperator02() { - evaluate("'abc'=='abc'?1:2", 1, Integer.class); - } - - @Test - void ternaryOperator03() { + void ternaryExpressionWithInvalidConditionType() { // cannot convert String to boolean - evaluateAndCheckError("'hello'?1:2", SpelMessage.TYPE_CONVERSION_ERROR); + evaluateAndCheckError("'hello' ? 1 : 2", SpelMessage.TYPE_CONVERSION_ERROR); } @Test - void ternaryOperator04() { - Expression e = parser.parseExpression("1>2?3:4"); - assertThat(e.isWritable(context)).isFalse(); + void ternaryExpressionIsNotWritable() { + Expression exp = parser.parseExpression("1 > 2 ? 3 : 4"); + assertThat(exp.isWritable(context)).isFalse(); } @Test - void ternaryOperator05() { - evaluate("1>2?#var=4:#var=5", 5, Integer.class); - evaluate("3?:#var=5", 3, Integer.class); - evaluate("null?:#var=5", 5, Integer.class); - evaluate("2>4?(3>2?true:false):(5<3?true:false)", false, Boolean.class); + void ternaryExpressions() { + evaluate("2 > 4 ? 1 : 2", 2, Integer.class); + evaluate("'abc' == 'abc' ? 1 : 2", 1, Integer.class); + evaluate("1 > 2 ? #var = 4 : #var = 5", 5, Integer.class); + evaluate("2 > 4 ? (3 > 2 ? true : false) : (5 < 3 ? true : false)", false, Boolean.class); } @Test - void ternaryOperator06() { - evaluate("3?:#var=5", 3, Integer.class); - evaluate("null?:#var=5", 5, Integer.class); - evaluate("2>4?(3>2?true:false):(5<3?true:false)", false, Boolean.class); - } - - @Test - void ternaryExpressionWithImplicitGrouping() { + void ternaryExpressionsWithImplicitGrouping() { evaluate("4 % 2 == 0 ? 2 : 3 * 10", 2, Integer.class); evaluate("4 % 2 == 1 ? 2 : 3 * 10", 30, Integer.class); } @Test - void ternaryExpressionWithExplicitGrouping() { + void ternaryExpressionsWithExplicitGrouping() { evaluate("((4 % 2 == 0) ? 2 : 1) * 10", 20, Integer.class); } - - @Test - void ternaryOperatorWithNullValue() { - assertThatExceptionOfType(EvaluationException.class) - .isThrownBy(parser.parseExpression("null ? 0 : 1")::getValue); - } - } @Nested diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index 5312dbbca5c..6073839af0a 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java @@ -2056,12 +2056,13 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { @Test void ternary() { - Expression expression = parser.parseExpression("true?'a':'b'"); + expression = parser.parseExpression("true?'a':'b'"); String resultI = expression.getValue(String.class); assertCanCompile(expression); String resultC = expression.getValue(String.class); assertThat(resultI).isEqualTo("a"); assertThat(resultC).isEqualTo("a"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); expression = parser.parseExpression("false?'a':'b'"); resultI = expression.getValue(String.class); @@ -2069,11 +2070,13 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { resultC = expression.getValue(String.class); assertThat(resultI).isEqualTo("b"); assertThat(resultC).isEqualTo("b"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); expression = parser.parseExpression("false?1:'b'"); // All literals so we can do this straight away assertCanCompile(expression); assertThat(expression.getValue()).isEqualTo("b"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); boolean root = true; expression = parser.parseExpression("(#root and true)?T(Integer).valueOf(1):T(Long).valueOf(3L)"); @@ -2083,21 +2086,25 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertThat(expression.getValue(root)).isEqualTo(3L); assertCanCompile(expression); assertThat(expression.getValue(root)).isEqualTo(3L); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); root = true; assertThat(expression.getValue(root)).isEqualTo(1); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); } - @Test - void ternaryWithBooleanReturn_SPR12271() { + @Test // gh-16876 + void ternaryWithBooleanWrapperCondition() { expression = parser.parseExpression("T(Boolean).TRUE?'abc':'def'"); assertThat(expression.getValue()).isEqualTo("abc"); assertCanCompile(expression); assertThat(expression.getValue()).isEqualTo("abc"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); expression = parser.parseExpression("T(Boolean).FALSE?'abc':'def'"); assertThat(expression.getValue()).isEqualTo("def"); assertCanCompile(expression); assertThat(expression.getValue()).isEqualTo("def"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); } @Test @@ -2289,31 +2296,30 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { @Test void elvis() { - Expression expression = parser.parseExpression("'a'?:'b'"); - String resultI = expression.getValue(String.class); + expression = parser.parseExpression("'a' ?: 'b'"); + assertThat(expression.getValue(String.class)).isEqualTo("a"); assertCanCompile(expression); - String resultC = expression.getValue(String.class); - assertThat(resultI).isEqualTo("a"); - assertThat(resultC).isEqualTo("a"); + assertThat(expression.getValue(String.class)).isEqualTo("a"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); - expression = parser.parseExpression("null?:'a'"); - resultI = expression.getValue(String.class); + expression = parser.parseExpression("null ?: 'a'"); + assertThat(expression.getValue(String.class)).isEqualTo("a"); assertCanCompile(expression); - resultC = expression.getValue(String.class); - assertThat(resultI).isEqualTo("a"); - assertThat(resultC).isEqualTo("a"); + assertThat(expression.getValue(String.class)).isEqualTo("a"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/Object"); - String s = "abc"; - expression = parser.parseExpression("#root?:'b'"); + String root = "abc"; + expression = parser.parseExpression("#root ?: 'b'"); assertCannotCompile(expression); - resultI = expression.getValue(s, String.class); - assertThat(resultI).isEqualTo("abc"); + assertThat(expression.getValue(root, String.class)).isEqualTo("abc"); assertCanCompile(expression); + assertThat(expression.getValue(root, String.class)).isEqualTo("abc"); + assertThat(getAst().getExitDescriptor()).isEqualTo("Ljava/lang/String"); } public static String concat(String a, String b) { - return a+b; + return a + b; } public static String concat2(Object... args) {