• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package pathtools
16
17import (
18	"os"
19	"path/filepath"
20	"reflect"
21	"strings"
22	"testing"
23)
24
25var pwd, _ = os.Getwd()
26
27type globTestCase struct {
28	pattern  string
29	matches  []string
30	excludes []string
31	deps     []string
32	err      error
33}
34
35var globTestCases = []globTestCase{
36	// Current directory tests
37	{
38		pattern: "*",
39		matches: []string{"a/", "b/", "c/", "d.ext", "e.ext"},
40		deps:    []string{"."},
41	},
42	{
43		pattern: "*.ext",
44		matches: []string{"d.ext", "e.ext"},
45		deps:    []string{"."},
46	},
47	{
48		pattern: "*/a",
49		matches: []string{"a/a/", "b/a"},
50		deps:    []string{".", "a", "b", "c"},
51	},
52	{
53		pattern: "*/*/a",
54		matches: []string{"a/a/a"},
55		deps:    []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"},
56	},
57	{
58		pattern: "*/a/a",
59		matches: []string{"a/a/a"},
60		deps:    []string{".", "a", "b", "c", "a/a"},
61	},
62	{
63		pattern: "c/*/?",
64		matches: []string{"c/h/h"},
65		deps:    []string{"c", "c/f", "c/g", "c/h"},
66	},
67	{
68		pattern: "c/*/[gh]*",
69		matches: []string{"c/g/g.ext", "c/h/h"},
70		deps:    []string{"c", "c/f", "c/g", "c/h"},
71	},
72	{
73		pattern: "c/*/[fgh]*",
74		matches: []string{"c/f/f.ext", "c/g/g.ext", "c/h/h"},
75		deps:    []string{"c", "c/f", "c/g", "c/h"},
76	},
77	{
78		pattern: "c/*/[f-h]*",
79		matches: []string{"c/f/f.ext", "c/g/g.ext", "c/h/h"},
80		deps:    []string{"c", "c/f", "c/g", "c/h"},
81	},
82	// ./ directory tests
83	{
84		pattern: "./*",
85		matches: []string{"a/", "b/", "c/", "d.ext", "e.ext"},
86		deps:    []string{"."},
87	},
88	{
89		pattern: "./*.ext",
90		matches: []string{"d.ext", "e.ext"},
91		deps:    []string{"."},
92	},
93	{
94		pattern: "./*/a",
95		matches: []string{"a/a/", "b/a"},
96		deps:    []string{".", "a", "b", "c"},
97	},
98	{
99		pattern: "./[ac]/a",
100		matches: []string{"a/a/"},
101		deps:    []string{".", "a", "c"},
102	},
103
104	// subdirectory tests
105	{
106		pattern: "c/*/*.ext",
107		matches: []string{"c/f/f.ext", "c/g/g.ext"},
108		deps:    []string{"c", "c/f", "c/g", "c/h"},
109	},
110	{
111		pattern: "a/*/a",
112		matches: []string{"a/a/a"},
113		deps:    []string{"a", "a/a", "a/b"},
114	},
115
116	// absolute tests
117	{
118		pattern: filepath.Join(pwd, "testdata/glob/c/*/*.ext"),
119		matches: []string{
120			filepath.Join(pwd, "testdata/glob/c/f/f.ext"),
121			filepath.Join(pwd, "testdata/glob/c/g/g.ext"),
122		},
123		deps: []string{
124			filepath.Join(pwd, "testdata/glob/c"),
125			filepath.Join(pwd, "testdata/glob/c/f"),
126			filepath.Join(pwd, "testdata/glob/c/g"),
127			filepath.Join(pwd, "testdata/glob/c/h"),
128		},
129	},
130
131	// no-wild tests
132	{
133		pattern: "a",
134		matches: []string{"a/"},
135		deps:    []string{"a"},
136	},
137	{
138		pattern: "a/a",
139		matches: []string{"a/a/"},
140		deps:    []string{"a/a"},
141	},
142
143	// clean tests
144	{
145		pattern: "./c/*/*.ext",
146		matches: []string{"c/f/f.ext", "c/g/g.ext"},
147		deps:    []string{"c", "c/f", "c/g", "c/h"},
148	},
149	{
150		pattern: "c/../c/*/*.ext",
151		matches: []string{"c/f/f.ext", "c/g/g.ext"},
152		deps:    []string{"c", "c/f", "c/g", "c/h"},
153	},
154
155	// recursive tests
156	{
157		pattern: "**/a",
158		matches: []string{"a/", "a/a/", "a/a/a", "b/a"},
159		deps:    []string{".", "a", "a/a", "a/b", "b", "c", "c/f", "c/g", "c/h"},
160	},
161	{
162		pattern: "a/**/a",
163		matches: []string{"a/a/", "a/a/a"},
164		deps:    []string{"a", "a/a", "a/b"},
165	},
166	{
167		pattern: "a/**/*",
168		matches: []string{"a/a/", "a/b/", "a/a/a", "a/b/b"},
169		deps:    []string{"a", "a/a", "a/b"},
170	},
171
172	// absolute recursive tests
173	{
174		pattern: filepath.Join(pwd, "testdata/glob/**/*.ext"),
175		matches: []string{
176			filepath.Join(pwd, "testdata/glob/d.ext"),
177			filepath.Join(pwd, "testdata/glob/e.ext"),
178			filepath.Join(pwd, "testdata/glob/c/f/f.ext"),
179			filepath.Join(pwd, "testdata/glob/c/g/g.ext"),
180		},
181		deps: []string{
182			filepath.Join(pwd, "testdata/glob"),
183			filepath.Join(pwd, "testdata/glob/a"),
184			filepath.Join(pwd, "testdata/glob/a/a"),
185			filepath.Join(pwd, "testdata/glob/a/b"),
186			filepath.Join(pwd, "testdata/glob/b"),
187			filepath.Join(pwd, "testdata/glob/c"),
188			filepath.Join(pwd, "testdata/glob/c/f"),
189			filepath.Join(pwd, "testdata/glob/c/g"),
190			filepath.Join(pwd, "testdata/glob/c/h"),
191		},
192	},
193
194	// recursive error tests
195	{
196		pattern: "**/**/*",
197		err:     GlobMultipleRecursiveErr,
198	},
199	{
200		pattern: "a/**/**/*",
201		err:     GlobMultipleRecursiveErr,
202	},
203	{
204		pattern: "**/a/**/*",
205		err:     GlobMultipleRecursiveErr,
206	},
207	{
208		pattern: "**/**/a/*",
209		err:     GlobMultipleRecursiveErr,
210	},
211	{
212		pattern: "a/**",
213		err:     GlobLastRecursiveErr,
214	},
215	{
216		pattern: "**/**",
217		err:     GlobLastRecursiveErr,
218	},
219	{
220		pattern: "a**/",
221		err:     GlobInvalidRecursiveErr,
222	},
223	{
224		pattern: "**a/",
225		err:     GlobInvalidRecursiveErr,
226	},
227
228	// exclude tests
229	{
230		pattern:  "*.ext",
231		excludes: []string{"d.ext"},
232		matches:  []string{"e.ext"},
233		deps:     []string{"."},
234	},
235	{
236		pattern:  "*/*",
237		excludes: []string{"a/b"},
238		matches:  []string{"a/a/", "b/a", "c/c", "c/f/", "c/g/", "c/h/"},
239		deps:     []string{".", "a", "b", "c"},
240	},
241	{
242		pattern:  "*/*",
243		excludes: []string{"a/b", "c/c"},
244		matches:  []string{"a/a/", "b/a", "c/f/", "c/g/", "c/h/"},
245		deps:     []string{".", "a", "b", "c"},
246	},
247	{
248		pattern:  "*/*",
249		excludes: []string{"c/*", "*/a"},
250		matches:  []string{"a/b/"},
251		deps:     []string{".", "a", "b", "c"},
252	},
253	{
254		pattern:  "*/*",
255		excludes: []string{"*/*"},
256		matches:  nil,
257		deps:     []string{".", "a", "b", "c"},
258	},
259
260	// absolute exclude tests
261	{
262		pattern:  filepath.Join(pwd, "testdata/glob/c/*/*.ext"),
263		excludes: []string{filepath.Join(pwd, "testdata/glob/c/*/f.ext")},
264		matches: []string{
265			filepath.Join(pwd, "testdata/glob/c/g/g.ext"),
266		},
267		deps: []string{
268			filepath.Join(pwd, "testdata/glob/c"),
269			filepath.Join(pwd, "testdata/glob/c/f"),
270			filepath.Join(pwd, "testdata/glob/c/g"),
271			filepath.Join(pwd, "testdata/glob/c/h"),
272		},
273	},
274	{
275		pattern:  filepath.Join(pwd, "testdata/glob/c/*/*.ext"),
276		excludes: []string{filepath.Join(pwd, "testdata/glob/c/f/*.ext")},
277		matches: []string{
278			filepath.Join(pwd, "testdata/glob/c/g/g.ext"),
279		},
280		deps: []string{
281			filepath.Join(pwd, "testdata/glob/c"),
282			filepath.Join(pwd, "testdata/glob/c/f"),
283			filepath.Join(pwd, "testdata/glob/c/g"),
284			filepath.Join(pwd, "testdata/glob/c/h"),
285		},
286	},
287
288	// recursive exclude tests
289	{
290		pattern:  "*.ext",
291		excludes: []string{"**/*.ext"},
292		matches:  nil,
293		deps:     []string{"."},
294	},
295	{
296		pattern:  "*/*",
297		excludes: []string{"**/b"},
298		matches:  []string{"a/a/", "b/a", "c/c", "c/f/", "c/g/", "c/h/"},
299		deps:     []string{".", "a", "b", "c"},
300	},
301	{
302		pattern:  "*/*",
303		excludes: []string{"a/**/*"},
304		matches:  []string{"b/a", "c/c", "c/f/", "c/g/", "c/h/"},
305		deps:     []string{".", "a", "b", "c"},
306	},
307	{
308		pattern:  "**/*",
309		excludes: []string{"**/*"},
310		matches:  nil,
311		deps:     []string{".", "a", "a/a", "a/b", "b", "c", "c/f", "c/g", "c/h"},
312	},
313	{
314		pattern:  "*/*/*",
315		excludes: []string{"a/**/a"},
316		matches:  []string{"a/b/b", "c/f/f.ext", "c/g/g.ext", "c/h/h"},
317		deps:     []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"},
318	},
319	{
320		pattern:  "*/*/*",
321		excludes: []string{"**/a"},
322		matches:  []string{"a/b/b", "c/f/f.ext", "c/g/g.ext", "c/h/h"},
323		deps:     []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"},
324	},
325	{
326		pattern:  "c/*/*.ext",
327		excludes: []string{"c/**/f.ext"},
328		matches:  []string{"c/g/g.ext"},
329		deps:     []string{"c", "c/f", "c/g", "c/h"},
330	},
331
332	// absoulte recursive exclude tests
333	{
334		pattern:  filepath.Join(pwd, "testdata/glob/c/*/*.ext"),
335		excludes: []string{filepath.Join(pwd, "testdata/glob/**/f.ext")},
336		matches: []string{
337			filepath.Join(pwd, "testdata/glob/c/g/g.ext"),
338		},
339		deps: []string{
340			filepath.Join(pwd, "testdata/glob/c"),
341			filepath.Join(pwd, "testdata/glob/c/f"),
342			filepath.Join(pwd, "testdata/glob/c/g"),
343			filepath.Join(pwd, "testdata/glob/c/h"),
344		},
345	},
346
347	// clean exclude tests
348	{
349		pattern:  "./c/*/*.ext",
350		excludes: []string{"./c/*/f.ext"},
351		matches:  []string{"c/g/g.ext"},
352		deps:     []string{"c", "c/f", "c/g", "c/h"},
353	},
354	{
355		pattern:  "c/*/*.ext",
356		excludes: []string{"./c/*/f.ext"},
357		matches:  []string{"c/g/g.ext"},
358		deps:     []string{"c", "c/f", "c/g", "c/h"},
359	},
360	{
361		pattern:  "./c/*/*.ext",
362		excludes: []string{"c/*/f.ext"},
363		matches:  []string{"c/g/g.ext"},
364		deps:     []string{"c", "c/f", "c/g", "c/h"},
365	},
366
367	// non-existant non-wild path tests
368	{
369		pattern: "d/*",
370		matches: nil,
371		deps:    []string{"."},
372	},
373	{
374		pattern: "d",
375		matches: nil,
376		deps:    []string{"."},
377	},
378	{
379		pattern: "a/d/*",
380		matches: nil,
381		deps:    []string{"a"},
382	},
383	{
384		pattern: "a/d",
385		matches: nil,
386		deps:    []string{"a"},
387	},
388	{
389		pattern: "a/a/d/*",
390		matches: nil,
391		deps:    []string{"a/a"},
392	},
393	{
394		pattern: "a/a/d",
395		matches: nil,
396		deps:    []string{"a/a"},
397	},
398	{
399		pattern: "a/d/a/*",
400		matches: nil,
401		deps:    []string{"a"},
402	},
403	{
404		pattern: "a/d/a",
405		matches: nil,
406		deps:    []string{"a"},
407	},
408	{
409		pattern: "a/d/a/*/a",
410		matches: nil,
411		deps:    []string{"a"},
412	},
413	{
414		pattern: "a/d/a/**/a",
415		matches: nil,
416		deps:    []string{"a"},
417	},
418
419	// recursive exclude error tests
420	{
421		pattern:  "**/*",
422		excludes: []string{"**/**/*"},
423		err:      GlobMultipleRecursiveErr,
424	},
425	{
426		pattern:  "**/*",
427		excludes: []string{"a/**/**/*"},
428		err:      GlobMultipleRecursiveErr,
429	},
430	{
431		pattern:  "**/*",
432		excludes: []string{"**/a/**/*"},
433		err:      GlobMultipleRecursiveErr,
434	},
435	{
436		pattern:  "**/*",
437		excludes: []string{"**/**/a/*"},
438		err:      GlobMultipleRecursiveErr,
439	},
440	{
441		pattern:  "**/*",
442		excludes: []string{"a/**"},
443		err:      GlobLastRecursiveErr,
444	},
445	{
446		pattern:  "**/*",
447		excludes: []string{"**/**"},
448		err:      GlobLastRecursiveErr,
449	},
450
451	// If names are excluded by default, but referenced explicitly, they should return results
452	{
453		pattern: ".test/*",
454		matches: []string{".test/a"},
455		deps:    []string{".test"},
456	},
457	{
458		pattern: ".t*/a",
459		matches: []string{".test/a"},
460		deps:    []string{".", ".test"},
461	},
462	{
463		pattern: ".*/.*",
464		matches: []string{".test/.ing"},
465		deps:    []string{".", ".test"},
466	},
467	{
468		pattern: ".t*",
469		matches: []string{".test/", ".testing"},
470		deps:    []string{"."},
471	},
472}
473
474func TestMockGlob(t *testing.T) {
475	files := []string{
476		"a/a/a",
477		"a/b/b",
478		"b/a",
479		"c/c",
480		"c/f/f.ext",
481		"c/g/g.ext",
482		"c/h/h",
483		"d.ext",
484		"e.ext",
485		".test/a",
486		".testing",
487		".test/.ing",
488	}
489
490	mockFiles := make(map[string][]byte)
491
492	for _, f := range files {
493		mockFiles[f] = nil
494		mockFiles[filepath.Join(pwd, "testdata/glob", f)] = nil
495	}
496
497	mock := MockFs(mockFiles)
498
499	for _, testCase := range globTestCases {
500		t.Run(testCase.pattern, func(t *testing.T) {
501			testGlob(t, mock, testCase, FollowSymlinks)
502		})
503	}
504}
505
506func TestGlob(t *testing.T) {
507	os.Chdir("testdata/glob")
508	defer os.Chdir("../..")
509	for _, testCase := range globTestCases {
510		t.Run(testCase.pattern, func(t *testing.T) {
511			testGlob(t, OsFs, testCase, FollowSymlinks)
512		})
513	}
514}
515
516var globEscapeTestCases = []globTestCase{
517	{
518		pattern: `**/*`,
519		matches: []string{`*`, `**/`, `?`, `a/`, `b`, `**/*`, `**/a`, `**/b/`, `**/b/b`, `a/a`},
520		deps:    []string{`.`, `**`, `**/b`, `a`},
521	},
522	{
523		pattern: `**/\*`,
524		matches: []string{`*`, `**/*`},
525		deps:    []string{`.`, `**`, `**/b`, `a`},
526	},
527	{
528		pattern: `\*\*/*`,
529		matches: []string{`**/*`, `**/a`, `**/b/`},
530		deps:    []string{`.`, `**`},
531	},
532	{
533		pattern: `\*\*/**/*`,
534		matches: []string{`**/*`, `**/a`, `**/b/`, `**/b/b`},
535		deps:    []string{`.`, `**`, `**/b`},
536	},
537}
538
539func TestMockGlobEscapes(t *testing.T) {
540	files := []string{
541		`*`,
542		`**/*`,
543		`**/a`,
544		`**/b/b`,
545		`?`,
546		`a/a`,
547		`b`,
548	}
549
550	mockFiles := make(map[string][]byte)
551
552	for _, f := range files {
553		mockFiles[f] = nil
554	}
555
556	mock := MockFs(mockFiles)
557
558	for _, testCase := range globEscapeTestCases {
559		t.Run(testCase.pattern, func(t *testing.T) {
560			testGlob(t, mock, testCase, FollowSymlinks)
561		})
562	}
563
564}
565
566func TestGlobEscapes(t *testing.T) {
567	os.Chdir("testdata/escapes")
568	defer os.Chdir("../..")
569	for _, testCase := range globEscapeTestCases {
570		t.Run(testCase.pattern, func(t *testing.T) {
571			testGlob(t, OsFs, testCase, FollowSymlinks)
572		})
573	}
574
575}
576
577var globSymlinkTestCases = []globTestCase{
578	{
579		pattern: `**/*`,
580		matches: []string{"a/", "b/", "c/", "d/", "e", "a/a/", "a/a/a", "b/a/", "b/a/a", "c/a", "d/a"},
581		deps:    []string{".", "a", "a/a", "b", "b/a", "c", "d"},
582	},
583	{
584		pattern: `b/**/*`,
585		matches: []string{"b/a/", "b/a/a"},
586		deps:    []string{"b", "b/a"},
587	},
588}
589
590func TestMockGlobSymlinks(t *testing.T) {
591	files := []string{
592		"a/a/a",
593		"b -> a",
594		"c -> a/a",
595		"d -> c",
596		"e -> a/a/a",
597	}
598
599	mockFiles := make(map[string][]byte)
600
601	for _, f := range files {
602		mockFiles[f] = nil
603	}
604
605	mock := MockFs(mockFiles)
606
607	for _, testCase := range globSymlinkTestCases {
608		t.Run(testCase.pattern, func(t *testing.T) {
609			testGlob(t, mock, testCase, FollowSymlinks)
610		})
611	}
612}
613
614func TestGlobSymlinks(t *testing.T) {
615	os.Chdir("testdata/symlinks")
616	defer os.Chdir("../..")
617
618	for _, testCase := range globSymlinkTestCases {
619		t.Run(testCase.pattern, func(t *testing.T) {
620			testGlob(t, OsFs, testCase, FollowSymlinks)
621		})
622	}
623}
624
625var globDontFollowSymlinkTestCases = []globTestCase{
626	{
627		pattern: `**/*`,
628		matches: []string{"a/", "b", "c", "d", "e", "a/a/", "a/a/a"},
629		deps:    []string{".", "a", "a/a"},
630	},
631	{
632		pattern: `b/**/*`,
633		matches: []string{"b/a/", "b/a/a"},
634		deps:    []string{"b", "b/a"},
635	},
636}
637
638func TestMockGlobDontFollowSymlinks(t *testing.T) {
639	files := []string{
640		"a/a/a",
641		"b -> a",
642		"c -> a/a",
643		"d -> c",
644		"e -> a/a/a",
645	}
646
647	mockFiles := make(map[string][]byte)
648
649	for _, f := range files {
650		mockFiles[f] = nil
651	}
652
653	mock := MockFs(mockFiles)
654
655	for _, testCase := range globDontFollowSymlinkTestCases {
656		t.Run(testCase.pattern, func(t *testing.T) {
657			testGlob(t, mock, testCase, DontFollowSymlinks)
658		})
659	}
660}
661
662func TestGlobDontFollowSymlinks(t *testing.T) {
663	os.Chdir("testdata/symlinks")
664	defer os.Chdir("../..")
665
666	for _, testCase := range globDontFollowSymlinkTestCases {
667		t.Run(testCase.pattern, func(t *testing.T) {
668			testGlob(t, OsFs, testCase, DontFollowSymlinks)
669		})
670	}
671}
672
673var globDontFollowDanglingSymlinkTestCases = []globTestCase{
674	{
675		pattern: `**/*`,
676		matches: []string{"a/", "b", "c", "d", "dangling", "e", "f", "a/a/", "a/a/a", "a/a/f"},
677		deps:    []string{".", "a", "a/a"},
678	},
679	{
680		pattern: `dangling`,
681		matches: []string{"dangling"},
682		deps:    []string{"dangling"},
683	},
684}
685
686func TestMockGlobDontFollowDanglingSymlinks(t *testing.T) {
687	files := []string{
688		"a/a/a",
689		"a/a/f -> ../../f",
690		"b -> a",
691		"c -> a/a",
692		"d -> c",
693		"e -> a/a/a",
694		"f",
695		"dangling -> missing",
696	}
697
698	mockFiles := make(map[string][]byte)
699
700	for _, f := range files {
701		mockFiles[f] = nil
702	}
703
704	mock := MockFs(mockFiles)
705
706	for _, testCase := range globDontFollowDanglingSymlinkTestCases {
707		t.Run(testCase.pattern, func(t *testing.T) {
708			testGlob(t, mock, testCase, DontFollowSymlinks)
709		})
710	}
711}
712
713func TestGlobDontFollowDanglingSymlinks(t *testing.T) {
714	os.Chdir("testdata/dangling")
715	defer os.Chdir("../..")
716
717	for _, testCase := range globDontFollowDanglingSymlinkTestCases {
718		t.Run(testCase.pattern, func(t *testing.T) {
719			testGlob(t, OsFs, testCase, DontFollowSymlinks)
720		})
721	}
722}
723
724func testGlob(t *testing.T, fs FileSystem, testCase globTestCase, follow ShouldFollowSymlinks) {
725	t.Helper()
726	matches, deps, err := fs.Glob(testCase.pattern, testCase.excludes, follow)
727	if err != testCase.err {
728		if err == nil {
729			t.Fatalf("missing error: %s", testCase.err)
730		} else {
731			t.Fatalf("error: %s", err)
732		}
733		return
734	}
735
736	if !reflect.DeepEqual(matches, testCase.matches) {
737		t.Errorf("incorrect matches list:")
738		t.Errorf(" pattern: %q", testCase.pattern)
739		if testCase.excludes != nil {
740			t.Errorf("excludes: %q", testCase.excludes)
741		}
742		t.Errorf("     got: %#v", matches)
743		t.Errorf("expected: %#v", testCase.matches)
744	}
745	if !reflect.DeepEqual(deps, testCase.deps) {
746		t.Errorf("incorrect deps list:")
747		t.Errorf(" pattern: %q", testCase.pattern)
748		if testCase.excludes != nil {
749			t.Errorf("excludes: %q", testCase.excludes)
750		}
751		t.Errorf("     got: %#v", deps)
752		t.Errorf("expected: %#v", testCase.deps)
753	}
754}
755
756func TestMatch(t *testing.T) {
757	testCases := []struct {
758		pattern, name string
759		match         bool
760	}{
761		{"a/*", "b/", false},
762		{"a/*", "b/a", false},
763		{"a/*", "b/b/", false},
764		{"a/*", "b/b/c", false},
765		{"a/**/*", "b/", false},
766		{"a/**/*", "b/a", false},
767		{"a/**/*", "b/b/", false},
768		{"a/**/*", "b/b/c", false},
769
770		{"a/*", "a/", false},
771		{"a/*", "a/a", true},
772		{"a/*", "a/b/", false},
773		{"a/*", "a/b/c", false},
774
775		{"a/*/", "a/", false},
776		{"a/*/", "a/a", false},
777		{"a/*/", "a/b/", true},
778		{"a/*/", "a/b/c", false},
779
780		{"a/**/*", "a/", false},
781		{"a/**/*", "a/a", true},
782		{"a/**/*", "a/b/", false},
783		{"a/**/*", "a/b/c", true},
784
785		{"a/**/*/", "a/", false},
786		{"a/**/*/", "a/a", false},
787		{"a/**/*/", "a/b/", true},
788		{"a/**/*/", "a/b/c", false},
789
790		{"**/*", "a/", false},
791		{"**/*", "a/a", true},
792		{"**/*", "a/b/", false},
793		{"**/*", "a/b/c", true},
794
795		{"**/*/", "a/", true},
796		{"**/*/", "a/a", false},
797		{"**/*/", "a/b/", true},
798		{"**/*/", "a/b/c", false},
799
800		{`a/\*\*/\*`, `a/**/*`, true},
801		{`a/\*\*/\*`, `a/a/*`, false},
802		{`a/\*\*/\*`, `a/**/a`, false},
803		{`a/\*\*/\*`, `a/a/a`, false},
804
805		{`a/**/\*`, `a/**/*`, true},
806		{`a/**/\*`, `a/a/*`, true},
807		{`a/**/\*`, `a/**/a`, false},
808		{`a/**/\*`, `a/a/a`, false},
809
810		{`a/\*\*/*`, `a/**/*`, true},
811		{`a/\*\*/*`, `a/a/*`, false},
812		{`a/\*\*/*`, `a/**/a`, true},
813		{`a/\*\*/*`, `a/a/a`, false},
814
815		{`*/**/a`, `a/a/a`, true},
816		{`*/**/a`, `*/a/a`, true},
817		{`*/**/a`, `a/**/a`, true},
818		{`*/**/a`, `*/**/a`, true},
819
820		{`\*/\*\*/a`, `a/a/a`, false},
821		{`\*/\*\*/a`, `*/a/a`, false},
822		{`\*/\*\*/a`, `a/**/a`, false},
823		{`\*/\*\*/a`, `*/**/a`, true},
824
825		{`a/?`, `a/?`, true},
826		{`a/?`, `a/a`, true},
827		{`a/\?`, `a/?`, true},
828		{`a/\?`, `a/a`, false},
829
830		{`a/?`, `a/?`, true},
831		{`a/?`, `a/a`, true},
832		{`a/\?`, `a/?`, true},
833		{`a/\?`, `a/a`, false},
834
835		{`a/[a-c]`, `a/b`, true},
836		{`a/[abc]`, `a/b`, true},
837
838		{`a/\[abc]`, `a/b`, false},
839		{`a/\[abc]`, `a/[abc]`, true},
840
841		{`a/\[abc\]`, `a/b`, false},
842		{`a/\[abc\]`, `a/[abc]`, true},
843
844		{`a/?`, `a/?`, true},
845		{`a/?`, `a/a`, true},
846		{`a/\?`, `a/?`, true},
847		{`a/\?`, `a/a`, false},
848
849		{"/a/*", "/a/", false},
850		{"/a/*", "/a/a", true},
851		{"/a/*", "/a/b/", false},
852		{"/a/*", "/a/b/c", false},
853
854		{"/a/*/", "/a/", false},
855		{"/a/*/", "/a/a", false},
856		{"/a/*/", "/a/b/", true},
857		{"/a/*/", "/a/b/c", false},
858
859		{"/a/**/*", "/a/", false},
860		{"/a/**/*", "/a/a", true},
861		{"/a/**/*", "/a/b/", false},
862		{"/a/**/*", "/a/b/c", true},
863
864		{"/**/*", "/a/", false},
865		{"/**/*", "/a/a", true},
866		{"/**/*", "/a/b/", false},
867		{"/**/*", "/a/b/c", true},
868
869		{"/**/*/", "/a/", true},
870		{"/**/*/", "/a/a", false},
871		{"/**/*/", "/a/b/", true},
872		{"/**/*/", "/a/b/c", false},
873
874		{`a`, `/a`, false},
875		{`/a`, `a`, false},
876		{`*`, `/a`, false},
877		{`/*`, `a`, false},
878		{`**/*`, `/a`, false},
879		{`/**/*`, `a`, false},
880	}
881
882	for _, test := range testCases {
883		t.Run(test.pattern+","+test.name, func(t *testing.T) {
884			match, err := Match(test.pattern, test.name)
885			if err != nil {
886				t.Fatal(err)
887			}
888			if match != test.match {
889				t.Errorf("want: %v, got %v", test.match, match)
890			}
891		})
892	}
893
894	// Run the same test cases through Glob
895	for _, test := range testCases {
896		// Glob and Match disagree on matching directories
897		if strings.HasSuffix(test.name, "/") || strings.HasSuffix(test.pattern, "/") {
898			continue
899		}
900		t.Run("glob:"+test.pattern+","+test.name, func(t *testing.T) {
901			mockFiles := map[string][]byte{
902				test.name: nil,
903			}
904
905			mock := MockFs(mockFiles)
906
907			matches, _, err := mock.Glob(test.pattern, nil, DontFollowSymlinks)
908			t.Log(test.name, test.pattern, matches)
909			if err != nil {
910				t.Fatal(err)
911			}
912
913			match := false
914			for _, x := range matches {
915				if x == test.name {
916					match = true
917				}
918			}
919
920			if match != test.match {
921				t.Errorf("want: %v, got %v", test.match, match)
922			}
923		})
924	}
925}
926