From 0e9fb0ac91e7db21f2415d520d8aad3890dd1497 Mon Sep 17 00:00:00 2001 From: David Stotijn Date: Wed, 23 Mar 2022 15:39:45 +0100 Subject: [PATCH] Add tests for `search.Expression` interface implementations --- pkg/search/ast_test.go | 212 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 pkg/search/ast_test.go diff --git a/pkg/search/ast_test.go b/pkg/search/ast_test.go new file mode 100644 index 0000000..e81cdd8 --- /dev/null +++ b/pkg/search/ast_test.go @@ -0,0 +1,212 @@ +package search_test + +import ( + "regexp" + "testing" + + "github.com/dstotijn/hetty/pkg/search" +) + +func TestExpressionString(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + expression search.Expression + expected string + }{ + { + name: "string literal expression", + expression: search.StringLiteral{Value: "foobar"}, + expected: `"foobar"`, + }, + { + name: "boolean expression with equal operator", + expression: search.InfixExpression{ + Operator: search.TokOpEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" = "bar")`, + }, + { + name: "boolean expression with not equal operator", + expression: search.InfixExpression{ + Operator: search.TokOpNotEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" != "bar")`, + }, + { + name: "boolean expression with greater than operator", + expression: search.InfixExpression{ + Operator: search.TokOpGt, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" > "bar")`, + }, + { + name: "boolean expression with less than operator", + expression: search.InfixExpression{ + Operator: search.TokOpLt, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" < "bar")`, + }, + { + name: "boolean expression with greater than or equal operator", + expression: search.InfixExpression{ + Operator: search.TokOpGtEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" >= "bar")`, + }, + { + name: "boolean expression with less than or equal operator", + expression: search.InfixExpression{ + Operator: search.TokOpLtEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" <= "bar")`, + }, + { + name: "boolean expression with regular expression operator", + expression: search.InfixExpression{ + Operator: search.TokOpRe, + Left: search.StringLiteral{Value: "foo"}, + Right: search.RegexpLiteral{regexp.MustCompile("bar")}, + }, + expected: `("foo" =~ "bar")`, + }, + { + name: "boolean expression with not regular expression operator", + expression: search.InfixExpression{ + Operator: search.TokOpNotRe, + Left: search.StringLiteral{Value: "foo"}, + Right: search.RegexpLiteral{regexp.MustCompile("bar")}, + }, + expected: `("foo" !~ "bar")`, + }, + { + name: "boolean expression with AND, OR and NOT operators", + expression: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.StringLiteral{Value: "foo"}, + Right: search.InfixExpression{ + Operator: search.TokOpOr, + Left: search.StringLiteral{Value: "bar"}, + Right: search.PrefixExpression{ + Operator: search.TokOpNot, + Right: search.StringLiteral{Value: "baz"}, + }, + }, + }, + expected: `("foo" AND ("bar" OR (NOT "baz")))`, + }, + { + name: "boolean expression with nested group", + expression: search.InfixExpression{ + Operator: search.TokOpOr, + Left: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + Right: search.PrefixExpression{ + Operator: search.TokOpNot, + Right: search.StringLiteral{Value: "baz"}, + }, + }, + expected: `(("foo" AND "bar") OR (NOT "baz"))`, + }, + { + name: "implicit boolean expression with string literal operands", + expression: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + Right: search.StringLiteral{Value: "baz"}, + }, + expected: `(("foo" AND "bar") AND "baz")`, + }, + { + name: "implicit boolean expression nested in group", + expression: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + expected: `("foo" AND "bar")`, + }, + { + name: "implicit and explicit boolean expression with string literal operands", + expression: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.StringLiteral{Value: "foo"}, + Right: search.InfixExpression{ + Operator: search.TokOpOr, + Left: search.StringLiteral{Value: "bar"}, + Right: search.StringLiteral{Value: "baz"}, + }, + }, + Right: search.StringLiteral{Value: "yolo"}, + }, + expected: `(("foo" AND ("bar" OR "baz")) AND "yolo")`, + }, + { + name: "implicit boolean expression with comparison operands", + expression: search.InfixExpression{ + Operator: search.TokOpAnd, + Left: search.InfixExpression{ + Operator: search.TokOpEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + Right: search.InfixExpression{ + Operator: search.TokOpRe, + Left: search.StringLiteral{Value: "baz"}, + Right: search.RegexpLiteral{regexp.MustCompile("yolo")}, + }, + }, + expected: `(("foo" = "bar") AND ("baz" =~ "yolo"))`, + }, + { + name: "eq operator takes precedence over boolean ops", + expression: search.InfixExpression{ + Operator: search.TokOpOr, + Left: search.InfixExpression{ + Operator: search.TokOpEq, + Left: search.StringLiteral{Value: "foo"}, + Right: search.StringLiteral{Value: "bar"}, + }, + Right: search.InfixExpression{ + Operator: search.TokOpEq, + Left: search.StringLiteral{Value: "baz"}, + Right: search.StringLiteral{Value: "yolo"}, + }, + }, + expected: `(("foo" = "bar") OR ("baz" = "yolo"))`, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := tt.expression.String() + if tt.expected != got { + t.Errorf("expected: %v, got: %v", tt.expected, got) + } + }) + } +}