Skip to content

Commit

Permalink
Add extended filter/parser tests & adjust expected error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
yhabteab committed May 2, 2023
1 parent b73c58d commit 7af03f7
Showing 1 changed file with 157 additions and 29 deletions.
186 changes: 157 additions & 29 deletions internal/filter/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
})
}

Expand Down Expand Up @@ -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|doe<john&column!=value|column=value")
assert.Nil(t, err, "There should be no errors but got: %s", err)

expectAny := &Any{rules: []Filter{
&All{rules: []Filter{
&Equal{column: "foo", value: "bar"},
&Equal{column: "bar", value: "foo"},
&UnEqual{column: "bar", value: "foo"},
&GreaterThan{column: "john", value: "doe"},
}},
&Any{rules: []Filter{
&All{rules: []Filter{
&LessThan{column: "doe", value: "john"},
&UnEqual{column: "column", value: "value"},
}},
&Equal{column: "column", value: "value"},
}},
}}
assert.Equal(t, expectAny, rule)

rule, err = ParseFilter("foo=bar&bar!=foo&(john>doe|doe<john&column!=value)|column=value")
assert.Nil(t, err, "There should be no errors but got: %s", err)

expectAny = &Any{rules: []Filter{
&All{rules: []Filter{
&Equal{column: "foo", value: "bar"},
&Equal{column: "bar", value: "foo"},
&UnEqual{column: "bar", value: "foo"},
&Any{rules: []Filter{
&GreaterThan{column: "john", value: "doe"},
&All{rules: []Filter{
&LessThan{column: "doe", value: "john"},
&UnEqual{column: "column", value: "value"},
}},
}},
}},
&Equal{column: "column", value: "value"},
}}
assert.Equal(t, expected, rule)
})
assert.Equal(t, expectAny, rule)

t.Run("ParserIdentifiesSingleCondition", func(t *testing.T) {
rule, err := ParseFilter("foo=bar")
rule, err = ParseFilter("foo=bar&bar!=foo|(john>doe|doe<john&column!=value)&column=value")
assert.Nil(t, err, "There should be no errors but got: %s", err)

expected := &Equal{column: "foo", value: "bar"}
assert.Equal(t, expected, rule, "Parser doesn't parse single condition correctly")
expectAny = &Any{rules: []Filter{
// The first two filter conditions
&All{rules: []Filter{
&Equal{column: "foo", value: "bar"},
&UnEqual{column: "bar", value: "foo"},
}},
&All{rules: []Filter{
&Any{rules: []Filter{ // Represents the filter conditions within the parentheses
&GreaterThan{column: "john", value: "doe"},
&All{rules: []Filter{
&LessThan{column: "doe", value: "john"},
&UnEqual{column: "column", value: "value"},
}},
}},
// The last filter condition
&Equal{column: "column", value: "value"},
}},
}}
assert.Equal(t, expectAny, rule)
})

t.Run("UrlEncodedFilterExpression", func(t *testing.T) {
Expand Down

0 comments on commit 7af03f7

Please sign in to comment.