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 15 package pathtools 16 17 import ( 18 "os" 19 "path/filepath" 20 "reflect" 21 "testing" 22 ) 23 24 var pwd, _ = os.Getwd() 25 26 type globTestCase struct { 27 pattern string 28 matches []string 29 excludes []string 30 deps []string 31 err error 32 } 33 34 var globTestCases = []globTestCase{ 35 // Current directory tests 36 { 37 pattern: "*", 38 matches: []string{"a/", "b/", "c/", "d.ext", "e.ext"}, 39 deps: []string{"."}, 40 }, 41 { 42 pattern: "*.ext", 43 matches: []string{"d.ext", "e.ext"}, 44 deps: []string{"."}, 45 }, 46 { 47 pattern: "*/a", 48 matches: []string{"a/a/", "b/a"}, 49 deps: []string{".", "a", "b", "c"}, 50 }, 51 { 52 pattern: "*/*/a", 53 matches: []string{"a/a/a"}, 54 deps: []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"}, 55 }, 56 { 57 pattern: "*/a/a", 58 matches: []string{"a/a/a"}, 59 deps: []string{".", "a", "b", "c", "a/a"}, 60 }, 61 { 62 pattern: "c/*/?", 63 matches: []string{"c/h/h"}, 64 deps: []string{"c", "c/f", "c/g", "c/h"}, 65 }, 66 { 67 pattern: "c/*/[gh]*", 68 matches: []string{"c/g/g.ext", "c/h/h"}, 69 deps: []string{"c", "c/f", "c/g", "c/h"}, 70 }, 71 { 72 pattern: "c/*/[fgh]*", 73 matches: []string{"c/f/f.ext", "c/g/g.ext", "c/h/h"}, 74 deps: []string{"c", "c/f", "c/g", "c/h"}, 75 }, 76 { 77 pattern: "c/*/[f-h]*", 78 matches: []string{"c/f/f.ext", "c/g/g.ext", "c/h/h"}, 79 deps: []string{"c", "c/f", "c/g", "c/h"}, 80 }, 81 // ./ directory tests 82 { 83 pattern: "./*", 84 matches: []string{"a/", "b/", "c/", "d.ext", "e.ext"}, 85 deps: []string{"."}, 86 }, 87 { 88 pattern: "./*.ext", 89 matches: []string{"d.ext", "e.ext"}, 90 deps: []string{"."}, 91 }, 92 { 93 pattern: "./*/a", 94 matches: []string{"a/a/", "b/a"}, 95 deps: []string{".", "a", "b", "c"}, 96 }, 97 { 98 pattern: "./[ac]/a", 99 matches: []string{"a/a/"}, 100 deps: []string{".", "a", "c"}, 101 }, 102 103 // subdirectory tests 104 { 105 pattern: "c/*/*.ext", 106 matches: []string{"c/f/f.ext", "c/g/g.ext"}, 107 deps: []string{"c", "c/f", "c/g", "c/h"}, 108 }, 109 { 110 pattern: "a/*/a", 111 matches: []string{"a/a/a"}, 112 deps: []string{"a", "a/a", "a/b"}, 113 }, 114 115 // absolute tests 116 { 117 pattern: filepath.Join(pwd, "testdata/glob/c/*/*.ext"), 118 matches: []string{ 119 filepath.Join(pwd, "testdata/glob/c/f/f.ext"), 120 filepath.Join(pwd, "testdata/glob/c/g/g.ext"), 121 }, 122 deps: []string{ 123 filepath.Join(pwd, "testdata/glob/c"), 124 filepath.Join(pwd, "testdata/glob/c/f"), 125 filepath.Join(pwd, "testdata/glob/c/g"), 126 filepath.Join(pwd, "testdata/glob/c/h"), 127 }, 128 }, 129 130 // no-wild tests 131 { 132 pattern: "a", 133 matches: []string{"a/"}, 134 deps: []string{"a"}, 135 }, 136 { 137 pattern: "a/a", 138 matches: []string{"a/a/"}, 139 deps: []string{"a/a"}, 140 }, 141 142 // clean tests 143 { 144 pattern: "./c/*/*.ext", 145 matches: []string{"c/f/f.ext", "c/g/g.ext"}, 146 deps: []string{"c", "c/f", "c/g", "c/h"}, 147 }, 148 { 149 pattern: "c/../c/*/*.ext", 150 matches: []string{"c/f/f.ext", "c/g/g.ext"}, 151 deps: []string{"c", "c/f", "c/g", "c/h"}, 152 }, 153 154 // recursive tests 155 { 156 pattern: "**/a", 157 matches: []string{"a/", "a/a/", "a/a/a", "b/a"}, 158 deps: []string{".", "a", "a/a", "a/b", "b", "c", "c/f", "c/g", "c/h"}, 159 }, 160 { 161 pattern: "a/**/a", 162 matches: []string{"a/a/", "a/a/a"}, 163 deps: []string{"a", "a/a", "a/b"}, 164 }, 165 { 166 pattern: "a/**/*", 167 matches: []string{"a/a/", "a/b/", "a/a/a", "a/b/b"}, 168 deps: []string{"a", "a/a", "a/b"}, 169 }, 170 171 // absolute recursive tests 172 { 173 pattern: filepath.Join(pwd, "testdata/glob/**/*.ext"), 174 matches: []string{ 175 filepath.Join(pwd, "testdata/glob/d.ext"), 176 filepath.Join(pwd, "testdata/glob/e.ext"), 177 filepath.Join(pwd, "testdata/glob/c/f/f.ext"), 178 filepath.Join(pwd, "testdata/glob/c/g/g.ext"), 179 }, 180 deps: []string{ 181 filepath.Join(pwd, "testdata/glob"), 182 filepath.Join(pwd, "testdata/glob/a"), 183 filepath.Join(pwd, "testdata/glob/a/a"), 184 filepath.Join(pwd, "testdata/glob/a/b"), 185 filepath.Join(pwd, "testdata/glob/b"), 186 filepath.Join(pwd, "testdata/glob/c"), 187 filepath.Join(pwd, "testdata/glob/c/f"), 188 filepath.Join(pwd, "testdata/glob/c/g"), 189 filepath.Join(pwd, "testdata/glob/c/h"), 190 }, 191 }, 192 193 // recursive error tests 194 { 195 pattern: "**/**/*", 196 err: GlobMultipleRecursiveErr, 197 }, 198 { 199 pattern: "a/**/**/*", 200 err: GlobMultipleRecursiveErr, 201 }, 202 { 203 pattern: "**/a/**/*", 204 err: GlobMultipleRecursiveErr, 205 }, 206 { 207 pattern: "**/**/a/*", 208 err: GlobMultipleRecursiveErr, 209 }, 210 { 211 pattern: "a/**", 212 err: GlobLastRecursiveErr, 213 }, 214 { 215 pattern: "**/**", 216 err: GlobLastRecursiveErr, 217 }, 218 219 // exclude tests 220 { 221 pattern: "*.ext", 222 excludes: []string{"d.ext"}, 223 matches: []string{"e.ext"}, 224 deps: []string{"."}, 225 }, 226 { 227 pattern: "*/*", 228 excludes: []string{"a/b"}, 229 matches: []string{"a/a/", "b/a", "c/c", "c/f/", "c/g/", "c/h/"}, 230 deps: []string{".", "a", "b", "c"}, 231 }, 232 { 233 pattern: "*/*", 234 excludes: []string{"a/b", "c/c"}, 235 matches: []string{"a/a/", "b/a", "c/f/", "c/g/", "c/h/"}, 236 deps: []string{".", "a", "b", "c"}, 237 }, 238 { 239 pattern: "*/*", 240 excludes: []string{"c/*", "*/a"}, 241 matches: []string{"a/b/"}, 242 deps: []string{".", "a", "b", "c"}, 243 }, 244 { 245 pattern: "*/*", 246 excludes: []string{"*/*"}, 247 matches: nil, 248 deps: []string{".", "a", "b", "c"}, 249 }, 250 251 // absolute exclude tests 252 { 253 pattern: filepath.Join(pwd, "testdata/glob/c/*/*.ext"), 254 excludes: []string{filepath.Join(pwd, "testdata/glob/c/*/f.ext")}, 255 matches: []string{ 256 filepath.Join(pwd, "testdata/glob/c/g/g.ext"), 257 }, 258 deps: []string{ 259 filepath.Join(pwd, "testdata/glob/c"), 260 filepath.Join(pwd, "testdata/glob/c/f"), 261 filepath.Join(pwd, "testdata/glob/c/g"), 262 filepath.Join(pwd, "testdata/glob/c/h"), 263 }, 264 }, 265 { 266 pattern: filepath.Join(pwd, "testdata/glob/c/*/*.ext"), 267 excludes: []string{filepath.Join(pwd, "testdata/glob/c/f/*.ext")}, 268 matches: []string{ 269 filepath.Join(pwd, "testdata/glob/c/g/g.ext"), 270 }, 271 deps: []string{ 272 filepath.Join(pwd, "testdata/glob/c"), 273 filepath.Join(pwd, "testdata/glob/c/f"), 274 filepath.Join(pwd, "testdata/glob/c/g"), 275 filepath.Join(pwd, "testdata/glob/c/h"), 276 }, 277 }, 278 279 // recursive exclude tests 280 { 281 pattern: "*.ext", 282 excludes: []string{"**/*.ext"}, 283 matches: nil, 284 deps: []string{"."}, 285 }, 286 { 287 pattern: "*/*", 288 excludes: []string{"**/b"}, 289 matches: []string{"a/a/", "b/a", "c/c", "c/f/", "c/g/", "c/h/"}, 290 deps: []string{".", "a", "b", "c"}, 291 }, 292 { 293 pattern: "*/*", 294 excludes: []string{"a/**/*"}, 295 matches: []string{"b/a", "c/c", "c/f/", "c/g/", "c/h/"}, 296 deps: []string{".", "a", "b", "c"}, 297 }, 298 { 299 pattern: "**/*", 300 excludes: []string{"**/*"}, 301 matches: nil, 302 deps: []string{".", "a", "a/a", "a/b", "b", "c", "c/f", "c/g", "c/h"}, 303 }, 304 { 305 pattern: "*/*/*", 306 excludes: []string{"a/**/a"}, 307 matches: []string{"a/b/b", "c/f/f.ext", "c/g/g.ext", "c/h/h"}, 308 deps: []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"}, 309 }, 310 { 311 pattern: "*/*/*", 312 excludes: []string{"**/a"}, 313 matches: []string{"a/b/b", "c/f/f.ext", "c/g/g.ext", "c/h/h"}, 314 deps: []string{".", "a", "b", "c", "a/a", "a/b", "c/f", "c/g", "c/h"}, 315 }, 316 { 317 pattern: "c/*/*.ext", 318 excludes: []string{"c/**/f.ext"}, 319 matches: []string{"c/g/g.ext"}, 320 deps: []string{"c", "c/f", "c/g", "c/h"}, 321 }, 322 323 // absoulte recursive exclude tests 324 { 325 pattern: filepath.Join(pwd, "testdata/glob/c/*/*.ext"), 326 excludes: []string{filepath.Join(pwd, "testdata/glob/**/f.ext")}, 327 matches: []string{ 328 filepath.Join(pwd, "testdata/glob/c/g/g.ext"), 329 }, 330 deps: []string{ 331 filepath.Join(pwd, "testdata/glob/c"), 332 filepath.Join(pwd, "testdata/glob/c/f"), 333 filepath.Join(pwd, "testdata/glob/c/g"), 334 filepath.Join(pwd, "testdata/glob/c/h"), 335 }, 336 }, 337 338 // clean exclude tests 339 { 340 pattern: "./c/*/*.ext", 341 excludes: []string{"./c/*/f.ext"}, 342 matches: []string{"c/g/g.ext"}, 343 deps: []string{"c", "c/f", "c/g", "c/h"}, 344 }, 345 { 346 pattern: "c/*/*.ext", 347 excludes: []string{"./c/*/f.ext"}, 348 matches: []string{"c/g/g.ext"}, 349 deps: []string{"c", "c/f", "c/g", "c/h"}, 350 }, 351 { 352 pattern: "./c/*/*.ext", 353 excludes: []string{"c/*/f.ext"}, 354 matches: []string{"c/g/g.ext"}, 355 deps: []string{"c", "c/f", "c/g", "c/h"}, 356 }, 357 358 // non-existant non-wild path tests 359 { 360 pattern: "d/*", 361 matches: nil, 362 deps: []string{"."}, 363 }, 364 { 365 pattern: "d", 366 matches: nil, 367 deps: []string{"."}, 368 }, 369 { 370 pattern: "a/d/*", 371 matches: nil, 372 deps: []string{"a"}, 373 }, 374 { 375 pattern: "a/d", 376 matches: nil, 377 deps: []string{"a"}, 378 }, 379 { 380 pattern: "a/a/d/*", 381 matches: nil, 382 deps: []string{"a/a"}, 383 }, 384 { 385 pattern: "a/a/d", 386 matches: nil, 387 deps: []string{"a/a"}, 388 }, 389 { 390 pattern: "a/d/a/*", 391 matches: nil, 392 deps: []string{"a"}, 393 }, 394 { 395 pattern: "a/d/a", 396 matches: nil, 397 deps: []string{"a"}, 398 }, 399 { 400 pattern: "a/d/a/*/a", 401 matches: nil, 402 deps: []string{"a"}, 403 }, 404 { 405 pattern: "a/d/a/**/a", 406 matches: nil, 407 deps: []string{"a"}, 408 }, 409 410 // recursive exclude error tests 411 { 412 pattern: "**/*", 413 excludes: []string{"**/**/*"}, 414 err: GlobMultipleRecursiveErr, 415 }, 416 { 417 pattern: "**/*", 418 excludes: []string{"a/**/**/*"}, 419 err: GlobMultipleRecursiveErr, 420 }, 421 { 422 pattern: "**/*", 423 excludes: []string{"**/a/**/*"}, 424 err: GlobMultipleRecursiveErr, 425 }, 426 { 427 pattern: "**/*", 428 excludes: []string{"**/**/a/*"}, 429 err: GlobMultipleRecursiveErr, 430 }, 431 { 432 pattern: "**/*", 433 excludes: []string{"a/**"}, 434 err: GlobLastRecursiveErr, 435 }, 436 { 437 pattern: "**/*", 438 excludes: []string{"**/**"}, 439 err: GlobLastRecursiveErr, 440 }, 441 442 // If names are excluded by default, but referenced explicitly, they should return results 443 { 444 pattern: ".test/*", 445 matches: []string{".test/a"}, 446 deps: []string{".test"}, 447 }, 448 { 449 pattern: ".t*/a", 450 matches: []string{".test/a"}, 451 deps: []string{".", ".test"}, 452 }, 453 { 454 pattern: ".*/.*", 455 matches: []string{".test/.ing"}, 456 deps: []string{".", ".test"}, 457 }, 458 { 459 pattern: ".t*", 460 matches: []string{".test/", ".testing"}, 461 deps: []string{"."}, 462 }, 463 } 464 465 func TestMockGlob(t *testing.T) { 466 files := []string{ 467 "a/a/a", 468 "a/b/b", 469 "b/a", 470 "c/c", 471 "c/f/f.ext", 472 "c/g/g.ext", 473 "c/h/h", 474 "d.ext", 475 "e.ext", 476 ".test/a", 477 ".testing", 478 ".test/.ing", 479 } 480 481 mockFiles := make(map[string][]byte) 482 483 for _, f := range files { 484 mockFiles[f] = nil 485 mockFiles[filepath.Join(pwd, "testdata/glob", f)] = nil 486 } 487 488 mock := MockFs(mockFiles) 489 490 for _, testCase := range globTestCases { 491 t.Run(testCase.pattern, func(t *testing.T) { 492 testGlob(t, mock, testCase, FollowSymlinks) 493 }) 494 } 495 } 496 497 func TestGlob(t *testing.T) { 498 os.Chdir("testdata/glob") 499 defer os.Chdir("../..") 500 for _, testCase := range globTestCases { 501 t.Run(testCase.pattern, func(t *testing.T) { 502 testGlob(t, OsFs, testCase, FollowSymlinks) 503 }) 504 } 505 } 506 507 var globEscapeTestCases = []globTestCase{ 508 { 509 pattern: `**/*`, 510 matches: []string{`*`, `**/`, `?`, `a/`, `b`, `**/*`, `**/a`, `**/b/`, `**/b/b`, `a/a`}, 511 deps: []string{`.`, `**`, `**/b`, `a`}, 512 }, 513 { 514 pattern: `**/\*`, 515 matches: []string{`*`, `**/*`}, 516 deps: []string{`.`, `**`, `**/b`, `a`}, 517 }, 518 { 519 pattern: `\*\*/*`, 520 matches: []string{`**/*`, `**/a`, `**/b/`}, 521 deps: []string{`.`, `**`}, 522 }, 523 { 524 pattern: `\*\*/**/*`, 525 matches: []string{`**/*`, `**/a`, `**/b/`, `**/b/b`}, 526 deps: []string{`.`, `**`, `**/b`}, 527 }, 528 } 529 530 func TestMockGlobEscapes(t *testing.T) { 531 files := []string{ 532 `*`, 533 `**/*`, 534 `**/a`, 535 `**/b/b`, 536 `?`, 537 `a/a`, 538 `b`, 539 } 540 541 mockFiles := make(map[string][]byte) 542 543 for _, f := range files { 544 mockFiles[f] = nil 545 } 546 547 mock := MockFs(mockFiles) 548 549 for _, testCase := range globEscapeTestCases { 550 t.Run(testCase.pattern, func(t *testing.T) { 551 testGlob(t, mock, testCase, FollowSymlinks) 552 }) 553 } 554 555 } 556 557 func TestGlobEscapes(t *testing.T) { 558 os.Chdir("testdata/escapes") 559 defer os.Chdir("../..") 560 for _, testCase := range globEscapeTestCases { 561 t.Run(testCase.pattern, func(t *testing.T) { 562 testGlob(t, OsFs, testCase, FollowSymlinks) 563 }) 564 } 565 566 } 567 568 var globSymlinkTestCases = []globTestCase{ 569 { 570 pattern: `**/*`, 571 matches: []string{"a/", "b/", "c/", "d/", "e", "a/a/", "a/a/a", "b/a/", "b/a/a", "c/a", "d/a"}, 572 deps: []string{".", "a", "a/a", "b", "b/a", "c", "d"}, 573 }, 574 { 575 pattern: `b/**/*`, 576 matches: []string{"b/a/", "b/a/a"}, 577 deps: []string{"b", "b/a"}, 578 }, 579 } 580 581 func TestMockGlobSymlinks(t *testing.T) { 582 files := []string{ 583 "a/a/a", 584 "b -> a", 585 "c -> a/a", 586 "d -> c", 587 "e -> a/a/a", 588 } 589 590 mockFiles := make(map[string][]byte) 591 592 for _, f := range files { 593 mockFiles[f] = nil 594 } 595 596 mock := MockFs(mockFiles) 597 598 for _, testCase := range globSymlinkTestCases { 599 t.Run(testCase.pattern, func(t *testing.T) { 600 testGlob(t, mock, testCase, FollowSymlinks) 601 }) 602 } 603 } 604 605 func TestGlobSymlinks(t *testing.T) { 606 os.Chdir("testdata/symlinks") 607 defer os.Chdir("../..") 608 609 for _, testCase := range globSymlinkTestCases { 610 t.Run(testCase.pattern, func(t *testing.T) { 611 testGlob(t, OsFs, testCase, FollowSymlinks) 612 }) 613 } 614 } 615 616 var globDontFollowSymlinkTestCases = []globTestCase{ 617 { 618 pattern: `**/*`, 619 matches: []string{"a/", "b", "c", "d", "e", "a/a/", "a/a/a"}, 620 deps: []string{".", "a", "a/a"}, 621 }, 622 { 623 pattern: `b/**/*`, 624 matches: []string{"b/a/", "b/a/a"}, 625 deps: []string{"b", "b/a"}, 626 }, 627 } 628 629 func TestMockGlobDontFollowSymlinks(t *testing.T) { 630 files := []string{ 631 "a/a/a", 632 "b -> a", 633 "c -> a/a", 634 "d -> c", 635 "e -> a/a/a", 636 } 637 638 mockFiles := make(map[string][]byte) 639 640 for _, f := range files { 641 mockFiles[f] = nil 642 } 643 644 mock := MockFs(mockFiles) 645 646 for _, testCase := range globDontFollowSymlinkTestCases { 647 t.Run(testCase.pattern, func(t *testing.T) { 648 testGlob(t, mock, testCase, DontFollowSymlinks) 649 }) 650 } 651 } 652 653 func TestGlobDontFollowSymlinks(t *testing.T) { 654 os.Chdir("testdata/symlinks") 655 defer os.Chdir("../..") 656 657 for _, testCase := range globDontFollowSymlinkTestCases { 658 t.Run(testCase.pattern, func(t *testing.T) { 659 testGlob(t, OsFs, testCase, DontFollowSymlinks) 660 }) 661 } 662 } 663 664 var globDontFollowDanglingSymlinkTestCases = []globTestCase{ 665 { 666 pattern: `**/*`, 667 matches: []string{"a/", "b", "c", "d", "dangling", "e", "f", "a/a/", "a/a/a", "a/a/f"}, 668 deps: []string{".", "a", "a/a"}, 669 }, 670 { 671 pattern: `dangling`, 672 matches: []string{"dangling"}, 673 deps: []string{"dangling"}, 674 }, 675 } 676 677 func TestMockGlobDontFollowDanglingSymlinks(t *testing.T) { 678 files := []string{ 679 "a/a/a", 680 "a/a/f -> ../../f", 681 "b -> a", 682 "c -> a/a", 683 "d -> c", 684 "e -> a/a/a", 685 "f", 686 "dangling -> missing", 687 } 688 689 mockFiles := make(map[string][]byte) 690 691 for _, f := range files { 692 mockFiles[f] = nil 693 } 694 695 mock := MockFs(mockFiles) 696 697 for _, testCase := range globDontFollowDanglingSymlinkTestCases { 698 t.Run(testCase.pattern, func(t *testing.T) { 699 testGlob(t, mock, testCase, DontFollowSymlinks) 700 }) 701 } 702 } 703 704 func TestGlobDontFollowDanglingSymlinks(t *testing.T) { 705 os.Chdir("testdata/dangling") 706 defer os.Chdir("../..") 707 708 for _, testCase := range globDontFollowDanglingSymlinkTestCases { 709 t.Run(testCase.pattern, func(t *testing.T) { 710 testGlob(t, OsFs, testCase, DontFollowSymlinks) 711 }) 712 } 713 } 714 715 func testGlob(t *testing.T, fs FileSystem, testCase globTestCase, follow ShouldFollowSymlinks) { 716 t.Helper() 717 matches, deps, err := fs.Glob(testCase.pattern, testCase.excludes, follow) 718 if err != testCase.err { 719 if err == nil { 720 t.Fatalf("missing error: %s", testCase.err) 721 } else { 722 t.Fatalf("error: %s", err) 723 } 724 return 725 } 726 727 if !reflect.DeepEqual(matches, testCase.matches) { 728 t.Errorf("incorrect matches list:") 729 t.Errorf(" pattern: %q", testCase.pattern) 730 if testCase.excludes != nil { 731 t.Errorf("excludes: %q", testCase.excludes) 732 } 733 t.Errorf(" got: %#v", matches) 734 t.Errorf("expected: %#v", testCase.matches) 735 } 736 if !reflect.DeepEqual(deps, testCase.deps) { 737 t.Errorf("incorrect deps 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", deps) 743 t.Errorf("expected: %#v", testCase.deps) 744 } 745 } 746 747 func TestMatch(t *testing.T) { 748 testCases := []struct { 749 pattern, name string 750 match bool 751 }{ 752 {"a/*", "b/", false}, 753 {"a/*", "b/a", false}, 754 {"a/*", "b/b/", false}, 755 {"a/*", "b/b/c", false}, 756 {"a/**/*", "b/", false}, 757 {"a/**/*", "b/a", false}, 758 {"a/**/*", "b/b/", false}, 759 {"a/**/*", "b/b/c", false}, 760 761 {"a/*", "a/", false}, 762 {"a/*", "a/a", true}, 763 {"a/*", "a/b/", false}, 764 {"a/*", "a/b/c", false}, 765 766 {"a/*/", "a/", false}, 767 {"a/*/", "a/a", false}, 768 {"a/*/", "a/b/", true}, 769 {"a/*/", "a/b/c", false}, 770 771 {"a/**/*", "a/", false}, 772 {"a/**/*", "a/a", true}, 773 {"a/**/*", "a/b/", false}, 774 {"a/**/*", "a/b/c", true}, 775 776 {"a/**/*/", "a/", false}, 777 {"a/**/*/", "a/a", false}, 778 {"a/**/*/", "a/b/", true}, 779 {"a/**/*/", "a/b/c", false}, 780 781 {`a/\*\*/\*`, `a/**/*`, true}, 782 {`a/\*\*/\*`, `a/a/*`, false}, 783 {`a/\*\*/\*`, `a/**/a`, false}, 784 {`a/\*\*/\*`, `a/a/a`, false}, 785 786 {`a/**/\*`, `a/**/*`, true}, 787 {`a/**/\*`, `a/a/*`, true}, 788 {`a/**/\*`, `a/**/a`, false}, 789 {`a/**/\*`, `a/a/a`, false}, 790 791 {`a/\*\*/*`, `a/**/*`, true}, 792 {`a/\*\*/*`, `a/a/*`, false}, 793 {`a/\*\*/*`, `a/**/a`, true}, 794 {`a/\*\*/*`, `a/a/a`, false}, 795 796 {`*/**/a`, `a/a/a`, true}, 797 {`*/**/a`, `*/a/a`, true}, 798 {`*/**/a`, `a/**/a`, true}, 799 {`*/**/a`, `*/**/a`, true}, 800 801 {`\*/\*\*/a`, `a/a/a`, false}, 802 {`\*/\*\*/a`, `*/a/a`, false}, 803 {`\*/\*\*/a`, `a/**/a`, false}, 804 {`\*/\*\*/a`, `*/**/a`, true}, 805 806 {`a/?`, `a/?`, true}, 807 {`a/?`, `a/a`, true}, 808 {`a/\?`, `a/?`, true}, 809 {`a/\?`, `a/a`, false}, 810 811 {`a/?`, `a/?`, true}, 812 {`a/?`, `a/a`, true}, 813 {`a/\?`, `a/?`, true}, 814 {`a/\?`, `a/a`, false}, 815 816 {`a/[a-c]`, `a/b`, true}, 817 {`a/[abc]`, `a/b`, true}, 818 819 {`a/\[abc]`, `a/b`, false}, 820 {`a/\[abc]`, `a/[abc]`, true}, 821 822 {`a/\[abc\]`, `a/b`, false}, 823 {`a/\[abc\]`, `a/[abc]`, true}, 824 825 {`a/?`, `a/?`, true}, 826 {`a/?`, `a/a`, true}, 827 {`a/\?`, `a/?`, true}, 828 {`a/\?`, `a/a`, false}, 829 } 830 831 for _, test := range testCases { 832 t.Run(test.pattern+","+test.name, func(t *testing.T) { 833 match, err := Match(test.pattern, test.name) 834 if err != nil { 835 t.Fatal(err) 836 } 837 if match != test.match { 838 t.Errorf("want: %v, got %v", test.match, match) 839 } 840 }) 841 } 842 } 843