add tests, fix tests, fix bugs

This commit is contained in:
Matt Jaffee 2018-06-15 15:02:41 -05:00
parent 4b856bea55
commit 23bca175ae
No known key found for this signature in database
GPG key ID: 08A3DFFF987B11BF
4 changed files with 617 additions and 294 deletions

View file

@ -135,7 +135,7 @@ func TestParser_Parse(t *testing.T) {
// Parse with both child calls and arguments.
t.Run("ChildrenAndArguments", func(t *testing.T) {
q, err := pql.ParseString(`TopN(Bitmap(id=100, field=other), field=f, n=3)`)
q, err := pql.ParseString(`TopN(f, Bitmap(id=100, field=other), n=3)`)
if err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(q.Calls[0],
@ -145,7 +145,7 @@ func TestParser_Parse(t *testing.T) {
Name: "Bitmap",
Args: map[string]interface{}{"id": int64(100), "field": "other"},
}},
Args: map[string]interface{}{"n": int64(3), "field": "f"},
Args: map[string]interface{}{"n": int64(3), "_field": "f"},
},
) {
t.Fatalf("unexpected call: %#v", q.Calls[0])
@ -154,15 +154,15 @@ func TestParser_Parse(t *testing.T) {
// Parse a list argument.
t.Run("ListArgument", func(t *testing.T) {
q, err := pql.ParseString(`TopN(field="f", ids=[0,10,30])`)
q, err := pql.ParseString(`TopN(f, ids=[0,10,30])`)
if err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(q.Calls[0],
&pql.Call{
Name: "TopN",
Args: map[string]interface{}{
"field": "f",
"ids": []interface{}{int64(0), int64(10), int64(30)},
"_field": "f",
"ids": []interface{}{int64(0), int64(10), int64(30)},
},
},
) {

View file

@ -9,11 +9,11 @@ Calls <- whitesp (Call whitesp)* !.
Call <- 'Set' {p.startCall("Set")} open uintcol comma args (comma timestamp)? close {p.endCall()}
/ 'SetRowAttrs' {p.startCall("SetRowAttrs")} open posfield comma uintrow comma args close {p.endCall()}
/ 'SetColAttrs' {p.startCall("SetColAttrs")} open posfield comma uintcol comma args close {p.endCall()}
/ 'ClearBit' {p.startCall("ClearBit")} open uintcol comma args close {p.endCall()}
/ 'TopN' {p.startCall("TopN")} open posfield (comma args)? close {p.endCall()}
/ 'Clear' {p.startCall("Clear")} open uintcol comma args close {p.endCall()}
/ 'TopN' {p.startCall("TopN")} open posfield (comma allargs)? close {p.endCall()}
/ 'Range' {p.startCall("Range")} open (arg / conditional) close {p.endCall()}
/ < IDENT > { p.startCall(buffer[begin:end] ) } open allargs comma? close { p.endCall() }
allargs <- Call (comma Call)* (comma args)? / comma? args / sp
allargs <- Call (comma Call)* (comma args)? / args / sp
args <- arg (comma args)? sp
arg <- ( field sp '=' sp value
/ field sp COND sp value
@ -27,7 +27,6 @@ COND <- ( '><' { p.addBTWN() }
/ '>' { p.addGT() }
)
conditional <- {p.startConditional()} int ('<=' / '<') fieldExpr ('<=' / '<') int {p.endConditional()}
open <- '(' sp
value <- ( item
/ lbrack { p.startList() } list rbrack { p.endList() }
)
@ -53,12 +52,13 @@ int <- '-'? [1-9] [0-9]* / '0'
uintrow <- <uint>{p.addPosNum("_row", buffer[begin:end])}
uintcol <- <uint>{p.addPosNum("_col", buffer[begin:end])}
open <- '(' sp
close <- ')' sp
sp <- ( ' ' / '\t' )*
comma <- sp ',' whitesp
lbrack <- '[' sp
rbrack <- sp ']' sp
whitesp <- ( ' ' / '\t' / '\n' )*
IDENT <- [[A-Z]] ([[A-Z]] / [0-9] / '-' / '_' / '.')*
IDENT <- !('Set(' / 'SetRowAttrs(' / 'SetColAttrs(' / 'Clear(' / 'TopN(' / 'Range(') [[A-Z]] ([[A-Z]] / [0-9])*
timestamp <- <[0-9][0-9][0-9][0-9]'-'[01][0-9]'-'[0-3][0-9]'T'[0-9][0-9]':'[0-9][0-9]> {p.addPosStr("_timestamp", buffer[begin:end])}

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,13 @@
package pql
import (
"strconv"
"testing"
)
func TestPEG(t *testing.T) {
p := PQL{Buffer: `
SetBit(Union(Zitmap(row==4), Intersect(Qitmap(blah>4), Ritmap(field="http://zoo9.com=\\'hello' and \"hello\"")), Hitmap(row=ag-bee)), a="4z", b=5) Count(Union(Witmap(row=5.73, frame=.10), Range(zztop><[2, 9]))) TopN(fields=["hello", "goodbye", "zero"])`[1:]}
SetBit(Union(Zitmap(row==4), Intersect(Qitmap(blah>4), Ritmap(field="http://zoo9.com=\\'hello' and \"hello\"")), Hitmap(row=ag-bee)), a="4z", b=5) Count(Union(Witmap(row=5.73, frame=.10), Range(zztop><[2, 9]))) TopN(blah, fields=["hello", "goodbye", "zero"])`[1:]}
p.Init()
err := p.Parse()
if err != nil {
@ -21,11 +22,11 @@ SetBit(Union(Zitmap(row==4), Intersect(Qitmap(blah>4), Ritmap(field="http://zoo9
t.Fatalf("should have been an error because of the interior unescaped double quote")
}
q, err := ParseString("TopN(Bitmap(id==other), field=f, n=0)")
q, err := ParseString("TopN(blah, Bitmap(id==other), field=f, n=0)")
if err != nil {
t.Fatalf("should have parsed: %v", err)
}
if q.String() != `TopN(Bitmap(id == "other"), field="f", n=0)` {
if q.String() != `TopN(Bitmap(id == "other"), _field="blah", field="f", n=0)` {
t.Fatalf("Failed, got: %s", q)
}
@ -44,3 +45,154 @@ SetBit(Union(Zitmap(row==4), Intersect(Qitmap(blah>4), Ritmap(field="http://zoo9
}
}
func TestPEGWorking(t *testing.T) {
tests := []struct {
name string
input string
ncalls int
}{
{
name: "Empty",
input: "",
ncalls: 0},
{
name: "Set",
input: "Set(1, a=4)",
ncalls: 1},
{
name: "DoubleSet",
input: "Set(1, a=4)Set(2, a=4)",
ncalls: 2},
{
name: "DoubleSetSpc",
input: "Set(1, a=4) Set(2, a=4)",
ncalls: 2},
{
name: "DoubleSetNewline",
input: "Set(1, a=4) \n Set(2, a=4)",
ncalls: 2},
{
name: "SetWithArbCall",
input: "Set(1, a=4)Blerg(z=ha)",
ncalls: 2},
{
name: "SetArbSet",
input: "Set(1, a=4)Blerg(z=ha)Set(2, z=99)",
ncalls: 3},
{
name: "ArbSetArb",
input: "Arb(q=1, a=4)Set(1, z=9)Arb(z=99)",
ncalls: 3},
{
name: "SetStringArg",
input: "Set(1, a=zoom)",
ncalls: 1},
{
name: "SetManyArgs",
input: "Set(1, a=4, b=5)",
ncalls: 1},
{
name: "SetManyMixedArgs",
input: "Set(1, a=4, bsd=haha)",
ncalls: 1},
{
name: "SetTimestamp",
input: "Set(1, a=4, 2017-04-03T19:34)",
ncalls: 1},
{
name: "Union()",
input: "Union()",
ncalls: 1},
{
name: "UnionOneRow",
input: "Union(Row(a=1))",
ncalls: 1},
{
name: "UnionTwoRows",
input: "Union(Row(a=1), Row(z=44))",
ncalls: 1},
{
name: "UnionNested",
input: "Union(Intersect(Row(), Union(Row(), Row())), Row())",
ncalls: 1},
{
name: "TopN no args",
input: "TopN(boondoggle)",
ncalls: 1},
{
name: "TopN with args",
input: "TopN(boon, doggle=9)",
ncalls: 1},
{
name: "double quoted args",
input: `B(a="zm''e")`,
ncalls: 1},
{
name: "single quoted args",
input: `B(a='zm""e')`,
ncalls: 1},
}
for i, test := range tests {
t.Run(test.name+strconv.Itoa(i), func(t *testing.T) {
q, err := ParseString(test.input)
if err != nil {
t.Fatalf("parsing query '%s': %v", test.input, err)
}
if len(q.Calls) != test.ncalls {
t.Fatalf("wrong number of calls for '%s': %#v", test.input, q.Calls)
}
})
}
}
func TestPEGErrors(t *testing.T) {
tests := []struct {
name string
input string
}{
{
name: "SetEmpty",
input: "Set()"},
{
name: "SetNoCol",
input: "Set(a=4)"},
{
name: "SetNoParens",
input: "Set"},
{
name: "SetBadTimestamp",
input: "Set(1, a=4, 2017-94-03T19:34)"},
{
name: "SetTimestampNoArg",
input: "Set(1, 2017-04-03T19:34)"},
{
name: "SetRowAttrsNoField",
input: "SetRowAttrs(a=4)"},
{
name: "SetColAttrsNoField",
input: "SetColAttrs(a=4)"},
{
name: "ClearNoCol",
input: "Clear(a=4)"},
{
name: "SetStartingComma",
input: "Set(, 1, a=4)"},
{
name: "StartinCommaArb",
input: "Zeeb(, a=4)"},
{
name: "TopN No Field",
input: "TopN(a=77)"},
}
for i, test := range tests {
t.Run(test.name+strconv.Itoa(i), func(t *testing.T) {
q, err := ParseString(test.input)
if err == nil {
t.Fatalf("parsing query '%s' - expected error, got: %s", test.input, q)
}
})
}
}