/*
* *************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
* *************************************************************************************
*/
package com.espertech.esper.epl.parse;
import com.espertech.esper.collection.Pair;
import junit.framework.TestCase;
import org.antlr.runtime.CommonTokenStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.antlr.runtime.tree.Tree;
import com.espertech.esper.support.epl.parse.SupportParserHelper;
import com.espertech.esper.support.bean.SupportBean;
import com.espertech.esper.epl.generated.EsperEPL2GrammarParser;
public class TestEventPatternParser extends TestCase
{
public void testDisplayAST() throws Exception
{
String expression = "A -> [10] B until C -> D";
log.debug(".testDisplayAST parsing: " + expression);
Pair<Tree, CommonTokenStream> ast = parse(expression);
SupportParserHelper.displayAST(ast.getFirst());
}
public void testInvalidCases() throws Exception
{
// Base vocabulary
assertIsInvalid("");
assertIsInvalid("a(");
assertIsInvalid("a)");
assertIsInvalid("a((");
assertIsInvalid("a())");
assertIsInvalid("a(a=)");
assertIsInvalid("a(a=2 3)");
assertIsInvalid("a(a=2a)");
assertIsInvalid("a(a=\"2)");
assertIsInvalid("a(a=1x5)");
assertIsInvalid("a(a=)");
assertIsInvalid("a(=2)");
assertIsInvalid("a(a=2b=3)");
assertIsInvalid("a(a=2,)");
assertIsInvalid("a(a=2,b=)");
assertIsInvalid("e(a2>)");
assertIsInvalid("e(a2<=<4)");
assertIsInvalid("e(a2>=>6)");
assertIsInvalid("e(a in [])");
assertIsInvalid("e(a in [1:])");
assertIsInvalid("e(a in [:5])");
assertIsInvalid("e(a in [:5)))");
assertIsInvalid("e(a in ((:5)))");
assertIsInvalid("e(a in [[:5)");
assertIsInvalid("e(a in [1:5:8]");
assertIsInvalid("e(a in [1,,2])");
assertIsInvalid("e(a in [1:2]");
assertIsInvalid("e(a in [1:2] b=3)");
// Followed by
assertIsInvalid("every e() ->");
assertIsInvalid("every e() -> b() ->");
assertIsInvalid("e() -> b)");
assertIsInvalid("e() -> -> b()");
assertIsInvalid("e() -> every -> b()");
assertIsInvalid("-> every e()");
assertIsInvalid("e() -> f() -> g() -> every");
// Or
assertIsInvalid("e() or");
assertIsInvalid("or e()");
assertIsInvalid("a() or or e()");
assertIsInvalid("a() or e() or");
assertIsInvalid("f() or f() or f() o");
// And
assertIsInvalid("e() and");
assertIsInvalid("and e()");
assertIsInvalid("a() and and e()");
assertIsInvalid("a() and e() and");
assertIsInvalid("f() and f() and f() an");
// Not
assertIsInvalid("not e(");
assertIsInvalid("n o t e()");
assertIsInvalid("note a()");
assertIsInvalid("a() not");
assertIsInvalid("not f() not");
assertIsInvalid("not not f()");
assertIsInvalid("every not f()");
assertIsInvalid("not every not f()");
assertIsInvalid("every every not f()");
// where a:b
assertIsInvalid("a() where a:b(33s)");
assertIsInvalid("a() where a:b('+1E4)");
assertIsInvalid("a() where a:b(22L2)");
assertIsInvalid("a() where a:b(2) or b() every where a:b(3)");
assertIsInvalid("a() where a:b(2) or b() not where a:b(3)");
assertIsInvalid("where a:b(5) a()");
assertIsInvalid("every where a:b(5) a()");
assertIsInvalid("every a() where a:b(1) every");
assertIsInvalid("(every a()) (where a:b(1))");
assertIsInvalid("every ((every a(id=\"A1\")) where a:b(10l) and c()");
assertIsInvalid("timer:interval(10) timer:interval(20)");
assertIsInvalid("a() timer:interval(10)");
assertIsInvalid("timer:interval(10) b()");
assertIsInvalid("timer:interval(10) -> b() or timer:interval(20))");
assertIsInvalid("timer:interval(1x)");
assertIsInvalid("a() or timer:interval(10) b()");
assertIsInvalid("unmatched timer:interval()");
// At
assertIsInvalid("timer:at(,*,*,*,*)");
assertIsInvalid("timer:at(,*,*,*,*,*)");
assertIsInvalid("timer:at(*,,*,*,*)");
assertIsInvalid("timer:at(*,*,*,*,)");
assertIsInvalid("timer:at(*,*,*,*,*,)");
assertIsInvalid("timer:at(*,*,*,*,*,)");
assertIsInvalid("timer:at(*,*,*,*,1G)");
assertIsInvalid("timer:at(1a,*,*,*,*)");
assertIsInvalid("timer:at(*,*,=2*,*,*)");
assertIsInvalid("timer:at(*,*,*,*,1a=3) or b()");
assertIsInvalid("timer:at(*,[1a],*,*,*)");
assertIsInvalid("timer:at(*,[1a=3],*,*,*)");
assertIsInvalid("timer:at(*,[2,,5],*,*,*)");
assertIsInvalid("timer:at(*,[,2,5,7],*,*,*)");
assertIsInvalid("timer:at(*,[2,5,7,],*,*,*)");
assertIsInvalid("timer:at(*,[2,5][2,4],*,*,*)");
assertIsInvalid("timer:at(*,*,1x:1y,*,*)");
assertIsInvalid("timer:at(*,*,1:1y,*,*)");
assertIsInvalid("timer:at(*,*,1x:2,*,*)");
assertIsInvalid("timer:at(*,*,:2,*,*)");
assertIsInvalid("timer:at(*,*,2:,*,*)");
assertIsInvalid("timer:at(*,*,:,*,*)");
assertIsInvalid("timer:at(*,*,0/*,*,*)");
assertIsInvalid("timer:at(*,*,*/*,*,*)");
assertIsInvalid("timer:at([2:2x],*,*,*,*)");
assertIsInvalid("timer:at(3:3],*,*,*,*)");
assertIsInvalid("timer:at(3:3:3,*,*,*,*)");
assertIsInvalid("timer:at([3,*,*,*,*)");
assertIsInvalid("timer:at([3,*,*,*,*],q)");
assertIsInvalid("timer:at(3,3,3,*,*,*])");
// Custom EventObserver
assertIsInvalid("a:b(");
assertIsInvalid("a:b)");
assertIsInvalid("a:b('a',, 10)");
// Use of results
assertIsInvalid("a=A() -> b=B(pb1=a.)");
assertIsInvalid("a=A() -> b=B(pb1=.sss)");
assertIsInvalid("a=A() -> b=B(pb1=1.sss)");
assertIsInvalid("a=A() -> b=B(pb1=s.1)");
assertIsInvalid("a=A() -> b=B(pb1=s.1)");
assertIsInvalid("a=A() -> b=B(pb1 in [s.1:a.s2])");
assertIsInvalid("a=A() -> b=B(pb1 in [s.x:a.1])");
// Use of index, mapped, nested and combined properties
assertIsInvalid("A(x[0 = 1)");
assertIsInvalid("A(x 0] = 1)");
assertIsInvalid("A(x(b = 1)");
assertIsInvalid("A(x y) = 1)");
assertIsInvalid("A(x[0][1] = 1)");
assertIsInvalid("A(x[0]. = 1)");
assertIsInvalid("A(x. = 1)");
assertIsInvalid("A(x.y. = 1)");
assertIsInvalid("A(.y = 1)");
assertIsInvalid("A(y[0](g) = 1)");
assertIsInvalid("A(y(g)..z = 1)");
assertIsInvalid("A(x[aaa] = 1)");
}
public void testValidCases() throws Exception
{
String className = SupportBean.class.getName();
// Base vocabulary
assertIsValid(className);
assertIsValid(className + "(intPrimitive=444)");
assertIsValid(className + "(string=\"\")");
assertIsValid(className + "(string=\"ddddd\")");
assertIsValid(className + "(doubleBoxed=444E43)");
assertIsValid(className + "(doubleBoxed=1.2345)");
assertIsValid(className + "(doubleBoxed=0)");
assertIsValid(className + "(doubleBoxed=-394847575)");
assertIsValid(className + "(doublePrimitive=37374)");
assertIsValid(className + "(doublePrimitive=+2)");
assertIsValid(className + "(boolPrimitive=false)");
assertIsValid(className + "(boolPrimitive=true)");
assertIsValid(className + "(boolPrimitive=true,intPrimitive=4,string=\"d\")");
assertIsValid(className + "(string=\"b\",\nbyteBoxed=3)");
assertIsValid(className + "(intPrimitive<5,intBoxed>3,doublePrimitive<=2,doubleBoxed>=5)");
assertIsValid(className + " ( intPrimitive<5, \n intBoxed>3, \n doublePrimitive<=2,\t doubleBoxed>=5)");
assertIsValid(className + "(boolBoxed=true)");
assertIsValid(className + "(intPrimitive in [1:2])");
assertIsValid(className + "(intPrimitive in (1:2])");
assertIsValid(className + "(intPrimitive in (1:2))");
assertIsValid(className + "(intPrimitive in [1:2))");
assertIsValid(className + "(intPrimitive in (-34243232:+342342343])");
assertIsValid(className + "(longPrimitive in (-34243232L:+342342343l])");
assertIsValid(className + "(doublePrimitive in [1E20:-1])");
assertIsValid(className + "(doublePrimitive in [45775.2244502:1.345674))");
assertIsValid(className + "(longPrimitive in [ 1 : 2 ])");
assertIsValid(className + "(intPrimitive in [1:2], longPrimitive=3)");
assertIsValid(className + "(intPrimitive=3, theString=\"a2\", longPrimitive in [1:2], doubleBoxed=3)");
assertIsValid(className + "(intPrimitive in [2:10])");
assertIsValid(className + "(doubleBoxed in [-0.00001:-0.1E2])");
assertIsValid(className + "(doubleBoxed in [60.0:61.0])");
assertIsValid("e(a2>b3)");
assertIsValid("e(b3)");
assertIsValid("e(a2<d4)");
assertIsValid("e(a2<>8)");
assertIsValid("A(x(1) = 1)");
assertIsValid("A(x(aaa) = 1)");
// With name
assertIsValid("se1=" + className);
assertIsValid("er2=" + className + "(intPrimitive=444)");
assertIsValid("x3=" + className + "(intPrimitive in [1:2])");
assertIsValid("gamma=" + className + "(doubleBoxed in [-0.00001:-0.1E2])");
// Every
assertIsValid("every " + className);
assertIsValid("every " + className + "(string=\"b\",\nintPrimitive=3)");
assertIsValid("(every " + className + "())");
assertIsValid("every(" + className + "())");
assertIsValid("((every " + className + "()))");
assertIsValid("every(every((every " + className + "())))");
// Followed by
assertIsValid(className + "() -> " + className);
assertIsValid("every " + className + "() -> every " + className);
assertIsValid(className + "() -> every " + className);
assertIsValid("every " + className + "() -> " + className);
assertIsValid("every " + className + "() -> every " + className);
assertIsValid(className + "() -> " + className + "() -> " + className);
// Or
assertIsValid(className + "() or " + className);
assertIsValid(className + "() or " + className + "() or " + className);
assertIsValid(className + "() -> " + className + "() or " + className);
assertIsValid(className + "() -> " + className + "() -> " + className + "() or " + className);
assertIsValid("every " + className + "() -> every " + className + "() or every " + className);
// And
assertIsValid(className + " and " + className);
assertIsValid(className + " and " + className + " and " + className);
assertIsValid(className + " -> " + className + " and " + className);
assertIsValid(className + " -> " + className + " -> " + className + "() and " + className);
assertIsValid("every " + className + "() -> every " + className + "() and every " + className);
// Not
assertIsValid("not " + className);
assertIsValid("not (" + className + "())");
assertIsValid("every(not (" + className + "()))");
assertIsValid(className + "() and not " + className);
assertIsValid(className + "() and " + className + "() and not " + className);
assertIsValid("not " + className + "(intPrimitive=3) and " + className + "(doubleBoxed=3)");
assertIsValid("(" + className + "() -> " + className + "()) and not " + className);
assertIsValid("((" + className + "() and not " + className + "()) and not " + className + "())");
assertIsValid(className + "() and not (" + className + "() -> " + className + "())");
assertIsValid("every " + className + "() -> every " + className + "() and not " + className);
assertIsValid("(not " + className + "())");
assertIsValid("not (" + className + "())");
// where
assertIsValid(className + "() where a:b(5)");
assertIsValid(className + "() where a:b(100354)");
assertIsValid(className + "() where a:b(1595950)");
assertIsValid("(" + className + "()) where a:b(5)");
assertIsValid("every " + className + "() where a:b(45)");
assertIsValid("not (" + className + "()) where a:b(5)");
assertIsValid("every ((" + className + "())) where a:b(5)");
assertIsValid("(every " + className + "()) where a:b(1000000)");
assertIsValid("every ((every " + className + "(string=\"A1\")) where a:b(10))");
assertIsValid(className + "() -> " + className + "() where a:b(10)");
assertIsValid(className + "() -> (" + className + "() where a:b(10))");
assertIsValid(className + "() or " + className + "() where a:b(10)");
assertIsValid(className + "() or (" + className + "() where a:b(10))");
assertIsValid("((" + className + "() where a:b(10)) or (" + className + "() where a:b(5))) where a:b(15)");
// timer:interval
assertIsValid("timer:interval(5)");
assertIsValid("timer:interval(100354)");
assertIsValid("timer:interval(15959500354)");
assertIsValid("timer:interval(1595950)");
assertIsValid("(timer:interval(5))");
assertIsValid("every timer:interval(5)");
assertIsValid("not timer:interval(5)");
assertIsValid("every (timer:interval(10) where a:b(5))");
assertIsValid("every timer:interval(10) where a:b(10)");
assertIsValid("every ((every timer:interval(4)) where a:b(10))");
assertIsValid(className + "() -> timer:interval(10)");
assertIsValid("timer:interval(20) -> timer:interval(10)");
assertIsValid("timer:interval(20) -> " + className + "(intPrimitive=3)");
assertIsValid(className + "() -> every (timer:interval(10))");
assertIsValid("timer:interval(30) or " + className + "() where a:b(10)");
assertIsValid("timer:interval(30) or every timer:interval(40) where a:b(10)");
assertIsValid(className + "() or (timer:interval(30) where a:b(10))");
assertIsValid(className + "() and timer:interval(30)");
assertIsValid("((" + className + "() where a:b(10)) or (" + className + "() where a:b(5))) where a:b(15)");
// timer:at
assertIsValid("timer:at(*,*,*,*,*)");
assertIsValid("timer:at(*,*,*,*,*,*)");
assertIsValid("timer:at(10,20,10,10,1)");
assertIsValid("timer:at(0,00,1,1,0)");
assertIsValid("timer:at(*,1,*,1,*)");
assertIsValid("timer:at(1,0,*,11,1,0)");
assertIsValid("timer:at([1],*,*,*,*,[2,3])");
assertIsValid("timer:at([0,0,0,0,0, 0, 1],[3,5,7],[1],[1,2],[3,4],[2,3])");
assertIsValid("timer:at(6:10,*,*,*,*)");
assertIsValid("timer:at(6:10,1:2,1:4,2:3,0:0)");
assertIsValid("timer:at(00000:00000,*, 1 : 2 ,*,*,9:10)");
assertIsValid("timer:at(*/1, *, *, *, *)");
assertIsValid("timer:at(*/1, * / 5 , */ 1, */ 1 , */1010210993,*/7)");
assertIsValid("timer:at(40,3:12,[2,3],*,0:3)");
assertIsValid("timer:at([2, */1, 1:5], [6:6, 6:6], [*/2, */3], [2,*/2,2,2:2], *, *)");
// Custom EventObserver
assertIsValid("a:b()");
assertIsValid("a:b('a', 10, false, true, 20, 0.111, 1E6)");
// Use of results
assertIsValid("a=A() -> b=B(pb1=a.pa1)");
assertIsValid("a=A() -> b=B(pb1 = a.pa1)");
assertIsValid("a=A(x=y.a) -> b=B(pb1 = a.pa1, o=5, p=q.a)");
assertIsValid("a=A() -> b=B(pb1 in [a.p1 : a.p2])");
assertIsValid("a=A() -> b=B(pb1 in [100.1 : a.p2])");
assertIsValid("a=A() -> b=B(pb1 in [a.xx : 200])");
// Use of index, mapped, nested and combined properties
assertIsValid("A(x[0] = 1)");
assertIsValid("A(x[565656] = 1)");
assertIsValid("A(x[565656] = 1, y[2]=2)");
assertIsValid("A(x('home') = 1)");
assertIsValid("A(x.y = 1)");
assertIsValid("A(x.y.z = 1)");
assertIsValid("A(x[1].y('g').z('r').zz = 1)");
assertIsValid("A(x.y[11111].b.b = 1)");
assertIsValid("A(x('1') = 1)");
assertIsValid("A(x(\"1\") = 1)");
assertIsValid("B(a('aa').b.c[1].d.e(\"ee\")=2)");
assertIsValid("a=X -> b=Y(id=a.indexed[0])");
// intervals specs
assertIsValid("timer:interval(5 seconds)");
assertIsValid("timer:interval(5 seconds 3.3 milliseconds)");
assertIsValid("timer:interval(1 days 5 seconds 3.3 milliseconds)");
assertIsValid("timer:interval(1 days 3.3 milliseconds)");
assertIsValid("timer:interval(1 day 1E1 minute 3.3 milliseconds)");
assertIsValid("timer:interval(1.0001 hours 1E1 minute)");
assertIsValid("timer:interval(1.1 minute 2.2 seconds)");
assertIsValid("A where timer:within(5 seconds)");
assertIsValid("A where timer:within(1 days 1 milliseconds)");
assertIsValid("A where timer:within(100 days 0.00001 millisecond)");
assertIsValid("A where timer:within(100 hours 3 minutes 1.00001 millisecond)");
// match until
assertIsValid("A until B");
assertIsValid("every A until B");
assertIsValid("every (A until B)");
assertIsValid("every ((A where timer:within(10 sec)) until (B where timer:within(10 sec)))");
assertIsValid("(A or B) until (B or C)");
assertIsValid("(A -> B) until (B -> C)");
assertIsValid("(A and B) until (B and C)");
assertIsValid("(a=A until b=B) or (d=D until e=E)");
assertIsValid("a=A until b=B or d=D until e=E");
assertIsValid("((a=A or X=x) until (b=B)) -> ((d=D) until (e=E and e=E))");
assertIsValid("every (A until B)");
assertIsValid("A -> B until C -> D");
assertIsValid("B until C -> B until C -> B until C");
assertIsValid("(B until B1) until (D until C) -> E");
assertIsValid("[1] A until B");
assertIsValid("[1:] A until B");
assertIsValid("[1 :] A until B");
assertIsValid("[:2] A until B");
assertIsValid("[: 2] A until B");
assertIsValid("[0 : 10] A until B");
assertIsValid("[0:10] A until B");
assertIsValid("[0 : 10] A until B");
assertIsValid("[5] A"); // no until
// annotation
assertIsValid("@SomeTag(value='val', val2='val') [5] A");
//every-distinct
assertIsValid("every-distinct(value, bcd) A");
assertIsValid("every-distinct(value, bcd) [5] A");
}
public void testParserNodeGeneration() throws Exception
{
String expression = "a(m=1) -> not b() or every c() and d() where a:b (5) and timer:interval(10)";
log.debug(".testParserNodeGeneration parsing: " + expression);
Pair<Tree, CommonTokenStream> parsed = parse(expression);
Tree ast = parsed.getFirst();
SupportParserHelper.displayAST(ast);
assertTrue(ast.getType() == EsperEPL2GrammarParser.FOLLOWED_BY_EXPR);
// 2 Children: filter a and or-subexpression with the rest
assertTrue(ast.getChildCount() == 2);
assertEquals(EsperEPL2GrammarParser.PATTERN_FILTER_EXPR, ast.getChild(0).getChild(0).getType());
// Assert on or-subexpression
Tree orExpr = ast.getChild(1).getChild(0);
assertTrue(orExpr.getType() == EsperEPL2GrammarParser.OR_EXPR);
assertTrue(orExpr.getChildCount() == 2);
assertTrue(orExpr.getChild(0).getType() == EsperEPL2GrammarParser.PATTERN_NOT_EXPR);
assertTrue(orExpr.getChild(0).getChildCount() == 1);
assertTrue(orExpr.getChild(0).getChild(0).getType() == EsperEPL2GrammarParser.PATTERN_FILTER_EXPR);
// Assert on and-subexpression
Tree andExpr = orExpr.getChild(1);
assertTrue(andExpr.getType() == EsperEPL2GrammarParser.AND_EXPR);
assertTrue(andExpr.getChildCount() == 3);
assertTrue(andExpr.getChild(0).getType() == EsperEPL2GrammarParser.EVERY_EXPR);
assertTrue(andExpr.getChild(0).getChildCount() == 1);
assertTrue(andExpr.getChild(0).getChild(0).getType() == EsperEPL2GrammarParser.PATTERN_FILTER_EXPR);
// Assert on where a:b and timer:interval sub-expressions
Tree guardPostFix = andExpr.getChild(1);
assertTrue(guardPostFix.getChildCount() == 4);
assertTrue(guardPostFix.getChild(0).getType() == EsperEPL2GrammarParser.PATTERN_FILTER_EXPR);
assertTrue(guardPostFix.getChild(1).getType() == EsperEPL2GrammarParser.IDENT);
Tree timerIntervalExpr = andExpr.getChild(2);
assertTrue(timerIntervalExpr.getChildCount() == 3);
assertTrue(timerIntervalExpr.getChild(0).getType() == EsperEPL2GrammarParser.IDENT);
// The tree generated....
/*
followedByExpression [18]
filterExpression [15]
a [17]
= [49]
m [41]
1 [24]
orExpression [6]
not [8]
filterExpression [15]
b [17]
andExpression [7]
every [9]
filterExpression [15]
c [17]
guardPostFix [19]
filterExpression [15]
d [17]
a [41]
b [41]
5 [24]
observerExpression [22]
timer [41]
interval [41]
10 [24]
*/
}
//
private void assertIsValid(String text) throws Exception
{
log.debug(".assertIsValid Trying text=" + text);
Pair<Tree, CommonTokenStream> ast = parse(text);
log.debug(".assertIsValid success, tree walking...");
SupportParserHelper.displayAST(ast.getFirst());
log.debug(".assertIsValid done");
}
private void assertIsInvalid(String text) throws Exception
{
log.debug(".assertIsInvalid Trying text=" + text);
try
{
parse(text);
assertFalse(true);
}
catch (Exception ex)
{
log.debug(".assertIsInvalid Expected ParseException exception was thrown and ignored, message=" + ex.getMessage());
}
}
private Pair<Tree, CommonTokenStream> parse(String expression) throws Exception
{
return SupportParserHelper.parsePattern(expression);
}
static Log log = LogFactory.getLog(TestEventPatternParser.class);
}