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.
21 type PathTest
struct {
25 var cleantests
= []PathTest
{
28 {"abc/def", "abc/def"},
33 {"../../abc", "../../abc"},
37 // Empty is current dir
40 // Remove trailing slash
42 {"abc/def/", "abc/def"},
49 // Remove doubled slash
50 {"abc//def//ghi", "abc/def/ghi"},
57 {"abc/./def", "abc/def"},
58 {"/./abc/def", "/abc/def"},
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"},
73 {"abc/./../def", "def"},
74 {"abc//./../def", "def"},
75 {"abc/../../././../def", "../../def"},
78 var wincleantests
= []PathTest
{
82 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
83 {`c:\abc\def\..\..`, `c:\`},
84 {`c:\..\abc`, `c:\abc`},
85 {`c:..\abc`, `c:..\abc`},
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`},
97 func TestClean(t
*testing
.T
) {
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
)
115 t
.Skip("skipping malloc count in short mode")
117 if runtime
.GOMAXPROCS(0) > 1 {
118 t
.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
122 t
.Log("Skipping AllocsPerRun for gccgo")
125 for _
, test
:= range tests
{
126 allocs
:= testing
.AllocsPerRun(100, func() { filepath
.Clean(test
.result
) })
128 t
.Errorf("Clean(%q): %v allocs, want zero", test
.result
, allocs
)
133 const sep
= filepath
.Separator
135 var slashtests
= []PathTest
{
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 {
158 const lsep
= filepath
.ListSeparator
160 var splitlisttests
= []SplitListTest
{
162 {string([]byte{'a', lsep
, 'b'}), []string{"a", "b"}},
163 {string([]byte{lsep
, 'a', lsep
, 'b'}), []string{"", "a", "b"}},
166 var winsplitlisttests
= []SplitListTest
{
168 {`"a"`, []string{`a`}},
171 {`";"`, []string{`;`}},
172 {`"a;b"`, []string{`a;b`}},
173 {`";";`, []string{`;`, ``}},
174 {`;";"`, []string{``, `;`}},
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
{
206 {"a/b/", "a/b/", ""},
212 var winsplittests
= []SplitTest
{
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 {
243 var jointests
= []JoinTest
{
249 {[]string{"/"}, "/"},
250 {[]string{"a"}, "a"},
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{"", ""}, ""},
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 {
310 var exttests
= []ExtTest
{
312 {"path.pb.go", ".go"},
314 {"a.dir/b.go", ".go"},
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
)
328 entries
[]*Node
// nil if the entry is a file
358 func walkTree(n
*Node
, path
string, f
func(path
string, n
*Node
)) {
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
)
370 t
.Errorf("makeTree: %v", err
)
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
)
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
{
396 *errors
= append(*errors
, err
)
403 walkTree(tree
, tree
.name
, func(path
string, n
*Node
) {
411 func chtmpdir(t
*testing
.T
) (restore
func()) {
412 oldwd
, err
:= os
.Getwd()
414 t
.Fatalf("chtmpdir: %v", err
)
416 d
, err
:= ioutil
.TempDir("", "test")
418 t
.Fatalf("chtmpdir: %v", err
)
420 if err
:= os
.Chdir(d
); err
!= nil {
421 t
.Fatalf("chtmpdir: %v", err
)
424 if err
:= os
.Chdir(oldwd
); err
!= nil {
425 t
.Fatalf("chtmpdir: %v", err
)
431 func TestWalk(t
*testing
.T
) {
432 if runtime
.GOOS
== "darwin" {
433 switch runtime
.GOARCH
{
435 restore
:= chtmpdir(t
)
440 errors
:= make([]error
, 0, 10)
442 markFn
:= func(path
string, info os
.FileInfo
, err error
) error
{
443 return mark(info
, err
, &errors
, clear
)
446 err
:= filepath
.Walk(tree
.name
, markFn
)
448 t
.Fatalf("no error expected, found: %s", err
)
450 if len(errors
) != 0 {
451 t
.Fatalf("unexpected errors: %s", errors
)
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
)
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
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
)
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
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)
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
)
517 if err
:= f
.Close(); err
!= nil {
522 func TestWalkSkipDirOnFile(t
*testing
.T
) {
523 td
, err
:= ioutil
.TempDir("", "walktest")
527 defer os
.RemoveAll(td
)
529 if err
:= os
.MkdirAll(filepath
.Join(td
, "dir"), 0755); err
!= nil {
532 touch(t
, filepath
.Join(td
, "dir/foo1"))
533 touch(t
, filepath
.Join(td
, "dir/foo2"))
536 walker
:= func(path
string, info os
.FileInfo
, err error
) error
{
537 if strings
.HasSuffix(path
, "foo2") {
540 if strings
.HasSuffix(path
, "foo1") {
541 return filepath
.SkipDir
546 err
= filepath
.Walk(td
, walker
)
551 t
.Errorf("SkipDir on file foo1 did not block processing of foo2")
554 err
= filepath
.Walk(filepath
.Join(td
, "dir"), walker
)
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")
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 {
576 touch(t
, filepath
.Join(dir
, "baz"))
577 touch(t
, filepath
.Join(dir
, "stat-error"))
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") {
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
595 t
.Errorf("Walk error: %v", err
)
597 want
:= map[string]error
{
603 "dir/stat-error": statErr
,
605 if !reflect
.DeepEqual(got
, want
) {
606 t
.Errorf("Walked %#v; want %#v", got
, want
)
610 var basetests
= []PathTest
{
624 var winbasetests
= []PathTest
{
630 {`\\host\share\`, `\`},
631 {`\\host\share\a`, `a`},
632 {`\\host\share\a\b`, `b`},
635 func TestBase(t
*testing
.T
) {
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
{
667 var windirtests
= []PathTest
{
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
) {
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 {
701 var isabstests
= []IsAbsTest
{
704 {"/usr/bin/gcc", true},
712 var winisabstests
= []IsAbsTest
{
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
})
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.
755 var EvalSymlinksTestDirs
= []EvalSymlinksTest
{
758 {"test/dir/link3", "../../"},
759 {"test/link1", "../test"},
760 {"test/link2", "dir"},
761 {"test/linkabs", "/"},
764 var EvalSymlinksTests
= []EvalSymlinksTest
{
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
{
785 t
.Fatalf("did not find %q in testDirs slice", path
)
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")
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
)
808 t
.Fatal("eval symlink for tmp dir:", err
)
811 tests
:= EvalSymlinksTests
812 testdirs
:= EvalSymlinksTestDirs
813 if runtime
.GOOS
== "windows" {
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
{
828 path
:= simpleJoin(tmpDir
, d
.path
)
830 err
= os
.Mkdir(path
, 0755)
832 err
= os
.Symlink(d
.dest
, path
)
839 wd
, err
:= os
.Getwd()
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]) {
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(".")
866 err
:= os
.Chdir(path
)
871 p
, err
:= filepath
.EvalSymlinks(".")
873 t
.Errorf(`EvalSymlinks(".") in %q directory error: %v`, d
.path
, err
)
879 want
:= filepath
.Clean(findEvalSymlinksTestDirsDest(t
, testdirs
, d
.path
))
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" {
896 err
:= os
.Chdir(path
)
902 volDot
:= filepath
.VolumeName(tmpDir
) + "."
904 p
, err
:= filepath
.EvalSymlinks(volDot
)
906 t
.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot
, d
.path
, err
)
912 want
:= filepath
.Clean(findEvalSymlinksTestDirsDest(t
, testdirs
, d
.path
))
916 t
.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot
, d
.path
, p
, volDot
, want
)
920 // test EvalSymlinks(".."+path)
929 err
:= os
.Chdir(simpleJoin(tmpDir
, "test"))
935 path
:= simpleJoin("..", d
.path
)
936 dest
:= simpleJoin("..", d
.dest
)
937 if filepath
.IsAbs(d
.dest
) || os
.IsPathSeparator(d
.dest
[0]) {
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
957 err
:= os
.Chdir(tmpDir
)
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
)
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")
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")
1000 defer os
.RemoveAll(tmpDir
)
1002 dir
:= filepath
.Join(tmpDir
, "dir")
1003 err
= os
.Mkdir(dir
, 0755)
1007 linkToDir
:= filepath
.Join(tmpDir
, "link_to_dir")
1008 err
= os
.Symlink(dir
, linkToDir
)
1012 file
:= filepath
.Join(linkToDir
, "file")
1013 err
= ioutil
.WriteFile(file
, nil, 0644)
1017 link1
:= filepath
.Join(linkToDir
, "link1")
1018 err
= os
.Symlink(file
, link1
)
1022 link2
:= filepath
.Join(linkToDir
, "link2")
1023 err
= os
.Symlink(link1
, link2
)
1028 // /tmp may itself be a symlink!
1029 realTmpDir
, err
:= filepath
.EvalSymlinks(tmpDir
)
1033 realDir
:= filepath
.Join(realTmpDir
, "dir")
1034 realFile
:= filepath
.Join(realDir
, "file")
1040 {linkToDir
, realDir
},
1045 for i
, test
:= range tests
{
1046 have
, err
:= filepath
.EvalSymlinks(test
.path
)
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{
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{
1073 "../a/b/./c/../../.././a",
1074 "../a/b/./c/../../.././a/",
1078 "$/a/b/c/../../.././a",
1079 "$/a/b/c/../../.././a/",
1082 func TestAbs(t
*testing
.T
) {
1083 root
, err
:= ioutil
.TempDir("", "TestAbs")
1085 t
.Fatal("TempDir failed: ", err
)
1087 defer os
.RemoveAll(root
)
1089 wd
, err
:= os
.Getwd()
1091 t
.Fatal("getwd failed: ", err
)
1093 err
= os
.Chdir(root
)
1095 t
.Fatal("chdir failed: ", err
)
1099 for _
, dir
:= range absTestDirs
{
1100 err
= os
.Mkdir(dir
, 0777)
1102 t
.Fatal("Mkdir failed: ", err
)
1106 if runtime
.GOOS
== "windows" {
1107 vol
:= filepath
.VolumeName(root
)
1109 for _
, path
:= range absTests
{
1110 if strings
.Contains(path
, "$") {
1114 extra
= append(extra
, path
)
1116 absTests
= append(absTests
, extra
...)
1119 err
= os
.Chdir(absTestDirs
[0])
1121 t
.Fatal("chdir failed: ", err
)
1124 for _
, path
:= range absTests
{
1125 path
= strings
.Replace(path
, "$", root
, -1)
1126 info
, err
:= os
.Stat(path
)
1128 t
.Errorf("%s: %s", path
, err
)
1132 abspath
, err
:= filepath
.Abs(path
)
1134 t
.Errorf("Abs(%q) error: %v", path
, err
)
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"},
1190 // can't do purely lexically
1193 {"../..", "..", "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" {
1219 t
.Errorf("Rel(%q, %q)=%q, want error", test
.root
, test
.path
, got
)
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 {
1237 var volumenametests
= []VolumeNameTest
{
1238 {`c:/foo/bar`, `c:`},
1244 {`\\\host\share`, ``},
1245 {`\\\host\\share`, ``},
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" {
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" {
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
)
1285 t
.Fatalf("EvalSymlinks(%q) failed: %q", lp
, err
)
1287 fup
, err
:= filepath
.EvalSymlinks(up
)
1289 t
.Fatalf("EvalSymlinks(%q) failed: %q", up
, err
)
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")
1308 bugs
:= filepath
.Join(root
, "fixedbugs")
1309 ken
:= filepath
.Join(root
, "ken")
1312 err
= filepath
.Walk(root
, func(pth
string, info os
.FileInfo
, err error
) error
{
1320 return filepath
.SkipDir
1323 t
.Fatal("filepath.Walk out of order - ken before fixedbugs")
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")
1342 defer os
.RemoveAll(tmpdir
)
1344 wd
, err
:= os
.Getwd()
1350 err
= os
.Chdir(tmpdir
)
1355 err
= mklink(tmpdir
, "link")
1360 var visited
[]string
1361 err
= filepath
.Walk(tmpdir
, func(path
string, info os
.FileInfo
, err error
) error
{
1365 rel
, err
:= filepath
.Rel(tmpdir
, path
)
1369 visited
= append(visited
, rel
)
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
)