Home | History | Annotate | Download | only in pathtools
      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