* gcc.dg/guality/guality.exp: Skip on AIX.
[official-gcc.git] / libgo / go / path / filepath / path_test.go
blob607bfed11ba01a3cd01513ad900015d237cb5be1
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 "io/ioutil"
9 "os"
10 "path/filepath"
11 "reflect"
12 "runtime"
13 "strings"
14 "testing"
17 type PathTest struct {
18 path, result string
21 var cleantests = []PathTest{
22 // Already clean
23 {"abc", "abc"},
24 {"abc/def", "abc/def"},
25 {"a/b/c", "a/b/c"},
26 {".", "."},
27 {"..", ".."},
28 {"../..", "../.."},
29 {"../../abc", "../../abc"},
30 {"/abc", "/abc"},
31 {"/", "/"},
33 // Empty is current dir
34 {"", "."},
36 // Remove trailing slash
37 {"abc/", "abc"},
38 {"abc/def/", "abc/def"},
39 {"a/b/c/", "a/b/c"},
40 {"./", "."},
41 {"../", ".."},
42 {"../../", "../.."},
43 {"/abc/", "/abc"},
45 // Remove doubled slash
46 {"abc//def//ghi", "abc/def/ghi"},
47 {"//abc", "/abc"},
48 {"///abc", "/abc"},
49 {"//abc//", "/abc"},
50 {"abc//", "abc"},
52 // Remove . elements
53 {"abc/./def", "abc/def"},
54 {"/./abc/def", "/abc/def"},
55 {"abc/.", "abc"},
57 // Remove .. elements
58 {"abc/def/ghi/../jkl", "abc/def/jkl"},
59 {"abc/def/../ghi/../jkl", "abc/jkl"},
60 {"abc/def/..", "abc"},
61 {"abc/def/../..", "."},
62 {"/abc/def/../..", "/"},
63 {"abc/def/../../..", ".."},
64 {"/abc/def/../../..", "/"},
65 {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
66 {"/../abc", "/abc"},
68 // Combinations
69 {"abc/./../def", "def"},
70 {"abc//./../def", "def"},
71 {"abc/../../././../def", "../../def"},
74 var wincleantests = []PathTest{
75 {`c:`, `c:.`},
76 {`c:\`, `c:\`},
77 {`c:\abc`, `c:\abc`},
78 {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
79 {`c:\abc\def\..\..`, `c:\`},
80 {`c:\..\abc`, `c:\abc`},
81 {`c:..\abc`, `c:..\abc`},
82 {`\`, `\`},
83 {`/`, `\`},
84 {`\\i\..\c$`, `\c$`},
85 {`\\i\..\i\c$`, `\i\c$`},
86 {`\\i\..\I\c$`, `\I\c$`},
87 {`\\host\share\foo\..\bar`, `\\host\share\bar`},
88 {`//host/share/foo/../baz`, `\\host\share\baz`},
89 {`\\a\b\..\c`, `\\a\b\c`},
90 {`\\a\b`, `\\a\b`},
93 func TestClean(t *testing.T) {
94 tests := cleantests
95 if runtime.GOOS == "windows" {
96 for i := range tests {
97 tests[i].result = filepath.FromSlash(tests[i].result)
99 tests = append(tests, wincleantests...)
101 for _, test := range tests {
102 if s := filepath.Clean(test.path); s != test.result {
103 t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
105 if s := filepath.Clean(test.result); s != test.result {
106 t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)
110 if runtime.GOMAXPROCS(0) > 1 {
111 t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
112 return
115 t.Log("Skipping AllocsPerRun for gccgo")
116 return
118 for _, test := range tests {
119 allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) })
120 if allocs > 0 {
121 t.Errorf("Clean(%q): %v allocs, want zero", test.result, allocs)
126 const sep = filepath.Separator
128 var slashtests = []PathTest{
129 {"", ""},
130 {"/", string(sep)},
131 {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
132 {"a//b", string([]byte{'a', sep, sep, 'b'})},
135 func TestFromAndToSlash(t *testing.T) {
136 for _, test := range slashtests {
137 if s := filepath.FromSlash(test.path); s != test.result {
138 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
140 if s := filepath.ToSlash(test.result); s != test.path {
141 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
146 type SplitListTest struct {
147 list string
148 result []string
151 const lsep = filepath.ListSeparator
153 var splitlisttests = []SplitListTest{
154 {"", []string{}},
155 {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},
156 {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},
159 var winsplitlisttests = []SplitListTest{
160 // quoted
161 {`"a"`, []string{`a`}},
163 // semicolon
164 {`";"`, []string{`;`}},
165 {`"a;b"`, []string{`a;b`}},
166 {`";";`, []string{`;`, ``}},
167 {`;";"`, []string{``, `;`}},
169 // partially quoted
170 {`a";"b`, []string{`a;b`}},
171 {`a; ""b`, []string{`a`, ` b`}},
172 {`"a;b`, []string{`a;b`}},
173 {`""a;b`, []string{`a`, `b`}},
174 {`"""a;b`, []string{`a;b`}},
175 {`""""a;b`, []string{`a`, `b`}},
176 {`a";b`, []string{`a;b`}},
177 {`a;b";c`, []string{`a`, `b;c`}},
178 {`"a";b";c`, []string{`a`, `b;c`}},
181 func TestSplitList(t *testing.T) {
182 tests := splitlisttests
183 if runtime.GOOS == "windows" {
184 tests = append(tests, winsplitlisttests...)
186 for _, test := range tests {
187 if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {
188 t.Errorf("SplitList(%#q) = %#q, want %#q", test.list, l, test.result)
193 type SplitTest struct {
194 path, dir, file string
197 var unixsplittests = []SplitTest{
198 {"a/b", "a/", "b"},
199 {"a/b/", "a/b/", ""},
200 {"a/", "a/", ""},
201 {"a", "", "a"},
202 {"/", "/", ""},
205 var winsplittests = []SplitTest{
206 {`c:`, `c:`, ``},
207 {`c:/`, `c:/`, ``},
208 {`c:/foo`, `c:/`, `foo`},
209 {`c:/foo/bar`, `c:/foo/`, `bar`},
210 {`//host/share`, `//host/share`, ``},
211 {`//host/share/`, `//host/share/`, ``},
212 {`//host/share/foo`, `//host/share/`, `foo`},
213 {`\\host\share`, `\\host\share`, ``},
214 {`\\host\share\`, `\\host\share\`, ``},
215 {`\\host\share\foo`, `\\host\share\`, `foo`},
218 func TestSplit(t *testing.T) {
219 var splittests []SplitTest
220 splittests = unixsplittests
221 if runtime.GOOS == "windows" {
222 splittests = append(splittests, winsplittests...)
224 for _, test := range splittests {
225 if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
226 t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
231 type JoinTest struct {
232 elem []string
233 path string
236 var jointests = []JoinTest{
237 // zero parameters
238 {[]string{}, ""},
240 // one parameter
241 {[]string{""}, ""},
242 {[]string{"a"}, "a"},
244 // two parameters
245 {[]string{"a", "b"}, "a/b"},
246 {[]string{"a", ""}, "a"},
247 {[]string{"", "b"}, "b"},
248 {[]string{"/", "a"}, "/a"},
249 {[]string{"/", ""}, "/"},
250 {[]string{"a/", "b"}, "a/b"},
251 {[]string{"a/", ""}, "a"},
252 {[]string{"", ""}, ""},
255 var winjointests = []JoinTest{
256 {[]string{`directory`, `file`}, `directory\file`},
257 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
258 {[]string{`C:\Windows\`, ``}, `C:\Windows`},
259 {[]string{`C:\`, `Windows`}, `C:\Windows`},
260 {[]string{`C:`, `Windows`}, `C:\Windows`},
261 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
262 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
265 // join takes a []string and passes it to Join.
266 func join(elem []string, args ...string) string {
267 args = elem
268 return filepath.Join(args...)
271 func TestJoin(t *testing.T) {
272 if runtime.GOOS == "windows" {
273 jointests = append(jointests, winjointests...)
275 for _, test := range jointests {
276 if p := join(test.elem); p != filepath.FromSlash(test.path) {
277 t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
282 type ExtTest struct {
283 path, ext string
286 var exttests = []ExtTest{
287 {"path.go", ".go"},
288 {"path.pb.go", ".go"},
289 {"a.dir/b", ""},
290 {"a.dir/b.go", ".go"},
291 {"a.dir/", ""},
294 func TestExt(t *testing.T) {
295 for _, test := range exttests {
296 if x := filepath.Ext(test.path); x != test.ext {
297 t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
302 type Node struct {
303 name string
304 entries []*Node // nil if the entry is a file
305 mark int
308 var tree = &Node{
309 "testdata",
310 []*Node{
311 {"a", nil, 0},
312 {"b", []*Node{}, 0},
313 {"c", nil, 0},
315 "d",
316 []*Node{
317 {"x", nil, 0},
318 {"y", []*Node{}, 0},
320 "z",
321 []*Node{
322 {"u", nil, 0},
323 {"v", nil, 0},
334 func walkTree(n *Node, path string, f func(path string, n *Node)) {
335 f(path, n)
336 for _, e := range n.entries {
337 walkTree(e, filepath.Join(path, e.name), f)
341 func makeTree(t *testing.T) {
342 walkTree(tree, tree.name, func(path string, n *Node) {
343 if n.entries == nil {
344 fd, err := os.Create(path)
345 if err != nil {
346 t.Errorf("makeTree: %v", err)
347 return
349 fd.Close()
350 } else {
351 os.Mkdir(path, 0770)
356 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
358 func checkMarks(t *testing.T, report bool) {
359 walkTree(tree, tree.name, func(path string, n *Node) {
360 if n.mark != 1 && report {
361 t.Errorf("node %s mark = %d; expected 1", path, n.mark)
363 n.mark = 0
367 // Assumes that each node name is unique. Good enough for a test.
368 // If clear is true, any incoming error is cleared before return. The errors
369 // are always accumulated, though.
370 func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
371 if err != nil {
372 *errors = append(*errors, err)
373 if clear {
374 return nil
376 return err
378 name := info.Name()
379 walkTree(tree, tree.name, func(path string, n *Node) {
380 if n.name == name {
381 n.mark++
384 return nil
387 func TestWalk(t *testing.T) {
388 makeTree(t)
389 errors := make([]error, 0, 10)
390 clear := true
391 markFn := func(path string, info os.FileInfo, err error) error {
392 return mark(path, info, err, &errors, clear)
394 // Expect no errors.
395 err := filepath.Walk(tree.name, markFn)
396 if err != nil {
397 t.Fatalf("no error expected, found: %s", err)
399 if len(errors) != 0 {
400 t.Fatalf("unexpected errors: %s", errors)
402 checkMarks(t, true)
403 errors = errors[0:0]
405 // Test permission errors. Only possible if we're not root
406 // and only on some file systems (AFS, FAT). To avoid errors during
407 // all.bash on those file systems, skip during go test -short.
408 if os.Getuid() > 0 && !testing.Short() {
409 // introduce 2 errors: chmod top-level directories to 0
410 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
411 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
413 // 3) capture errors, expect two.
414 // mark respective subtrees manually
415 markTree(tree.entries[1])
416 markTree(tree.entries[3])
417 // correct double-marking of directory itself
418 tree.entries[1].mark--
419 tree.entries[3].mark--
420 err := filepath.Walk(tree.name, markFn)
421 if err != nil {
422 t.Fatalf("expected no error return from Walk, got %s", err)
424 if len(errors) != 2 {
425 t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
427 // the inaccessible subtrees were marked manually
428 checkMarks(t, true)
429 errors = errors[0:0]
431 // 4) capture errors, stop after first error.
432 // mark respective subtrees manually
433 markTree(tree.entries[1])
434 markTree(tree.entries[3])
435 // correct double-marking of directory itself
436 tree.entries[1].mark--
437 tree.entries[3].mark--
438 clear = false // error will stop processing
439 err = filepath.Walk(tree.name, markFn)
440 if err == nil {
441 t.Fatalf("expected error return from Walk")
443 if len(errors) != 1 {
444 t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
446 // the inaccessible subtrees were marked manually
447 checkMarks(t, false)
448 errors = errors[0:0]
450 // restore permissions
451 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
452 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
455 // cleanup
456 if err := os.RemoveAll(tree.name); err != nil {
457 t.Errorf("removeTree: %v", err)
461 var basetests = []PathTest{
462 {"", "."},
463 {".", "."},
464 {"/.", "."},
465 {"/", "/"},
466 {"////", "/"},
467 {"x/", "x"},
468 {"abc", "abc"},
469 {"abc/def", "def"},
470 {"a/b/.x", ".x"},
471 {"a/b/c.", "c."},
472 {"a/b/c.x", "c.x"},
475 var winbasetests = []PathTest{
476 {`c:\`, `\`},
477 {`c:.`, `.`},
478 {`c:\a\b`, `b`},
479 {`c:a\b`, `b`},
480 {`c:a\b\c`, `c`},
481 {`\\host\share\`, `\`},
482 {`\\host\share\a`, `a`},
483 {`\\host\share\a\b`, `b`},
486 func TestBase(t *testing.T) {
487 tests := basetests
488 if runtime.GOOS == "windows" {
489 // make unix tests work on windows
490 for i := range tests {
491 tests[i].result = filepath.Clean(tests[i].result)
493 // add windows specific tests
494 tests = append(tests, winbasetests...)
496 for _, test := range tests {
497 if s := filepath.Base(test.path); s != test.result {
498 t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
503 var dirtests = []PathTest{
504 {"", "."},
505 {".", "."},
506 {"/.", "/"},
507 {"/", "/"},
508 {"////", "/"},
509 {"/foo", "/"},
510 {"x/", "x"},
511 {"abc", "."},
512 {"abc/def", "abc"},
513 {"a/b/.x", "a/b"},
514 {"a/b/c.", "a/b"},
515 {"a/b/c.x", "a/b"},
518 var windirtests = []PathTest{
519 {`c:\`, `c:\`},
520 {`c:.`, `c:.`},
521 {`c:\a\b`, `c:\a`},
522 {`c:a\b`, `c:a`},
523 {`c:a\b\c`, `c:a\b`},
524 {`\\host\share\`, `\\host\share\`},
525 {`\\host\share\a`, `\\host\share\`},
526 {`\\host\share\a\b`, `\\host\share\a`},
529 func TestDir(t *testing.T) {
530 tests := dirtests
531 if runtime.GOOS == "windows" {
532 // make unix tests work on windows
533 for i := range tests {
534 tests[i].result = filepath.Clean(tests[i].result)
536 // add windows specific tests
537 tests = append(tests, windirtests...)
539 for _, test := range tests {
540 if s := filepath.Dir(test.path); s != test.result {
541 t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
546 type IsAbsTest struct {
547 path string
548 isAbs bool
551 var isabstests = []IsAbsTest{
552 {"", false},
553 {"/", true},
554 {"/usr/bin/gcc", true},
555 {"..", false},
556 {"/a/../bb", true},
557 {".", false},
558 {"./", false},
559 {"lala", false},
562 var winisabstests = []IsAbsTest{
563 {`C:\`, true},
564 {`c\`, false},
565 {`c::`, false},
566 {`c:`, false},
567 {`/`, false},
568 {`\`, false},
569 {`\Windows`, false},
570 {`c:a\b`, false},
571 {`\\host\share\foo`, true},
572 {`//host/share/foo/bar`, true},
575 func TestIsAbs(t *testing.T) {
576 var tests []IsAbsTest
577 if runtime.GOOS == "windows" {
578 tests = append(tests, winisabstests...)
579 // All non-windows tests should fail, because they have no volume letter.
580 for _, test := range isabstests {
581 tests = append(tests, IsAbsTest{test.path, false})
583 // All non-windows test should work as intended if prefixed with volume letter.
584 for _, test := range isabstests {
585 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
587 } else {
588 tests = isabstests
591 for _, test := range tests {
592 if r := filepath.IsAbs(test.path); r != test.isAbs {
593 t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
598 type EvalSymlinksTest struct {
599 // If dest is empty, the path is created; otherwise the dest is symlinked to the path.
600 path, dest string
603 var EvalSymlinksTestDirs = []EvalSymlinksTest{
604 {"test", ""},
605 {"test/dir", ""},
606 {"test/dir/link3", "../../"},
607 {"test/link1", "../test"},
608 {"test/link2", "dir"},
609 {"test/linkabs", "/"},
612 var EvalSymlinksTests = []EvalSymlinksTest{
613 {"test", "test"},
614 {"test/dir", "test/dir"},
615 {"test/dir/../..", "."},
616 {"test/link1", "test"},
617 {"test/link2", "test/dir"},
618 {"test/link1/dir", "test/dir"},
619 {"test/link2/..", "test"},
620 {"test/dir/link3", "."},
621 {"test/link2/link3/test", "test"},
622 {"test/linkabs", "/"},
625 var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
626 {`c:\`, `c:\`},
629 // simpleJoin builds a file name from the directory and path.
630 // It does not use Join because we don't want ".." to be evaluated.
631 func simpleJoin(dir, path string) string {
632 return dir + string(filepath.Separator) + path
635 func TestEvalSymlinks(t *testing.T) {
636 tmpDir, err := ioutil.TempDir("", "evalsymlink")
637 if err != nil {
638 t.Fatal("creating temp dir:", err)
640 defer os.RemoveAll(tmpDir)
642 // /tmp may itself be a symlink! Avoid the confusion, although
643 // it means trusting the thing we're testing.
644 tmpDir, err = filepath.EvalSymlinks(tmpDir)
645 if err != nil {
646 t.Fatal("eval symlink for tmp dir:", err)
649 // Create the symlink farm using relative paths.
650 for _, d := range EvalSymlinksTestDirs {
651 var err error
652 path := simpleJoin(tmpDir, d.path)
653 if d.dest == "" {
654 err = os.Mkdir(path, 0755)
655 } else {
656 if runtime.GOOS != "windows" {
657 err = os.Symlink(d.dest, path)
660 if err != nil {
661 t.Fatal(err)
665 var tests []EvalSymlinksTest
666 if runtime.GOOS == "windows" {
667 for _, d := range EvalSymlinksTests {
668 if d.path == d.dest {
669 // will test only real files and directories
670 tests = append(tests, d)
671 // test "canonical" names
672 d2 := EvalSymlinksTest{
673 path: strings.ToUpper(d.path),
674 dest: d.dest,
676 tests = append(tests, d2)
679 } else {
680 tests = EvalSymlinksTests
683 // Evaluate the symlink farm.
684 for _, d := range tests {
685 path := simpleJoin(tmpDir, d.path)
686 dest := simpleJoin(tmpDir, d.dest)
687 if filepath.IsAbs(d.dest) {
688 dest = d.dest
690 if p, err := filepath.EvalSymlinks(path); err != nil {
691 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
692 } else if filepath.Clean(p) != filepath.Clean(dest) {
693 t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
698 // Test directories relative to temporary directory.
699 // The tests are run in absTestDirs[0].
700 var absTestDirs = []string{
701 "a",
702 "a/b",
703 "a/b/c",
706 // Test paths relative to temporary directory. $ expands to the directory.
707 // The tests are run in absTestDirs[0].
708 // We create absTestDirs first.
709 var absTests = []string{
710 ".",
711 "b",
712 "../a",
713 "../a/b",
714 "../a/b/./c/../../.././a",
715 "$",
716 "$/.",
717 "$/a/../a/b",
718 "$/a/b/c/../../.././a",
721 func TestAbs(t *testing.T) {
722 oldwd, err := os.Getwd()
723 if err != nil {
724 t.Fatal("Getwd failed: ", err)
726 defer os.Chdir(oldwd)
728 root, err := ioutil.TempDir("", "TestAbs")
729 if err != nil {
730 t.Fatal("TempDir failed: ", err)
732 defer os.RemoveAll(root)
734 wd, err := os.Getwd()
735 if err != nil {
736 t.Fatal("getwd failed: ", err)
738 err = os.Chdir(root)
739 if err != nil {
740 t.Fatal("chdir failed: ", err)
742 defer os.Chdir(wd)
744 for _, dir := range absTestDirs {
745 err = os.Mkdir(dir, 0777)
746 if err != nil {
747 t.Fatal("Mkdir failed: ", err)
751 err = os.Chdir(absTestDirs[0])
752 if err != nil {
753 t.Fatal("chdir failed: ", err)
756 for _, path := range absTests {
757 path = strings.Replace(path, "$", root, -1)
758 info, err := os.Stat(path)
759 if err != nil {
760 t.Errorf("%s: %s", path, err)
761 continue
764 abspath, err := filepath.Abs(path)
765 if err != nil {
766 t.Errorf("Abs(%q) error: %v", path, err)
767 continue
769 absinfo, err := os.Stat(abspath)
770 if err != nil || !os.SameFile(absinfo, info) {
771 t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
773 if !filepath.IsAbs(abspath) {
774 t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
776 if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
777 t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
782 type RelTests struct {
783 root, path, want string
786 var reltests = []RelTests{
787 {"a/b", "a/b", "."},
788 {"a/b/.", "a/b", "."},
789 {"a/b", "a/b/.", "."},
790 {"./a/b", "a/b", "."},
791 {"a/b", "./a/b", "."},
792 {"ab/cd", "ab/cde", "../cde"},
793 {"ab/cd", "ab/c", "../c"},
794 {"a/b", "a/b/c/d", "c/d"},
795 {"a/b", "a/b/../c", "../c"},
796 {"a/b/../c", "a/b", "../b"},
797 {"a/b/c", "a/c/d", "../../c/d"},
798 {"a/b", "c/d", "../../c/d"},
799 {"a/b/c/d", "a/b", "../.."},
800 {"a/b/c/d", "a/b/", "../.."},
801 {"a/b/c/d/", "a/b", "../.."},
802 {"a/b/c/d/", "a/b/", "../.."},
803 {"../../a/b", "../../a/b/c/d", "c/d"},
804 {"/a/b", "/a/b", "."},
805 {"/a/b/.", "/a/b", "."},
806 {"/a/b", "/a/b/.", "."},
807 {"/ab/cd", "/ab/cde", "../cde"},
808 {"/ab/cd", "/ab/c", "../c"},
809 {"/a/b", "/a/b/c/d", "c/d"},
810 {"/a/b", "/a/b/../c", "../c"},
811 {"/a/b/../c", "/a/b", "../b"},
812 {"/a/b/c", "/a/c/d", "../../c/d"},
813 {"/a/b", "/c/d", "../../c/d"},
814 {"/a/b/c/d", "/a/b", "../.."},
815 {"/a/b/c/d", "/a/b/", "../.."},
816 {"/a/b/c/d/", "/a/b", "../.."},
817 {"/a/b/c/d/", "/a/b/", "../.."},
818 {"/../../a/b", "/../../a/b/c/d", "c/d"},
819 {".", "a/b", "a/b"},
820 {".", "..", ".."},
822 // can't do purely lexically
823 {"..", ".", "err"},
824 {"..", "a", "err"},
825 {"../..", "..", "err"},
826 {"a", "/a", "err"},
827 {"/a", "a", "err"},
830 var winreltests = []RelTests{
831 {`C:a\b\c`, `C:a/b/d`, `..\d`},
832 {`C:\`, `D:\`, `err`},
833 {`C:`, `D:`, `err`},
836 func TestRel(t *testing.T) {
837 tests := append([]RelTests{}, reltests...)
838 if runtime.GOOS == "windows" {
839 for i := range tests {
840 tests[i].want = filepath.FromSlash(tests[i].want)
842 tests = append(tests, winreltests...)
844 for _, test := range tests {
845 got, err := filepath.Rel(test.root, test.path)
846 if test.want == "err" {
847 if err == nil {
848 t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got)
850 continue
852 if err != nil {
853 t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err)
855 if got != test.want {
856 t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want)
861 type VolumeNameTest struct {
862 path string
863 vol string
866 var volumenametests = []VolumeNameTest{
867 {`c:/foo/bar`, `c:`},
868 {`c:`, `c:`},
869 {`2:`, ``},
870 {``, ``},
871 {`\\\host`, ``},
872 {`\\\host\`, ``},
873 {`\\\host\share`, ``},
874 {`\\\host\\share`, ``},
875 {`\\host`, ``},
876 {`//host`, ``},
877 {`\\host\`, ``},
878 {`//host/`, ``},
879 {`\\host\share`, `\\host\share`},
880 {`//host/share`, `//host/share`},
881 {`\\host\share\`, `\\host\share`},
882 {`//host/share/`, `//host/share`},
883 {`\\host\share\foo`, `\\host\share`},
884 {`//host/share/foo`, `//host/share`},
885 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
886 {`//host/share//foo///bar////baz`, `//host/share`},
887 {`\\host\share\foo\..\bar`, `\\host\share`},
888 {`//host/share/foo/../bar`, `//host/share`},
891 func TestVolumeName(t *testing.T) {
892 if runtime.GOOS != "windows" {
893 return
895 for _, v := range volumenametests {
896 if vol := filepath.VolumeName(v.path); vol != v.vol {
897 t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol)
902 func TestDriveLetterInEvalSymlinks(t *testing.T) {
903 if runtime.GOOS != "windows" {
904 return
906 wd, _ := os.Getwd()
907 if len(wd) < 3 {
908 t.Errorf("Current directory path %q is too short", wd)
910 lp := strings.ToLower(wd)
911 up := strings.ToUpper(wd)
912 flp, err := filepath.EvalSymlinks(lp)
913 if err != nil {
914 t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err)
916 fup, err := filepath.EvalSymlinks(up)
917 if err != nil {
918 t.Fatalf("EvalSymlinks(%q) failed: %q", up, err)
920 if flp != fup {
921 t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup)
925 /* This test does not work gccgo, since the sources are arranged
926 differently.
928 func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
929 root, err := filepath.EvalSymlinks(runtime.GOROOT())
930 if err != nil {
931 t.Fatal(err)
933 lib := filepath.Join(root, "lib")
934 src := filepath.Join(root, "src")
935 seenSrc := false
936 filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
937 if err != nil {
938 t.Fatal(err)
941 switch pth {
942 case lib:
943 return filepath.SkipDir
944 case src:
945 seenSrc = true
947 return nil
949 if !seenSrc {
950 t.Fatalf("%q not seen", src)