From 7af03f71c7fcc10de0b2c30c3d293be280747dd3 Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Tue, 2 May 2023 09:46:55 +0200 Subject: [PATCH] Add extended filter/parser tests & adjust expected error messages --- internal/filter/parser_test.go | 186 ++++++++++++++++++++++++++++----- 1 file changed, 157 insertions(+), 29 deletions(-) diff --git a/internal/filter/parser_test.go b/internal/filter/parser_test.go index da936f30d..b950adc6a 100644 --- a/internal/filter/parser_test.go +++ b/internal/filter/parser_test.go @@ -10,49 +10,71 @@ func TestParser(t *testing.T) { t.Parallel() t.Run("MissingLogicalOperatorsAfterConditionsAreDetected", func(t *testing.T) { - _, err := ParseFilter("(a=b|c=d)e=f") + rule, err := ParseFilter("(a=b|c=d)e=f") - expected := "invalid filter '(a=b|c=d)e=f', unexpected e at pos 10: Expected logical operator" + assert.Equal(t, rule, nil) + expected := "invalid filter '(a=b|c=d)e=f', missing logical operator at pos 10" assert.EqualError(t, err, expected, "Errors should be the same") }) t.Run("MissingLogicalOperatorsAfterOperatorsAreDetected", func(t *testing.T) { _, err := ParseFilter("(a=b|c=d|)e=f") - expected := "invalid filter '(a=b|c=d|)e=f', unexpected e at pos 11: Expected logical operator" + expected := "invalid filter '(a=b|c=d|)e=f', unexpected logical operator \"|\" at pos 9" assert.EqualError(t, err, expected, "Errors should be the same") }) - t.Run("ParserIdentifiesInvalidExpression", func(t *testing.T) { + t.Run("ParserIdentifiesInvalidFilters", func(t *testing.T) { _, err := ParseFilter("col=(") - assert.EqualError(t, err, "invalid filter 'col=(', unexpected ( at pos 5", "Errors should be the same") + assert.EqualError(t, err, "invalid filter 'col=(', unexpected \"(\" at pos 4", "Errors should be the same") _, err = ParseFilter("(((x=a)&y=b") - assert.EqualError(t, err, "invalid filter '(((x=a)&y=b', missing 2 closing ')' at pos 11", "Errors should be the same") + assert.EqualError(t, err, "invalid filter '(((x=a)&y=b', mismatching opening and closing parentheses", "Errors should be the same") _, err = ParseFilter("(x=a)&y=b)") - assert.EqualError(t, err, "invalid filter '(x=a)&y=b)', unexpected ) at pos 10", "Errors should be the same") + assert.EqualError(t, err, "invalid filter '(x=a)&y=b)', unexpected \")\" at pos 10", "Errors should be the same") _, err = ParseFilter("!(&") - assert.EqualError(t, err, "invalid filter '!(&', unexpected & at pos 3", "Errors should be the same") - - _, err = ParseFilter("!(!&") - assert.EqualError(t, err, "invalid filter '!(!&', unexpected & at pos 4: operator level 1", "Errors should be the same") - - _, err = ParseFilter("!(|test") - assert.EqualError(t, err, "invalid filter '!(|test', unexpected | at pos 3", "Errors should be the same") + assert.EqualError(t, err, "invalid filter '!(&', unexpected logical operator \"&\" at pos 3", "Errors should be the same") _, err = ParseFilter("foo&bar=(te(st)") - assert.EqualError(t, err, "invalid filter 'foo&bar=(te(st)', unexpected ( at pos 9", "Errors should be the same") + assert.EqualError(t, err, "invalid filter 'foo&bar=(te(st)', unexpected \"(\" at pos 8", "Errors should be the same") _, err = ParseFilter("foo&bar=te(st)") - assert.EqualError(t, err, "invalid filter 'foo&bar=te(st)', unexpected ( at pos 11", "Errors should be the same") + assert.EqualError(t, err, "invalid filter 'foo&bar=te(st)', missing logical operator at pos 12", "Errors should be the same") _, err = ParseFilter("foo&bar=test)") - assert.EqualError(t, err, "invalid filter 'foo&bar=test)', unexpected ) at pos 13", "Errors should be the same") + assert.EqualError(t, err, "invalid filter 'foo&bar=test)', unexpected \")\" at pos 13", "Errors should be the same") _, err = ParseFilter("!()|&()&)") - assert.EqualError(t, err, "invalid filter '!()|&()&)', unexpected closing ')' at pos 9", "Errors should be the same") + assert.EqualError(t, err, "invalid filter '!()|&()&)', empty filter groups are not allowed at pos 2", "Errors should be the same") + + _, err = ParseFilter("=foo") + assert.EqualError(t, err, "invalid filter '=foo', unexpected binary \"=\" operator at pos 0") + + _, err = ParseFilter("foo>") + assert.EqualError(t, err, "invalid filter 'foo>', unexpected binary \">\" operator at pos 4") + + _, err = ParseFilter("foo==") + assert.EqualError(t, err, "invalid filter 'foo==', unsupported operator \"==\" at pos 4") + + _, err = ParseFilter("=>foo") + assert.EqualError(t, err, "invalid filter '=>foo', unsupported operator \"=>\" at pos 1") + + _, err = ParseFilter("&foo") + assert.EqualError(t, err, "invalid filter '&foo', unexpected logical operator \"&\" at pos 1") + + _, err = ParseFilter("&&foo") + assert.EqualError(t, err, "invalid filter '&&foo', unsupported logical operator \"&&\" at pos 1") + + _, err = ParseFilter("(&foo=bar)") + assert.EqualError(t, err, "invalid filter '(&foo=bar)', unexpected logical operator \"&\" at pos 2") + + _, err = ParseFilter("(foo=bar|)") + assert.EqualError(t, err, "invalid filter '(foo=bar|)', unexpected logical operator \"|\" at pos 9") + + _, err = ParseFilter("((((((") + assert.EqualError(t, err, "invalid filter '((((((', too many opening parentheses") }) } @@ -107,35 +129,141 @@ func TestFilter(t *testing.T) { rule, err = ParseFilter("!foo") assert.Nil(t, err, "There should be no errors but got: %s", err) + rule, err = ParseFilter("foo") exists, _ := NewExists("foo") + assert.Nil(t, err, "There should be no errors but got: %s", err) + assert.Equal(t, exists, rule) + + rule, err = ParseFilter("!foo") + exists, _ = NewExists("foo") + assert.Nil(t, err, "There should be no errors but got: %s", err) assert.Equal(t, &None{rules: []Filter{exists}}, rule) - rule, err = ParseFilter("foo") + rule, err = ParseFilter("!foo=bar") assert.Nil(t, err, "There should be no errors but got: %s", err) - assert.Equal(t, exists, rule) + assert.Equal(t, &None{rules: []Filter{&Equal{column: "foo", value: "bar"}}}, rule) + }) + + t.Run("ParseFilterChain", func(t *testing.T) { + rule, err := ParseFilter("(foo=bar)") + assert.Nil(t, err, "There should be no errors but got: %s", err) + assert.Equal(t, &Equal{column: "foo", value: "bar"}, rule) + + rule, err = ParseFilter("(!foo=bar)") + assert.Nil(t, err, "There should be no errors but got: %s", err) + none := &None{rules: []Filter{ + &Equal{column: "foo", value: "bar"}, + }} + assert.Equal(t, none, rule) + + rule, err = ParseFilter("!(foo=bar)") + assert.Nil(t, err, "There should be no errors but got: %s", err) + none = &None{rules: []Filter{ + &Equal{column: "foo", value: "bar"}, + }} + assert.Equal(t, none, rule) + + rule, err = ParseFilter("!(!foo=bar)") + assert.Nil(t, err, "There should be no errors but got: %s", err) + none = &None{rules: []Filter{ + &None{rules: []Filter{&Equal{column: "foo", value: "bar"}}}, + }} + assert.Equal(t, none, rule) + + rule, err = ParseFilter("((!foo=bar)&bar!=foo)") + assert.Nil(t, err, "There should be no errors but got: %s", err) + all := &All{rules: []Filter{ + &None{rules: []Filter{&Equal{column: "foo", value: "bar"}}}, + &UnEqual{column: "bar", value: "foo"}, + }} + assert.Equal(t, all, rule) - rule, err = ParseFilter("!(foo=bar|bar=foo)&(foo=bar|bar=foo)") + rule, err = ParseFilter("foo=bar&bar!=foo") + assert.Nil(t, err, "There should be no errors but got: %s", err) + + expect := &All{rules: []Filter{ + &Equal{column: "foo", value: "bar"}, + &UnEqual{column: "bar", value: "foo"}, + }} + assert.Equal(t, expect, rule) + + rule, err = ParseFilter("!(foo=bar|bar=foo)&(foo!=bar|bar!=foo)") assert.Nil(t, err, "There should be no errors but got: %s", err) expected := &All{rules: []Filter{ &None{rules: []Filter{ + &Any{rules: []Filter{ + &Equal{column: "foo", value: "bar"}, + &Equal{column: "bar", value: "foo"}, + }}, + }}, + &Any{rules: []Filter{ + &UnEqual{column: "foo", value: "bar"}, + &UnEqual{column: "bar", value: "foo"}, + }}, + }} + assert.Equal(t, expected, rule) + + rule, err = ParseFilter("foo=bar&bar!=foo&john>doe|doedoe|doedoe|doe