mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Replace lexer, add parser
This commit is contained in:
216
pkg/search/parser_test.go
Normal file
216
pkg/search/parser_test.go
Normal file
@ -0,0 +1,216 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedExpression Expression
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "empty query",
|
||||
input: "",
|
||||
expectedExpression: nil,
|
||||
expectedError: errors.New("unexpected EOF"),
|
||||
},
|
||||
{
|
||||
name: "string literal expression",
|
||||
input: "foobar",
|
||||
expectedExpression: &StringLiteral{Value: "foobar"},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with equal operator",
|
||||
input: "foo = bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpEq,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with not equal operator",
|
||||
input: "foo != bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpNotEq,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with greater than operator",
|
||||
input: "foo > bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpGt,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with less than operator",
|
||||
input: "foo < bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpLt,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with greater than or equal operator",
|
||||
input: "foo >= bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpGtEq,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with less than or equal operator",
|
||||
input: "foo <= bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpLtEq,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with regular expression operator",
|
||||
input: "foo =~ bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpRe,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with not regular expression operator",
|
||||
input: "foo !~ bar",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpNotRe,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with AND, OR and NOT operators",
|
||||
input: "foo AND bar OR NOT baz",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &InfixExpression{
|
||||
Operator: TokOpOr,
|
||||
Left: &StringLiteral{Value: "bar"},
|
||||
Right: &PrefixExpression{
|
||||
Operator: TokOpNot,
|
||||
Right: &StringLiteral{Value: "baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "boolean expression with nested group",
|
||||
input: "(foo AND bar) OR NOT baz",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpOr,
|
||||
Left: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
Right: &PrefixExpression{
|
||||
Operator: TokOpNot,
|
||||
Right: &StringLiteral{Value: "baz"},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "implicit boolean expression with string literal operands",
|
||||
input: "foo bar baz",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
Right: &StringLiteral{Value: "baz"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "implicit and explicit boolean expression with string literal operands",
|
||||
input: "foo bar OR baz yolo",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &InfixExpression{
|
||||
Operator: TokOpOr,
|
||||
Left: &StringLiteral{Value: "bar"},
|
||||
Right: &StringLiteral{Value: "baz"},
|
||||
},
|
||||
},
|
||||
Right: &StringLiteral{Value: "yolo"},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "implicit boolean expression with comparison operands",
|
||||
input: "foo=bar baz=~yolo",
|
||||
expectedExpression: &InfixExpression{
|
||||
Operator: TokOpAnd,
|
||||
Left: &InfixExpression{
|
||||
Operator: TokOpEq,
|
||||
Left: &StringLiteral{Value: "foo"},
|
||||
Right: &StringLiteral{Value: "bar"},
|
||||
},
|
||||
Right: &InfixExpression{
|
||||
Operator: TokOpRe,
|
||||
Left: &StringLiteral{Value: "baz"},
|
||||
Right: &StringLiteral{Value: "yolo"},
|
||||
},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := ParseQuery(tt.input)
|
||||
assertError(t, tt.expectedError, err)
|
||||
if !reflect.DeepEqual(tt.expectedExpression, got) {
|
||||
t.Errorf("expected: %v, got: %v", tt.expectedExpression, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertError(t *testing.T, exp, got error) {
|
||||
switch {
|
||||
case exp == nil && got != nil:
|
||||
t.Fatalf("expected: nil, got: %v", got)
|
||||
case exp != nil && got == nil:
|
||||
t.Fatalf("expected: %v, got: nil", exp.Error())
|
||||
case exp != nil && got != nil && exp.Error() != got.Error():
|
||||
t.Fatalf("expected: %v, got: %v", exp.Error(), got.Error())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user