1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
19 type MatchTest
struct {
25 var matchTests
= []MatchTest
{
26 {"abc", "abc", true, nil},
27 {"*", "abc", true, nil},
28 {"*c", "abc", true, nil},
29 {"a*", "a", true, nil},
30 {"a*", "abc", true, nil},
31 {"a*", "ab/c", false, nil},
32 {"a*/b", "abc/b", true, nil},
33 {"a*/b", "a/c/b", false, nil},
34 {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
35 {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
36 {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
37 {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
38 {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
39 {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
40 {"ab[c]", "abc", true, nil},
41 {"ab[b-d]", "abc", true, nil},
42 {"ab[e-g]", "abc", false, nil},
43 {"ab[^c]", "abc", false, nil},
44 {"ab[^b-d]", "abc", false, nil},
45 {"ab[^e-g]", "abc", true, nil},
46 {"a\\*b", "a*b", true, nil},
47 {"a\\*b", "ab", false, nil},
48 {"a?b", "a☺b", true, nil},
49 {"a[^a]b", "a☺b", true, nil},
50 {"a???b", "a☺b", false, nil},
51 {"a[^a][^a][^a]b", "a☺b", false, nil},
52 {"[a-ζ]*", "α", true, nil},
53 {"*[a-ζ]", "A", false, nil},
54 {"a?b", "a/b", false, nil},
55 {"a*b", "a/b", false, nil},
56 {"[\\]a]", "]", true, nil},
57 {"[\\-]", "-", true, nil},
58 {"[x\\-]", "x", true, nil},
59 {"[x\\-]", "-", true, nil},
60 {"[x\\-]", "z", false, nil},
61 {"[\\-x]", "x", true, nil},
62 {"[\\-x]", "-", true, nil},
63 {"[\\-x]", "a", false, nil},
64 {"[]a]", "]", false, ErrBadPattern
},
65 {"[-]", "-", false, ErrBadPattern
},
66 {"[x-]", "x", false, ErrBadPattern
},
67 {"[x-]", "-", false, ErrBadPattern
},
68 {"[x-]", "z", false, ErrBadPattern
},
69 {"[-x]", "x", false, ErrBadPattern
},
70 {"[-x]", "-", false, ErrBadPattern
},
71 {"[-x]", "a", false, ErrBadPattern
},
72 {"\\", "a", false, ErrBadPattern
},
73 {"[a-b-c]", "a", false, ErrBadPattern
},
74 {"[", "a", false, ErrBadPattern
},
75 {"[^", "a", false, ErrBadPattern
},
76 {"[^bc", "a", false, ErrBadPattern
},
77 {"a[", "a", false, ErrBadPattern
},
78 {"a[", "ab", false, ErrBadPattern
},
79 {"a[", "x", false, ErrBadPattern
},
80 {"a/b[", "x", false, ErrBadPattern
},
81 {"*x", "xxx", true, nil},
84 func errp(e error
) string {
91 func TestMatch(t
*testing
.T
) {
92 for _
, tt
:= range matchTests
{
95 if runtime
.GOOS
== "windows" {
96 if strings
.Contains(pattern
, "\\") {
97 // no escape allowed on windows.
100 pattern
= Clean(pattern
)
103 ok
, err
:= Match(pattern
, s
)
104 if ok
!= tt
.match || err
!= tt
.err
{
105 t
.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern
, s
, ok
, errp(err
), tt
.match
, errp(tt
.err
))
110 // contains reports whether vector contains the string s.
111 func contains(vector
[]string, s
string) bool {
112 for _
, elem
:= range vector
{
120 var globTests
= []struct {
121 pattern
, result
string
123 {"match.go", "match.go"},
124 {"mat?h.go", "match.go"},
126 // Does not work in gccgo test environment.
127 // {"../*/match.go", "../filepath/match.go"},
130 func TestGlob(t
*testing
.T
) {
131 for _
, tt
:= range globTests
{
132 pattern
:= tt
.pattern
134 if runtime
.GOOS
== "windows" {
135 pattern
= Clean(pattern
)
136 result
= Clean(result
)
138 matches
, err
:= Glob(pattern
)
140 t
.Errorf("Glob error for %q: %s", pattern
, err
)
143 if !contains(matches
, result
) {
144 t
.Errorf("Glob(%#q) = %#v want %v", pattern
, matches
, result
)
147 for _
, pattern
:= range []string{"no_match", "../*/no_match"} {
148 matches
, err
:= Glob(pattern
)
150 t
.Errorf("Glob error for %q: %s", pattern
, err
)
153 if len(matches
) != 0 {
154 t
.Errorf("Glob(%#q) = %#v want []", pattern
, matches
)
159 func TestGlobError(t
*testing
.T
) {
160 bad
:= []string{`[]`, `nonexist/[]`}
161 for _
, pattern
:= range bad
{
162 if _
, err
:= Glob(pattern
); err
!= ErrBadPattern
{
163 t
.Errorf("Glob(%#q) returned err=%v, want ErrBadPattern", pattern
, err
)
168 func TestGlobUNC(t
*testing
.T
) {
169 // Just make sure this runs without crashing for now.
174 var globSymlinkTests
= []struct {
178 {"test1", "link1", false},
179 {"test2", "link2", true},
182 func TestGlobSymlink(t
*testing
.T
) {
183 testenv
.MustHaveSymlink(t
)
185 tmpDir
:= t
.TempDir()
186 for _
, tt
:= range globSymlinkTests
{
187 path
:= Join(tmpDir
, tt
.path
)
188 dest
:= Join(tmpDir
, tt
.dest
)
189 f
, err
:= os
.Create(path
)
193 if err
:= f
.Close(); err
!= nil {
196 err
= os
.Symlink(path
, dest
)
201 // Break the symlink.
204 matches
, err
:= Glob(dest
)
206 t
.Errorf("GlobSymlink error for %q: %s", dest
, err
)
208 if !contains(matches
, dest
) {
209 t
.Errorf("Glob(%#q) = %#v want %v", dest
, matches
, dest
)
214 type globTest
struct {
219 func (test
*globTest
) buildWant(root
string) []string {
220 want
:= make([]string, 0)
221 for _
, m
:= range test
.matches
{
222 want
= append(want
, root
+FromSlash(m
))
228 func (test
*globTest
) globAbs(root
, rootPattern
string) error
{
229 p
:= FromSlash(rootPattern
+ `\` + test
.pattern
)
235 want
:= test
.buildWant(root
+ `\`)
236 if strings
.Join(want
, "_") == strings
.Join(have
, "_") {
239 return fmt
.Errorf("Glob(%q) returns %q, but %q expected", p
, have
, want
)
242 func (test
*globTest
) globRel(root
string) error
{
243 p
:= root
+ FromSlash(test
.pattern
)
249 want
:= test
.buildWant(root
)
250 if strings
.Join(want
, "_") == strings
.Join(have
, "_") {
253 // try also matching version without root prefix
254 wantWithNoRoot
:= test
.buildWant("")
255 if strings
.Join(wantWithNoRoot
, "_") == strings
.Join(have
, "_") {
258 return fmt
.Errorf("Glob(%q) returns %q, but %q expected", p
, have
, want
)
261 func TestWindowsGlob(t
*testing
.T
) {
262 if runtime
.GOOS
!= "windows" {
263 t
.Skipf("skipping windows specific test")
266 tmpDir
:= tempDirCanonical(t
)
268 t
.Fatalf("tmpDir path %q is too short", tmpDir
)
270 if tmpDir
[1] != ':' {
271 t
.Fatalf("tmpDir path %q must have drive letter in it", tmpDir
)
282 for _
, dir
:= range dirs
{
283 err
:= os
.MkdirAll(Join(tmpDir
, dir
), 0777)
288 for _
, file
:= range files
{
289 err
:= os
.WriteFile(Join(tmpDir
, file
), nil, 0666)
296 {"a", []string{"a"}},
297 {"b", []string{"b"}},
299 {"*", []string{"a", "b", "dir"}},
300 {"d*", []string{"dir"}},
301 {"*i*", []string{"dir"}},
302 {"*r", []string{"dir"}},
303 {"?ir", []string{"dir"}},
305 {"d*/*/bin/git.exe", []string{"dir/d/bin/git.exe"}},
308 // test absolute paths
309 for _
, test
:= range tests
{
311 if err
:= test
.globAbs(tmpDir
, tmpDir
); err
!= nil {
314 // test C:\*Documents and Settings\...
316 p
= strings
.Replace(p
, `:\`, `:\*`, 1)
317 if err
:= test
.globAbs(tmpDir
, p
); err
!= nil {
320 // test C:\Documents and Settings*\...
322 p
= strings
.Replace(p
, `:\`, `:`, 1)
323 p
= strings
.Replace(p
, `\`, `*\`, 1)
324 p
= strings
.Replace(p
, `:`, `:\`, 1)
325 if err
:= test
.globAbs(tmpDir
, p
); err
!= nil {
330 // test relative paths
331 wd
, err
:= os
.Getwd()
335 err
= os
.Chdir(tmpDir
)
345 for _
, test
:= range tests
{
346 err
:= test
.globRel("")
350 err
= test
.globRel(`.\`)
354 err
= test
.globRel(tmpDir
[:2]) // C:
361 func TestNonWindowsGlobEscape(t
*testing
.T
) {
362 if runtime
.GOOS
== "windows" {
363 t
.Skipf("skipping non-windows specific test")
365 pattern
:= `\match.go`
366 want
:= []string{"match.go"}
367 matches
, err
:= Glob(pattern
)
369 t
.Fatalf("Glob error for %q: %s", pattern
, err
)
371 if !reflect
.DeepEqual(matches
, want
) {
372 t
.Fatalf("Glob(%#q) = %v want %v", pattern
, matches
, want
)