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 724var globFollowDanglingSymlinkTestCases = []globTestCase{ 725 { 726 pattern: `**/*`, 727 matches: []string{"a/", "b/", "c/", "d/", "dangling", "e", "f", "a/a/", "a/a/a", "a/a/f", "b/a/", "b/a/a", "b/a/f", "c/a", "c/f", "d/a", "d/f"}, 728 deps: []string{".", "a", "a/a", "b", "b/a", "c", "d"}, 729 }, 730 { 731 pattern: `dangling`, 732 matches: []string{"dangling"}, 733 deps: []string{"dangling"}, 734 }, 735} 736 737func TestMockGlobFollowDanglingSymlinks(t *testing.T) { 738 files := []string{ 739 "a/a/a", 740 "a/a/f -> ../../f", 741 "b -> a", 742 "c -> a/a", 743 "d -> c", 744 "e -> a/a/a", 745 "f", 746 "dangling -> missing", 747 } 748 749 mockFiles := make(map[string][]byte) 750 751 for _, f := range files { 752 mockFiles[f] = nil 753 } 754 755 mock := MockFs(mockFiles) 756 757 for _, testCase := range globFollowDanglingSymlinkTestCases { 758 t.Run(testCase.pattern, func(t *testing.T) { 759 testGlob(t, mock, testCase, FollowSymlinks) 760 }) 761 } 762} 763 764func TestGlobFollowDanglingSymlinks(t *testing.T) { 765 os.Chdir("testdata/dangling") 766 defer os.Chdir("../..") 767 768 for _, testCase := range globFollowDanglingSymlinkTestCases { 769 t.Run(testCase.pattern, func(t *testing.T) { 770 testGlob(t, OsFs, testCase, FollowSymlinks) 771 }) 772 } 773} 774 775func testGlob(t *testing.T, fs FileSystem, testCase globTestCase, follow ShouldFollowSymlinks) { 776 t.Helper() 777 result, err := fs.Glob(testCase.pattern, testCase.excludes, follow) 778 if err != testCase.err { 779 if err == nil { 780 t.Fatalf("missing error: %s", testCase.err) 781 } else { 782 t.Fatalf("error: %s", err) 783 } 784 return 785 } 786 787 if !reflect.DeepEqual(result.Matches, testCase.matches) { 788 t.Errorf("incorrect matches list:") 789 t.Errorf(" pattern: %q", testCase.pattern) 790 if testCase.excludes != nil { 791 t.Errorf("excludes: %q", testCase.excludes) 792 } 793 t.Errorf(" got: %#v", result.Matches) 794 t.Errorf("expected: %#v", testCase.matches) 795 } 796 if !reflect.DeepEqual(result.Deps, testCase.deps) { 797 t.Errorf("incorrect deps list:") 798 t.Errorf(" pattern: %q", testCase.pattern) 799 if testCase.excludes != nil { 800 t.Errorf("excludes: %q", testCase.excludes) 801 } 802 t.Errorf(" got: %#v", result.Deps) 803 t.Errorf("expected: %#v", testCase.deps) 804 } 805} 806 807func TestMatch(t *testing.T) { 808 testCases := []struct { 809 pattern, name string 810 match bool 811 }{ 812 {"a/*", "b/", false}, 813 {"a/*", "b/a", false}, 814 {"a/*", "b/b/", false}, 815 {"a/*", "b/b/c", false}, 816 {"a/**/*", "b/", false}, 817 {"a/**/*", "b/a", false}, 818 {"a/**/*", "b/b/", false}, 819 {"a/**/*", "b/b/c", false}, 820 821 {"a/*", "a/", false}, 822 {"a/*", "a/a", true}, 823 {"a/*", "a/b/", false}, 824 {"a/*", "a/b/c", false}, 825 826 {"a/*/", "a/", false}, 827 {"a/*/", "a/a", false}, 828 {"a/*/", "a/b/", true}, 829 {"a/*/", "a/b/c", false}, 830 831 {"a/**/*", "a/", false}, 832 {"a/**/*", "a/a", true}, 833 {"a/**/*", "a/b/", false}, 834 {"a/**/*", "a/b/c", true}, 835 836 {"a/**/*/", "a/", false}, 837 {"a/**/*/", "a/a", false}, 838 {"a/**/*/", "a/b/", true}, 839 {"a/**/*/", "a/b/c", false}, 840 841 {"**/*", "a/", false}, 842 {"**/*", "a/a", true}, 843 {"**/*", "a/b/", false}, 844 {"**/*", "a/b/c", true}, 845 846 {"**/*/", "a/", true}, 847 {"**/*/", "a/a", false}, 848 {"**/*/", "a/b/", true}, 849 {"**/*/", "a/b/c", false}, 850 851 {`a/\*\*/\*`, `a/**/*`, true}, 852 {`a/\*\*/\*`, `a/a/*`, false}, 853 {`a/\*\*/\*`, `a/**/a`, false}, 854 {`a/\*\*/\*`, `a/a/a`, false}, 855 856 {`a/**/\*`, `a/**/*`, true}, 857 {`a/**/\*`, `a/a/*`, true}, 858 {`a/**/\*`, `a/**/a`, false}, 859 {`a/**/\*`, `a/a/a`, false}, 860 861 {`a/\*\*/*`, `a/**/*`, true}, 862 {`a/\*\*/*`, `a/a/*`, false}, 863 {`a/\*\*/*`, `a/**/a`, true}, 864 {`a/\*\*/*`, `a/a/a`, false}, 865 866 {`*/**/a`, `a/a/a`, true}, 867 {`*/**/a`, `*/a/a`, true}, 868 {`*/**/a`, `a/**/a`, true}, 869 {`*/**/a`, `*/**/a`, true}, 870 871 {`\*/\*\*/a`, `a/a/a`, false}, 872 {`\*/\*\*/a`, `*/a/a`, false}, 873 {`\*/\*\*/a`, `a/**/a`, false}, 874 {`\*/\*\*/a`, `*/**/a`, true}, 875 876 {`a/?`, `a/?`, true}, 877 {`a/?`, `a/a`, true}, 878 {`a/\?`, `a/?`, true}, 879 {`a/\?`, `a/a`, false}, 880 881 {`a/?`, `a/?`, true}, 882 {`a/?`, `a/a`, true}, 883 {`a/\?`, `a/?`, true}, 884 {`a/\?`, `a/a`, false}, 885 886 {`a/[a-c]`, `a/b`, true}, 887 {`a/[abc]`, `a/b`, true}, 888 889 {`a/\[abc]`, `a/b`, false}, 890 {`a/\[abc]`, `a/[abc]`, true}, 891 892 {`a/\[abc\]`, `a/b`, false}, 893 {`a/\[abc\]`, `a/[abc]`, true}, 894 895 {`a/?`, `a/?`, true}, 896 {`a/?`, `a/a`, true}, 897 {`a/\?`, `a/?`, true}, 898 {`a/\?`, `a/a`, false}, 899 900 {"/a/*", "/a/", false}, 901 {"/a/*", "/a/a", true}, 902 {"/a/*", "/a/b/", false}, 903 {"/a/*", "/a/b/c", false}, 904 905 {"/a/*/", "/a/", false}, 906 {"/a/*/", "/a/a", false}, 907 {"/a/*/", "/a/b/", true}, 908 {"/a/*/", "/a/b/c", false}, 909 910 {"/a/**/*", "/a/", false}, 911 {"/a/**/*", "/a/a", true}, 912 {"/a/**/*", "/a/b/", false}, 913 {"/a/**/*", "/a/b/c", true}, 914 915 {"/**/*", "/a/", false}, 916 {"/**/*", "/a/a", true}, 917 {"/**/*", "/a/b/", false}, 918 {"/**/*", "/a/b/c", true}, 919 920 {"/**/*/", "/a/", true}, 921 {"/**/*/", "/a/a", false}, 922 {"/**/*/", "/a/b/", true}, 923 {"/**/*/", "/a/b/c", false}, 924 925 {`a`, `/a`, false}, 926 {`/a`, `a`, false}, 927 {`*`, `/a`, false}, 928 {`/*`, `a`, false}, 929 {`**/*`, `/a`, false}, 930 {`/**/*`, `a`, false}, 931 } 932 933 for _, test := range testCases { 934 t.Run(test.pattern+","+test.name, func(t *testing.T) { 935 match, err := Match(test.pattern, test.name) 936 if err != nil { 937 t.Fatal(err) 938 } 939 if match != test.match { 940 t.Errorf("want: %v, got %v", test.match, match) 941 } 942 }) 943 } 944 945 // Run the same test cases through Glob 946 for _, test := range testCases { 947 // Glob and Match disagree on matching directories 948 if strings.HasSuffix(test.name, "/") || strings.HasSuffix(test.pattern, "/") { 949 continue 950 } 951 t.Run("glob:"+test.pattern+","+test.name, func(t *testing.T) { 952 mockFiles := map[string][]byte{ 953 test.name: nil, 954 } 955 956 mock := MockFs(mockFiles) 957 958 result, err := mock.Glob(test.pattern, nil, DontFollowSymlinks) 959 t.Log(test.name, test.pattern, result.Matches) 960 if err != nil { 961 t.Fatal(err) 962 } 963 964 match := false 965 for _, x := range result.Matches { 966 if x == test.name { 967 match = true 968 } 969 } 970 971 if match != test.match { 972 t.Errorf("want: %v, got %v", test.match, match) 973 } 974 }) 975 } 976} 977