|
|
|
|
@@ -16,6 +16,8 @@
|
|
|
|
|
|
|
|
|
|
package org.springframework.expression.spel;
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Disabled;
|
|
|
|
|
import org.junit.jupiter.api.Nested;
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
|
|
|
|
|
import org.springframework.expression.spel.standard.SpelExpression;
|
|
|
|
|
@@ -37,413 +39,485 @@ class ParsingTests {
|
|
|
|
|
private final SpelExpressionParser parser = new SpelExpressionParser();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// literals
|
|
|
|
|
@Test
|
|
|
|
|
void literalBoolean01() {
|
|
|
|
|
parseCheck("false");
|
|
|
|
|
@Nested
|
|
|
|
|
class Miscellaneous {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalNull() {
|
|
|
|
|
parseCheck("null");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalDate01() {
|
|
|
|
|
parseCheck("date('1974/08/24')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalDate02() {
|
|
|
|
|
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mixedOperators() {
|
|
|
|
|
parseCheck("true and 5>3", "(true and (5 > 3))");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void assignmentToVariables() {
|
|
|
|
|
parseCheck("#var1='value1'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsCountStringArray() {
|
|
|
|
|
parseCheck("new String[] {'abc','def','xyz'}.count()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsCountIntArray() {
|
|
|
|
|
parseCheck("new int[] {1,2,3}.count()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsMax() {
|
|
|
|
|
parseCheck("new int[] {1,2,3}.max()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsMin() {
|
|
|
|
|
parseCheck("new int[] {1,2,3}.min()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsAverage() {
|
|
|
|
|
parseCheck("new int[] {1,2,3}.average()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsSort() {
|
|
|
|
|
parseCheck("new int[] {3,2,1}.sort()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsNonNull() {
|
|
|
|
|
parseCheck("{'a','b',null,'d',null}.nonNull()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void collectionProcessorsDistinct() {
|
|
|
|
|
parseCheck("{'a','b','a','d','e'}.distinct()");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void lambdaMax() {
|
|
|
|
|
parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))",
|
|
|
|
|
"(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void lambdaFactorial() {
|
|
|
|
|
parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))",
|
|
|
|
|
"(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void projection() {
|
|
|
|
|
parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void selection() {
|
|
|
|
|
parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}",
|
|
|
|
|
"{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void selectionFirst() {
|
|
|
|
|
parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}",
|
|
|
|
|
"{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void selectionLast() {
|
|
|
|
|
parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}",
|
|
|
|
|
"{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalLong01() {
|
|
|
|
|
parseCheck("37L", "37");
|
|
|
|
|
@Nested
|
|
|
|
|
class LiteralBooleans {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalBooleanFalse() {
|
|
|
|
|
parseCheck("false");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalBooleanTrue() {
|
|
|
|
|
parseCheck("true");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalBooleanNotTrue() {
|
|
|
|
|
parseCheck("!true");
|
|
|
|
|
parseCheck("not true", "!true");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalBoolean02() {
|
|
|
|
|
parseCheck("true");
|
|
|
|
|
@Nested
|
|
|
|
|
class LiteralNumbers {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalLong() {
|
|
|
|
|
parseCheck("37L", "37");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalIntegers() {
|
|
|
|
|
parseCheck("1");
|
|
|
|
|
parseCheck("1415");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalReal() {
|
|
|
|
|
parseCheck("6.0221415E+23", "6.0221415E23");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalHex() {
|
|
|
|
|
parseCheck("0x7FFFFFFF", "2147483647");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalBoolean03() {
|
|
|
|
|
parseCheck("!true");
|
|
|
|
|
@Nested
|
|
|
|
|
class LiteralStrings {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void insideSingleQuotes() {
|
|
|
|
|
parseCheck("'hello'");
|
|
|
|
|
parseCheck("'hello world'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void insideDoubleQuotes() {
|
|
|
|
|
parseCheck("\"hello\"", "'hello'");
|
|
|
|
|
parseCheck("\"hello world\"", "'hello world'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void singleQuotesInsideSingleQuotes() {
|
|
|
|
|
parseCheck("'Tony''s Pizza'");
|
|
|
|
|
parseCheck("'big ''''pizza'''' parlor'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void doubleQuotesInsideDoubleQuotes() {
|
|
|
|
|
parseCheck("\"big \"\"pizza\"\" parlor\"", "'big \"pizza\" parlor'");
|
|
|
|
|
parseCheck("\"big \"\"\"\"pizza\"\"\"\" parlor\"", "'big \"\"pizza\"\" parlor'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void singleQuotesInsideDoubleQuotes() {
|
|
|
|
|
parseCheck("\"Tony's Pizza\"", "'Tony''s Pizza'");
|
|
|
|
|
parseCheck("\"big ''pizza'' parlor\"", "'big ''''pizza'''' parlor'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void doubleQuotesInsideSingleQuotes() {
|
|
|
|
|
parseCheck("'big \"pizza\" parlor'");
|
|
|
|
|
parseCheck("'two double \"\" quotes'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inCompoundExpressions() {
|
|
|
|
|
parseCheck("'123''4' == '123''4'", "('123''4' == '123''4')");
|
|
|
|
|
parseCheck("('123''4'=='123''4')", "('123''4' == '123''4')");
|
|
|
|
|
parseCheck("\"123\"\"4\" == \"123\"\"4\"", "('123\"4' == '123\"4')");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalInteger01() {
|
|
|
|
|
parseCheck("1");
|
|
|
|
|
@Nested
|
|
|
|
|
class BooleanOperators {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr01() {
|
|
|
|
|
parseCheck("false or false", "(false or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr02() {
|
|
|
|
|
parseCheck("false or true", "(false or true)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr03() {
|
|
|
|
|
parseCheck("true or false", "(true or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr04() {
|
|
|
|
|
parseCheck("true or false", "(true or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsMix() {
|
|
|
|
|
parseCheck("false or true and false", "(false or (true and false))");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalInteger02() {
|
|
|
|
|
parseCheck("1415");
|
|
|
|
|
@Nested
|
|
|
|
|
class RelationalOperators {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGT() {
|
|
|
|
|
parseCheck("3>6", "(3 > 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsLT() {
|
|
|
|
|
parseCheck("3<6", "(3 < 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsLE() {
|
|
|
|
|
parseCheck("3<=6", "(3 <= 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGE01() {
|
|
|
|
|
parseCheck("3>=6", "(3 >= 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGE02() {
|
|
|
|
|
parseCheck("3>=3", "(3 >= 3)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("Unsupported syntax/feature")
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsIn() {
|
|
|
|
|
parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsBetweenNumbers() {
|
|
|
|
|
parseCheck("1 between {1, 5}", "(1 between {1,5})");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsBetweenStrings() {
|
|
|
|
|
parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsInstanceOfInt() {
|
|
|
|
|
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsInstanceOfList() {
|
|
|
|
|
parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsMatches() {
|
|
|
|
|
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
|
|
|
|
|
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalString01() {
|
|
|
|
|
parseCheck("'hello'");
|
|
|
|
|
@Nested
|
|
|
|
|
class MathematicalOperators {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAddIntegers() {
|
|
|
|
|
parseCheck("2+4", "(2 + 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAddStrings() {
|
|
|
|
|
parseCheck("'a'+'b'", "('a' + 'b')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAddMultipleStrings() {
|
|
|
|
|
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsSubtract() {
|
|
|
|
|
parseCheck("5-4", "(5 - 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsMultiply() {
|
|
|
|
|
parseCheck("7*4", "(7 * 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsDivide() {
|
|
|
|
|
parseCheck("8/4", "(8 / 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorModulus() {
|
|
|
|
|
parseCheck("7 % 4", "(7 % 4)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalString02() {
|
|
|
|
|
parseCheck("'joe bloggs'");
|
|
|
|
|
@Nested
|
|
|
|
|
class References {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void references() {
|
|
|
|
|
parseCheck("@foo");
|
|
|
|
|
parseCheck("@'foo.bar'");
|
|
|
|
|
parseCheck("@\"foo.bar.goo\"" , "@'foo.bar.goo'");
|
|
|
|
|
parseCheck("@$$foo");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalString03() {
|
|
|
|
|
parseCheck("'Tony''s Pizza'", "'Tony's Pizza'");
|
|
|
|
|
@Nested
|
|
|
|
|
class Properties {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void propertiesSingle() {
|
|
|
|
|
parseCheck("name");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void propertiesDouble() {
|
|
|
|
|
parseCheck("placeofbirth.CitY");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void propertiesMultiple() {
|
|
|
|
|
parseCheck("a.b.c.d.e");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalReal01() {
|
|
|
|
|
parseCheck("6.0221415E+23", "6.0221415E23");
|
|
|
|
|
@Nested
|
|
|
|
|
class InlineCollections {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineListOfIntegers() {
|
|
|
|
|
parseCheck("{1,2,3,4}");
|
|
|
|
|
parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineListOfStrings() {
|
|
|
|
|
parseCheck("{'abc','xyz'}", "{'abc','xyz'}");
|
|
|
|
|
parseCheck("{\"abc\", 'xyz'}", "{'abc','xyz'}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineMapStringToObject() {
|
|
|
|
|
parseCheck("{'key1':'Value 1','today':DateTime.Today}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineMapIntegerToString() {
|
|
|
|
|
parseCheck("{1:'January',2:'February',3:'March'}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalHex01() {
|
|
|
|
|
parseCheck("0x7FFFFFFF", "2147483647");
|
|
|
|
|
@Nested
|
|
|
|
|
class MethodsConstructorsAndArrays {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void methods() {
|
|
|
|
|
parseCheck("echo(12)");
|
|
|
|
|
parseCheck("echo(name)");
|
|
|
|
|
parseCheck("age.doubleItAndAdd(12)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void constructors() {
|
|
|
|
|
parseCheck("new String('hello')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void arrayConstruction01() {
|
|
|
|
|
parseCheck("new String[3]");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void arrayConstruction02() {
|
|
|
|
|
parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Disabled("toStringAST() is broken for array construction")
|
|
|
|
|
@Test
|
|
|
|
|
void arrayConstruction03() {
|
|
|
|
|
parseCheck("new String[] {'abc','xyz'}", "new String[] {'abc','xyz'}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalDate01() {
|
|
|
|
|
parseCheck("date('1974/08/24')");
|
|
|
|
|
@Nested
|
|
|
|
|
class VariablesAndFunctions {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void variables() {
|
|
|
|
|
parseCheck("#foo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void functions() {
|
|
|
|
|
parseCheck("#fn(1,2,3)");
|
|
|
|
|
parseCheck("#fn('hello')");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalDate02() {
|
|
|
|
|
parseCheck("date('19740824T131030','yyyyMMddTHHmmss')");
|
|
|
|
|
@Nested
|
|
|
|
|
class ElvisAndTernaryOperators {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void elvis() {
|
|
|
|
|
parseCheck("3?:1", "(3 ?: 1)");
|
|
|
|
|
parseCheck("(2*3)?:1*10", "((2 * 3) ?: (1 * 10))");
|
|
|
|
|
parseCheck("((2*3)?:1)*10", "(((2 * 3) ?: 1) * 10)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void ternary() {
|
|
|
|
|
parseCheck("1>2?3:4", "((1 > 2) ? 3 : 4)");
|
|
|
|
|
parseCheck("(a ? 1 : 0) * 10", "((a ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("(a?1:0)*10", "((a ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("(4 % 2 == 0 ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("((4 % 2 == 0) ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
|
|
|
|
|
"(({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd')");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void literalNull01() {
|
|
|
|
|
parseCheck("null");
|
|
|
|
|
@Nested
|
|
|
|
|
class TypeReferences {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void typeReferences01() {
|
|
|
|
|
parseCheck("T(java.lang.String)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void typeReferences02() {
|
|
|
|
|
parseCheck("T(String)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// boolean operators
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr01() {
|
|
|
|
|
parseCheck("false or false", "(false or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr02() {
|
|
|
|
|
parseCheck("false or true", "(false or true)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr03() {
|
|
|
|
|
parseCheck("true or false", "(true or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsOr04() {
|
|
|
|
|
parseCheck("true or false", "(true or false)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void booleanOperatorsMix01() {
|
|
|
|
|
parseCheck("false or true and false", "(false or (true and false))");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// relational operators
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGT01() {
|
|
|
|
|
parseCheck("3>6", "(3 > 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsLT01() {
|
|
|
|
|
parseCheck("3<6", "(3 < 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsLE01() {
|
|
|
|
|
parseCheck("3<=6", "(3 <= 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGE01() {
|
|
|
|
|
parseCheck("3>=6", "(3 >= 6)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsGE02() {
|
|
|
|
|
parseCheck("3>=3", "(3 >= 3)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void elvis() {
|
|
|
|
|
parseCheck("3?:1", "(3 ?: 1)");
|
|
|
|
|
parseCheck("(2*3)?:1*10", "((2 * 3) ?: (1 * 10))");
|
|
|
|
|
parseCheck("((2*3)?:1)*10", "(((2 * 3) ?: 1) * 10)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// void relOperatorsIn01() {
|
|
|
|
|
// parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void relOperatorsBetween01() {
|
|
|
|
|
// parseCheck("1 between {1, 5}", "(1 between {1,5})");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void relOperatorsBetween02() {
|
|
|
|
|
// parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})");
|
|
|
|
|
// }// true
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsIs01() {
|
|
|
|
|
parseCheck("'xyz' instanceof int", "('xyz' instanceof int)");
|
|
|
|
|
}// false
|
|
|
|
|
|
|
|
|
|
// void relOperatorsIs02() {
|
|
|
|
|
// parseCheck("{1, 2, 3, 4, 5} instanceof List", "({1,2,3,4,5} instanceof List)");
|
|
|
|
|
// }// true
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsMatches01() {
|
|
|
|
|
parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')");
|
|
|
|
|
}// false
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void relOperatorsMatches02() {
|
|
|
|
|
parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')");
|
|
|
|
|
}// true
|
|
|
|
|
|
|
|
|
|
// mathematical operators
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAdd01() {
|
|
|
|
|
parseCheck("2+4", "(2 + 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAdd02() {
|
|
|
|
|
parseCheck("'a'+'b'", "('a' + 'b')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsAdd03() {
|
|
|
|
|
parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsSubtract01() {
|
|
|
|
|
parseCheck("5-4", "(5 - 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsMultiply01() {
|
|
|
|
|
parseCheck("7*4", "(7 * 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorsDivide01() {
|
|
|
|
|
parseCheck("8/4", "(8 / 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void mathOperatorModulus01() {
|
|
|
|
|
parseCheck("7 % 4", "(7 % 4)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mixed operators
|
|
|
|
|
@Test
|
|
|
|
|
void mixedOperators01() {
|
|
|
|
|
parseCheck("true and 5>3", "(true and (5 > 3))");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// collection processors
|
|
|
|
|
// void collectionProcessorsCount01() {
|
|
|
|
|
// parseCheck("new String[] {'abc','def','xyz'}.count()");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void collectionProcessorsCount02() {
|
|
|
|
|
// parseCheck("new int[] {1,2,3}.count()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsMax01() {
|
|
|
|
|
// parseCheck("new int[] {1,2,3}.max()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsMin01() {
|
|
|
|
|
// parseCheck("new int[] {1,2,3}.min()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsAverage01() {
|
|
|
|
|
// parseCheck("new int[] {1,2,3}.average()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsSort01() {
|
|
|
|
|
// parseCheck("new int[] {3,2,1}.sort()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsNonNull01() {
|
|
|
|
|
// parseCheck("{'a','b',null,'d',null}.nonNull()");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void collectionProcessorsDistinct01() {
|
|
|
|
|
// parseCheck("{'a','b','a','d','e'}.distinct()");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// references
|
|
|
|
|
@Test
|
|
|
|
|
void references01() {
|
|
|
|
|
parseCheck("@foo");
|
|
|
|
|
parseCheck("@'foo.bar'");
|
|
|
|
|
parseCheck("@\"foo.bar.goo\"" , "@'foo.bar.goo'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void references03() {
|
|
|
|
|
parseCheck("@$$foo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// properties
|
|
|
|
|
@Test
|
|
|
|
|
void properties01() {
|
|
|
|
|
parseCheck("name");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void properties02() {
|
|
|
|
|
parseCheck("placeofbirth.CitY");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void properties03() {
|
|
|
|
|
parseCheck("a.b.c.d.e");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// inline list creation
|
|
|
|
|
@Test
|
|
|
|
|
void inlineListCreation01() {
|
|
|
|
|
parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineListCreation02() {
|
|
|
|
|
parseCheck("{'abc','xyz'}", "{'abc','xyz'}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// inline map creation
|
|
|
|
|
@Test
|
|
|
|
|
void inlineMapCreation01() {
|
|
|
|
|
parseCheck("{'key1':'Value 1','today':DateTime.Today}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineMapCreation02() {
|
|
|
|
|
parseCheck("{1:'January',2:'February',3:'March'}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// methods
|
|
|
|
|
@Test
|
|
|
|
|
void methods01() {
|
|
|
|
|
parseCheck("echo(12)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void methods02() {
|
|
|
|
|
parseCheck("echo(name)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void methods03() {
|
|
|
|
|
parseCheck("age.doubleItAndAdd(12)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// constructors
|
|
|
|
|
@Test
|
|
|
|
|
void constructors01() {
|
|
|
|
|
parseCheck("new String('hello')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// void constructors02() {
|
|
|
|
|
// parseCheck("new String[3]");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// array construction
|
|
|
|
|
// void arrayConstruction01() {
|
|
|
|
|
// parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void arrayConstruction02() {
|
|
|
|
|
// parseCheck("new String[] {'abc','xyz'}", "new String[] {'abc','xyz'}");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// variables and functions
|
|
|
|
|
@Test
|
|
|
|
|
void variables01() {
|
|
|
|
|
parseCheck("#foo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void functions01() {
|
|
|
|
|
parseCheck("#fn(1,2,3)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void functions02() {
|
|
|
|
|
parseCheck("#fn('hello')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// projections and selections
|
|
|
|
|
// void projections01() {
|
|
|
|
|
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void selections01() {
|
|
|
|
|
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}",
|
|
|
|
|
// "{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void selectionsFirst01() {
|
|
|
|
|
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}",
|
|
|
|
|
// "{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void selectionsLast01() {
|
|
|
|
|
// parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}",
|
|
|
|
|
// "{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// assignment
|
|
|
|
|
@Test
|
|
|
|
|
void assignmentToVariables01() {
|
|
|
|
|
parseCheck("#var1='value1'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ternary operator
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void ternaryOperator01() {
|
|
|
|
|
parseCheck("1>2?3:4", "((1 > 2) ? 3 : 4)");
|
|
|
|
|
parseCheck("(a ? 1 : 0) * 10", "((a ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("(a?1:0)*10", "((a ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("(4 % 2 == 0 ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
|
|
|
|
parseCheck("((4 % 2 == 0) ? 1 : 0) * 10", "((((4 % 2) == 0) ? 1 : 0) * 10)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void ternaryOperator02() {
|
|
|
|
|
parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'",
|
|
|
|
|
"(({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd')");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// void lambdaMax() {
|
|
|
|
|
// parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", "(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))");
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// void lambdaFactorial() {
|
|
|
|
|
// parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))",
|
|
|
|
|
// "(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))");
|
|
|
|
|
// } // 120
|
|
|
|
|
|
|
|
|
|
// Type references
|
|
|
|
|
@Test
|
|
|
|
|
void typeReferences01() {
|
|
|
|
|
parseCheck("T(java.lang.String)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void typeReferences02() {
|
|
|
|
|
parseCheck("T(String)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
void inlineList1() {
|
|
|
|
|
parseCheck("{1,2,3,4}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parse the supplied expression and then create a string representation of the resultant AST, it should be the same
|
|
|
|
|
|