github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/path/filepath/match_test.go (about) 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. 4 5 package filepath_test 6 7 import ( 8 "fmt" 9 "internal/testenv" 10 "os" 11 . "path/filepath" 12 "reflect" 13 "runtime" 14 "sort" 15 "strings" 16 "testing" 17 ) 18 19 type MatchTest struct { 20 pattern, s string 21 match bool 22 err error 23 } 24 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}, 82 } 83 84 func errp(e error) string { 85 if e == nil { 86 return "<nil>" 87 } 88 return e.Error() 89 } 90 91 func TestMatch(t *testing.T) { 92 for _, tt := range matchTests { 93 pattern := tt.pattern 94 s := tt.s 95 if runtime.GOOS == "windows" { 96 if strings.Contains(pattern, "\\") { 97 // no escape allowed on windows. 98 continue 99 } 100 pattern = Clean(pattern) 101 s = Clean(s) 102 } 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)) 106 } 107 } 108 } 109 110 // contains reports whether vector contains the string s. 111 func contains(vector []string, s string) bool { 112 for _, elem := range vector { 113 if elem == s { 114 return true 115 } 116 } 117 return false 118 } 119 120 var globTests = []struct { 121 pattern, result string 122 }{ 123 {"match.go", "match.go"}, 124 {"mat?h.go", "match.go"}, 125 {"*", "match.go"}, 126 {"../*/match.go", "../filepath/match.go"}, 127 } 128 129 func TestGlob(t *testing.T) { 130 for _, tt := range globTests { 131 pattern := tt.pattern 132 result := tt.result 133 if runtime.GOOS == "windows" { 134 pattern = Clean(pattern) 135 result = Clean(result) 136 } 137 matches, err := Glob(pattern) 138 if err != nil { 139 t.Errorf("Glob error for %q: %s", pattern, err) 140 continue 141 } 142 if !contains(matches, result) { 143 t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result) 144 } 145 } 146 for _, pattern := range []string{"no_match", "../*/no_match"} { 147 matches, err := Glob(pattern) 148 if err != nil { 149 t.Errorf("Glob error for %q: %s", pattern, err) 150 continue 151 } 152 if len(matches) != 0 { 153 t.Errorf("Glob(%#q) = %#v want []", pattern, matches) 154 } 155 } 156 } 157 158 func TestGlobError(t *testing.T) { 159 bad := []string{`[]`, `nonexist/[]`} 160 for _, pattern := range bad { 161 if _, err := Glob(pattern); err != ErrBadPattern { 162 t.Errorf("Glob(%#q) returned err=%v, want ErrBadPattern", pattern, err) 163 } 164 } 165 } 166 167 func TestGlobUNC(t *testing.T) { 168 // Just make sure this runs without crashing for now. 169 // See issue 15879. 170 Glob(`\\?\C:\*`) 171 } 172 173 var globSymlinkTests = []struct { 174 path, dest string 175 brokenLink bool 176 }{ 177 {"test1", "link1", false}, 178 {"test2", "link2", true}, 179 } 180 181 func TestGlobSymlink(t *testing.T) { 182 testenv.MustHaveSymlink(t) 183 184 tmpDir, err := os.MkdirTemp("", "globsymlink") 185 if err != nil { 186 t.Fatal("creating temp dir:", err) 187 } 188 defer os.RemoveAll(tmpDir) 189 190 for _, tt := range globSymlinkTests { 191 path := Join(tmpDir, tt.path) 192 dest := Join(tmpDir, tt.dest) 193 f, err := os.Create(path) 194 if err != nil { 195 t.Fatal(err) 196 } 197 if err := f.Close(); err != nil { 198 t.Fatal(err) 199 } 200 err = os.Symlink(path, dest) 201 if err != nil { 202 t.Fatal(err) 203 } 204 if tt.brokenLink { 205 // Break the symlink. 206 os.Remove(path) 207 } 208 matches, err := Glob(dest) 209 if err != nil { 210 t.Errorf("GlobSymlink error for %q: %s", dest, err) 211 } 212 if !contains(matches, dest) { 213 t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest) 214 } 215 } 216 } 217 218 type globTest struct { 219 pattern string 220 matches []string 221 } 222 223 func (test *globTest) buildWant(root string) []string { 224 want := make([]string, 0) 225 for _, m := range test.matches { 226 want = append(want, root+FromSlash(m)) 227 } 228 sort.Strings(want) 229 return want 230 } 231 232 func (test *globTest) globAbs(root, rootPattern string) error { 233 p := FromSlash(rootPattern + `\` + test.pattern) 234 have, err := Glob(p) 235 if err != nil { 236 return err 237 } 238 sort.Strings(have) 239 want := test.buildWant(root + `\`) 240 if strings.Join(want, "_") == strings.Join(have, "_") { 241 return nil 242 } 243 return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want) 244 } 245 246 func (test *globTest) globRel(root string) error { 247 p := root + FromSlash(test.pattern) 248 have, err := Glob(p) 249 if err != nil { 250 return err 251 } 252 sort.Strings(have) 253 want := test.buildWant(root) 254 if strings.Join(want, "_") == strings.Join(have, "_") { 255 return nil 256 } 257 // try also matching version without root prefix 258 wantWithNoRoot := test.buildWant("") 259 if strings.Join(wantWithNoRoot, "_") == strings.Join(have, "_") { 260 return nil 261 } 262 return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want) 263 } 264 265 func TestWindowsGlob(t *testing.T) { 266 if runtime.GOOS != "windows" { 267 t.Skipf("skipping windows specific test") 268 } 269 270 tmpDir, err := os.MkdirTemp("", "TestWindowsGlob") 271 if err != nil { 272 t.Fatal(err) 273 } 274 defer os.RemoveAll(tmpDir) 275 276 // /tmp may itself be a symlink 277 tmpDir, err = EvalSymlinks(tmpDir) 278 if err != nil { 279 t.Fatal("eval symlink for tmp dir:", err) 280 } 281 282 if len(tmpDir) < 3 { 283 t.Fatalf("tmpDir path %q is too short", tmpDir) 284 } 285 if tmpDir[1] != ':' { 286 t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir) 287 } 288 289 dirs := []string{ 290 "a", 291 "b", 292 "dir/d/bin", 293 } 294 files := []string{ 295 "dir/d/bin/git.exe", 296 } 297 for _, dir := range dirs { 298 err := os.MkdirAll(Join(tmpDir, dir), 0777) 299 if err != nil { 300 t.Fatal(err) 301 } 302 } 303 for _, file := range files { 304 err := os.WriteFile(Join(tmpDir, file), nil, 0666) 305 if err != nil { 306 t.Fatal(err) 307 } 308 } 309 310 tests := []globTest{ 311 {"a", []string{"a"}}, 312 {"b", []string{"b"}}, 313 {"c", []string{}}, 314 {"*", []string{"a", "b", "dir"}}, 315 {"d*", []string{"dir"}}, 316 {"*i*", []string{"dir"}}, 317 {"*r", []string{"dir"}}, 318 {"?ir", []string{"dir"}}, 319 {"?r", []string{}}, 320 {"d*/*/bin/git.exe", []string{"dir/d/bin/git.exe"}}, 321 } 322 323 // test absolute paths 324 for _, test := range tests { 325 var p string 326 err = test.globAbs(tmpDir, tmpDir) 327 if err != nil { 328 t.Error(err) 329 } 330 // test C:\*Documents and Settings\... 331 p = tmpDir 332 p = strings.Replace(p, `:\`, `:\*`, 1) 333 err = test.globAbs(tmpDir, p) 334 if err != nil { 335 t.Error(err) 336 } 337 // test C:\Documents and Settings*\... 338 p = tmpDir 339 p = strings.Replace(p, `:\`, `:`, 1) 340 p = strings.Replace(p, `\`, `*\`, 1) 341 p = strings.Replace(p, `:`, `:\`, 1) 342 err = test.globAbs(tmpDir, p) 343 if err != nil { 344 t.Error(err) 345 } 346 } 347 348 // test relative paths 349 wd, err := os.Getwd() 350 if err != nil { 351 t.Fatal(err) 352 } 353 err = os.Chdir(tmpDir) 354 if err != nil { 355 t.Fatal(err) 356 } 357 defer func() { 358 err := os.Chdir(wd) 359 if err != nil { 360 t.Fatal(err) 361 } 362 }() 363 for _, test := range tests { 364 err := test.globRel("") 365 if err != nil { 366 t.Error(err) 367 } 368 err = test.globRel(`.\`) 369 if err != nil { 370 t.Error(err) 371 } 372 err = test.globRel(tmpDir[:2]) // C: 373 if err != nil { 374 t.Error(err) 375 } 376 } 377 } 378 379 func TestNonWindowsGlobEscape(t *testing.T) { 380 if runtime.GOOS == "windows" { 381 t.Skipf("skipping non-windows specific test") 382 } 383 pattern := `\match.go` 384 want := []string{"match.go"} 385 matches, err := Glob(pattern) 386 if err != nil { 387 t.Fatalf("Glob error for %q: %s", pattern, err) 388 } 389 if !reflect.DeepEqual(matches, want) { 390 t.Fatalf("Glob(%#q) = %v want %v", pattern, matches, want) 391 } 392 }