diff --git a/internal/server/token.go b/internal/server/token.go index d1397fe6..e7b94d2f 100644 --- a/internal/server/token.go +++ b/internal/server/token.go @@ -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) { ps := &parentStack{} vsout = vsin[:] - var negate bool + var negate, needObj bool loop: for { nvs, wtok, ok := tokenval(vsout) @@ -723,6 +723,7 @@ loop: case tokenLParen: newExpr := &areaExpression{negate: negate, op: NOOP} negate = false + needObj = false if ae != nil { ae.children = append(ae.children, newExpr) } @@ -730,8 +731,8 @@ loop: ps.push(ae) vsout = nvs case tokenRParen: - if negate { - err = errInvalidArgument(tokenNOT) + if needObj { + err = errInvalidArgument(tokenRParen) return } if parent, empty := ps.pop(); empty { @@ -743,12 +744,14 @@ loop: vsout = nvs case tokenNOT: negate = true + needObj = true vsout = nvs case tokenAND: - if negate { - err = errInvalidArgument(tokenNOT) + if needObj { + err = errInvalidArgument(tokenAND) return } + needObj = true if ae == nil { err = errInvalidArgument(tokenAND) return @@ -774,10 +777,11 @@ loop: } vsout = nvs case tokenOR: - if negate { - err = errInvalidArgument(tokenNOT) + if needObj { + err = errInvalidArgument(tokenOR) return } + needObj = true if ae == nil { err = errInvalidArgument(tokenOR) return @@ -804,6 +808,7 @@ loop: } else { newExpr := &areaExpression{negate: negate, obj: parsedObj, op: NOOP} negate = false + needObj = false if ae == nil { ae = newExpr } else { @@ -812,12 +817,15 @@ loop: vsout = parsedVs } default: - if negate { - err = errInvalidArgument(tokenNOT) + if needObj { + err = errInvalidArgument(wtok) return } break loop } } + if !ps.isEmpty() || needObj || ae == nil || (ae.obj == nil && len(ae.children) == 0) { + err = errInvalidNumberOfArguments + } return } diff --git a/tests/testcmd_test.go b/tests/testcmd_test.go index 9cb833b0..82d6a4c6 100644 --- a/tests/testcmd_test.go +++ b/tests/testcmd_test.go @@ -8,6 +8,7 @@ func subTestTestCmd(t *testing.T, mc *mockServer) { runStep(t, mc, "WITHIN", testcmd_WITHIN_test) runStep(t, mc, "INTERSECTS", testcmd_INTERSECTS_test) runStep(t, mc, "INTERSECTS_CLIP", testcmd_INTERSECTS_CLIP_test) + runStep(t, mc, "ExpressionErrors", testcmd_expressionErrors_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 { poly := `{ "type": "Polygon",