Skip to content

Commit 6ab1cf5

Browse files
committed
Add extended filter/parser tests & adjust expected error messages
1 parent c52bc4f commit 6ab1cf5

File tree

2 files changed

+256
-52
lines changed

2 files changed

+256
-52
lines changed

internal/filter/parser_test.go

Lines changed: 254 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,57 +9,80 @@ import (
99
func TestParser(t *testing.T) {
1010
t.Parallel()
1111

12-
t.Run("MissingLogicalOperatorsAfterConditionsAreDetected", func(t *testing.T) {
13-
_, err := ParseFilter("(a=b|c=d)e=f")
12+
t.Run("ParseInvalidFilters", func(t *testing.T) {
13+
t.Parallel()
1414

15-
expected := "invalid filter '(a=b|c=d)e=f', unexpected e at pos 10: Expected logical operator"
16-
assert.EqualError(t, err, expected, "Errors should be the same")
17-
})
18-
19-
t.Run("MissingLogicalOperatorsAfterOperatorsAreDetected", func(t *testing.T) {
20-
_, err := ParseFilter("(a=b|c=d|)e=f")
15+
rule, err := ParseFilter("(a=b|c=d)e=f")
16+
assert.Equal(t, rule, nil)
17+
assert.EqualError(t, err, "1:10 (9): no match found, expected: \"&\", \"|\" or EOF")
2118

22-
expected := "invalid filter '(a=b|c=d|)e=f', unexpected e at pos 11: Expected logical operator"
23-
assert.EqualError(t, err, expected, "Errors should be the same")
24-
})
19+
_, err = ParseFilter("(a=b|c=d|)e=f")
20+
assert.EqualError(t, err, "1:10 (9): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
2521

26-
t.Run("ParserIdentifiesInvalidExpression", func(t *testing.T) {
27-
_, err := ParseFilter("col=(")
28-
assert.EqualError(t, err, "invalid filter 'col=(', unexpected ( at pos 5", "Errors should be the same")
22+
_, err = ParseFilter("col=(")
23+
assert.EqualError(t, err, "1:5 (4): no match found, expected: [^!&|~<>=()]")
2924

3025
_, err = ParseFilter("(((x=a)&y=b")
31-
assert.EqualError(t, err, "invalid filter '(((x=a)&y=b', missing 2 closing ')' at pos 11", "Errors should be the same")
26+
assert.EqualError(t, err, "1:12 (11): no match found, expected: \"&\", \")\", \"|\" or [^!&|~<>=()]")
3227

3328
_, err = ParseFilter("(x=a)&y=b)")
34-
assert.EqualError(t, err, "invalid filter '(x=a)&y=b)', unexpected ) at pos 10", "Errors should be the same")
29+
assert.EqualError(t, err, "1:10 (9): no match found, expected: \"&\", \"|\", [^!&|~<>=()] or EOF")
3530

3631
_, err = ParseFilter("!(&")
37-
assert.EqualError(t, err, "invalid filter '!(&', unexpected & at pos 3", "Errors should be the same")
38-
39-
_, err = ParseFilter("!(!&")
40-
assert.EqualError(t, err, "invalid filter '!(!&', unexpected & at pos 4: operator level 1", "Errors should be the same")
41-
42-
_, err = ParseFilter("!(|test")
43-
assert.EqualError(t, err, "invalid filter '!(|test', unexpected | at pos 3", "Errors should be the same")
32+
assert.EqualError(t, err, "1:3 (2): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
4433

4534
_, err = ParseFilter("foo&bar=(te(st)")
46-
assert.EqualError(t, err, "invalid filter 'foo&bar=(te(st)', unexpected ( at pos 9", "Errors should be the same")
35+
assert.EqualError(t, err, "1:9 (8): no match found, expected: [^!&|~<>=()]")
4736

4837
_, err = ParseFilter("foo&bar=te(st)")
49-
assert.EqualError(t, err, "invalid filter 'foo&bar=te(st)', unexpected ( at pos 11", "Errors should be the same")
38+
assert.EqualError(t, err, "1:11 (10): no match found, expected: \"&\", \"|\", [^!&|~<>=()] or EOF")
5039

5140
_, err = ParseFilter("foo&bar=test)")
52-
assert.EqualError(t, err, "invalid filter 'foo&bar=test)', unexpected ) at pos 13", "Errors should be the same")
41+
assert.EqualError(t, err, "1:13 (12): no match found, expected: \"&\", \"|\", [^!&|~<>=()] or EOF")
5342

5443
_, err = ParseFilter("!()|&()&)")
55-
assert.EqualError(t, err, "invalid filter '!()|&()&)', unexpected closing ')' at pos 9", "Errors should be the same")
44+
assert.EqualError(t, err, "1:3 (2): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
45+
46+
_, err = ParseFilter("=foo")
47+
assert.EqualError(t, err, "1:1 (0): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
48+
49+
_, err = ParseFilter("foo>")
50+
assert.EqualError(t, err, "1:5 (4): no match found, expected: [^!&|~<>=()]")
51+
52+
_, err = ParseFilter("foo==")
53+
assert.EqualError(t, err, "1:5 (4): no match found, expected: [^!&|~<>=()]")
54+
55+
_, err = ParseFilter("=>foo")
56+
assert.EqualError(t, err, "1:1 (0): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
57+
58+
_, err = ParseFilter("&foo")
59+
assert.EqualError(t, err, "1:1 (0): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
60+
61+
_, err = ParseFilter("&&foo")
62+
assert.EqualError(t, err, "1:1 (0): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
63+
64+
_, err = ParseFilter("(&foo=bar)")
65+
assert.EqualError(t, err, "1:2 (1): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
66+
67+
_, err = ParseFilter("(foo=bar|)")
68+
assert.EqualError(t, err, "1:10 (9): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
69+
70+
_, err = ParseFilter("((((((")
71+
assert.EqualError(t, err, "1:7 (6): no match found, expected: \"!\", \"(\" or [^!&|~<>=()]")
72+
73+
_, err = ParseFilter("foo&bar&col=val!=val")
74+
assert.EqualError(t, err, "1:16 (15): no match found, expected: \"&\", \"|\", [^!&|~<>=()] or EOF")
75+
76+
_, err = ParseFilter("col%7umn")
77+
assert.EqualError(t, err, "1:1 (0): rule ExistsExpr: invalid URL escape \"%7u\"")
78+
79+
_, err = ParseFilter("((0&((((((((((((((0=0)")
80+
assert.EqualError(t, err, "1:23 (22): no match found, expected: \"&\", \")\" or \"|\"")
5681
})
57-
}
5882

59-
func TestFilter(t *testing.T) {
60-
t.Parallel()
83+
t.Run("ParseAllKindOfSimpleFilters", func(t *testing.T) {
84+
t.Parallel()
6185

62-
t.Run("ParserIdentifiesAllKindOfFilters", func(t *testing.T) {
6386
rule, err := ParseFilter("foo=bar")
6487
assert.Nil(t, err, "There should be no errors but got: %s", err)
6588
assert.IsType(t, &Equal{}, rule)
@@ -68,11 +91,11 @@ func TestFilter(t *testing.T) {
6891
assert.Nil(t, err, "There should be no errors but got: %s", err)
6992
assert.IsType(t, &UnEqual{}, rule)
7093

71-
rule, err = ParseFilter("foo=bar*")
94+
rule, err = ParseFilter("foo~bar*")
7295
assert.Nil(t, err, "There should be no errors but got: %s", err)
7396
assert.IsType(t, &Like{}, rule)
7497

75-
rule, err = ParseFilter("foo!=bar*")
98+
rule, err = ParseFilter("foo!~bar*")
7699
assert.Nil(t, err, "There should be no errors but got: %s", err)
77100
assert.IsType(t, &Unlike{}, rule)
78101

@@ -104,49 +127,229 @@ func TestFilter(t *testing.T) {
104127
assert.Nil(t, err, "There should be no errors but got: %s", err)
105128
assert.IsType(t, &None{}, rule)
106129

130+
rule, err = ParseFilter("foo")
131+
assert.Nil(t, err, "There should be no errors but got: %s", err)
132+
assert.Equal(t, &Exists{column: "foo"}, rule)
133+
107134
rule, err = ParseFilter("!foo")
108135
assert.Nil(t, err, "There should be no errors but got: %s", err)
136+
assert.Equal(t, &None{rules: []Filter{&Exists{column: "foo"}}}, rule)
137+
138+
rule, err = ParseFilter("!foo=bar")
139+
assert.Nil(t, err, "There should be no errors but got: %s", err)
140+
assert.Equal(t, &None{rules: []Filter{&Equal{column: "foo", value: "bar"}}}, rule)
141+
})
109142

110-
exists, _ := NewExists("foo")
111-
assert.Equal(t, &None{rules: []Filter{exists}}, rule)
143+
t.Run("ParseFilterChain", func(t *testing.T) {
144+
t.Parallel()
112145

113-
rule, err = ParseFilter("foo")
146+
rule, err := ParseFilter("(foo=bar)")
147+
assert.Nil(t, err, "There should be no errors but got: %s", err)
148+
assert.Equal(t, &Equal{column: "foo", value: "bar"}, rule)
149+
150+
rule, err = ParseFilter("(!foo=bar)")
151+
assert.Nil(t, err, "There should be no errors but got: %s", err)
152+
none := &None{rules: []Filter{
153+
&Equal{column: "foo", value: "bar"},
154+
}}
155+
assert.Equal(t, none, rule)
156+
157+
rule, err = ParseFilter("!(foo=bar)")
158+
assert.Nil(t, err, "There should be no errors but got: %s", err)
159+
none = &None{rules: []Filter{
160+
&Equal{column: "foo", value: "bar"},
161+
}}
162+
assert.Equal(t, none, rule)
163+
164+
rule, err = ParseFilter("!(!foo=bar)")
165+
assert.Nil(t, err, "There should be no errors but got: %s", err)
166+
none = &None{rules: []Filter{
167+
&None{rules: []Filter{&Equal{column: "foo", value: "bar"}}},
168+
}}
169+
assert.Equal(t, none, rule)
170+
171+
rule, err = ParseFilter("((!foo=bar)&bar!=foo)")
172+
assert.Nil(t, err, "There should be no errors but got: %s", err)
173+
all := &All{rules: []Filter{
174+
&None{rules: []Filter{&Equal{column: "foo", value: "bar"}}},
175+
&UnEqual{column: "bar", value: "foo"},
176+
}}
177+
assert.Equal(t, all, rule)
178+
179+
rule, err = ParseFilter("!foo&!bar")
180+
assert.Nil(t, err, "There should be no errors but got: %s", err)
181+
var expected Filter
182+
expected = &All{rules: []Filter{
183+
&None{rules: []Filter{&Exists{column: "foo"}}},
184+
&None{rules: []Filter{&Exists{column: "bar"}}},
185+
}}
186+
assert.Equal(t, expected, rule)
187+
188+
rule, err = ParseFilter("!(!foo|bar)")
189+
assert.Nil(t, err, "There should be no errors but got: %s", err)
190+
191+
expected = &None{rules: []Filter{
192+
&Any{rules: []Filter{
193+
&None{rules: []Filter{&Exists{column: "foo"}}},
194+
&Exists{column: "bar"},
195+
}},
196+
}}
197+
assert.Equal(t, expected, rule)
198+
199+
rule, err = ParseFilter("!(!(foo|bar))")
200+
assert.Nil(t, err, "There should be no errors but got: %s", err)
201+
202+
expected = &None{rules: []Filter{
203+
&None{rules: []Filter{
204+
&Any{rules: []Filter{
205+
&Exists{column: "foo"},
206+
&Exists{column: "bar"},
207+
}},
208+
}},
209+
}}
210+
assert.Equal(t, expected, rule)
211+
212+
rule, err = ParseFilter("foo=bar&bar!=foo")
114213
assert.Nil(t, err, "There should be no errors but got: %s", err)
115-
assert.Equal(t, exists, rule)
116214

117-
rule, err = ParseFilter("!(foo=bar|bar=foo)&(foo=bar|bar=foo)")
215+
expect := &All{rules: []Filter{
216+
&Equal{column: "foo", value: "bar"},
217+
&UnEqual{column: "bar", value: "foo"},
218+
}}
219+
assert.Equal(t, expect, rule)
220+
221+
rule, err = ParseFilter("!(foo=bar|bar=foo)&(foo!=bar|bar!=foo)")
118222
assert.Nil(t, err, "There should be no errors but got: %s", err)
119223

120-
expected := &All{rules: []Filter{
224+
expected = &All{rules: []Filter{
121225
&None{rules: []Filter{
226+
&Any{rules: []Filter{
227+
&Equal{column: "foo", value: "bar"},
228+
&Equal{column: "bar", value: "foo"},
229+
}},
230+
}},
231+
&Any{rules: []Filter{
232+
&UnEqual{column: "foo", value: "bar"},
233+
&UnEqual{column: "bar", value: "foo"},
234+
}},
235+
}}
236+
assert.Equal(t, expected, rule)
237+
238+
rule, err = ParseFilter("foo=bar&bar!=foo&john>doe|doe<john&column!=value|column=value")
239+
assert.Nil(t, err, "There should be no errors but got: %s", err)
240+
241+
expectAny := &Any{rules: []Filter{
242+
&All{rules: []Filter{
122243
&Equal{column: "foo", value: "bar"},
123-
&Equal{column: "bar", value: "foo"},
244+
&UnEqual{column: "bar", value: "foo"},
245+
&GreaterThan{column: "john", value: "doe"},
124246
}},
125247
&Any{rules: []Filter{
248+
&All{rules: []Filter{
249+
&LessThan{column: "doe", value: "john"},
250+
&UnEqual{column: "column", value: "value"},
251+
}},
252+
&Equal{column: "column", value: "value"},
253+
}},
254+
}}
255+
assert.Equal(t, expectAny, rule)
256+
257+
rule, err = ParseFilter("foo=bar&bar!=foo&(john>doe|doe<john&column!=value)|column=value")
258+
assert.Nil(t, err, "There should be no errors but got: %s", err)
259+
260+
expectAny = &Any{rules: []Filter{
261+
&All{rules: []Filter{
126262
&Equal{column: "foo", value: "bar"},
127-
&Equal{column: "bar", value: "foo"},
263+
&UnEqual{column: "bar", value: "foo"},
264+
&Any{rules: []Filter{
265+
&GreaterThan{column: "john", value: "doe"},
266+
&All{rules: []Filter{
267+
&LessThan{column: "doe", value: "john"},
268+
&UnEqual{column: "column", value: "value"},
269+
}},
270+
}},
128271
}},
272+
&Equal{column: "column", value: "value"},
129273
}}
130-
assert.Equal(t, expected, rule)
131-
})
274+
assert.Equal(t, expectAny, rule)
132275

133-
t.Run("ParserIdentifiesSingleCondition", func(t *testing.T) {
134-
rule, err := ParseFilter("foo=bar")
276+
rule, err = ParseFilter("foo=bar&bar!=foo|(john>doe|doe<john&column!=value)&column=value")
277+
assert.Nil(t, err, "There should be no errors but got: %s", err)
278+
279+
expectAny = &Any{rules: []Filter{
280+
// The first two filter conditions
281+
&All{rules: []Filter{
282+
&Equal{column: "foo", value: "bar"},
283+
&UnEqual{column: "bar", value: "foo"},
284+
}},
285+
&All{rules: []Filter{
286+
&Any{rules: []Filter{ // Represents the filter conditions within the parentheses
287+
&GreaterThan{column: "john", value: "doe"},
288+
&All{rules: []Filter{
289+
&LessThan{column: "doe", value: "john"},
290+
&UnEqual{column: "column", value: "value"},
291+
}},
292+
}},
293+
// The last filter condition
294+
&Equal{column: "column", value: "value"},
295+
}},
296+
}}
297+
assert.Equal(t, expectAny, rule)
298+
299+
rule, err = ParseFilter("foo=bar&bar!=foo|(john>doe|doe<john&(column!=value|value!~column))&column=value")
135300
assert.Nil(t, err, "There should be no errors but got: %s", err)
136301

137-
expected := &Equal{column: "foo", value: "bar"}
138-
assert.Equal(t, expected, rule, "Parser doesn't parse single condition correctly")
302+
expectAny = &Any{rules: []Filter{
303+
// The first two filter conditions
304+
&All{rules: []Filter{
305+
&Equal{column: "foo", value: "bar"},
306+
&UnEqual{column: "bar", value: "foo"},
307+
}},
308+
&All{rules: []Filter{
309+
&Any{rules: []Filter{ // Represents the filter conditions within the parentheses
310+
&GreaterThan{column: "john", value: "doe"},
311+
&All{rules: []Filter{
312+
&LessThan{column: "doe", value: "john"},
313+
&Any{rules: []Filter{ // Represents the filter conditions within the nested parentheses
314+
&UnEqual{column: "column", value: "value"},
315+
&Unlike{column: "value", value: "column"},
316+
}},
317+
}},
318+
}},
319+
// The last filter condition
320+
&Equal{column: "column", value: "value"},
321+
}},
322+
}}
323+
assert.Equal(t, expectAny, rule)
139324
})
140325

141-
t.Run("UrlEncodedFilterExpression", func(t *testing.T) {
326+
t.Run("UrlEncodedFilter", func(t *testing.T) {
327+
t.Parallel()
328+
142329
rule, err := ParseFilter("col%3Cumn<val%3Cue")
143330
assert.Nil(t, err, "There should be no errors but got: %s", err)
144331
assert.Equal(t, &LessThan{column: "col<umn", value: "val<ue"}, rule)
145332

333+
rule, err = ParseFilter("col%7Cumn")
334+
assert.Nil(t, err, "There should be no errors but got: %s", err)
335+
assert.Equal(t, &Exists{column: "col|umn"}, rule)
336+
146337
rule, err = ParseFilter("col%7Cumn=val%7Cue")
147338
assert.Nil(t, err, "There should be no errors but got: %s", err)
148339
assert.Equal(t, &Equal{column: "col|umn", value: "val|ue"}, rule)
149340

341+
rule, err = ParseFilter("col%7Cumn!=val%7Cue")
342+
assert.Nil(t, err, "There should be no errors but got: %s", err)
343+
assert.Equal(t, &UnEqual{column: "col|umn", value: "val|ue"}, rule)
344+
345+
rule, err = ParseFilter("col%7Cumn~val%7Cue")
346+
assert.Nil(t, err, "There should be no errors but got: %s", err)
347+
assert.Equal(t, &Like{column: "col|umn", value: "val|ue"}, rule)
348+
349+
rule, err = ParseFilter("col%7Cumn!~val%7Cue")
350+
assert.Nil(t, err, "There should be no errors but got: %s", err)
351+
assert.Equal(t, &Unlike{column: "col|umn", value: "val|ue"}, rule)
352+
150353
rule, err = ParseFilter("col%26umn<=val%26ue")
151354
assert.Nil(t, err, "There should be no errors but got: %s", err)
152355
assert.Equal(t, &LessThanOrEqual{column: "col&umn", value: "val&ue"}, rule)
@@ -174,8 +377,8 @@ func FuzzParser(f *testing.F) {
174377
f.Add("foo&bar=test)")
175378
f.Add("foo=bar")
176379
f.Add("foo!=bar")
177-
f.Add("foo=bar*")
178-
f.Add("foo!=bar*")
380+
f.Add("foo~bar*")
381+
f.Add("foo!~bar*")
179382
f.Add("foo<bar")
180383
f.Add("foo<=bar")
181384
f.Add("foo>bar")
@@ -187,6 +390,7 @@ func FuzzParser(f *testing.F) {
187390
f.Add("foo")
188391
f.Add("!(foo=bar|bar=foo)&(foo=bar|bar=foo)")
189392
f.Add("foo=bar")
393+
f.Add("col%7umn")
190394
f.Add("col%3Cumn<val%3Cue")
191395
f.Add("col%7Cumn=val%7Cue")
192396
f.Add("col%26umn<=val%26ue")

0 commit comments

Comments
 (0)