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