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