libgo: update to go1.9
[official-gcc.git] / libgo / go / path / filepath / path_test.go
blobf2e92528a969f4c000cfac6c27467fb0be2a844f
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.
5 package filepath_test
7 import (
8 "errors"
9 "fmt"
10 "internal/testenv"
11 "io/ioutil"
12 "os"
13 "path/filepath"
14 "reflect"
15 "runtime"
16 "sort"
17 "strings"
18 "testing"
21 type PathTest struct {
22 path, result string
25 var cleantests = []PathTest{
26 // Already clean
27 {"abc", "abc"},
28 {"abc/def", "abc/def"},
29 {"a/b/c", "a/b/c"},
30 {".", "."},
31 {"..", ".."},
32 {"../..", "../.."},
33 {"../../abc", "../../abc"},
34 {"/abc", "/abc"},
35 {"/", "/"},
37 // Empty is current dir
38 {"", "."},
40 // Remove trailing slash
41 {"abc/", "abc"},
42 {"abc/def/", "abc/def"},
43 {"a/b/c/", "a/b/c"},
44 {"./", "."},
45 {"../", ".."},
46 {"../../", "../.."},
47 {"/abc/", "/abc"},
49 // Remove doubled slash
50 {"abc//def//ghi", "abc/def/ghi"},
51 {"//abc", "/abc"},
52 {"///abc", "/abc"},
53 {"//abc//", "/abc"},
54 {"abc//", "abc"},
56 // Remove . elements
57 {"abc/./def", "abc/def"},
58 {"/./abc/def", "/abc/def"},
59 {"abc/.", "abc"},
61 // Remove .. elements
62 {"abc/def/ghi/../jkl", "abc/def/jkl"},
63 {"abc/def/../ghi/../jkl", "abc/jkl"},
64 {"abc/def/..", "abc"},
65 {"abc/def/../..", "."},
66 {"/abc/def/../..", "/"},
67 {"abc/def/../../..", ".."},
68 {"/abc/def/../../..", "/"},
69 {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
70 {"/../abc", "/abc"},
72 // Combinations
73 {"abc/./../def", "def"},
74 {"abc//./../def", "def"},
75 {"abc/../../././../def", "../../def"},
78 var wincleantests = []PathTest{
79 {`c:`, `c:.`},
80 {`c:\`, `c:\`},
81 {`c:\abc`, `c:\abc`},
82 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
83 {`c:\abc\def\..\..`, `c:\`},
84 {`c:\..\abc`, `c:\abc`},
85 {`c:..\abc`, `c:..\abc`},
86 {`\`, `\`},
87 {`/`, `\`},
88 {`\\i\..\c$`, `\c$`},
89 {`\\i\..\i\c$`, `\i\c$`},
90 {`\\i\..\I\c$`, `\I\c$`},
91 {`\\host\share\foo\..\bar`, `\\host\share\bar`},
92 {`//host/share/foo/../baz`, `\\host\share\baz`},
93 {`\\a\b\..\c`, `\\a\b\c`},
94 {`\\a\b`, `\\a\b`},
97 func TestClean(t *testing.T) {
98 tests := cleantests
99 if runtime.GOOS == "windows" {
100 for i := range tests {
101 tests[i].result = filepath.FromSlash(tests[i].result)
103 tests = append(tests, wincleantests...)
105 for _, test := range tests {
106 if s := filepath.Clean(test.path); s != test.result {
107 t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
109 if s := filepath.Clean(test.result); s != test.result {
110 t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)
114 if testing.Short() {
115 t.Skip("skipping malloc count in short mode")
117 if runtime.GOMAXPROCS(0) > 1 {
118 t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
119 return
122 t.Log("Skipping AllocsPerRun for gccgo")
123 return
125 for _, test := range tests {
126 allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) })
127 if allocs > 0 {
128 t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs)
133 const sep = filepath.Separator
135 var slashtests = []PathTest{
136 {"", ""},
137 {"/", string(sep)},
138 {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
139 {"a//b", string([]byte{'a', sep, sep, 'b'})},
142 func TestFromAndToSlash(t *testing.T) {
143 for _, test := range slashtests {
144 if s := filepath.FromSlash(test.path); s != test.result {
145 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
147 if s := filepath.ToSlash(test.result); s != test.path {
148 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
153 type SplitListTest struct {
154 list string
155 result []string
158 const lsep = filepath.ListSeparator
160 var splitlisttests = []SplitListTest{
161 {"", []string{}},
162 {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},
163 {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},
166 var winsplitlisttests = []SplitListTest{
167 // quoted
168 {`"a"`, []string{`a`}},
170 // semicolon
171 {`";"`, []string{`;`}},
172 {`"a;b"`, []string{`a;b`}},
173 {`";";`, []string{`;`, ``}},
174 {`;";"`, []string{``, `;`}},
176 // partially quoted
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`, []string{`a;b`}},
184 {`a;b";c`, []string{`a`, `b;c`}},
185 {`"a";b";c`, []string{`a`, `b;c`}},
188 func TestSplitList(t *testing.T) {
189 tests := splitlisttests
190 if runtime.GOOS == "windows" {
191 tests = append(tests, winsplitlisttests...)
193 for _, test := range tests {
194 if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {
195 t.Errorf("SplitList(%#q) = %#q, want %#q", test.list, l, test.result)
200 type SplitTest struct {
201 path, dir, file string
204 var unixsplittests = []SplitTest{
205 {"a/b", "a/", "b"},
206 {"a/b/", "a/b/", ""},
207 {"a/", "a/", ""},
208 {"a", "", "a"},
209 {"/", "/", ""},
212 var winsplittests = []SplitTest{
213 {`c:`, `c:`, ``},
214 {`c:/`, `c:/`, ``},
215 {`c:/foo`, `c:/`, `foo`},
216 {`c:/foo/bar`, `c:/foo/`, `bar`},
217 {`//host/share`, `//host/share`, ``},
218 {`//host/share/`, `//host/share/`, ``},
219 {`//host/share/foo`, `//host/share/`, `foo`},
220 {`\\host\share`, `\\host\share`, ``},
221 {`\\host\share\`, `\\host\share\`, ``},
222 {`\\host\share\foo`, `\\host\share\`, `foo`},
225 func TestSplit(t *testing.T) {
226 var splittests []SplitTest
227 splittests = unixsplittests
228 if runtime.GOOS == "windows" {
229 splittests = append(splittests, winsplittests...)
231 for _, test := range splittests {
232 if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
233 t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
238 type JoinTest struct {
239 elem []string
240 path string
243 var jointests = []JoinTest{
244 // zero parameters
245 {[]string{}, ""},
247 // one parameter
248 {[]string{""}, ""},
249 {[]string{"/"}, "/"},
250 {[]string{"a"}, "a"},
252 // two parameters
253 {[]string{"a", "b"}, "a/b"},
254 {[]string{"a", ""}, "a"},
255 {[]string{"", "b"}, "b"},
256 {[]string{"/", "a"}, "/a"},
257 {[]string{"/", "a/b"}, "/a/b"},
258 {[]string{"/", ""}, "/"},
259 {[]string{"//", "a"}, "/a"},
260 {[]string{"/a", "b"}, "/a/b"},
261 {[]string{"a/", "b"}, "a/b"},
262 {[]string{"a/", ""}, "a"},
263 {[]string{"", ""}, ""},
265 // three parameters
266 {[]string{"/", "a", "b"}, "/a/b"},
269 var winjointests = []JoinTest{
270 {[]string{`directory`, `file`}, `directory\file`},
271 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
272 {[]string{`C:\Windows\`, ``}, `C:\Windows`},
273 {[]string{`C:\`, `Windows`}, `C:\Windows`},
274 {[]string{`C:`, `a`}, `C:a`},
275 {[]string{`C:`, `a\b`}, `C:a\b`},
276 {[]string{`C:`, `a`, `b`}, `C:a\b`},
277 {[]string{`C:.`, `a`}, `C:a`},
278 {[]string{`C:a`, `b`}, `C:a\b`},
279 {[]string{`C:a`, `b`, `d`}, `C:a\b\d`},
280 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
281 {[]string{`\\host\share\foo`}, `\\host\share\foo`},
282 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
283 {[]string{`\`}, `\`},
284 {[]string{`\`, ``}, `\`},
285 {[]string{`\`, `a`}, `\a`},
286 {[]string{`\\`, `a`}, `\a`},
287 {[]string{`\`, `a`, `b`}, `\a\b`},
288 {[]string{`\\`, `a`, `b`}, `\a\b`},
289 {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
290 {[]string{`\\a`, `b`, `c`}, `\a\b\c`},
291 {[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
294 func TestJoin(t *testing.T) {
295 if runtime.GOOS == "windows" {
296 jointests = append(jointests, winjointests...)
298 for _, test := range jointests {
299 expected := filepath.FromSlash(test.path)
300 if p := filepath.Join(test.elem...); p != expected {
301 t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
306 type ExtTest struct {
307 path, ext string
310 var exttests = []ExtTest{
311 {"path.go", ".go"},
312 {"path.pb.go", ".go"},
313 {"a.dir/b", ""},
314 {"a.dir/b.go", ".go"},
315 {"a.dir/", ""},
318 func TestExt(t *testing.T) {
319 for _, test := range exttests {
320 if x := filepath.Ext(test.path); x != test.ext {
321 t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
326 type Node struct {
327 name string
328 entries []*Node // nil if the entry is a file
329 mark int
332 var tree = &Node{
333 "testdata",
334 []*Node{
335 {"a", nil, 0},
336 {"b", []*Node{}, 0},
337 {"c", nil, 0},
339 "d",
340 []*Node{
341 {"x", nil, 0},
342 {"y", []*Node{}, 0},
344 "z",
345 []*Node{
346 {"u", nil, 0},
347 {"v", nil, 0},
358 func walkTree(n *Node, path string, f func(path string, n *Node)) {
359 f(path, n)
360 for _, e := range n.entries {
361 walkTree(e, filepath.Join(path, e.name), f)
365 func makeTree(t *testing.T) {
366 walkTree(tree, tree.name, func(path string, n *Node) {
367 if n.entries == nil {
368 fd, err := os.Create(path)
369 if err != nil {
370 t.Errorf("makeTree: %v", err)
371 return
373 fd.Close()
374 } else {
375 os.Mkdir(path, 0770)
380 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
382 func checkMarks(t *testing.T, report bool) {
383 walkTree(tree, tree.name, func(path string, n *Node) {
384 if n.mark != 1 && report {
385 t.Errorf("node %s mark = %d; expected 1", path, n.mark)
387 n.mark = 0
391 // Assumes that each node name is unique. Good enough for a test.
392 // If clear is true, any incoming error is cleared before return. The errors
393 // are always accumulated, though.
394 func mark(info os.FileInfo, err error, errors *[]error, clear bool) error {
395 if err != nil {
396 *errors = append(*errors, err)
397 if clear {
398 return nil
400 return err
402 name := info.Name()
403 walkTree(tree, tree.name, func(path string, n *Node) {
404 if n.name == name {
405 n.mark++
408 return nil
411 func chtmpdir(t *testing.T) (restore func()) {
412 oldwd, err := os.Getwd()
413 if err != nil {
414 t.Fatalf("chtmpdir: %v", err)
416 d, err := ioutil.TempDir("", "test")
417 if err != nil {
418 t.Fatalf("chtmpdir: %v", err)
420 if err := os.Chdir(d); err != nil {
421 t.Fatalf("chtmpdir: %v", err)
423 return func() {
424 if err := os.Chdir(oldwd); err != nil {
425 t.Fatalf("chtmpdir: %v", err)
427 os.RemoveAll(d)
431 func TestWalk(t *testing.T) {
432 if runtime.GOOS == "darwin" {
433 switch runtime.GOARCH {
434 case "arm", "arm64":
435 restore := chtmpdir(t)
436 defer restore()
439 makeTree(t)
440 errors := make([]error, 0, 10)
441 clear := true
442 markFn := func(path string, info os.FileInfo, err error) error {
443 return mark(info, err, &errors, clear)
445 // Expect no errors.
446 err := filepath.Walk(tree.name, markFn)
447 if err != nil {
448 t.Fatalf("no error expected, found: %s", err)
450 if len(errors) != 0 {
451 t.Fatalf("unexpected errors: %s", errors)
453 checkMarks(t, true)
454 errors = errors[0:0]
456 // Test permission errors. Only possible if we're not root
457 // and only on some file systems (AFS, FAT). To avoid errors during
458 // all.bash on those file systems, skip during go test -short.
459 if os.Getuid() > 0 && !testing.Short() {
460 // introduce 2 errors: chmod top-level directories to 0
461 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
462 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
464 // 3) capture errors, expect two.
465 // mark respective subtrees manually
466 markTree(tree.entries[1])
467 markTree(tree.entries[3])
468 // correct double-marking of directory itself
469 tree.entries[1].mark--
470 tree.entries[3].mark--
471 err := filepath.Walk(tree.name, markFn)
472 if err != nil {
473 t.Fatalf("expected no error return from Walk, got %s", err)
475 if len(errors) != 2 {
476 t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
478 // the inaccessible subtrees were marked manually
479 checkMarks(t, true)
480 errors = errors[0:0]
482 // 4) capture errors, stop after first error.
483 // mark respective subtrees manually
484 markTree(tree.entries[1])
485 markTree(tree.entries[3])
486 // correct double-marking of directory itself
487 tree.entries[1].mark--
488 tree.entries[3].mark--
489 clear = false // error will stop processing
490 err = filepath.Walk(tree.name, markFn)
491 if err == nil {
492 t.Fatalf("expected error return from Walk")
494 if len(errors) != 1 {
495 t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
497 // the inaccessible subtrees were marked manually
498 checkMarks(t, false)
499 errors = errors[0:0]
501 // restore permissions
502 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
503 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
506 // cleanup
507 if err := os.RemoveAll(tree.name); err != nil {
508 t.Errorf("removeTree: %v", err)
512 func touch(t *testing.T, name string) {
513 f, err := os.Create(name)
514 if err != nil {
515 t.Fatal(err)
517 if err := f.Close(); err != nil {
518 t.Fatal(err)
522 func TestWalkSkipDirOnFile(t *testing.T) {
523 td, err := ioutil.TempDir("", "walktest")
524 if err != nil {
525 t.Fatal(err)
527 defer os.RemoveAll(td)
529 if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
530 t.Fatal(err)
532 touch(t, filepath.Join(td, "dir/foo1"))
533 touch(t, filepath.Join(td, "dir/foo2"))
535 sawFoo2 := false
536 walker := func(path string, info os.FileInfo, err error) error {
537 if strings.HasSuffix(path, "foo2") {
538 sawFoo2 = true
540 if strings.HasSuffix(path, "foo1") {
541 return filepath.SkipDir
543 return nil
546 err = filepath.Walk(td, walker)
547 if err != nil {
548 t.Fatal(err)
550 if sawFoo2 {
551 t.Errorf("SkipDir on file foo1 did not block processing of foo2")
554 err = filepath.Walk(filepath.Join(td, "dir"), walker)
555 if err != nil {
556 t.Fatal(err)
558 if sawFoo2 {
559 t.Errorf("SkipDir on file foo1 did not block processing of foo2")
563 func TestWalkFileError(t *testing.T) {
564 td, err := ioutil.TempDir("", "walktest")
565 if err != nil {
566 t.Fatal(err)
568 defer os.RemoveAll(td)
570 touch(t, filepath.Join(td, "foo"))
571 touch(t, filepath.Join(td, "bar"))
572 dir := filepath.Join(td, "dir")
573 if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
574 t.Fatal(err)
576 touch(t, filepath.Join(dir, "baz"))
577 touch(t, filepath.Join(dir, "stat-error"))
578 defer func() {
579 *filepath.LstatP = os.Lstat
581 statErr := errors.New("some stat error")
582 *filepath.LstatP = func(path string) (os.FileInfo, error) {
583 if strings.HasSuffix(path, "stat-error") {
584 return nil, statErr
586 return os.Lstat(path)
588 got := map[string]error{}
589 err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error {
590 rel, _ := filepath.Rel(td, path)
591 got[filepath.ToSlash(rel)] = err
592 return nil
594 if err != nil {
595 t.Errorf("Walk error: %v", err)
597 want := map[string]error{
598 ".": nil,
599 "foo": nil,
600 "bar": nil,
601 "dir": nil,
602 "dir/baz": nil,
603 "dir/stat-error": statErr,
605 if !reflect.DeepEqual(got, want) {
606 t.Errorf("Walked %#v; want %#v", got, want)
610 var basetests = []PathTest{
611 {"", "."},
612 {".", "."},
613 {"/.", "."},
614 {"/", "/"},
615 {"////", "/"},
616 {"x/", "x"},
617 {"abc", "abc"},
618 {"abc/def", "def"},
619 {"a/b/.x", ".x"},
620 {"a/b/c.", "c."},
621 {"a/b/c.x", "c.x"},
624 var winbasetests = []PathTest{
625 {`c:\`, `\`},
626 {`c:.`, `.`},
627 {`c:\a\b`, `b`},
628 {`c:a\b`, `b`},
629 {`c:a\b\c`, `c`},
630 {`\\host\share\`, `\`},
631 {`\\host\share\a`, `a`},
632 {`\\host\share\a\b`, `b`},
635 func TestBase(t *testing.T) {
636 tests := basetests
637 if runtime.GOOS == "windows" {
638 // make unix tests work on windows
639 for i := range tests {
640 tests[i].result = filepath.Clean(tests[i].result)
642 // add windows specific tests
643 tests = append(tests, winbasetests...)
645 for _, test := range tests {
646 if s := filepath.Base(test.path); s != test.result {
647 t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
652 var dirtests = []PathTest{
653 {"", "."},
654 {".", "."},
655 {"/.", "/"},
656 {"/", "/"},
657 {"////", "/"},
658 {"/foo", "/"},
659 {"x/", "x"},
660 {"abc", "."},
661 {"abc/def", "abc"},
662 {"a/b/.x", "a/b"},
663 {"a/b/c.", "a/b"},
664 {"a/b/c.x", "a/b"},
667 var windirtests = []PathTest{
668 {`c:\`, `c:\`},
669 {`c:.`, `c:.`},
670 {`c:\a\b`, `c:\a`},
671 {`c:a\b`, `c:a`},
672 {`c:a\b\c`, `c:a\b`},
673 {`\\host\share`, `\\host\share`},
674 {`\\host\share\`, `\\host\share\`},
675 {`\\host\share\a`, `\\host\share\`},
676 {`\\host\share\a\b`, `\\host\share\a`},
679 func TestDir(t *testing.T) {
680 tests := dirtests
681 if runtime.GOOS == "windows" {
682 // make unix tests work on windows
683 for i := range tests {
684 tests[i].result = filepath.Clean(tests[i].result)
686 // add windows specific tests
687 tests = append(tests, windirtests...)
689 for _, test := range tests {
690 if s := filepath.Dir(test.path); s != test.result {
691 t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
696 type IsAbsTest struct {
697 path string
698 isAbs bool
701 var isabstests = []IsAbsTest{
702 {"", false},
703 {"/", true},
704 {"/usr/bin/gcc", true},
705 {"..", false},
706 {"/a/../bb", true},
707 {".", false},
708 {"./", false},
709 {"lala", false},
712 var winisabstests = []IsAbsTest{
713 {`C:\`, true},
714 {`c\`, false},
715 {`c::`, false},
716 {`c:`, false},
717 {`/`, false},
718 {`\`, false},
719 {`\Windows`, false},
720 {`c:a\b`, false},
721 {`c:\a\b`, true},
722 {`c:/a/b`, true},
723 {`\\host\share\foo`, true},
724 {`//host/share/foo/bar`, true},
727 func TestIsAbs(t *testing.T) {
728 var tests []IsAbsTest
729 if runtime.GOOS == "windows" {
730 tests = append(tests, winisabstests...)
731 // All non-windows tests should fail, because they have no volume letter.
732 for _, test := range isabstests {
733 tests = append(tests, IsAbsTest{test.path, false})
735 // All non-windows test should work as intended if prefixed with volume letter.
736 for _, test := range isabstests {
737 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
739 } else {
740 tests = isabstests
743 for _, test := range tests {
744 if r := filepath.IsAbs(test.path); r != test.isAbs {
745 t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
750 type EvalSymlinksTest struct {
751 // If dest is empty, the path is created; otherwise the dest is symlinked to the path.
752 path, dest string
755 var EvalSymlinksTestDirs = []EvalSymlinksTest{
756 {"test", ""},
757 {"test/dir", ""},
758 {"test/dir/link3", "../../"},
759 {"test/link1", "../test"},
760 {"test/link2", "dir"},
761 {"test/linkabs", "/"},
764 var EvalSymlinksTests = []EvalSymlinksTest{
765 {"test", "test"},
766 {"test/dir", "test/dir"},
767 {"test/dir/../..", "."},
768 {"test/link1", "test"},
769 {"test/link2", "test/dir"},
770 {"test/link1/dir", "test/dir"},
771 {"test/link2/..", "test"},
772 {"test/dir/link3", "."},
773 {"test/link2/link3/test", "test"},
774 {"test/linkabs", "/"},
777 // findEvalSymlinksTestDirsDest searches testDirs
778 // for matching path and returns correspondent dest.
779 func findEvalSymlinksTestDirsDest(t *testing.T, testDirs []EvalSymlinksTest, path string) string {
780 for _, d := range testDirs {
781 if d.path == path {
782 return d.dest
785 t.Fatalf("did not find %q in testDirs slice", path)
786 return ""
789 // simpleJoin builds a file name from the directory and path.
790 // It does not use Join because we don't want ".." to be evaluated.
791 func simpleJoin(dir, path string) string {
792 return dir + string(filepath.Separator) + path
795 func TestEvalSymlinks(t *testing.T) {
796 testenv.MustHaveSymlink(t)
798 tmpDir, err := ioutil.TempDir("", "evalsymlink")
799 if err != nil {
800 t.Fatal("creating temp dir:", err)
802 defer os.RemoveAll(tmpDir)
804 // /tmp may itself be a symlink! Avoid the confusion, although
805 // it means trusting the thing we're testing.
806 tmpDir, err = filepath.EvalSymlinks(tmpDir)
807 if err != nil {
808 t.Fatal("eval symlink for tmp dir:", err)
811 tests := EvalSymlinksTests
812 testdirs := EvalSymlinksTestDirs
813 if runtime.GOOS == "windows" {
814 if len(tmpDir) < 3 {
815 t.Fatalf("tmpDir path %q is too short", tmpDir)
817 if tmpDir[1] != ':' {
818 t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir)
820 newtest := EvalSymlinksTest{"test/linkabswin", tmpDir[:3]}
821 tests = append(tests, newtest)
822 testdirs = append(testdirs, newtest)
825 // Create the symlink farm using relative paths.
826 for _, d := range testdirs {
827 var err error
828 path := simpleJoin(tmpDir, d.path)
829 if d.dest == "" {
830 err = os.Mkdir(path, 0755)
831 } else {
832 err = os.Symlink(d.dest, path)
834 if err != nil {
835 t.Fatal(err)
839 wd, err := os.Getwd()
840 if err != nil {
841 t.Fatal(err)
844 // Evaluate the symlink farm.
845 for _, d := range tests {
846 path := simpleJoin(tmpDir, d.path)
847 dest := simpleJoin(tmpDir, d.dest)
848 if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) {
849 dest = d.dest
851 if p, err := filepath.EvalSymlinks(path); err != nil {
852 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
853 } else if filepath.Clean(p) != filepath.Clean(dest) {
854 t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
857 // test EvalSymlinks(".")
858 func() {
859 defer func() {
860 err := os.Chdir(wd)
861 if err != nil {
862 t.Fatal(err)
866 err := os.Chdir(path)
867 if err != nil {
868 t.Error(err)
869 return
871 p, err := filepath.EvalSymlinks(".")
872 if err != nil {
873 t.Errorf(`EvalSymlinks(".") in %q directory error: %v`, d.path, err)
874 return
876 if p == "." {
877 return
879 want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path))
880 if p == want {
881 return
883 t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want)
886 // test EvalSymlinks("C:.") on Windows
887 if runtime.GOOS == "windows" {
888 func() {
889 defer func() {
890 err := os.Chdir(wd)
891 if err != nil {
892 t.Fatal(err)
896 err := os.Chdir(path)
897 if err != nil {
898 t.Error(err)
899 return
902 volDot := filepath.VolumeName(tmpDir) + "."
904 p, err := filepath.EvalSymlinks(volDot)
905 if err != nil {
906 t.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot, d.path, err)
907 return
909 if p == volDot {
910 return
912 want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path))
913 if p == want {
914 return
916 t.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot, d.path, p, volDot, want)
920 // test EvalSymlinks(".."+path)
921 func() {
922 defer func() {
923 err := os.Chdir(wd)
924 if err != nil {
925 t.Fatal(err)
929 err := os.Chdir(simpleJoin(tmpDir, "test"))
930 if err != nil {
931 t.Error(err)
932 return
935 path := simpleJoin("..", d.path)
936 dest := simpleJoin("..", d.dest)
937 if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) {
938 dest = d.dest
941 if p, err := filepath.EvalSymlinks(path); err != nil {
942 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
943 } else if filepath.Clean(p) != filepath.Clean(dest) {
944 t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
948 // test EvalSymlinks where parameter is relative path
949 func() {
950 defer func() {
951 err := os.Chdir(wd)
952 if err != nil {
953 t.Fatal(err)
957 err := os.Chdir(tmpDir)
958 if err != nil {
959 t.Error(err)
960 return
962 if p, err := filepath.EvalSymlinks(d.path); err != nil {
963 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
964 } else if filepath.Clean(p) != filepath.Clean(d.dest) {
965 t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
971 func TestEvalSymlinksIsNotExist(t *testing.T) {
972 testenv.MustHaveSymlink(t)
974 defer chtmpdir(t)()
976 _, err := filepath.EvalSymlinks("notexist")
977 if !os.IsNotExist(err) {
978 t.Errorf("expected the file is not found, got %v\n", err)
981 err = os.Symlink("notexist", "link")
982 if err != nil {
983 t.Fatal(err)
985 defer os.Remove("link")
987 _, err = filepath.EvalSymlinks("link")
988 if !os.IsNotExist(err) {
989 t.Errorf("expected the file is not found, got %v\n", err)
993 func TestIssue13582(t *testing.T) {
994 testenv.MustHaveSymlink(t)
996 tmpDir, err := ioutil.TempDir("", "issue13582")
997 if err != nil {
998 t.Fatal(err)
1000 defer os.RemoveAll(tmpDir)
1002 dir := filepath.Join(tmpDir, "dir")
1003 err = os.Mkdir(dir, 0755)
1004 if err != nil {
1005 t.Fatal(err)
1007 linkToDir := filepath.Join(tmpDir, "link_to_dir")
1008 err = os.Symlink(dir, linkToDir)
1009 if err != nil {
1010 t.Fatal(err)
1012 file := filepath.Join(linkToDir, "file")
1013 err = ioutil.WriteFile(file, nil, 0644)
1014 if err != nil {
1015 t.Fatal(err)
1017 link1 := filepath.Join(linkToDir, "link1")
1018 err = os.Symlink(file, link1)
1019 if err != nil {
1020 t.Fatal(err)
1022 link2 := filepath.Join(linkToDir, "link2")
1023 err = os.Symlink(link1, link2)
1024 if err != nil {
1025 t.Fatal(err)
1028 // /tmp may itself be a symlink!
1029 realTmpDir, err := filepath.EvalSymlinks(tmpDir)
1030 if err != nil {
1031 t.Fatal(err)
1033 realDir := filepath.Join(realTmpDir, "dir")
1034 realFile := filepath.Join(realDir, "file")
1036 tests := []struct {
1037 path, want string
1039 {dir, realDir},
1040 {linkToDir, realDir},
1041 {file, realFile},
1042 {link1, realFile},
1043 {link2, realFile},
1045 for i, test := range tests {
1046 have, err := filepath.EvalSymlinks(test.path)
1047 if err != nil {
1048 t.Fatal(err)
1050 if have != test.want {
1051 t.Errorf("test#%d: EvalSymlinks(%q) returns %q, want %q", i, test.path, have, test.want)
1056 // Test directories relative to temporary directory.
1057 // The tests are run in absTestDirs[0].
1058 var absTestDirs = []string{
1059 "a",
1060 "a/b",
1061 "a/b/c",
1064 // Test paths relative to temporary directory. $ expands to the directory.
1065 // The tests are run in absTestDirs[0].
1066 // We create absTestDirs first.
1067 var absTests = []string{
1068 ".",
1069 "b",
1070 "b/",
1071 "../a",
1072 "../a/b",
1073 "../a/b/./c/../../.././a",
1074 "../a/b/./c/../../.././a/",
1075 "$",
1076 "$/.",
1077 "$/a/../a/b",
1078 "$/a/b/c/../../.././a",
1079 "$/a/b/c/../../.././a/",
1082 func TestAbs(t *testing.T) {
1083 root, err := ioutil.TempDir("", "TestAbs")
1084 if err != nil {
1085 t.Fatal("TempDir failed: ", err)
1087 defer os.RemoveAll(root)
1089 wd, err := os.Getwd()
1090 if err != nil {
1091 t.Fatal("getwd failed: ", err)
1093 err = os.Chdir(root)
1094 if err != nil {
1095 t.Fatal("chdir failed: ", err)
1097 defer os.Chdir(wd)
1099 for _, dir := range absTestDirs {
1100 err = os.Mkdir(dir, 0777)
1101 if err != nil {
1102 t.Fatal("Mkdir failed: ", err)
1106 if runtime.GOOS == "windows" {
1107 vol := filepath.VolumeName(root)
1108 var extra []string
1109 for _, path := range absTests {
1110 if strings.Contains(path, "$") {
1111 continue
1113 path = vol + path
1114 extra = append(extra, path)
1116 absTests = append(absTests, extra...)
1119 err = os.Chdir(absTestDirs[0])
1120 if err != nil {
1121 t.Fatal("chdir failed: ", err)
1124 for _, path := range absTests {
1125 path = strings.Replace(path, "$", root, -1)
1126 info, err := os.Stat(path)
1127 if err != nil {
1128 t.Errorf("%s: %s", path, err)
1129 continue
1132 abspath, err := filepath.Abs(path)
1133 if err != nil {
1134 t.Errorf("Abs(%q) error: %v", path, err)
1135 continue
1137 absinfo, err := os.Stat(abspath)
1138 if err != nil || !os.SameFile(absinfo, info) {
1139 t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
1141 if !filepath.IsAbs(abspath) {
1142 t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
1144 if filepath.IsAbs(abspath) && abspath != filepath.Clean(abspath) {
1145 t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
1150 type RelTests struct {
1151 root, path, want string
1154 var reltests = []RelTests{
1155 {"a/b", "a/b", "."},
1156 {"a/b/.", "a/b", "."},
1157 {"a/b", "a/b/.", "."},
1158 {"./a/b", "a/b", "."},
1159 {"a/b", "./a/b", "."},
1160 {"ab/cd", "ab/cde", "../cde"},
1161 {"ab/cd", "ab/c", "../c"},
1162 {"a/b", "a/b/c/d", "c/d"},
1163 {"a/b", "a/b/../c", "../c"},
1164 {"a/b/../c", "a/b", "../b"},
1165 {"a/b/c", "a/c/d", "../../c/d"},
1166 {"a/b", "c/d", "../../c/d"},
1167 {"a/b/c/d", "a/b", "../.."},
1168 {"a/b/c/d", "a/b/", "../.."},
1169 {"a/b/c/d/", "a/b", "../.."},
1170 {"a/b/c/d/", "a/b/", "../.."},
1171 {"../../a/b", "../../a/b/c/d", "c/d"},
1172 {"/a/b", "/a/b", "."},
1173 {"/a/b/.", "/a/b", "."},
1174 {"/a/b", "/a/b/.", "."},
1175 {"/ab/cd", "/ab/cde", "../cde"},
1176 {"/ab/cd", "/ab/c", "../c"},
1177 {"/a/b", "/a/b/c/d", "c/d"},
1178 {"/a/b", "/a/b/../c", "../c"},
1179 {"/a/b/../c", "/a/b", "../b"},
1180 {"/a/b/c", "/a/c/d", "../../c/d"},
1181 {"/a/b", "/c/d", "../../c/d"},
1182 {"/a/b/c/d", "/a/b", "../.."},
1183 {"/a/b/c/d", "/a/b/", "../.."},
1184 {"/a/b/c/d/", "/a/b", "../.."},
1185 {"/a/b/c/d/", "/a/b/", "../.."},
1186 {"/../../a/b", "/../../a/b/c/d", "c/d"},
1187 {".", "a/b", "a/b"},
1188 {".", "..", ".."},
1190 // can't do purely lexically
1191 {"..", ".", "err"},
1192 {"..", "a", "err"},
1193 {"../..", "..", "err"},
1194 {"a", "/a", "err"},
1195 {"/a", "a", "err"},
1198 var winreltests = []RelTests{
1199 {`C:a\b\c`, `C:a/b/d`, `..\d`},
1200 {`C:\`, `D:\`, `err`},
1201 {`C:`, `D:`, `err`},
1202 {`C:\Projects`, `c:\projects\src`, `src`},
1203 {`C:\Projects`, `c:\projects`, `.`},
1204 {`C:\Projects\a\..`, `c:\projects`, `.`},
1207 func TestRel(t *testing.T) {
1208 tests := append([]RelTests{}, reltests...)
1209 if runtime.GOOS == "windows" {
1210 for i := range tests {
1211 tests[i].want = filepath.FromSlash(tests[i].want)
1213 tests = append(tests, winreltests...)
1215 for _, test := range tests {
1216 got, err := filepath.Rel(test.root, test.path)
1217 if test.want == "err" {
1218 if err == nil {
1219 t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got)
1221 continue
1223 if err != nil {
1224 t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err)
1226 if got != test.want {
1227 t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want)
1232 type VolumeNameTest struct {
1233 path string
1234 vol string
1237 var volumenametests = []VolumeNameTest{
1238 {`c:/foo/bar`, `c:`},
1239 {`c:`, `c:`},
1240 {`2:`, ``},
1241 {``, ``},
1242 {`\\\host`, ``},
1243 {`\\\host\`, ``},
1244 {`\\\host\share`, ``},
1245 {`\\\host\\share`, ``},
1246 {`\\host`, ``},
1247 {`//host`, ``},
1248 {`\\host\`, ``},
1249 {`//host/`, ``},
1250 {`\\host\share`, `\\host\share`},
1251 {`//host/share`, `//host/share`},
1252 {`\\host\share\`, `\\host\share`},
1253 {`//host/share/`, `//host/share`},
1254 {`\\host\share\foo`, `\\host\share`},
1255 {`//host/share/foo`, `//host/share`},
1256 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
1257 {`//host/share//foo///bar////baz`, `//host/share`},
1258 {`\\host\share\foo\..\bar`, `\\host\share`},
1259 {`//host/share/foo/../bar`, `//host/share`},
1262 func TestVolumeName(t *testing.T) {
1263 if runtime.GOOS != "windows" {
1264 return
1266 for _, v := range volumenametests {
1267 if vol := filepath.VolumeName(v.path); vol != v.vol {
1268 t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol)
1273 func TestDriveLetterInEvalSymlinks(t *testing.T) {
1274 if runtime.GOOS != "windows" {
1275 return
1277 wd, _ := os.Getwd()
1278 if len(wd) < 3 {
1279 t.Errorf("Current directory path %q is too short", wd)
1281 lp := strings.ToLower(wd)
1282 up := strings.ToUpper(wd)
1283 flp, err := filepath.EvalSymlinks(lp)
1284 if err != nil {
1285 t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err)
1287 fup, err := filepath.EvalSymlinks(up)
1288 if err != nil {
1289 t.Fatalf("EvalSymlinks(%q) failed: %q", up, err)
1291 if flp != fup {
1292 t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup)
1296 func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
1297 t.Skip("skipping test because gccgo sources are arranged differently.")
1298 if runtime.GOOS == "darwin" {
1299 switch runtime.GOARCH {
1300 case "arm", "arm64":
1301 t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
1304 root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
1305 if err != nil {
1306 t.Fatal(err)
1308 bugs := filepath.Join(root, "fixedbugs")
1309 ken := filepath.Join(root, "ken")
1310 seenBugs := false
1311 seenKen := false
1312 err = filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
1313 if err != nil {
1314 t.Fatal(err)
1317 switch pth {
1318 case bugs:
1319 seenBugs = true
1320 return filepath.SkipDir
1321 case ken:
1322 if !seenBugs {
1323 t.Fatal("filepath.Walk out of order - ken before fixedbugs")
1325 seenKen = true
1327 return nil
1329 if err != nil {
1330 t.Fatal(err)
1332 if !seenKen {
1333 t.Fatalf("%q not seen", ken)
1337 func testWalkSymlink(t *testing.T, mklink func(target, link string) error) {
1338 tmpdir, err := ioutil.TempDir("", "testWalkSymlink")
1339 if err != nil {
1340 t.Fatal(err)
1342 defer os.RemoveAll(tmpdir)
1344 wd, err := os.Getwd()
1345 if err != nil {
1346 t.Fatal(err)
1348 defer os.Chdir(wd)
1350 err = os.Chdir(tmpdir)
1351 if err != nil {
1352 t.Fatal(err)
1355 err = mklink(tmpdir, "link")
1356 if err != nil {
1357 t.Fatal(err)
1360 var visited []string
1361 err = filepath.Walk(tmpdir, func(path string, info os.FileInfo, err error) error {
1362 if err != nil {
1363 t.Fatal(err)
1365 rel, err := filepath.Rel(tmpdir, path)
1366 if err != nil {
1367 t.Fatal(err)
1369 visited = append(visited, rel)
1370 return nil
1372 if err != nil {
1373 t.Fatal(err)
1375 sort.Strings(visited)
1376 want := []string{".", "link"}
1377 if fmt.Sprintf("%q", visited) != fmt.Sprintf("%q", want) {
1378 t.Errorf("unexpected paths visited %q, want %q", visited, want)
1382 func TestWalkSymlink(t *testing.T) {
1383 testenv.MustHaveSymlink(t)
1384 testWalkSymlink(t, os.Symlink)