@Test public void test_contextExpression() { assertThat(parseCompileEvaluate("{}"), is(Collections.emptyMap())); assertThat(parseCompileEvaluate("{ }"), is(Collections.emptyMap())); assertThat(parseCompileEvaluate("{ a : 1 }"), is(mapOf(entry("a", new BigDecimal(1))))); assertThat(parseCompileEvaluate("{ \"a\" : 1 }"), is(mapOf(entry("a", new BigDecimal(1))))); assertThat(parseCompileEvaluate("{ \" a\" : 1 }"), is(mapOf(entry(" a", new BigDecimal(1))))); // Demonstrating a bad practice. assertThat(parseCompileEvaluate("{ a : 1, b : 2, c : 3 }"), is(mapOf(entry("a", new BigDecimal(1)), entry("b", new BigDecimal(2)), entry("c", new BigDecimal(3))))); assertThat(parseCompileEvaluate("{ a : 1, a name : \"John Doe\" }"), is(mapOf(entry("a", new BigDecimal(1)), entry("a name", "John Doe")))); assertThat(parseCompileEvaluate("{ a : 1, b : a }"), is(mapOf(entry("a", new BigDecimal(1)), entry("b", new BigDecimal(1))))); }
@Parameterized.Parameters(name = "{index}: {0} ({1}) = {2}") public static Collection<Object[]> data() { final Object[][] cases = new Object[][] { //normal: {"for x in [1, 2, 3] return x+1", Stream.of(1, 2, 3 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() ), null}, //extended: {"for x in 1..3 return x+1", Stream.of(1, 2, 3 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() ), null}, {"for x in 1..\"ciao\" return x+1", null, FEELEvent.Severity.ERROR}, {"for x in 3..1 return x+1", Stream.of(3, 2, 1 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() ), null}, {"for x in 1..1 return x+1", Stream.of(1 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() ), null}, {"for x in 1..3, y in 4..6 return [x+1, y-1]", l(l(2, 3), l(2, 4), l(2, 5), l(3, 3), l(3, 4), l(3, 5), l(4, 3), l(4, 4), l(4, 5)), null}, {"{ a: 1, b : 3, c : for x in a..b return x+1}", mapOf(entry("a", BigDecimal.valueOf(1)), entry("b", BigDecimal.valueOf(3)), entry("c", Stream.of(1, 2, 3 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() )) ), null}, {"{ a: 1, b : 3, c : for x in a+2..b-2 return x+1}", mapOf(entry("a", BigDecimal.valueOf(1)), entry("b", BigDecimal.valueOf(3)), entry("c", Stream.of(3, 2, 1 ).map(x -> BigDecimal.valueOf(x + 1 ) ).collect(Collectors.toList() )) ), null}, {"{ a: \"ciao\", b : 3, c : for x in a..b return x+1}", mapOf(entry("a", "ciao"), entry("b", BigDecimal.valueOf(3)), entry("c", null)), FEELEvent.Severity.ERROR}, {"for i in 0..10 return if i = 0 then 1 else i * partial[-1]", Stream.of(1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ).map(BigDecimal::valueOf).collect(Collectors.toList() ), null}, }; return addAdditionalParameters(cases, true); }
@Test public void testQualifiedName3() { String inputExpression = "a date.year"; Type dateType = BuiltInType.DATE; CompiledFEELExpression qualRef = parse(inputExpression, mapOf(entry("a date", dateType))); LOG.debug("{}", qualRef); EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext(); context.setValue("a date", LocalDate.of(2016, 8, 2)); Object result = qualRef.apply(context); LOG.debug("{}", result); assertThat(result, is(BigDecimal.valueOf(2016))); }
/** * See {@link FEELParserTest} */ @Test public void testContextWithMultipleEntries() { String inputExpression = "{ \"a string key\" : 10," + "\n" + " a non-string key : 11," + "\n" + " a key.with + /' odd chars : 12 }"; assertThat(parseCompileEvaluate(inputExpression), is(mapOf(entry("a string key", new BigDecimal(10)), entry("a non-string key", new BigDecimal(11)), entry("a key.with + /' odd chars", new BigDecimal(12))))); }
@Test public void testNameReference() { String inputExpression = "someSimpleName"; CompiledFEELExpression nameRef = parse( inputExpression, mapOf( entry("someSimpleName", BuiltInType.STRING) ) ); LOG.debug("{}", nameRef); EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext(); context.setValue("someSimpleName", 123L); Object result = nameRef.apply(context); LOG.debug("{}", result); assertThat(result, is( BigDecimal.valueOf(123) )); }
/** * See {@link FEELParserTest} */ @Test public void testNestedContexts2() { String complexContext = "{ an applicant : { \n" + " home address : { \n" + " street name: \"broadway st\", \n" + " city : \"New York\" \n" + " } \n" + " }, \n" + " street : an applicant.home address.street name \n" + "} "; assertThat(parseCompileEvaluate(complexContext), is(mapOf(entry("an applicant", mapOf(entry("home address", mapOf(entry("street name", "broadway st"), entry("city", "New York"))))), entry("street", "broadway st")))); }
@Test public void test_filterPath_tricky1() { CompiledFEELExpression nameRef = parse( "[ {x:1, y:2}, {x:2, y:3} ][x]"); LOG.debug("{}", nameRef); EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext(); context.setValue("x", 2); Object result = nameRef.apply(context); LOG.debug("{}", result); assertThat(result, is(mapOf(entry("x", new BigDecimal(2)), entry("y", new BigDecimal(3))))); }
@Test public void testQualifiedName() { String inputExpression = "My Person.Full Name"; MapBackedType personType = new MapBackedType("Person", mapOf( entry("Full Name", BuiltInType.STRING), entry("Age", BuiltInType.NUMBER) ) ); BaseNode qualRef = parse( inputExpression, mapOf( entry("My Person", personType) ) ); assertThat( qualRef, is( instanceOf( QualifiedNameNode.class ) ) ); assertThat( qualRef.getResultType(), is( BuiltInType.STRING ) ); List<NameRefNode> parts = ((QualifiedNameNode) qualRef).getParts(); // `My Person` ... assertThat( parts.get(0), is( instanceOf( NameRefNode.class ) ) ); assertThat( parts.get(0).getResultType(), is( personType ) ); // ... `.Full Name` assertThat( parts.get(1), is( instanceOf( NameRefNode.class ) ) ); assertThat( parts.get(1).getResultType(), is( BuiltInType.STRING ) ); assertLocation( inputExpression, qualRef ); }
@Test public void testQualifiedName() { String inputExpression = "My Person.Full Name"; Type personType = new MapBackedType("Person", mapOf( entry("Full Name", BuiltInType.STRING), entry("Age", BuiltInType.NUMBER) ) ); CompiledFEELExpression qualRef = parse( inputExpression, mapOf( entry("My Person", personType) ) ); LOG.debug("{}", qualRef); EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext(); context.setValue("My Person", mapOf( entry("Full Name", "John Doe"), entry("Age", 47) )); Object result = qualRef.apply(context); LOG.debug("{}", result); assertThat(result, is( "John Doe" )); // check number coercion for qualified name CompiledFEELExpression personAgeExpression = parse("My Person.Age", mapOf(entry("My Person", personType))); LOG.debug("{}", personAgeExpression); Object resultPersonAge = personAgeExpression.apply(context); // Please notice input variable in context is a Map containing and entry value for int 47. LOG.debug("{}", resultPersonAge); assertThat(resultPersonAge, is(BigDecimal.valueOf(47))); }
@Test public void testNameReference() { String inputExpression = "someSimpleName"; BaseNode nameRef = parse( inputExpression, mapOf( entry("someSimpleName", BuiltInType.STRING) ) ); assertThat( nameRef, is( instanceOf( NameRefNode.class ) ) ); assertThat( nameRef.getResultType(), is( BuiltInType.STRING ) ); assertLocation( inputExpression, nameRef ); }
@Test public void testQualifiedName2() { String inputExpression = "My Person.Full Name"; Type personType = JavaBackedType.of(MyPerson.class); CompiledFEELExpression qualRef = parse( inputExpression, mapOf( entry("My Person", personType) ) ); LOG.debug("{}", qualRef); EvaluationContext context = CodegenTestUtil.newEmptyEvaluationContext(); context.setValue("My Person", new MyPerson()); Object result = qualRef.apply(context); LOG.debug("{}", result); assertThat(result, is( "John Doe" )); }
@Test public void testMultiplication() { String inputExpression = "10 * x"; BaseNode infix = parse( inputExpression, mapOf(entry("x", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode mult = (InfixOpNode) infix; assertThat( mult.getLeft(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "10" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NameRefNode.class ) ) ); assertThat( mult.getRight().getText(), is( "x" ) ); }
@Test public void test_filterPath() { // Filtering by index assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][1]"), is("a")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][2]"), is("b")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][3]"), is("c")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][-1]"), is("c")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][-2]"), is("b")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][-3]"), is("a")); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][4]"), nullValue()); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][984]"), nullValue()); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][-4]"), nullValue()); assertThat(parseCompileEvaluate("[\"a\", \"b\", \"c\"][-984]"), nullValue()); assertThat(parseCompileEvaluate("\"a\"[1]"), is("a")); assertThat(parseCompileEvaluate("\"a\"[2]"), nullValue()); assertThat(parseCompileEvaluate("\"a\"[-1]"), is("a")); assertThat(parseCompileEvaluate("\"a\"[-2]"), nullValue()); // Filtering by boolean expression assertThat(parseCompileEvaluate("[1, 2, 3, 4][item = 4]"), is(Arrays.asList(BigDecimal.valueOf(4)))); assertThat(parseCompileEvaluate("[1, 2, 3, 4][item > 2]"), is(Arrays.asList(BigDecimal.valueOf(3), BigDecimal.valueOf(4)))); assertThat(parseCompileEvaluate("[1, 2, 3, 4][item > 5]"), is(Collections.emptyList())); assertThat(parseCompileEvaluate("[ {x:1, y:2}, {x:2, y:3} ][x = 1]"), is(Arrays.asList(mapOf(entry("x", new BigDecimal(1)), entry("y", new BigDecimal(2)))))); assertThat(parseCompileEvaluate("[ {x:1, y:2}, {x:2, y:3} ][x > 1]"), is(Arrays.asList(mapOf(entry("x", new BigDecimal(2)), entry("y", new BigDecimal(3)))))); assertThat(parseCompileEvaluate("[ {x:1, y:2}, {x:2, y:3} ][x = 0]"), is(Collections.emptyList())); }
@Test public void testPower2() { String inputExpression = "(y * 5) ** 3"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode exp = (InfixOpNode) infix; assertThat( exp.getLeft(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( exp.getLeft().getText(), is( "y * 5" ) ); assertThat( exp.getOperator(), is( InfixOpNode.InfixOperator.POW ) ); assertThat( exp.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( exp.getRight().getText(), is( "3" ) ); InfixOpNode mult = (InfixOpNode) exp.getLeft(); assertThat( mult.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "y" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getRight().getText(), is( "5" ) ); }
@Test public void testSub1() { String inputExpression = "(y - 5) ** 3"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode sub = (InfixOpNode) infix; assertThat( sub.getLeft(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( sub.getLeft().getText(), is( "y - 5" ) ); assertThat( sub.getOperator(), is( InfixOpNode.InfixOperator.POW ) ); assertThat( sub.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( sub.getRight().getText(), is( "3" ) ); InfixOpNode mult = (InfixOpNode) sub.getLeft(); assertThat( mult.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "y" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.SUB ) ); assertThat( mult.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getRight().getText(), is( "5" ) ); }
@Test public void testPower3() { String inputExpression = "y ** 5 * 3"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode mult = (InfixOpNode) infix; assertThat( mult.getLeft(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "y ** 5" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getRight().getText(), is( "3" ) ); InfixOpNode exp = (InfixOpNode) mult.getLeft(); assertThat( exp.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( exp.getLeft().getText(), is( "y" ) ); assertThat( exp.getOperator(), is( InfixOpNode.InfixOperator.POW ) ); assertThat( exp.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( exp.getRight().getText(), is( "5" ) ); }
@Test public void testPower4() { String inputExpression = "y ** ( 5 * 3 )"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode exp = (InfixOpNode) infix; assertThat( exp.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( exp.getLeft().getText(), is( "y" ) ); assertThat( exp.getOperator(), is( InfixOpNode.InfixOperator.POW ) ); assertThat( exp.getRight(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( exp.getRight().getText(), is( "5 * 3" ) ); InfixOpNode mult = (InfixOpNode) exp.getRight(); assertThat( mult.getLeft(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "5" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getRight().getText(), is( "3" ) ); }
@Test public void testPower1() { String inputExpression = "y * 5 ** 3"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode mult = (InfixOpNode) infix; assertThat( mult.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "y" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( mult.getRight().getText(), is( "5 ** 3" ) ); InfixOpNode exp = (InfixOpNode) mult.getRight(); assertThat( exp.getLeft(), is( instanceOf( NumberNode.class ) ) ); assertThat( exp.getLeft().getText(), is( "5" ) ); assertThat( exp.getOperator(), is( InfixOpNode.InfixOperator.POW ) ); assertThat( exp.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( exp.getRight().getText(), is( "3" ) ); }
@Test public void testAdd1() { String inputExpression = "y + 5 * 3"; BaseNode infix = parse( inputExpression, mapOf(entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode add = (InfixOpNode) infix; assertThat( add.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( add.getLeft().getText(), is( "y" ) ); assertThat( add.getOperator(), is( InfixOpNode.InfixOperator.ADD ) ); assertThat( add.getRight(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( add.getRight().getText(), is( "5 * 3" ) ); InfixOpNode mult = (InfixOpNode) add.getRight(); assertThat( mult.getLeft(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "5" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( mult.getRight().getText(), is( "3" ) ); }
@Test public void testDivision() { String inputExpression = "y / 5 * ( x )"; BaseNode infix = parse( inputExpression, mapOf(entry("x", BuiltInType.NUMBER), entry("y", BuiltInType.NUMBER)) ); assertThat( infix, is( instanceOf( InfixOpNode.class ) ) ); assertThat( infix.getResultType(), is( BuiltInType.NUMBER ) ); assertThat( infix.getText(), is( inputExpression ) ); InfixOpNode mult = (InfixOpNode) infix; assertThat( mult.getLeft(), is( instanceOf( InfixOpNode.class ) ) ); assertThat( mult.getLeft().getText(), is( "y / 5" ) ); InfixOpNode div = (InfixOpNode) mult.getLeft(); assertThat( div.getLeft(), is( instanceOf( NameRefNode.class ) ) ); assertThat( div.getLeft().getText(), is( "y" ) ); assertThat( div.getOperator(), is( InfixOpNode.InfixOperator.DIV ) ); assertThat( div.getRight(), is( instanceOf( NumberNode.class ) ) ); assertThat( div.getRight().getText(), is( "5" ) ); assertThat( mult.getOperator(), is( InfixOpNode.InfixOperator.MULT ) ); assertThat( mult.getRight(), is( instanceOf( NameRefNode.class ) ) ); assertThat( mult.getRight().getText(), is( "x" ) ); }