Add expression errors test. Make parser stricter.

This commit is contained in:
Alex Roitman 2019-06-13 13:10:47 -07:00
parent 0c3a5d02ca
commit 2d83e18934
2 changed files with 52 additions and 9 deletions

View File

@ -712,7 +712,7 @@ func (ps *parentStack) pop() (e *areaExpression, empty bool) {
func (s *Server) parseAreaExpression(vsin []string, doClip bool) (vsout []string, ae *areaExpression, err error) { func (s *Server) parseAreaExpression(vsin []string, doClip bool) (vsout []string, ae *areaExpression, err error) {
ps := &parentStack{} ps := &parentStack{}
vsout = vsin[:] vsout = vsin[:]
var negate bool var negate, needObj bool
loop: loop:
for { for {
nvs, wtok, ok := tokenval(vsout) nvs, wtok, ok := tokenval(vsout)
@ -723,6 +723,7 @@ loop:
case tokenLParen: case tokenLParen:
newExpr := &areaExpression{negate: negate, op: NOOP} newExpr := &areaExpression{negate: negate, op: NOOP}
negate = false negate = false
needObj = false
if ae != nil { if ae != nil {
ae.children = append(ae.children, newExpr) ae.children = append(ae.children, newExpr)
} }
@ -730,8 +731,8 @@ loop:
ps.push(ae) ps.push(ae)
vsout = nvs vsout = nvs
case tokenRParen: case tokenRParen:
if negate { if needObj {
err = errInvalidArgument(tokenNOT) err = errInvalidArgument(tokenRParen)
return return
} }
if parent, empty := ps.pop(); empty { if parent, empty := ps.pop(); empty {
@ -743,12 +744,14 @@ loop:
vsout = nvs vsout = nvs
case tokenNOT: case tokenNOT:
negate = true negate = true
needObj = true
vsout = nvs vsout = nvs
case tokenAND: case tokenAND:
if negate { if needObj {
err = errInvalidArgument(tokenNOT) err = errInvalidArgument(tokenAND)
return return
} }
needObj = true
if ae == nil { if ae == nil {
err = errInvalidArgument(tokenAND) err = errInvalidArgument(tokenAND)
return return
@ -774,10 +777,11 @@ loop:
} }
vsout = nvs vsout = nvs
case tokenOR: case tokenOR:
if negate { if needObj {
err = errInvalidArgument(tokenNOT) err = errInvalidArgument(tokenOR)
return return
} }
needObj = true
if ae == nil { if ae == nil {
err = errInvalidArgument(tokenOR) err = errInvalidArgument(tokenOR)
return return
@ -804,6 +808,7 @@ loop:
} else { } else {
newExpr := &areaExpression{negate: negate, obj: parsedObj, op: NOOP} newExpr := &areaExpression{negate: negate, obj: parsedObj, op: NOOP}
negate = false negate = false
needObj = false
if ae == nil { if ae == nil {
ae = newExpr ae = newExpr
} else { } else {
@ -812,12 +817,15 @@ loop:
vsout = parsedVs vsout = parsedVs
} }
default: default:
if negate { if needObj {
err = errInvalidArgument(tokenNOT) err = errInvalidArgument(wtok)
return return
} }
break loop break loop
} }
} }
if !ps.isEmpty() || needObj || ae == nil || (ae.obj == nil && len(ae.children) == 0) {
err = errInvalidNumberOfArguments
}
return return
} }

View File

@ -8,6 +8,7 @@ func subTestTestCmd(t *testing.T, mc *mockServer) {
runStep(t, mc, "WITHIN", testcmd_WITHIN_test) runStep(t, mc, "WITHIN", testcmd_WITHIN_test)
runStep(t, mc, "INTERSECTS", testcmd_INTERSECTS_test) runStep(t, mc, "INTERSECTS", testcmd_INTERSECTS_test)
runStep(t, mc, "INTERSECTS_CLIP", testcmd_INTERSECTS_CLIP_test) runStep(t, mc, "INTERSECTS_CLIP", testcmd_INTERSECTS_CLIP_test)
runStep(t, mc, "ExpressionErrors", testcmd_expressionErrors_test)
runStep(t, mc, "Expressions", testcmd_expression_test) runStep(t, mc, "Expressions", testcmd_expression_test)
} }
@ -117,6 +118,40 @@ func testcmd_INTERSECTS_CLIP_test(mc *mockServer) error {
}) })
} }
func testcmd_expressionErrors_test(mc *mockServer) error {
return mc.DoBatch([][]interface{}{
{"SET", "mykey", "foo", "OBJECT", `{"type":"LineString","coordinates":[[-122.4408378,37.7341129],[-122.4408378,37.733]]}`}, {"OK"},
{"SET", "mykey", "bar", "OBJECT", `{"type":"LineString","coordinates":[[-122.4408378,37.7341129],[-122.4408378,37.733]]}`}, {"OK"},
{"SET", "mykey", "baz", "OBJECT", `{"type":"LineString","coordinates":[[-122.4408378,37.7341129],[-122.4408378,37.733]]}`}, {"OK"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "(", "GET", "mykey", "bar"}, {
"ERR wrong number of arguments for 'test' command"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", ")"}, {
"ERR invalid argument ')'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "OR", "GET", "mykey", "bar"}, {
"ERR invalid argument 'or'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "AND", "GET", "mykey", "bar"}, {
"ERR invalid argument 'and'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "OR", "AND", "GET", "mykey", "baz"}, {
"ERR invalid argument 'and'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "AND", "OR", "GET", "mykey", "baz"}, {
"ERR invalid argument 'or'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "OR", "OR", "GET", "mykey", "baz"}, {
"ERR invalid argument 'or'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "AND", "AND", "GET", "mykey", "baz"}, {
"ERR invalid argument 'and'"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "OR"}, {
"ERR wrong number of arguments for 'test' command"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "AND"}, {
"ERR wrong number of arguments for 'test' command"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "NOT"}, {
"ERR wrong number of arguments for 'test' command"},
{"TEST", "GET", "mykey", "foo", "INTERSECTS", "GET", "mykey", "bar", "NOT", "AND", "GET", "mykey", "baz"}, {
"ERR invalid argument 'and'"},
})
}
func testcmd_expression_test(mc *mockServer) error { func testcmd_expression_test(mc *mockServer) error {
poly := `{ poly := `{
"type": "Polygon", "type": "Polygon",