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.
15 type PathTest struct {
19 var cleantests = []PathTest{
23 {"abc/def", "abc/def"},
28 {"../../abc", "../../abc"},
32 // Remove trailing slash
34 {"abc/def/", "abc/def"},
41 // Remove doubled slash
42 {"abc//def//ghi", "abc/def/ghi"},
49 {"abc/./def", "abc/def"},
50 {"/./abc/def", "/abc/def"},
54 {"abc/def/ghi/../jkl", "abc/def/jkl"},
55 {"abc/def/../ghi/../jkl", "abc/jkl"},
56 {"abc/def/..", "abc"},
57 {"abc/def/../..", "."},
58 {"/abc/def/../..", "/"},
59 {"abc/def/../../..", ".."},
60 {"/abc/def/../../..", "/"},
61 {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
64 {"abc/./../def", "def"},
65 {"abc//./../def", "def"},
66 {"abc/../../././../def", "../../def"},
69 var wincleantests = []PathTest{
73 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
74 {`c:\abc\def\..\..`, `c:\`},
75 {`c:\..\abc`, `c:\abc`},
76 {`c:..\abc`, `c:..\abc`},
80 {`\\i\..\i\c$`, `\i\c$`},
81 {`\\i\..\I\c$`, `\I\c$`},
82 {`\\host\share\foo\..\bar`, `\\host\share\bar`},
83 {`//host/share/foo/../baz`, `\\host\share\baz`},
84 {`\\a\b\..\c`, `\\a\b\c`},
88 func TestClean(t *testing.T) {
90 if runtime.GOOS == "windows" {
91 for i := range tests {
92 tests[i].result = filepath.FromSlash(tests[i].result)
94 tests = append(tests, wincleantests...)
96 for _, test := range tests {
97 if s := filepath.Clean(test.path); s != test.result {
98 t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
103 const sep = filepath.Separator
105 var slashtests = []PathTest{
108 {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
109 {"a//b", string([]byte{'a', sep, sep, 'b'})},
112 func TestFromAndToSlash(t *testing.T) {
113 for _, test := range slashtests {
114 if s := filepath.FromSlash(test.path); s != test.result {
115 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
117 if s := filepath.ToSlash(test.result); s != test.path {
118 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
123 type SplitListTest struct {
128 const lsep = filepath.ListSeparator
130 var splitlisttests = []SplitListTest{
132 {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},
133 {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},
136 func TestSplitList(t *testing.T) {
137 for _, test := range splitlisttests {
138 if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {
139 t.Errorf("SplitList(%q) = %s, want %s", test.list, l, test.result)
144 type SplitTest struct {
145 path, dir, file string
148 var unixsplittests = []SplitTest{
150 {"a/b/", "a/b/", ""},
156 var winsplittests = []SplitTest{
159 {`c:/foo`, `c:/`, `foo`},
160 {`c:/foo/bar`, `c:/foo/`, `bar`},
161 {`//host/share`, `//host/share`, ``},
162 {`//host/share/`, `//host/share/`, ``},
163 {`//host/share/foo`, `//host/share/`, `foo`},
164 {`\\host\share`, `\\host\share`, ``},
165 {`\\host\share\`, `\\host\share\`, ``},
166 {`\\host\share\foo`, `\\host\share\`, `foo`},
169 func TestSplit(t *testing.T) {
170 var splittests []SplitTest
171 splittests = unixsplittests
172 if runtime.GOOS == "windows" {
173 splittests = append(splittests, winsplittests...)
175 for _, test := range splittests {
176 if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
177 t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
182 type JoinTest struct {
187 var jointests = []JoinTest{
193 {[]string{"a"}, "a"},
196 {[]string{"a", "b"}, "a/b"},
197 {[]string{"a", ""}, "a"},
198 {[]string{"", "b"}, "b"},
199 {[]string{"/", "a"}, "/a"},
200 {[]string{"/", ""}, "/"},
201 {[]string{"a/", "b"}, "a/b"},
202 {[]string{"a/", ""}, "a"},
203 {[]string{"", ""}, ""},
206 var winjointests = []JoinTest{
207 {[]string{`directory`, `file`}, `directory\file`},
208 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
209 {[]string{`C:\Windows\`, ``}, `C:\Windows`},
210 {[]string{`C:\`, `Windows`}, `C:\Windows`},
211 {[]string{`C:`, `Windows`}, `C:\Windows`},
212 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
213 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
216 // join takes a []string and passes it to Join.
217 func join(elem []string, args ...string) string {
219 return filepath.Join(args...)
222 func TestJoin(t *testing.T) {
223 if runtime.GOOS == "windows" {
224 jointests = append(jointests, winjointests...)
226 for _, test := range jointests {
227 if p := join(test.elem); p != filepath.FromSlash(test.path) {
228 t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
233 type ExtTest struct {
237 var exttests = []ExtTest{
239 {"path.pb.go", ".go"},
241 {"a.dir/b.go", ".go"},
245 func TestExt(t *testing.T) {
246 for _, test := range exttests {
247 if x := filepath.Ext(test.path); x != test.ext {
248 t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
255 entries []*Node // nil if the entry is a file
263 &Node{"b", []*Node{}, 0},
269 &Node{"y", []*Node{}, 0},
285 func walkTree(n *Node, path string, f func(path string, n *Node)) {
287 for _, e := range n.entries {
288 walkTree(e, filepath.Join(path, e.name), f)
292 func makeTree(t *testing.T) {
293 walkTree(tree, tree.name, func(path string, n *Node) {
294 if n.entries == nil {
295 fd, err := os.Create(path)
297 t.Errorf("makeTree: %v", err)
306 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
308 func checkMarks(t *testing.T, report bool) {
309 walkTree(tree, tree.name, func(path string, n *Node) {
310 if n.mark != 1 && report {
311 t.Errorf("node %s mark = %d; expected 1", path, n.mark)
317 // Assumes that each node name is unique. Good enough for a test.
318 // If clear is true, any incoming error is cleared before return. The errors
319 // are always accumulated, though.
320 func mark(path string, info *os.FileInfo, err error, errors *[]error, clear bool) error {
322 *errors = append(*errors, err)
328 walkTree(tree, tree.name, func(path string, n *Node) {
329 if n.name == info.Name {
336 func TestWalk(t *testing.T) {
338 errors := make([]error, 0, 10)
340 markFn := func(path string, info *os.FileInfo, err error) error {
341 return mark(path, info, err, &errors, clear)
344 err := filepath.Walk(tree.name, markFn)
346 t.Errorf("no error expected, found: %s", err)
348 if len(errors) != 0 {
349 t.Errorf("unexpected errors: %s", errors)
354 // Test permission errors. Only possible if we're not root
355 // and only on some file systems (AFS, FAT). To avoid errors during
356 // all.bash on those file systems, skip during gotest -short.
357 if os.Getuid() > 0 && !testing.Short() {
358 // introduce 2 errors: chmod top-level directories to 0
359 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
360 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
362 // 3) capture errors, expect two.
363 // mark respective subtrees manually
364 markTree(tree.entries[1])
365 markTree(tree.entries[3])
366 // correct double-marking of directory itself
367 tree.entries[1].mark--
368 tree.entries[3].mark--
369 err := filepath.Walk(tree.name, markFn)
371 t.Errorf("expected no error return from Walk, %s", err)
373 if len(errors) != 2 {
374 t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
376 // the inaccessible subtrees were marked manually
380 // 4) capture errors, stop after first error.
381 // mark respective subtrees manually
382 markTree(tree.entries[1])
383 markTree(tree.entries[3])
384 // correct double-marking of directory itself
385 tree.entries[1].mark--
386 tree.entries[3].mark--
387 clear = false // error will stop processing
388 err = filepath.Walk(tree.name, markFn)
390 t.Errorf("expected error return from Walk")
392 if len(errors) != 1 {
393 t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
395 // the inaccessible subtrees were marked manually
399 // restore permissions
400 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
401 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
405 if err := os.RemoveAll(tree.name); err != nil {
406 t.Errorf("removeTree: %v", err)
410 var basetests = []PathTest{
424 func TestBase(t *testing.T) {
425 for _, test := range basetests {
426 if s := filepath.ToSlash(filepath.Base(test.path)); s != test.result {
427 t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
432 type IsAbsTest struct {
437 var isabstests = []IsAbsTest{
440 {"/usr/bin/gcc", true},
448 var winisabstests = []IsAbsTest{
457 {`\\host\share\foo`, true},
458 {`//host/share/foo/bar`, true},
461 func TestIsAbs(t *testing.T) {
462 var tests []IsAbsTest
463 if runtime.GOOS == "windows" {
464 tests = append(tests, winisabstests...)
465 // All non-windows tests should fail, because they have no volume letter.
466 for _, test := range isabstests {
467 tests = append(tests, IsAbsTest{test.path, false})
469 // All non-windows test should work as intended if prefixed with volume letter.
470 for _, test := range isabstests {
471 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
477 for _, test := range tests {
478 if r := filepath.IsAbs(test.path); r != test.isAbs {
479 t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
484 type EvalSymlinksTest struct {
488 var EvalSymlinksTestDirs = []EvalSymlinksTest{
491 {"test/dir/link3", "../../"},
492 {"test/link1", "../test"},
493 {"test/link2", "dir"},
496 var EvalSymlinksTests = []EvalSymlinksTest{
498 {"test/dir", "test/dir"},
499 {"test/dir/../..", "."},
500 {"test/link1", "test"},
501 {"test/link2", "test/dir"},
502 {"test/link1/dir", "test/dir"},
503 {"test/link2/..", "test"},
504 {"test/dir/link3", "."},
505 {"test/link2/link3/test", "test"},
508 var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
512 func testEvalSymlinks(t *testing.T, tests []EvalSymlinksTest) {
513 for _, d := range tests {
514 if p, err := filepath.EvalSymlinks(d.path); err != nil {
515 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
516 } else if filepath.Clean(p) != filepath.Clean(d.dest) {
517 t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
522 func TestEvalSymlinks(t *testing.T) {
523 defer os.RemoveAll("test")
524 for _, d := range EvalSymlinksTestDirs {
527 err = os.Mkdir(d.path, 0755)
529 if runtime.GOOS != "windows" {
530 err = os.Symlink(d.dest, d.path)
537 var tests []EvalSymlinksTest
538 if runtime.GOOS == "windows" {
539 for _, d := range EvalSymlinksTests {
540 if d.path == d.dest {
541 // will test only real files and directories
542 tests = append(tests, d)
546 tests = EvalSymlinksTests
549 testEvalSymlinks(t, tests)
551 /* These tests do not work in the gccgo test environment.
552 goroot, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
554 t.Fatalf("EvalSymlinks(%q) error: %v", os.Getenv("GOROOT"), err)
556 testroot := filepath.Join(goroot, "src", "pkg", "path", "filepath")
557 for i, d := range tests {
558 tests[i].path = filepath.Join(testroot, d.path)
559 tests[i].dest = filepath.Join(testroot, d.dest)
561 if runtime.GOOS == "windows" {
562 for _, d := range EvalSymlinksAbsWindowsTests {
563 tests = append(tests, d)
566 testEvalSymlinks(t, tests)
570 /* These tests do not work in the gccgo test environment.
572 // Test paths relative to $GOROOT/src
573 var abstests = []string{
579 "$GOROOT/src/Make.pkg",
580 "$GOROOT/src/../src/Make.pkg",
585 func TestAbs(t *testing.T) {
586 oldwd, err := os.Getwd()
588 t.Fatal("Getwd failed: " + err.Error())
590 defer os.Chdir(oldwd)
591 goroot := os.Getenv("GOROOT")
592 cwd := filepath.Join(goroot, "src")
594 for _, path := range abstests {
595 path = strings.Replace(path, "$GOROOT", goroot, -1)
596 info, err := os.Stat(path)
598 t.Errorf("%s: %s", path, err)
601 abspath, err := filepath.Abs(path)
603 t.Errorf("Abs(%q) error: %v", path, err)
605 absinfo, err := os.Stat(abspath)
606 if err != nil || absinfo.Ino != info.Ino {
607 t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
609 if !filepath.IsAbs(abspath) {
610 t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
612 if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
613 t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
620 type RelTests struct {
621 root, path, want string
624 var reltests = []RelTests{
626 {"a/b/.", "a/b", "."},
627 {"a/b", "a/b/.", "."},
628 {"./a/b", "a/b", "."},
629 {"a/b", "./a/b", "."},
630 {"ab/cd", "ab/cde", "../cde"},
631 {"ab/cd", "ab/c", "../c"},
632 {"a/b", "a/b/c/d", "c/d"},
633 {"a/b", "a/b/../c", "../c"},
634 {"a/b/../c", "a/b", "../b"},
635 {"a/b/c", "a/c/d", "../../c/d"},
636 {"a/b", "c/d", "../../c/d"},
637 {"../../a/b", "../../a/b/c/d", "c/d"},
638 {"/a/b", "/a/b", "."},
639 {"/a/b/.", "/a/b", "."},
640 {"/a/b", "/a/b/.", "."},
641 {"/ab/cd", "/ab/cde", "../cde"},
642 {"/ab/cd", "/ab/c", "../c"},
643 {"/a/b", "/a/b/c/d", "c/d"},
644 {"/a/b", "/a/b/../c", "../c"},
645 {"/a/b/../c", "/a/b", "../b"},
646 {"/a/b/c", "/a/c/d", "../../c/d"},
647 {"/a/b", "/c/d", "../../c/d"},
648 {"/../../a/b", "/../../a/b/c/d", "c/d"},
652 // can't do purely lexically
655 {"../..", "..", "err"},
660 var winreltests = []RelTests{
661 {`C:a\b\c`, `C:a/b/d`, `..\d`},
662 {`C:\`, `D:\`, `err`},
666 func TestRel(t *testing.T) {
667 tests := append([]RelTests{}, reltests...)
668 if runtime.GOOS == "windows" {
669 for i := range tests {
670 tests[i].want = filepath.FromSlash(tests[i].want)
672 tests = append(tests, winreltests...)
674 for _, test := range tests {
675 got, err := filepath.Rel(test.root, test.path)
676 if test.want == "err" {
678 t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got)
683 t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err)
685 if got != test.want {
686 t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want)
691 type VolumeNameTest struct {
696 var volumenametests = []VolumeNameTest{
697 {`c:/foo/bar`, `c:`},
702 {`\\\host\share`, ``},
703 {`\\\host\\share`, ``},
708 {`\\host\share`, `\\host\share`},
709 {`//host/share`, `//host/share`},
710 {`\\host\share\`, `\\host\share`},
711 {`//host/share/`, `//host/share`},
712 {`\\host\share\foo`, `\\host\share`},
713 {`//host/share/foo`, `//host/share`},
714 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
715 {`//host/share//foo///bar////baz`, `//host/share`},
716 {`\\host\share\foo\..\bar`, `\\host\share`},
717 {`//host/share/foo/../bar`, `//host/share`},
720 func TestVolumeName(t *testing.T) {
721 if runtime.GOOS != "windows" {
724 for _, v := range volumenametests {
725 if vol := filepath.VolumeName(v.path); vol != v.vol {
726 t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol)