github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/path/filepath/path_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package filepath_test 6 7 import ( 8 "errors" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "reflect" 13 "runtime" 14 "strings" 15 "testing" 16 ) 17 18 var supportsSymlinks = true 19 20 type PathTest struct { 21 path, result string 22 } 23 24 var cleantests = []PathTest{ 25 // Already clean 26 {"abc", "abc"}, 27 {"abc/def", "abc/def"}, 28 {"a/b/c", "a/b/c"}, 29 {".", "."}, 30 {"..", ".."}, 31 {"../..", "../.."}, 32 {"../../abc", "../../abc"}, 33 {"/abc", "/abc"}, 34 {"/", "/"}, 35 36 // Empty is current dir 37 {"", "."}, 38 39 // Remove trailing slash 40 {"abc/", "abc"}, 41 {"abc/def/", "abc/def"}, 42 {"a/b/c/", "a/b/c"}, 43 {"./", "."}, 44 {"../", ".."}, 45 {"../../", "../.."}, 46 {"/abc/", "/abc"}, 47 48 // Remove doubled slash 49 {"abc//def//ghi", "abc/def/ghi"}, 50 {"//abc", "/abc"}, 51 {"///abc", "/abc"}, 52 {"//abc//", "/abc"}, 53 {"abc//", "abc"}, 54 55 // Remove . elements 56 {"abc/./def", "abc/def"}, 57 {"/./abc/def", "/abc/def"}, 58 {"abc/.", "abc"}, 59 60 // Remove .. elements 61 {"abc/def/ghi/../jkl", "abc/def/jkl"}, 62 {"abc/def/../ghi/../jkl", "abc/jkl"}, 63 {"abc/def/..", "abc"}, 64 {"abc/def/../..", "."}, 65 {"/abc/def/../..", "/"}, 66 {"abc/def/../../..", ".."}, 67 {"/abc/def/../../..", "/"}, 68 {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, 69 {"/../abc", "/abc"}, 70 71 // Combinations 72 {"abc/./../def", "def"}, 73 {"abc//./../def", "def"}, 74 {"abc/../../././../def", "../../def"}, 75 } 76 77 var wincleantests = []PathTest{ 78 {`c:`, `c:.`}, 79 {`c:\`, `c:\`}, 80 {`c:\abc`, `c:\abc`}, 81 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`}, 82 {`c:\abc\def\..\..`, `c:\`}, 83 {`c:\..\abc`, `c:\abc`}, 84 {`c:..\abc`, `c:..\abc`}, 85 {`\`, `\`}, 86 {`/`, `\`}, 87 {`\\i\..\c$`, `\c$`}, 88 {`\\i\..\i\c$`, `\i\c$`}, 89 {`\\i\..\I\c$`, `\I\c$`}, 90 {`\\host\share\foo\..\bar`, `\\host\share\bar`}, 91 {`//host/share/foo/../baz`, `\\host\share\baz`}, 92 {`\\a\b\..\c`, `\\a\b\c`}, 93 {`\\a\b`, `\\a\b`}, 94 } 95 96 func TestClean(t *testing.T) { 97 tests := cleantests 98 if runtime.GOOS == "windows" { 99 for i := range tests { 100 tests[i].result = filepath.FromSlash(tests[i].result) 101 } 102 tests = append(tests, wincleantests...) 103 } 104 for _, test := range tests { 105 if s := filepath.Clean(test.path); s != test.result { 106 t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result) 107 } 108 if s := filepath.Clean(test.result); s != test.result { 109 t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result) 110 } 111 } 112 113 if testing.Short() { 114 t.Skip("skipping malloc count in short mode") 115 } 116 if runtime.GOMAXPROCS(0) > 1 { 117 t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1") 118 return 119 } 120 121 t.Log("Skipping AllocsPerRun for gccgo") 122 return 123 124 for _, test := range tests { 125 allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) }) 126 if allocs > 0 { 127 t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs) 128 } 129 } 130 } 131 132 const sep = filepath.Separator 133 134 var slashtests = []PathTest{ 135 {"", ""}, 136 {"/", string(sep)}, 137 {"/a/b", string([]byte{sep, 'a', sep, 'b'})}, 138 {"a//b", string([]byte{'a', sep, sep, 'b'})}, 139 } 140 141 func TestFromAndToSlash(t *testing.T) { 142 for _, test := range slashtests { 143 if s := filepath.FromSlash(test.path); s != test.result { 144 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result) 145 } 146 if s := filepath.ToSlash(test.result); s != test.path { 147 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path) 148 } 149 } 150 } 151 152 type SplitListTest struct { 153 list string 154 result []string 155 } 156 157 const lsep = filepath.ListSeparator 158 159 var splitlisttests = []SplitListTest{ 160 {"", []string{}}, 161 {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}}, 162 {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}}, 163 } 164 165 var winsplitlisttests = []SplitListTest{ 166 // quoted 167 {`"a"`, []string{`a`}}, 168 169 // semicolon 170 {`";"`, []string{`;`}}, 171 {`"a;b"`, []string{`a;b`}}, 172 {`";";`, []string{`;`, ``}}, 173 {`;";"`, []string{``, `;`}}, 174 175 // partially quoted 176 {`a";"b`, []string{`a;b`}}, 177 {`a; ""b`, []string{`a`, ` b`}}, 178 {`"a;b`, []string{`a;b`}}, 179 {`""a;b`, []string{`a`, `b`}}, 180 {`"""a;b`, []string{`a;b`}}, 181 {`""""a;b`, []string{`a`, `b`}}, 182 {`a";b`, []string{`a;b`}}, 183 {`a;b";c`, []string{`a`, `b;c`}}, 184 {`"a";b";c`, []string{`a`, `b;c`}}, 185 } 186 187 func TestSplitList(t *testing.T) { 188 tests := splitlisttests 189 if runtime.GOOS == "windows" { 190 tests = append(tests, winsplitlisttests...) 191 } 192 for _, test := range tests { 193 if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) { 194 t.Errorf("SplitList(%#q) = %#q, want %#q", test.list, l, test.result) 195 } 196 } 197 } 198 199 type SplitTest struct { 200 path, dir, file string 201 } 202 203 var unixsplittests = []SplitTest{ 204 {"a/b", "a/", "b"}, 205 {"a/b/", "a/b/", ""}, 206 {"a/", "a/", ""}, 207 {"a", "", "a"}, 208 {"/", "/", ""}, 209 } 210 211 var winsplittests = []SplitTest{ 212 {`c:`, `c:`, ``}, 213 {`c:/`, `c:/`, ``}, 214 {`c:/foo`, `c:/`, `foo`}, 215 {`c:/foo/bar`, `c:/foo/`, `bar`}, 216 {`//host/share`, `//host/share`, ``}, 217 {`//host/share/`, `//host/share/`, ``}, 218 {`//host/share/foo`, `//host/share/`, `foo`}, 219 {`\\host\share`, `\\host\share`, ``}, 220 {`\\host\share\`, `\\host\share\`, ``}, 221 {`\\host\share\foo`, `\\host\share\`, `foo`}, 222 } 223 224 func TestSplit(t *testing.T) { 225 var splittests []SplitTest 226 splittests = unixsplittests 227 if runtime.GOOS == "windows" { 228 splittests = append(splittests, winsplittests...) 229 } 230 for _, test := range splittests { 231 if d, f := filepath.Split(test.path); d != test.dir || f != test.file { 232 t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file) 233 } 234 } 235 } 236 237 type JoinTest struct { 238 elem []string 239 path string 240 } 241 242 var jointests = []JoinTest{ 243 // zero parameters 244 {[]string{}, ""}, 245 246 // one parameter 247 {[]string{""}, ""}, 248 {[]string{"/"}, "/"}, 249 {[]string{"a"}, "a"}, 250 251 // two parameters 252 {[]string{"a", "b"}, "a/b"}, 253 {[]string{"a", ""}, "a"}, 254 {[]string{"", "b"}, "b"}, 255 {[]string{"/", "a"}, "/a"}, 256 {[]string{"/", "a/b"}, "/a/b"}, 257 {[]string{"/", ""}, "/"}, 258 {[]string{"//", "a"}, "/a"}, 259 {[]string{"/a", "b"}, "/a/b"}, 260 {[]string{"a/", "b"}, "a/b"}, 261 {[]string{"a/", ""}, "a"}, 262 {[]string{"", ""}, ""}, 263 264 // three parameters 265 {[]string{"/", "a", "b"}, "/a/b"}, 266 } 267 268 var winjointests = []JoinTest{ 269 {[]string{`directory`, `file`}, `directory\file`}, 270 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`}, 271 {[]string{`C:\Windows\`, ``}, `C:\Windows`}, 272 {[]string{`C:\`, `Windows`}, `C:\Windows`}, 273 {[]string{`C:`, `Windows`}, `C:\Windows`}, 274 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`}, 275 {[]string{`\\host\share\foo`}, `\\host\share\foo`}, 276 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`}, 277 {[]string{`\`}, `\`}, 278 {[]string{`\`, ``}, `\`}, 279 {[]string{`\`, `a`}, `\a`}, 280 {[]string{`\\`, `a`}, `\a`}, 281 {[]string{`\`, `a`, `b`}, `\a\b`}, 282 {[]string{`\\`, `a`, `b`}, `\a\b`}, 283 {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, 284 {[]string{`\\a`, `b`, `c`}, `\a\b\c`}, 285 {[]string{`\\a\`, `b`, `c`}, `\a\b\c`}, 286 } 287 288 func TestJoin(t *testing.T) { 289 if runtime.GOOS == "windows" { 290 jointests = append(jointests, winjointests...) 291 } 292 for _, test := range jointests { 293 expected := filepath.FromSlash(test.path) 294 if p := filepath.Join(test.elem...); p != expected { 295 t.Errorf("join(%q) = %q, want %q", test.elem, p, expected) 296 } 297 } 298 } 299 300 type ExtTest struct { 301 path, ext string 302 } 303 304 var exttests = []ExtTest{ 305 {"path.go", ".go"}, 306 {"path.pb.go", ".go"}, 307 {"a.dir/b", ""}, 308 {"a.dir/b.go", ".go"}, 309 {"a.dir/", ""}, 310 } 311 312 func TestExt(t *testing.T) { 313 for _, test := range exttests { 314 if x := filepath.Ext(test.path); x != test.ext { 315 t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext) 316 } 317 } 318 } 319 320 type Node struct { 321 name string 322 entries []*Node // nil if the entry is a file 323 mark int 324 } 325 326 var tree = &Node{ 327 "testdata", 328 []*Node{ 329 {"a", nil, 0}, 330 {"b", []*Node{}, 0}, 331 {"c", nil, 0}, 332 { 333 "d", 334 []*Node{ 335 {"x", nil, 0}, 336 {"y", []*Node{}, 0}, 337 { 338 "z", 339 []*Node{ 340 {"u", nil, 0}, 341 {"v", nil, 0}, 342 }, 343 0, 344 }, 345 }, 346 0, 347 }, 348 }, 349 0, 350 } 351 352 func walkTree(n *Node, path string, f func(path string, n *Node)) { 353 f(path, n) 354 for _, e := range n.entries { 355 walkTree(e, filepath.Join(path, e.name), f) 356 } 357 } 358 359 func makeTree(t *testing.T) { 360 walkTree(tree, tree.name, func(path string, n *Node) { 361 if n.entries == nil { 362 fd, err := os.Create(path) 363 if err != nil { 364 t.Errorf("makeTree: %v", err) 365 return 366 } 367 fd.Close() 368 } else { 369 os.Mkdir(path, 0770) 370 } 371 }) 372 } 373 374 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } 375 376 func checkMarks(t *testing.T, report bool) { 377 walkTree(tree, tree.name, func(path string, n *Node) { 378 if n.mark != 1 && report { 379 t.Errorf("node %s mark = %d; expected 1", path, n.mark) 380 } 381 n.mark = 0 382 }) 383 } 384 385 // Assumes that each node name is unique. Good enough for a test. 386 // If clear is true, any incoming error is cleared before return. The errors 387 // are always accumulated, though. 388 func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error { 389 if err != nil { 390 *errors = append(*errors, err) 391 if clear { 392 return nil 393 } 394 return err 395 } 396 name := info.Name() 397 walkTree(tree, tree.name, func(path string, n *Node) { 398 if n.name == name { 399 n.mark++ 400 } 401 }) 402 return nil 403 } 404 405 func chtmpdir(t *testing.T) (restore func()) { 406 oldwd, err := os.Getwd() 407 if err != nil { 408 t.Fatal("chtmpdir: %v", err) 409 } 410 d, err := ioutil.TempDir("", "test") 411 if err != nil { 412 t.Fatal("chtmpdir: %v", err) 413 } 414 if err := os.Chdir(d); err != nil { 415 t.Fatal("chtmpdir: %v", err) 416 } 417 return func() { 418 if err := os.Chdir(oldwd); err != nil { 419 t.Fatal("chtmpdir: %v", err) 420 } 421 os.RemoveAll(d) 422 } 423 } 424 425 func TestWalk(t *testing.T) { 426 if runtime.GOOS == "darwin" { 427 switch runtime.GOARCH { 428 case "arm", "arm64": 429 restore := chtmpdir(t) 430 defer restore() 431 } 432 } 433 makeTree(t) 434 errors := make([]error, 0, 10) 435 clear := true 436 markFn := func(path string, info os.FileInfo, err error) error { 437 return mark(path, info, err, &errors, clear) 438 } 439 // Expect no errors. 440 err := filepath.Walk(tree.name, markFn) 441 if err != nil { 442 t.Fatalf("no error expected, found: %s", err) 443 } 444 if len(errors) != 0 { 445 t.Fatalf("unexpected errors: %s", errors) 446 } 447 checkMarks(t, true) 448 errors = errors[0:0] 449 450 // Test permission errors. Only possible if we're not root 451 // and only on some file systems (AFS, FAT). To avoid errors during 452 // all.bash on those file systems, skip during go test -short. 453 if os.Getuid() > 0 && !testing.Short() { 454 // introduce 2 errors: chmod top-level directories to 0 455 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0) 456 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0) 457 458 // 3) capture errors, expect two. 459 // mark respective subtrees manually 460 markTree(tree.entries[1]) 461 markTree(tree.entries[3]) 462 // correct double-marking of directory itself 463 tree.entries[1].mark-- 464 tree.entries[3].mark-- 465 err := filepath.Walk(tree.name, markFn) 466 if err != nil { 467 t.Fatalf("expected no error return from Walk, got %s", err) 468 } 469 if len(errors) != 2 { 470 t.Errorf("expected 2 errors, got %d: %s", len(errors), errors) 471 } 472 // the inaccessible subtrees were marked manually 473 checkMarks(t, true) 474 errors = errors[0:0] 475 476 // 4) capture errors, stop after first error. 477 // mark respective subtrees manually 478 markTree(tree.entries[1]) 479 markTree(tree.entries[3]) 480 // correct double-marking of directory itself 481 tree.entries[1].mark-- 482 tree.entries[3].mark-- 483 clear = false // error will stop processing 484 err = filepath.Walk(tree.name, markFn) 485 if err == nil { 486 t.Fatalf("expected error return from Walk") 487 } 488 if len(errors) != 1 { 489 t.Errorf("expected 1 error, got %d: %s", len(errors), errors) 490 } 491 // the inaccessible subtrees were marked manually 492 checkMarks(t, false) 493 errors = errors[0:0] 494 495 // restore permissions 496 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770) 497 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770) 498 } 499 500 // cleanup 501 if err := os.RemoveAll(tree.name); err != nil { 502 t.Errorf("removeTree: %v", err) 503 } 504 } 505 506 func touch(t *testing.T, name string) { 507 f, err := os.Create(name) 508 if err != nil { 509 t.Fatal(err) 510 } 511 if err := f.Close(); err != nil { 512 t.Fatal(err) 513 } 514 } 515 516 func TestWalkSkipDirOnFile(t *testing.T) { 517 td, err := ioutil.TempDir("", "walktest") 518 if err != nil { 519 t.Fatal(err) 520 } 521 defer os.RemoveAll(td) 522 523 if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil { 524 t.Fatal(err) 525 } 526 touch(t, filepath.Join(td, "dir/foo1")) 527 touch(t, filepath.Join(td, "dir/foo2")) 528 529 sawFoo2 := false 530 filepath.Walk(td, func(path string, info os.FileInfo, err error) error { 531 if strings.HasSuffix(path, "foo2") { 532 sawFoo2 = true 533 } 534 if strings.HasSuffix(path, "foo1") { 535 return filepath.SkipDir 536 } 537 return nil 538 }) 539 540 if sawFoo2 { 541 t.Errorf("SkipDir on file foo1 did not block processing of foo2") 542 } 543 } 544 545 func TestWalkFileError(t *testing.T) { 546 td, err := ioutil.TempDir("", "walktest") 547 if err != nil { 548 t.Fatal(err) 549 } 550 defer os.RemoveAll(td) 551 552 touch(t, filepath.Join(td, "foo")) 553 touch(t, filepath.Join(td, "bar")) 554 dir := filepath.Join(td, "dir") 555 if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil { 556 t.Fatal(err) 557 } 558 touch(t, filepath.Join(dir, "baz")) 559 touch(t, filepath.Join(dir, "stat-error")) 560 defer func() { 561 *filepath.LstatP = os.Lstat 562 }() 563 statErr := errors.New("some stat error") 564 *filepath.LstatP = func(path string) (os.FileInfo, error) { 565 if strings.HasSuffix(path, "stat-error") { 566 return nil, statErr 567 } 568 return os.Lstat(path) 569 } 570 got := map[string]error{} 571 err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error { 572 rel, _ := filepath.Rel(td, path) 573 got[filepath.ToSlash(rel)] = err 574 return nil 575 }) 576 if err != nil { 577 t.Errorf("Walk error: %v", err) 578 } 579 want := map[string]error{ 580 ".": nil, 581 "foo": nil, 582 "bar": nil, 583 "dir": nil, 584 "dir/baz": nil, 585 "dir/stat-error": statErr, 586 } 587 if !reflect.DeepEqual(got, want) { 588 t.Errorf("Walked %#v; want %#v", got, want) 589 } 590 } 591 592 var basetests = []PathTest{ 593 {"", "."}, 594 {".", "."}, 595 {"/.", "."}, 596 {"/", "/"}, 597 {"////", "/"}, 598 {"x/", "x"}, 599 {"abc", "abc"}, 600 {"abc/def", "def"}, 601 {"a/b/.x", ".x"}, 602 {"a/b/c.", "c."}, 603 {"a/b/c.x", "c.x"}, 604 } 605 606 var winbasetests = []PathTest{ 607 {`c:\`, `\`}, 608 {`c:.`, `.`}, 609 {`c:\a\b`, `b`}, 610 {`c:a\b`, `b`}, 611 {`c:a\b\c`, `c`}, 612 {`\\host\share\`, `\`}, 613 {`\\host\share\a`, `a`}, 614 {`\\host\share\a\b`, `b`}, 615 } 616 617 func TestBase(t *testing.T) { 618 tests := basetests 619 if runtime.GOOS == "windows" { 620 // make unix tests work on windows 621 for i := range tests { 622 tests[i].result = filepath.Clean(tests[i].result) 623 } 624 // add windows specific tests 625 tests = append(tests, winbasetests...) 626 } 627 for _, test := range tests { 628 if s := filepath.Base(test.path); s != test.result { 629 t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result) 630 } 631 } 632 } 633 634 var dirtests = []PathTest{ 635 {"", "."}, 636 {".", "."}, 637 {"/.", "/"}, 638 {"/", "/"}, 639 {"////", "/"}, 640 {"/foo", "/"}, 641 {"x/", "x"}, 642 {"abc", "."}, 643 {"abc/def", "abc"}, 644 {"a/b/.x", "a/b"}, 645 {"a/b/c.", "a/b"}, 646 {"a/b/c.x", "a/b"}, 647 } 648 649 var windirtests = []PathTest{ 650 {`c:\`, `c:\`}, 651 {`c:.`, `c:.`}, 652 {`c:\a\b`, `c:\a`}, 653 {`c:a\b`, `c:a`}, 654 {`c:a\b\c`, `c:a\b`}, 655 {`\\host\share\`, `\\host\share\`}, 656 {`\\host\share\a`, `\\host\share\`}, 657 {`\\host\share\a\b`, `\\host\share\a`}, 658 } 659 660 func TestDir(t *testing.T) { 661 tests := dirtests 662 if runtime.GOOS == "windows" { 663 // make unix tests work on windows 664 for i := range tests { 665 tests[i].result = filepath.Clean(tests[i].result) 666 } 667 // add windows specific tests 668 tests = append(tests, windirtests...) 669 } 670 for _, test := range tests { 671 if s := filepath.Dir(test.path); s != test.result { 672 t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result) 673 } 674 } 675 } 676 677 type IsAbsTest struct { 678 path string 679 isAbs bool 680 } 681 682 var isabstests = []IsAbsTest{ 683 {"", false}, 684 {"/", true}, 685 {"/usr/bin/gcc", true}, 686 {"..", false}, 687 {"/a/../bb", true}, 688 {".", false}, 689 {"./", false}, 690 {"lala", false}, 691 } 692 693 var winisabstests = []IsAbsTest{ 694 {`C:\`, true}, 695 {`c\`, false}, 696 {`c::`, false}, 697 {`c:`, false}, 698 {`/`, false}, 699 {`\`, false}, 700 {`\Windows`, false}, 701 {`c:a\b`, false}, 702 {`c:\a\b`, true}, 703 {`c:/a/b`, true}, 704 {`\\host\share\foo`, true}, 705 {`//host/share/foo/bar`, true}, 706 } 707 708 func TestIsAbs(t *testing.T) { 709 var tests []IsAbsTest 710 if runtime.GOOS == "windows" { 711 tests = append(tests, winisabstests...) 712 // All non-windows tests should fail, because they have no volume letter. 713 for _, test := range isabstests { 714 tests = append(tests, IsAbsTest{test.path, false}) 715 } 716 // All non-windows test should work as intended if prefixed with volume letter. 717 for _, test := range isabstests { 718 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs}) 719 } 720 } else { 721 tests = isabstests 722 } 723 724 for _, test := range tests { 725 if r := filepath.IsAbs(test.path); r != test.isAbs { 726 t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs) 727 } 728 } 729 } 730 731 type EvalSymlinksTest struct { 732 // If dest is empty, the path is created; otherwise the dest is symlinked to the path. 733 path, dest string 734 } 735 736 var EvalSymlinksTestDirs = []EvalSymlinksTest{ 737 {"test", ""}, 738 {"test/dir", ""}, 739 {"test/dir/link3", "../../"}, 740 {"test/link1", "../test"}, 741 {"test/link2", "dir"}, 742 {"test/linkabs", "/"}, 743 } 744 745 var EvalSymlinksTests = []EvalSymlinksTest{ 746 {"test", "test"}, 747 {"test/dir", "test/dir"}, 748 {"test/dir/../..", "."}, 749 {"test/link1", "test"}, 750 {"test/link2", "test/dir"}, 751 {"test/link1/dir", "test/dir"}, 752 {"test/link2/..", "test"}, 753 {"test/dir/link3", "."}, 754 {"test/link2/link3/test", "test"}, 755 {"test/linkabs", "/"}, 756 } 757 758 var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{ 759 {`c:\`, `c:\`}, 760 } 761 762 // simpleJoin builds a file name from the directory and path. 763 // It does not use Join because we don't want ".." to be evaluated. 764 func simpleJoin(dir, path string) string { 765 return dir + string(filepath.Separator) + path 766 } 767 768 func TestEvalSymlinks(t *testing.T) { 769 switch runtime.GOOS { 770 case "nacl", "plan9": 771 t.Skipf("skipping on %s", runtime.GOOS) 772 } 773 774 tmpDir, err := ioutil.TempDir("", "evalsymlink") 775 if err != nil { 776 t.Fatal("creating temp dir:", err) 777 } 778 defer os.RemoveAll(tmpDir) 779 780 // /tmp may itself be a symlink! Avoid the confusion, although 781 // it means trusting the thing we're testing. 782 tmpDir, err = filepath.EvalSymlinks(tmpDir) 783 if err != nil { 784 t.Fatal("eval symlink for tmp dir:", err) 785 } 786 787 // Create the symlink farm using relative paths. 788 for _, d := range EvalSymlinksTestDirs { 789 var err error 790 path := simpleJoin(tmpDir, d.path) 791 if d.dest == "" { 792 err = os.Mkdir(path, 0755) 793 } else { 794 if supportsSymlinks { 795 err = os.Symlink(d.dest, path) 796 } 797 } 798 if err != nil { 799 t.Fatal(err) 800 } 801 } 802 803 var tests []EvalSymlinksTest 804 if supportsSymlinks { 805 tests = EvalSymlinksTests 806 } else { 807 for _, d := range EvalSymlinksTests { 808 if d.path == d.dest { 809 // will test only real files and directories 810 tests = append(tests, d) 811 // test "canonical" names 812 d2 := EvalSymlinksTest{ 813 path: strings.ToUpper(d.path), 814 dest: d.dest, 815 } 816 tests = append(tests, d2) 817 } 818 } 819 } 820 821 // Evaluate the symlink farm. 822 for _, d := range tests { 823 path := simpleJoin(tmpDir, d.path) 824 dest := simpleJoin(tmpDir, d.dest) 825 if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { 826 dest = d.dest 827 } 828 if p, err := filepath.EvalSymlinks(path); err != nil { 829 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) 830 } else if filepath.Clean(p) != filepath.Clean(dest) { 831 t.Errorf("Clean(%q)=%q, want %q", path, p, dest) 832 } 833 } 834 } 835 836 // Test directories relative to temporary directory. 837 // The tests are run in absTestDirs[0]. 838 var absTestDirs = []string{ 839 "a", 840 "a/b", 841 "a/b/c", 842 } 843 844 // Test paths relative to temporary directory. $ expands to the directory. 845 // The tests are run in absTestDirs[0]. 846 // We create absTestDirs first. 847 var absTests = []string{ 848 ".", 849 "b", 850 "../a", 851 "../a/b", 852 "../a/b/./c/../../.././a", 853 "$", 854 "$/.", 855 "$/a/../a/b", 856 "$/a/b/c/../../.././a", 857 } 858 859 func TestAbs(t *testing.T) { 860 root, err := ioutil.TempDir("", "TestAbs") 861 if err != nil { 862 t.Fatal("TempDir failed: ", err) 863 } 864 defer os.RemoveAll(root) 865 866 wd, err := os.Getwd() 867 if err != nil { 868 t.Fatal("getwd failed: ", err) 869 } 870 err = os.Chdir(root) 871 if err != nil { 872 t.Fatal("chdir failed: ", err) 873 } 874 defer os.Chdir(wd) 875 876 for _, dir := range absTestDirs { 877 err = os.Mkdir(dir, 0777) 878 if err != nil { 879 t.Fatal("Mkdir failed: ", err) 880 } 881 } 882 883 if runtime.GOOS == "windows" { 884 vol := filepath.VolumeName(root) 885 var extra []string 886 for _, path := range absTests { 887 if strings.Index(path, "$") != -1 { 888 continue 889 } 890 path = vol + path 891 extra = append(extra, path) 892 } 893 absTests = append(absTests, extra...) 894 } 895 896 err = os.Chdir(absTestDirs[0]) 897 if err != nil { 898 t.Fatal("chdir failed: ", err) 899 } 900 901 for _, path := range absTests { 902 path = strings.Replace(path, "$", root, -1) 903 info, err := os.Stat(path) 904 if err != nil { 905 t.Errorf("%s: %s", path, err) 906 continue 907 } 908 909 abspath, err := filepath.Abs(path) 910 if err != nil { 911 t.Errorf("Abs(%q) error: %v", path, err) 912 continue 913 } 914 absinfo, err := os.Stat(abspath) 915 if err != nil || !os.SameFile(absinfo, info) { 916 t.Errorf("Abs(%q)=%q, not the same file", path, abspath) 917 } 918 if !filepath.IsAbs(abspath) { 919 t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath) 920 } 921 if filepath.IsAbs(path) && abspath != filepath.Clean(path) { 922 t.Errorf("Abs(%q)=%q, isn't clean", path, abspath) 923 } 924 } 925 } 926 927 type RelTests struct { 928 root, path, want string 929 } 930 931 var reltests = []RelTests{ 932 {"a/b", "a/b", "."}, 933 {"a/b/.", "a/b", "."}, 934 {"a/b", "a/b/.", "."}, 935 {"./a/b", "a/b", "."}, 936 {"a/b", "./a/b", "."}, 937 {"ab/cd", "ab/cde", "../cde"}, 938 {"ab/cd", "ab/c", "../c"}, 939 {"a/b", "a/b/c/d", "c/d"}, 940 {"a/b", "a/b/../c", "../c"}, 941 {"a/b/../c", "a/b", "../b"}, 942 {"a/b/c", "a/c/d", "../../c/d"}, 943 {"a/b", "c/d", "../../c/d"}, 944 {"a/b/c/d", "a/b", "../.."}, 945 {"a/b/c/d", "a/b/", "../.."}, 946 {"a/b/c/d/", "a/b", "../.."}, 947 {"a/b/c/d/", "a/b/", "../.."}, 948 {"../../a/b", "../../a/b/c/d", "c/d"}, 949 {"/a/b", "/a/b", "."}, 950 {"/a/b/.", "/a/b", "."}, 951 {"/a/b", "/a/b/.", "."}, 952 {"/ab/cd", "/ab/cde", "../cde"}, 953 {"/ab/cd", "/ab/c", "../c"}, 954 {"/a/b", "/a/b/c/d", "c/d"}, 955 {"/a/b", "/a/b/../c", "../c"}, 956 {"/a/b/../c", "/a/b", "../b"}, 957 {"/a/b/c", "/a/c/d", "../../c/d"}, 958 {"/a/b", "/c/d", "../../c/d"}, 959 {"/a/b/c/d", "/a/b", "../.."}, 960 {"/a/b/c/d", "/a/b/", "../.."}, 961 {"/a/b/c/d/", "/a/b", "../.."}, 962 {"/a/b/c/d/", "/a/b/", "../.."}, 963 {"/../../a/b", "/../../a/b/c/d", "c/d"}, 964 {".", "a/b", "a/b"}, 965 {".", "..", ".."}, 966 967 // can't do purely lexically 968 {"..", ".", "err"}, 969 {"..", "a", "err"}, 970 {"../..", "..", "err"}, 971 {"a", "/a", "err"}, 972 {"/a", "a", "err"}, 973 } 974 975 var winreltests = []RelTests{ 976 {`C:a\b\c`, `C:a/b/d`, `..\d`}, 977 {`C:\`, `D:\`, `err`}, 978 {`C:`, `D:`, `err`}, 979 } 980 981 func TestRel(t *testing.T) { 982 tests := append([]RelTests{}, reltests...) 983 if runtime.GOOS == "windows" { 984 for i := range tests { 985 tests[i].want = filepath.FromSlash(tests[i].want) 986 } 987 tests = append(tests, winreltests...) 988 } 989 for _, test := range tests { 990 got, err := filepath.Rel(test.root, test.path) 991 if test.want == "err" { 992 if err == nil { 993 t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got) 994 } 995 continue 996 } 997 if err != nil { 998 t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err) 999 } 1000 if got != test.want { 1001 t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want) 1002 } 1003 } 1004 } 1005 1006 type VolumeNameTest struct { 1007 path string 1008 vol string 1009 } 1010 1011 var volumenametests = []VolumeNameTest{ 1012 {`c:/foo/bar`, `c:`}, 1013 {`c:`, `c:`}, 1014 {`2:`, ``}, 1015 {``, ``}, 1016 {`\\\host`, ``}, 1017 {`\\\host\`, ``}, 1018 {`\\\host\share`, ``}, 1019 {`\\\host\\share`, ``}, 1020 {`\\host`, ``}, 1021 {`//host`, ``}, 1022 {`\\host\`, ``}, 1023 {`//host/`, ``}, 1024 {`\\host\share`, `\\host\share`}, 1025 {`//host/share`, `//host/share`}, 1026 {`\\host\share\`, `\\host\share`}, 1027 {`//host/share/`, `//host/share`}, 1028 {`\\host\share\foo`, `\\host\share`}, 1029 {`//host/share/foo`, `//host/share`}, 1030 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, 1031 {`//host/share//foo///bar////baz`, `//host/share`}, 1032 {`\\host\share\foo\..\bar`, `\\host\share`}, 1033 {`//host/share/foo/../bar`, `//host/share`}, 1034 } 1035 1036 func TestVolumeName(t *testing.T) { 1037 if runtime.GOOS != "windows" { 1038 return 1039 } 1040 for _, v := range volumenametests { 1041 if vol := filepath.VolumeName(v.path); vol != v.vol { 1042 t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol) 1043 } 1044 } 1045 } 1046 1047 func TestDriveLetterInEvalSymlinks(t *testing.T) { 1048 if runtime.GOOS != "windows" { 1049 return 1050 } 1051 wd, _ := os.Getwd() 1052 if len(wd) < 3 { 1053 t.Errorf("Current directory path %q is too short", wd) 1054 } 1055 lp := strings.ToLower(wd) 1056 up := strings.ToUpper(wd) 1057 flp, err := filepath.EvalSymlinks(lp) 1058 if err != nil { 1059 t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err) 1060 } 1061 fup, err := filepath.EvalSymlinks(up) 1062 if err != nil { 1063 t.Fatalf("EvalSymlinks(%q) failed: %q", up, err) 1064 } 1065 if flp != fup { 1066 t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup) 1067 } 1068 } 1069 1070 func TestBug3486(t *testing.T) { // https://golang.org/issue/3486 1071 t.Skip("skipping test because gccgo sources are arranged differently.") 1072 if runtime.GOOS == "darwin" { 1073 switch runtime.GOARCH { 1074 case "arm", "arm64": 1075 t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH) 1076 } 1077 } 1078 root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test") 1079 if err != nil { 1080 t.Fatal(err) 1081 } 1082 bugs := filepath.Join(root, "bugs") 1083 ken := filepath.Join(root, "ken") 1084 seenBugs := false 1085 seenKen := false 1086 filepath.Walk(root, func(pth string, info os.FileInfo, err error) error { 1087 if err != nil { 1088 t.Fatal(err) 1089 } 1090 1091 switch pth { 1092 case bugs: 1093 seenBugs = true 1094 return filepath.SkipDir 1095 case ken: 1096 if !seenBugs { 1097 t.Fatal("filepath.Walk out of order - ken before bugs") 1098 } 1099 seenKen = true 1100 } 1101 return nil 1102 }) 1103 if !seenKen { 1104 t.Fatalf("%q not seen", ken) 1105 } 1106 }