github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/pkg/fileutils/fileutils_test.go (about) 1 package fileutils // import "github.com/docker/docker/pkg/fileutils" 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "path/filepath" 8 "runtime" 9 "strings" 10 "testing" 11 12 "gotest.tools/v3/assert" 13 is "gotest.tools/v3/assert/cmp" 14 ) 15 16 // CopyFile with invalid src 17 func TestCopyFileWithInvalidSrc(t *testing.T) { 18 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") // #nosec G303 19 defer os.RemoveAll(tempFolder) 20 if err != nil { 21 t.Fatal(err) 22 } 23 bytes, err := CopyFile("/invalid/file/path", path.Join(tempFolder, "dest")) 24 if err == nil { 25 t.Fatal("Should have fail to copy an invalid src file") 26 } 27 if bytes != 0 { 28 t.Fatal("Should have written 0 bytes") 29 } 30 31 } 32 33 // CopyFile with invalid dest 34 func TestCopyFileWithInvalidDest(t *testing.T) { 35 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 36 defer os.RemoveAll(tempFolder) 37 if err != nil { 38 t.Fatal(err) 39 } 40 src := path.Join(tempFolder, "file") 41 err = os.WriteFile(src, []byte("content"), 0740) 42 if err != nil { 43 t.Fatal(err) 44 } 45 bytes, err := CopyFile(src, path.Join(tempFolder, "/invalid/dest/path")) 46 if err == nil { 47 t.Fatal("Should have fail to copy an invalid src file") 48 } 49 if bytes != 0 { 50 t.Fatal("Should have written 0 bytes") 51 } 52 53 } 54 55 // CopyFile with same src and dest 56 func TestCopyFileWithSameSrcAndDest(t *testing.T) { 57 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 58 defer os.RemoveAll(tempFolder) 59 if err != nil { 60 t.Fatal(err) 61 } 62 file := path.Join(tempFolder, "file") 63 err = os.WriteFile(file, []byte("content"), 0740) 64 if err != nil { 65 t.Fatal(err) 66 } 67 bytes, err := CopyFile(file, file) 68 if err != nil { 69 t.Fatal(err) 70 } 71 if bytes != 0 { 72 t.Fatal("Should have written 0 bytes as it is the same file.") 73 } 74 } 75 76 // CopyFile with same src and dest but path is different and not clean 77 func TestCopyFileWithSameSrcAndDestWithPathNameDifferent(t *testing.T) { 78 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 79 defer os.RemoveAll(tempFolder) 80 if err != nil { 81 t.Fatal(err) 82 } 83 testFolder := path.Join(tempFolder, "test") 84 err = os.MkdirAll(testFolder, 0740) 85 if err != nil { 86 t.Fatal(err) 87 } 88 file := path.Join(testFolder, "file") 89 sameFile := testFolder + "/../test/file" 90 err = os.WriteFile(file, []byte("content"), 0740) 91 if err != nil { 92 t.Fatal(err) 93 } 94 bytes, err := CopyFile(file, sameFile) 95 if err != nil { 96 t.Fatal(err) 97 } 98 if bytes != 0 { 99 t.Fatal("Should have written 0 bytes as it is the same file.") 100 } 101 } 102 103 func TestCopyFile(t *testing.T) { 104 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 105 defer os.RemoveAll(tempFolder) 106 if err != nil { 107 t.Fatal(err) 108 } 109 src := path.Join(tempFolder, "src") 110 dest := path.Join(tempFolder, "dest") 111 os.WriteFile(src, []byte("content"), 0777) 112 os.WriteFile(dest, []byte("destContent"), 0777) 113 bytes, err := CopyFile(src, dest) 114 if err != nil { 115 t.Fatal(err) 116 } 117 if bytes != 7 { 118 t.Fatalf("Should have written %d bytes but wrote %d", 7, bytes) 119 } 120 actual, err := os.ReadFile(dest) 121 if err != nil { 122 t.Fatal(err) 123 } 124 if string(actual) != "content" { 125 t.Fatalf("Dest content was '%s', expected '%s'", string(actual), "content") 126 } 127 } 128 129 // Reading a symlink to a directory must return the directory 130 func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) { 131 // TODO Windows: Port this test 132 if runtime.GOOS == "windows" { 133 t.Skip("Needs porting to Windows") 134 } 135 var err error 136 if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil { 137 t.Errorf("failed to create directory: %s", err) 138 } 139 140 if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil { 141 t.Errorf("failed to create symlink: %s", err) 142 } 143 144 var path string 145 if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil { 146 t.Fatalf("failed to read symlink to directory: %s", err) 147 } 148 149 if path != "/tmp/testReadSymlinkToExistingDirectory" { 150 t.Fatalf("symlink returned unexpected directory: %s", path) 151 } 152 153 if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil { 154 t.Errorf("failed to remove temporary directory: %s", err) 155 } 156 157 if err = os.Remove("/tmp/dirLinkTest"); err != nil { 158 t.Errorf("failed to remove symlink: %s", err) 159 } 160 } 161 162 // Reading a non-existing symlink must fail 163 func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) { 164 var path string 165 var err error 166 if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil { 167 t.Fatalf("error expected for non-existing symlink") 168 } 169 170 if path != "" { 171 t.Fatalf("expected empty path, but '%s' was returned", path) 172 } 173 } 174 175 // Reading a symlink to a file must fail 176 func TestReadSymlinkedDirectoryToFile(t *testing.T) { 177 // TODO Windows: Port this test 178 if runtime.GOOS == "windows" { 179 t.Skip("Needs porting to Windows") 180 } 181 var err error 182 var file *os.File 183 184 // #nosec G303 185 if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil { 186 t.Fatalf("failed to create file: %s", err) 187 } 188 189 file.Close() 190 191 if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil { 192 t.Errorf("failed to create symlink: %s", err) 193 } 194 195 var path string 196 if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil { 197 t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed") 198 } 199 200 if path != "" { 201 t.Fatalf("path should've been empty: %s", path) 202 } 203 204 if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil { 205 t.Errorf("failed to remove file: %s", err) 206 } 207 208 if err = os.Remove("/tmp/fileLinkTest"); err != nil { 209 t.Errorf("failed to remove symlink: %s", err) 210 } 211 } 212 213 func TestWildcardMatches(t *testing.T) { 214 match, _ := Matches("fileutils.go", []string{"*"}) 215 if !match { 216 t.Errorf("failed to get a wildcard match, got %v", match) 217 } 218 } 219 220 // A simple pattern match should return true. 221 func TestPatternMatches(t *testing.T) { 222 match, _ := Matches("fileutils.go", []string{"*.go"}) 223 if !match { 224 t.Errorf("failed to get a match, got %v", match) 225 } 226 } 227 228 // An exclusion followed by an inclusion should return true. 229 func TestExclusionPatternMatchesPatternBefore(t *testing.T) { 230 match, _ := Matches("fileutils.go", []string{"!fileutils.go", "*.go"}) 231 if !match { 232 t.Errorf("failed to get true match on exclusion pattern, got %v", match) 233 } 234 } 235 236 // A folder pattern followed by an exception should return false. 237 func TestPatternMatchesFolderExclusions(t *testing.T) { 238 match, _ := Matches("docs/README.md", []string{"docs", "!docs/README.md"}) 239 if match { 240 t.Errorf("failed to get a false match on exclusion pattern, got %v", match) 241 } 242 } 243 244 // A folder pattern followed by an exception should return false. 245 func TestPatternMatchesFolderWithSlashExclusions(t *testing.T) { 246 match, _ := Matches("docs/README.md", []string{"docs/", "!docs/README.md"}) 247 if match { 248 t.Errorf("failed to get a false match on exclusion pattern, got %v", match) 249 } 250 } 251 252 // A folder pattern followed by an exception should return false. 253 func TestPatternMatchesFolderWildcardExclusions(t *testing.T) { 254 match, _ := Matches("docs/README.md", []string{"docs/*", "!docs/README.md"}) 255 if match { 256 t.Errorf("failed to get a false match on exclusion pattern, got %v", match) 257 } 258 } 259 260 // A pattern followed by an exclusion should return false. 261 func TestExclusionPatternMatchesPatternAfter(t *testing.T) { 262 match, _ := Matches("fileutils.go", []string{"*.go", "!fileutils.go"}) 263 if match { 264 t.Errorf("failed to get false match on exclusion pattern, got %v", match) 265 } 266 } 267 268 // A filename evaluating to . should return false. 269 func TestExclusionPatternMatchesWholeDirectory(t *testing.T) { 270 match, _ := Matches(".", []string{"*.go"}) 271 if match { 272 t.Errorf("failed to get false match on ., got %v", match) 273 } 274 } 275 276 // A single ! pattern should return an error. 277 func TestSingleExclamationError(t *testing.T) { 278 _, err := Matches("fileutils.go", []string{"!"}) 279 if err == nil { 280 t.Errorf("failed to get an error for a single exclamation point, got %v", err) 281 } 282 } 283 284 // Matches with no patterns 285 func TestMatchesWithNoPatterns(t *testing.T) { 286 matches, err := Matches("/any/path/there", []string{}) 287 if err != nil { 288 t.Fatal(err) 289 } 290 if matches { 291 t.Fatalf("Should not have match anything") 292 } 293 } 294 295 // Matches with malformed patterns 296 func TestMatchesWithMalformedPatterns(t *testing.T) { 297 matches, err := Matches("/any/path/there", []string{"["}) 298 if err == nil { 299 t.Fatal("Should have failed because of a malformed syntax in the pattern") 300 } 301 if matches { 302 t.Fatalf("Should not have match anything") 303 } 304 } 305 306 type matchesTestCase struct { 307 pattern string 308 text string 309 pass bool 310 } 311 312 type multiPatternTestCase struct { 313 patterns []string 314 text string 315 pass bool 316 } 317 318 func TestMatches(t *testing.T) { 319 tests := []matchesTestCase{ 320 {"**", "file", true}, 321 {"**", "file/", true}, 322 {"**/", "file", true}, // weird one 323 {"**/", "file/", true}, 324 {"**", "/", true}, 325 {"**/", "/", true}, 326 {"**", "dir/file", true}, 327 {"**/", "dir/file", true}, 328 {"**", "dir/file/", true}, 329 {"**/", "dir/file/", true}, 330 {"**/**", "dir/file", true}, 331 {"**/**", "dir/file/", true}, 332 {"dir/**", "dir/file", true}, 333 {"dir/**", "dir/file/", true}, 334 {"dir/**", "dir/dir2/file", true}, 335 {"dir/**", "dir/dir2/file/", true}, 336 {"**/dir", "dir", true}, 337 {"**/dir", "dir/file", true}, 338 {"**/dir2/*", "dir/dir2/file", true}, 339 {"**/dir2/*", "dir/dir2/file/", true}, 340 {"**/dir2/**", "dir/dir2/dir3/file", true}, 341 {"**/dir2/**", "dir/dir2/dir3/file/", true}, 342 {"**file", "file", true}, 343 {"**file", "dir/file", true}, 344 {"**/file", "dir/file", true}, 345 {"**file", "dir/dir/file", true}, 346 {"**/file", "dir/dir/file", true}, 347 {"**/file*", "dir/dir/file", true}, 348 {"**/file*", "dir/dir/file.txt", true}, 349 {"**/file*txt", "dir/dir/file.txt", true}, 350 {"**/file*.txt", "dir/dir/file.txt", true}, 351 {"**/file*.txt*", "dir/dir/file.txt", true}, 352 {"**/**/*.txt", "dir/dir/file.txt", true}, 353 {"**/**/*.txt2", "dir/dir/file.txt", false}, 354 {"**/*.txt", "file.txt", true}, 355 {"**/**/*.txt", "file.txt", true}, 356 {"a**/*.txt", "a/file.txt", true}, 357 {"a**/*.txt", "a/dir/file.txt", true}, 358 {"a**/*.txt", "a/dir/dir/file.txt", true}, 359 {"a/*.txt", "a/dir/file.txt", false}, 360 {"a/*.txt", "a/file.txt", true}, 361 {"a/*.txt**", "a/file.txt", true}, 362 {"a[b-d]e", "ae", false}, 363 {"a[b-d]e", "ace", true}, 364 {"a[b-d]e", "aae", false}, 365 {"a[^b-d]e", "aze", true}, 366 {".*", ".foo", true}, 367 {".*", "foo", false}, 368 {"abc.def", "abcdef", false}, 369 {"abc.def", "abc.def", true}, 370 {"abc.def", "abcZdef", false}, 371 {"abc?def", "abcZdef", true}, 372 {"abc?def", "abcdef", false}, 373 {"a\\\\", "a\\", true}, 374 {"**/foo/bar", "foo/bar", true}, 375 {"**/foo/bar", "dir/foo/bar", true}, 376 {"**/foo/bar", "dir/dir2/foo/bar", true}, 377 {"abc/**", "abc", false}, 378 {"abc/**", "abc/def", true}, 379 {"abc/**", "abc/def/ghi", true}, 380 {"**/.foo", ".foo", true}, 381 {"**/.foo", "bar.foo", false}, 382 {"a(b)c/def", "a(b)c/def", true}, 383 {"a(b)c/def", "a(b)c/xyz", false}, 384 {"a.|)$(}+{bc", "a.|)$(}+{bc", true}, 385 } 386 multiPatternTests := []multiPatternTestCase{ 387 {[]string{"**", "!util/docker/web"}, "util/docker/web/foo", false}, 388 {[]string{"**", "!util/docker/web", "util/docker/web/foo"}, "util/docker/web/foo", true}, 389 } 390 391 if runtime.GOOS != "windows" { 392 tests = append(tests, []matchesTestCase{ 393 {"a\\*b", "a*b", true}, 394 }...) 395 } 396 397 t.Run("MatchesOrParentMatches", func(t *testing.T) { 398 for _, test := range tests { 399 desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text) 400 pm, err := NewPatternMatcher([]string{test.pattern}) 401 assert.NilError(t, err, desc) 402 res, _ := pm.MatchesOrParentMatches(test.text) 403 assert.Check(t, is.Equal(test.pass, res), desc) 404 } 405 406 for _, test := range multiPatternTests { 407 desc := fmt.Sprintf("patterns=%q text=%q", test.patterns, test.text) 408 pm, err := NewPatternMatcher(test.patterns) 409 assert.NilError(t, err, desc) 410 res, _ := pm.MatchesOrParentMatches(test.text) 411 assert.Check(t, is.Equal(test.pass, res), desc) 412 } 413 }) 414 415 t.Run("MatchesUsingParentResult", func(t *testing.T) { 416 for _, test := range tests { 417 desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text) 418 pm, err := NewPatternMatcher([]string{test.pattern}) 419 assert.NilError(t, err, desc) 420 421 parentPath := filepath.Dir(filepath.FromSlash(test.text)) 422 parentPathDirs := strings.Split(parentPath, string(os.PathSeparator)) 423 424 parentMatched := false 425 if parentPath != "." { 426 for i := range parentPathDirs { 427 parentMatched, _ = pm.MatchesUsingParentResult(strings.Join(parentPathDirs[:i+1], "/"), parentMatched) 428 } 429 } 430 431 res, _ := pm.MatchesUsingParentResult(test.text, parentMatched) 432 assert.Check(t, is.Equal(test.pass, res), desc) 433 } 434 }) 435 436 t.Run("MatchesUsingParentResults", func(t *testing.T) { 437 check := func(pm *PatternMatcher, text string, pass bool, desc string) { 438 parentPath := filepath.Dir(filepath.FromSlash(text)) 439 parentPathDirs := strings.Split(parentPath, string(os.PathSeparator)) 440 441 parentMatchInfo := MatchInfo{} 442 if parentPath != "." { 443 for i := range parentPathDirs { 444 _, parentMatchInfo, _ = pm.MatchesUsingParentResults(strings.Join(parentPathDirs[:i+1], "/"), parentMatchInfo) 445 } 446 } 447 448 res, _, _ := pm.MatchesUsingParentResults(text, parentMatchInfo) 449 assert.Check(t, is.Equal(pass, res), desc) 450 } 451 452 for _, test := range tests { 453 desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text) 454 pm, err := NewPatternMatcher([]string{test.pattern}) 455 assert.NilError(t, err, desc) 456 457 check(pm, test.text, test.pass, desc) 458 } 459 460 for _, test := range multiPatternTests { 461 desc := fmt.Sprintf("pattern=%q text=%q", test.patterns, test.text) 462 pm, err := NewPatternMatcher(test.patterns) 463 assert.NilError(t, err, desc) 464 465 check(pm, test.text, test.pass, desc) 466 } 467 }) 468 469 t.Run("MatchesUsingParentResultsNoContext", func(t *testing.T) { 470 check := func(pm *PatternMatcher, text string, pass bool, desc string) { 471 res, _, _ := pm.MatchesUsingParentResults(text, MatchInfo{}) 472 assert.Check(t, is.Equal(pass, res), desc) 473 } 474 475 for _, test := range tests { 476 desc := fmt.Sprintf("pattern=%q text=%q", test.pattern, test.text) 477 pm, err := NewPatternMatcher([]string{test.pattern}) 478 assert.NilError(t, err, desc) 479 480 check(pm, test.text, test.pass, desc) 481 } 482 483 for _, test := range multiPatternTests { 484 desc := fmt.Sprintf("pattern=%q text=%q", test.patterns, test.text) 485 pm, err := NewPatternMatcher(test.patterns) 486 assert.NilError(t, err, desc) 487 488 check(pm, test.text, test.pass, desc) 489 } 490 }) 491 492 } 493 494 func TestCleanPatterns(t *testing.T) { 495 patterns := []string{"docs", "config"} 496 pm, err := NewPatternMatcher(patterns) 497 if err != nil { 498 t.Fatalf("invalid pattern %v", patterns) 499 } 500 cleaned := pm.Patterns() 501 if len(cleaned) != 2 { 502 t.Errorf("expected 2 element slice, got %v", len(cleaned)) 503 } 504 } 505 506 func TestCleanPatternsStripEmptyPatterns(t *testing.T) { 507 patterns := []string{"docs", "config", ""} 508 pm, err := NewPatternMatcher(patterns) 509 if err != nil { 510 t.Fatalf("invalid pattern %v", patterns) 511 } 512 cleaned := pm.Patterns() 513 if len(cleaned) != 2 { 514 t.Errorf("expected 2 element slice, got %v", len(cleaned)) 515 } 516 } 517 518 func TestCleanPatternsExceptionFlag(t *testing.T) { 519 patterns := []string{"docs", "!docs/README.md"} 520 pm, err := NewPatternMatcher(patterns) 521 if err != nil { 522 t.Fatalf("invalid pattern %v", patterns) 523 } 524 if !pm.Exclusions() { 525 t.Errorf("expected exceptions to be true, got %v", pm.Exclusions()) 526 } 527 } 528 529 func TestCleanPatternsLeadingSpaceTrimmed(t *testing.T) { 530 patterns := []string{"docs", " !docs/README.md"} 531 pm, err := NewPatternMatcher(patterns) 532 if err != nil { 533 t.Fatalf("invalid pattern %v", patterns) 534 } 535 if !pm.Exclusions() { 536 t.Errorf("expected exceptions to be true, got %v", pm.Exclusions()) 537 } 538 } 539 540 func TestCleanPatternsTrailingSpaceTrimmed(t *testing.T) { 541 patterns := []string{"docs", "!docs/README.md "} 542 pm, err := NewPatternMatcher(patterns) 543 if err != nil { 544 t.Fatalf("invalid pattern %v", patterns) 545 } 546 if !pm.Exclusions() { 547 t.Errorf("expected exceptions to be true, got %v", pm.Exclusions()) 548 } 549 } 550 551 func TestCleanPatternsErrorSingleException(t *testing.T) { 552 patterns := []string{"!"} 553 _, err := NewPatternMatcher(patterns) 554 if err == nil { 555 t.Errorf("expected error on single exclamation point, got %v", err) 556 } 557 } 558 559 func TestCreateIfNotExistsDir(t *testing.T) { 560 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 561 if err != nil { 562 t.Fatal(err) 563 } 564 defer os.RemoveAll(tempFolder) 565 566 folderToCreate := filepath.Join(tempFolder, "tocreate") 567 568 if err := CreateIfNotExists(folderToCreate, true); err != nil { 569 t.Fatal(err) 570 } 571 fileinfo, err := os.Stat(folderToCreate) 572 if err != nil { 573 t.Fatalf("Should have create a folder, got %v", err) 574 } 575 576 if !fileinfo.IsDir() { 577 t.Fatalf("Should have been a dir, seems it's not") 578 } 579 } 580 581 func TestCreateIfNotExistsFile(t *testing.T) { 582 tempFolder, err := os.MkdirTemp("", "docker-fileutils-test") 583 if err != nil { 584 t.Fatal(err) 585 } 586 defer os.RemoveAll(tempFolder) 587 588 fileToCreate := filepath.Join(tempFolder, "file/to/create") 589 590 if err := CreateIfNotExists(fileToCreate, false); err != nil { 591 t.Fatal(err) 592 } 593 fileinfo, err := os.Stat(fileToCreate) 594 if err != nil { 595 t.Fatalf("Should have create a file, got %v", err) 596 } 597 598 if fileinfo.IsDir() { 599 t.Fatalf("Should have been a file, seems it's not") 600 } 601 } 602 603 // These matchTests are stolen from go's filepath Match tests. 604 type matchTest struct { 605 pattern, s string 606 match bool 607 err error 608 } 609 610 var matchTests = []matchTest{ 611 {"abc", "abc", true, nil}, 612 {"*", "abc", true, nil}, 613 {"*c", "abc", true, nil}, 614 {"a*", "a", true, nil}, 615 {"a*", "abc", true, nil}, 616 {"a*", "ab/c", true, nil}, 617 {"a*/b", "abc/b", true, nil}, 618 {"a*/b", "a/c/b", false, nil}, 619 {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil}, 620 {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil}, 621 {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil}, 622 {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil}, 623 {"a*b?c*x", "abxbbxdbxebxczzx", true, nil}, 624 {"a*b?c*x", "abxbbxdbxebxczzy", false, nil}, 625 {"ab[c]", "abc", true, nil}, 626 {"ab[b-d]", "abc", true, nil}, 627 {"ab[e-g]", "abc", false, nil}, 628 {"ab[^c]", "abc", false, nil}, 629 {"ab[^b-d]", "abc", false, nil}, 630 {"ab[^e-g]", "abc", true, nil}, 631 {"a\\*b", "a*b", true, nil}, 632 {"a\\*b", "ab", false, nil}, 633 {"a?b", "a☺b", true, nil}, 634 {"a[^a]b", "a☺b", true, nil}, 635 {"a???b", "a☺b", false, nil}, 636 {"a[^a][^a][^a]b", "a☺b", false, nil}, 637 {"[a-ζ]*", "α", true, nil}, 638 {"*[a-ζ]", "A", false, nil}, 639 {"a?b", "a/b", false, nil}, 640 {"a*b", "a/b", false, nil}, 641 {"[\\]a]", "]", true, nil}, 642 {"[\\-]", "-", true, nil}, 643 {"[x\\-]", "x", true, nil}, 644 {"[x\\-]", "-", true, nil}, 645 {"[x\\-]", "z", false, nil}, 646 {"[\\-x]", "x", true, nil}, 647 {"[\\-x]", "-", true, nil}, 648 {"[\\-x]", "a", false, nil}, 649 {"[]a]", "]", false, filepath.ErrBadPattern}, 650 {"[-]", "-", false, filepath.ErrBadPattern}, 651 {"[x-]", "x", false, filepath.ErrBadPattern}, 652 {"[x-]", "-", false, filepath.ErrBadPattern}, 653 {"[x-]", "z", false, filepath.ErrBadPattern}, 654 {"[-x]", "x", false, filepath.ErrBadPattern}, 655 {"[-x]", "-", false, filepath.ErrBadPattern}, 656 {"[-x]", "a", false, filepath.ErrBadPattern}, 657 {"\\", "a", false, filepath.ErrBadPattern}, 658 {"[a-b-c]", "a", false, filepath.ErrBadPattern}, 659 {"[", "a", false, filepath.ErrBadPattern}, 660 {"[^", "a", false, filepath.ErrBadPattern}, 661 {"[^bc", "a", false, filepath.ErrBadPattern}, 662 {"a[", "a", false, filepath.ErrBadPattern}, // was nil but IMO its wrong 663 {"a[", "ab", false, filepath.ErrBadPattern}, 664 {"*x", "xxx", true, nil}, 665 } 666 667 func errp(e error) string { 668 if e == nil { 669 return "<nil>" 670 } 671 return e.Error() 672 } 673 674 // TestMatch test's our version of filepath.Match, called regexpMatch. 675 func TestMatch(t *testing.T) { 676 for _, tt := range matchTests { 677 pattern := tt.pattern 678 s := tt.s 679 if runtime.GOOS == "windows" { 680 if strings.Contains(pattern, "\\") { 681 // no escape allowed on windows. 682 continue 683 } 684 pattern = filepath.Clean(pattern) 685 s = filepath.Clean(s) 686 } 687 ok, err := Matches(s, []string{pattern}) 688 if ok != tt.match || err != tt.err { 689 t.Fatalf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err)) 690 } 691 } 692 }