1 package glob
2
3 import (
4 "regexp"
5 "testing"
6 )
7
8 const (
9 pattern_all = "[a-z][!a-x]*cat*[h][!b]*eyes*"
10 regexp_all = `^[a-z][^a-x].*cat.*[h][^b].*eyes.*$`
11 fixture_all_match = "my cat has very bright eyes"
12 fixture_all_mismatch = "my dog has very bright eyes"
13
14 pattern_plain = "google.com"
15 regexp_plain = `^google\.com$`
16 fixture_plain_match = "google.com"
17 fixture_plain_mismatch = "gobwas.com"
18
19 pattern_multiple = "https://*.google.*"
20 regexp_multiple = `^https:\/\/.*\.google\..*$`
21 fixture_multiple_match = "https://account.google.com"
22 fixture_multiple_mismatch = "https://google.com"
23
24 pattern_alternatives = "{https://*.google.*,*yandex.*,*yahoo.*,*mail.ru}"
25 regexp_alternatives = `^(https:\/\/.*\.google\..*|.*yandex\..*|.*yahoo\..*|.*mail\.ru)$`
26 fixture_alternatives_match = "http://yahoo.com"
27 fixture_alternatives_mismatch = "http://google.com"
28
29 pattern_alternatives_suffix = "{https://*gobwas.com,http://exclude.gobwas.com}"
30 regexp_alternatives_suffix = `^(https:\/\/.*gobwas\.com|http://exclude.gobwas.com)$`
31 fixture_alternatives_suffix_first_match = "https://safe.gobwas.com"
32 fixture_alternatives_suffix_first_mismatch = "http://safe.gobwas.com"
33 fixture_alternatives_suffix_second = "http://exclude.gobwas.com"
34
35 pattern_prefix = "abc*"
36 regexp_prefix = `^abc.*$`
37 pattern_suffix = "*def"
38 regexp_suffix = `^.*def$`
39 pattern_prefix_suffix = "ab*ef"
40 regexp_prefix_suffix = `^ab.*ef$`
41 fixture_prefix_suffix_match = "abcdef"
42 fixture_prefix_suffix_mismatch = "af"
43
44 pattern_alternatives_combine_lite = "{abc*def,abc?def,abc[zte]def}"
45 regexp_alternatives_combine_lite = `^(abc.*def|abc.def|abc[zte]def)$`
46 fixture_alternatives_combine_lite = "abczdef"
47
48 pattern_alternatives_combine_hard = "{abc*[a-c]def,abc?[d-g]def,abc[zte]?def}"
49 regexp_alternatives_combine_hard = `^(abc.*[a-c]def|abc.[d-g]def|abc[zte].def)$`
50 fixture_alternatives_combine_hard = "abczqdef"
51 )
52
53 type test struct {
54 pattern, match string
55 should bool
56 delimiters []rune
57 }
58
59 func glob(s bool, p, m string, d ...rune) test {
60 return test{p, m, s, d}
61 }
62
63 func TestGlob(t *testing.T) {
64 for _, test := range []test{
65 glob(true, "* ?at * eyes", "my cat has very bright eyes"),
66
67 glob(true, "", ""),
68 glob(false, "", "b"),
69
70 glob(true, "*ä", "åä"),
71 glob(true, "abc", "abc"),
72 glob(true, "a*c", "abc"),
73 glob(true, "a*c", "a12345c"),
74 glob(true, "a?c", "a1c"),
75 glob(true, "a.b", "a.b", '.'),
76 glob(true, "a.*", "a.b", '.'),
77 glob(true, "a.**", "a.b.c", '.'),
78 glob(true, "a.?.c", "a.b.c", '.'),
79 glob(true, "a.?.?", "a.b.c", '.'),
80 glob(true, "?at", "cat"),
81 glob(true, "?at", "fat"),
82 glob(true, "*", "abc"),
83 glob(true, `\*`, "*"),
84 glob(true, "**", "a.b.c", '.'),
85
86 glob(false, "?at", "at"),
87 glob(false, "?at", "fat", 'f'),
88 glob(false, "a.*", "a.b.c", '.'),
89 glob(false, "a.?.c", "a.bb.c", '.'),
90 glob(false, "*", "a.b.c", '.'),
91
92 glob(true, "*test", "this is a test"),
93 glob(true, "this*", "this is a test"),
94 glob(true, "*is *", "this is a test"),
95 glob(true, "*is*a*", "this is a test"),
96 glob(true, "**test**", "this is a test"),
97 glob(true, "**is**a***test*", "this is a test"),
98
99 glob(false, "*is", "this is a test"),
100 glob(false, "*no*", "this is a test"),
101 glob(true, "[!a]*", "this is a test3"),
102
103 glob(true, "*abc", "abcabc"),
104 glob(true, "**abc", "abcabc"),
105 glob(true, "???", "abc"),
106 glob(true, "?*?", "abc"),
107 glob(true, "?*?", "ac"),
108 glob(false, "sta", "stagnation"),
109 glob(true, "sta*", "stagnation"),
110 glob(false, "sta?", "stagnation"),
111 glob(false, "sta?n", "stagnation"),
112
113 glob(true, "{abc,def}ghi", "defghi"),
114 glob(true, "{abc,abcd}a", "abcda"),
115 glob(true, "{a,ab}{bc,f}", "abc"),
116 glob(true, "{*,**}{a,b}", "ab"),
117 glob(false, "{*,**}{a,b}", "ac"),
118
119 glob(true, "/{rate,[a-z][a-z][a-z]}*", "/rate"),
120 glob(true, "/{rate,[0-9][0-9][0-9]}*", "/rate"),
121 glob(true, "/{rate,[a-z][a-z][a-z]}*", "/usd"),
122
123 glob(true, "{*.google.*,*.yandex.*}", "www.google.com", '.'),
124 glob(true, "{*.google.*,*.yandex.*}", "www.yandex.com", '.'),
125 glob(false, "{*.google.*,*.yandex.*}", "yandex.com", '.'),
126 glob(false, "{*.google.*,*.yandex.*}", "google.com", '.'),
127
128 glob(true, "{*.google.*,yandex.*}", "www.google.com", '.'),
129 glob(true, "{*.google.*,yandex.*}", "yandex.com", '.'),
130 glob(false, "{*.google.*,yandex.*}", "www.yandex.com", '.'),
131 glob(false, "{*.google.*,yandex.*}", "google.com", '.'),
132
133 glob(true, pattern_all, fixture_all_match),
134 glob(false, pattern_all, fixture_all_mismatch),
135
136 glob(true, pattern_plain, fixture_plain_match),
137 glob(false, pattern_plain, fixture_plain_mismatch),
138
139 glob(true, pattern_multiple, fixture_multiple_match),
140 glob(false, pattern_multiple, fixture_multiple_mismatch),
141
142 glob(true, pattern_alternatives, fixture_alternatives_match),
143 glob(false, pattern_alternatives, fixture_alternatives_mismatch),
144
145 glob(true, pattern_alternatives_suffix, fixture_alternatives_suffix_first_match),
146 glob(false, pattern_alternatives_suffix, fixture_alternatives_suffix_first_mismatch),
147 glob(true, pattern_alternatives_suffix, fixture_alternatives_suffix_second),
148
149 glob(true, pattern_alternatives_combine_hard, fixture_alternatives_combine_hard),
150
151 glob(true, pattern_alternatives_combine_lite, fixture_alternatives_combine_lite),
152
153 glob(true, pattern_prefix, fixture_prefix_suffix_match),
154 glob(false, pattern_prefix, fixture_prefix_suffix_mismatch),
155
156 glob(true, pattern_suffix, fixture_prefix_suffix_match),
157 glob(false, pattern_suffix, fixture_prefix_suffix_mismatch),
158
159 glob(true, pattern_prefix_suffix, fixture_prefix_suffix_match),
160 glob(false, pattern_prefix_suffix, fixture_prefix_suffix_mismatch),
161 } {
162 t.Run("", func(t *testing.T) {
163 g := MustCompile(test.pattern, test.delimiters...)
164 result := g.Match(test.match)
165 if result != test.should {
166 t.Errorf(
167 "pattern %q matching %q should be %v but got %v\n%s",
168 test.pattern, test.match, test.should, result, g,
169 )
170 }
171 })
172 }
173 }
174
175 func TestQuoteMeta(t *testing.T) {
176 for id, test := range []struct {
177 in, out string
178 }{
179 {
180 in: `[foo*]`,
181 out: `\[foo\*\]`,
182 },
183 {
184 in: `{foo*}`,
185 out: `\{foo\*\}`,
186 },
187 {
188 in: `*?\[]{}`,
189 out: `\*\?\\\[\]\{\}`,
190 },
191 {
192 in: `some text and *?\[]{}`,
193 out: `some text and \*\?\\\[\]\{\}`,
194 },
195 } {
196 act := QuoteMeta(test.in)
197 if act != test.out {
198 t.Errorf("#%d QuoteMeta(%q) = %q; want %q", id, test.in, act, test.out)
199 }
200 if _, err := Compile(act); err != nil {
201 t.Errorf("#%d _, err := Compile(QuoteMeta(%q) = %q); err = %q", id, test.in, act, err)
202 }
203 }
204 }
205
206 func BenchmarkParseGlob(b *testing.B) {
207 for i := 0; i < b.N; i++ {
208 Compile(pattern_all)
209 }
210 }
211 func BenchmarkParseRegexp(b *testing.B) {
212 for i := 0; i < b.N; i++ {
213 regexp.MustCompile(regexp_all)
214 }
215 }
216
217 func BenchmarkAllGlobMatch(b *testing.B) {
218 m, _ := Compile(pattern_all)
219
220 for i := 0; i < b.N; i++ {
221 _ = m.Match(fixture_all_match)
222 }
223 }
224 func BenchmarkAllGlobMatchParallel(b *testing.B) {
225 m, _ := Compile(pattern_all)
226
227 b.RunParallel(func(pb *testing.PB) {
228 for pb.Next() {
229 _ = m.Match(fixture_all_match)
230 }
231 })
232 }
233
234 func BenchmarkAllRegexpMatch(b *testing.B) {
235 m := regexp.MustCompile(regexp_all)
236 f := []byte(fixture_all_match)
237
238 for i := 0; i < b.N; i++ {
239 _ = m.Match(f)
240 }
241 }
242 func BenchmarkAllGlobMismatch(b *testing.B) {
243 m, _ := Compile(pattern_all)
244
245 for i := 0; i < b.N; i++ {
246 _ = m.Match(fixture_all_mismatch)
247 }
248 }
249 func BenchmarkAllGlobMismatchParallel(b *testing.B) {
250 m, _ := Compile(pattern_all)
251
252 b.RunParallel(func(pb *testing.PB) {
253 for pb.Next() {
254 _ = m.Match(fixture_all_mismatch)
255 }
256 })
257 }
258 func BenchmarkAllRegexpMismatch(b *testing.B) {
259 m := regexp.MustCompile(regexp_all)
260 f := []byte(fixture_all_mismatch)
261
262 for i := 0; i < b.N; i++ {
263 _ = m.Match(f)
264 }
265 }
266
267 func BenchmarkMultipleGlobMatch(b *testing.B) {
268 m, _ := Compile(pattern_multiple)
269
270 for i := 0; i < b.N; i++ {
271 _ = m.Match(fixture_multiple_match)
272 }
273 }
274 func BenchmarkMultipleRegexpMatch(b *testing.B) {
275 m := regexp.MustCompile(regexp_multiple)
276 f := []byte(fixture_multiple_match)
277
278 for i := 0; i < b.N; i++ {
279 _ = m.Match(f)
280 }
281 }
282 func BenchmarkMultipleGlobMismatch(b *testing.B) {
283 m, _ := Compile(pattern_multiple)
284
285 for i := 0; i < b.N; i++ {
286 _ = m.Match(fixture_multiple_mismatch)
287 }
288 }
289 func BenchmarkMultipleRegexpMismatch(b *testing.B) {
290 m := regexp.MustCompile(regexp_multiple)
291 f := []byte(fixture_multiple_mismatch)
292
293 for i := 0; i < b.N; i++ {
294 _ = m.Match(f)
295 }
296 }
297
298 func BenchmarkAlternativesGlobMatch(b *testing.B) {
299 m, _ := Compile(pattern_alternatives)
300
301 for i := 0; i < b.N; i++ {
302 _ = m.Match(fixture_alternatives_match)
303 }
304 }
305 func BenchmarkAlternativesGlobMismatch(b *testing.B) {
306 m, _ := Compile(pattern_alternatives)
307
308 for i := 0; i < b.N; i++ {
309 _ = m.Match(fixture_alternatives_mismatch)
310 }
311 }
312 func BenchmarkAlternativesRegexpMatch(b *testing.B) {
313 m := regexp.MustCompile(regexp_alternatives)
314 f := []byte(fixture_alternatives_match)
315
316 for i := 0; i < b.N; i++ {
317 _ = m.Match(f)
318 }
319 }
320 func BenchmarkAlternativesRegexpMismatch(b *testing.B) {
321 m := regexp.MustCompile(regexp_alternatives)
322 f := []byte(fixture_alternatives_mismatch)
323
324 for i := 0; i < b.N; i++ {
325 _ = m.Match(f)
326 }
327 }
328
329 func BenchmarkAlternativesSuffixFirstGlobMatch(b *testing.B) {
330 m, _ := Compile(pattern_alternatives_suffix)
331
332 for i := 0; i < b.N; i++ {
333 _ = m.Match(fixture_alternatives_suffix_first_match)
334 }
335 }
336 func BenchmarkAlternativesSuffixFirstGlobMismatch(b *testing.B) {
337 m, _ := Compile(pattern_alternatives_suffix)
338
339 for i := 0; i < b.N; i++ {
340 _ = m.Match(fixture_alternatives_suffix_first_mismatch)
341 }
342 }
343 func BenchmarkAlternativesSuffixSecondGlobMatch(b *testing.B) {
344 m, _ := Compile(pattern_alternatives_suffix)
345
346 for i := 0; i < b.N; i++ {
347 _ = m.Match(fixture_alternatives_suffix_second)
348 }
349 }
350 func BenchmarkAlternativesCombineLiteGlobMatch(b *testing.B) {
351 m, _ := Compile(pattern_alternatives_combine_lite)
352
353 for i := 0; i < b.N; i++ {
354 _ = m.Match(fixture_alternatives_combine_lite)
355 }
356 }
357 func BenchmarkAlternativesCombineHardGlobMatch(b *testing.B) {
358 m, _ := Compile(pattern_alternatives_combine_hard)
359
360 for i := 0; i < b.N; i++ {
361 _ = m.Match(fixture_alternatives_combine_hard)
362 }
363 }
364 func BenchmarkAlternativesSuffixFirstRegexpMatch(b *testing.B) {
365 m := regexp.MustCompile(regexp_alternatives_suffix)
366 f := []byte(fixture_alternatives_suffix_first_match)
367
368 for i := 0; i < b.N; i++ {
369 _ = m.Match(f)
370 }
371 }
372 func BenchmarkAlternativesSuffixFirstRegexpMismatch(b *testing.B) {
373 m := regexp.MustCompile(regexp_alternatives_suffix)
374 f := []byte(fixture_alternatives_suffix_first_mismatch)
375
376 for i := 0; i < b.N; i++ {
377 _ = m.Match(f)
378 }
379 }
380 func BenchmarkAlternativesSuffixSecondRegexpMatch(b *testing.B) {
381 m := regexp.MustCompile(regexp_alternatives_suffix)
382 f := []byte(fixture_alternatives_suffix_second)
383
384 for i := 0; i < b.N; i++ {
385 _ = m.Match(f)
386 }
387 }
388 func BenchmarkAlternativesCombineLiteRegexpMatch(b *testing.B) {
389 m := regexp.MustCompile(regexp_alternatives_combine_lite)
390 f := []byte(fixture_alternatives_combine_lite)
391
392 for i := 0; i < b.N; i++ {
393 _ = m.Match(f)
394 }
395 }
396 func BenchmarkAlternativesCombineHardRegexpMatch(b *testing.B) {
397 m := regexp.MustCompile(regexp_alternatives_combine_hard)
398 f := []byte(fixture_alternatives_combine_hard)
399
400 for i := 0; i < b.N; i++ {
401 _ = m.Match(f)
402 }
403 }
404
405 func BenchmarkPlainGlobMatch(b *testing.B) {
406 m, _ := Compile(pattern_plain)
407
408 for i := 0; i < b.N; i++ {
409 _ = m.Match(fixture_plain_match)
410 }
411 }
412 func BenchmarkPlainRegexpMatch(b *testing.B) {
413 m := regexp.MustCompile(regexp_plain)
414 f := []byte(fixture_plain_match)
415
416 for i := 0; i < b.N; i++ {
417 _ = m.Match(f)
418 }
419 }
420 func BenchmarkPlainGlobMismatch(b *testing.B) {
421 m, _ := Compile(pattern_plain)
422
423 for i := 0; i < b.N; i++ {
424 _ = m.Match(fixture_plain_mismatch)
425 }
426 }
427 func BenchmarkPlainRegexpMismatch(b *testing.B) {
428 m := regexp.MustCompile(regexp_plain)
429 f := []byte(fixture_plain_mismatch)
430
431 for i := 0; i < b.N; i++ {
432 _ = m.Match(f)
433 }
434 }
435
436 func BenchmarkPrefixGlobMatch(b *testing.B) {
437 m, _ := Compile(pattern_prefix)
438
439 for i := 0; i < b.N; i++ {
440 _ = m.Match(fixture_prefix_suffix_match)
441 }
442 }
443 func BenchmarkPrefixRegexpMatch(b *testing.B) {
444 m := regexp.MustCompile(regexp_prefix)
445 f := []byte(fixture_prefix_suffix_match)
446
447 for i := 0; i < b.N; i++ {
448 _ = m.Match(f)
449 }
450 }
451 func BenchmarkPrefixGlobMismatch(b *testing.B) {
452 m, _ := Compile(pattern_prefix)
453
454 for i := 0; i < b.N; i++ {
455 _ = m.Match(fixture_prefix_suffix_mismatch)
456 }
457 }
458 func BenchmarkPrefixRegexpMismatch(b *testing.B) {
459 m := regexp.MustCompile(regexp_prefix)
460 f := []byte(fixture_prefix_suffix_mismatch)
461
462 for i := 0; i < b.N; i++ {
463 _ = m.Match(f)
464 }
465 }
466
467 func BenchmarkSuffixGlobMatch(b *testing.B) {
468 m, _ := Compile(pattern_suffix)
469
470 for i := 0; i < b.N; i++ {
471 _ = m.Match(fixture_prefix_suffix_match)
472 }
473 }
474 func BenchmarkSuffixRegexpMatch(b *testing.B) {
475 m := regexp.MustCompile(regexp_suffix)
476 f := []byte(fixture_prefix_suffix_match)
477
478 for i := 0; i < b.N; i++ {
479 _ = m.Match(f)
480 }
481 }
482 func BenchmarkSuffixGlobMismatch(b *testing.B) {
483 m, _ := Compile(pattern_suffix)
484
485 for i := 0; i < b.N; i++ {
486 _ = m.Match(fixture_prefix_suffix_mismatch)
487 }
488 }
489 func BenchmarkSuffixRegexpMismatch(b *testing.B) {
490 m := regexp.MustCompile(regexp_suffix)
491 f := []byte(fixture_prefix_suffix_mismatch)
492
493 for i := 0; i < b.N; i++ {
494 _ = m.Match(f)
495 }
496 }
497
498 func BenchmarkPrefixSuffixGlobMatch(b *testing.B) {
499 m, _ := Compile(pattern_prefix_suffix)
500
501 for i := 0; i < b.N; i++ {
502 _ = m.Match(fixture_prefix_suffix_match)
503 }
504 }
505 func BenchmarkPrefixSuffixRegexpMatch(b *testing.B) {
506 m := regexp.MustCompile(regexp_prefix_suffix)
507 f := []byte(fixture_prefix_suffix_match)
508
509 for i := 0; i < b.N; i++ {
510 _ = m.Match(f)
511 }
512 }
513 func BenchmarkPrefixSuffixGlobMismatch(b *testing.B) {
514 m, _ := Compile(pattern_prefix_suffix)
515
516 for i := 0; i < b.N; i++ {
517 _ = m.Match(fixture_prefix_suffix_mismatch)
518 }
519 }
520 func BenchmarkPrefixSuffixRegexpMismatch(b *testing.B) {
521 m := regexp.MustCompile(regexp_prefix_suffix)
522 f := []byte(fixture_prefix_suffix_mismatch)
523
524 for i := 0; i < b.N; i++ {
525 _ = m.Match(f)
526 }
527 }
528
View as plain text