]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/path/filepath/path_test.go
libgo: Update to current sources.
[thirdparty/gcc.git] / libgo / go / path / filepath / path_test.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package filepath_test
6
7 import (
8 "io/ioutil"
9 "os"
10 "path/filepath"
11 "reflect"
12 "runtime"
13 "strings"
14 "testing"
15 )
16
17 type PathTest struct {
18 path, result string
19 }
20
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 {"/", "/"},
32
33 // Empty is current dir
34 {"", "."},
35
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"},
44
45 // Remove doubled slash
46 {"abc//def//ghi", "abc/def/ghi"},
47 {"//abc", "/abc"},
48 {"///abc", "/abc"},
49 {"//abc//", "/abc"},
50 {"abc//", "abc"},
51
52 // Remove . elements
53 {"abc/./def", "abc/def"},
54 {"/./abc/def", "/abc/def"},
55 {"abc/.", "abc"},
56
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"},
67
68 // Combinations
69 {"abc/./../def", "def"},
70 {"abc//./../def", "def"},
71 {"abc/../../././../def", "../../def"},
72 }
73
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`},
91 }
92
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)
98 }
99 tests = append(tests, wincleantests...)
100 }
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)
104 }
105 if s := filepath.Clean(test.result); s != test.result {
106 t.Errorf("Clean(%q) = %q, want %q", test.result, s, test.result)
107 }
108 }
109
110 var ms runtime.MemStats
111 runtime.ReadMemStats(&ms)
112 allocs := -ms.Mallocs
113 const rounds = 100
114 for i := 0; i < rounds; i++ {
115 for _, test := range tests {
116 filepath.Clean(test.result)
117 }
118 }
119 runtime.ReadMemStats(&ms)
120 allocs += ms.Mallocs
121 /* Fails with gccgo, which has no escape analysis.
122 if allocs >= rounds {
123 t.Errorf("Clean cleaned paths: %d allocations per test round, want zero", allocs/rounds)
124 }
125 */
126 }
127
128 const sep = filepath.Separator
129
130 var slashtests = []PathTest{
131 {"", ""},
132 {"/", string(sep)},
133 {"/a/b", string([]byte{sep, 'a', sep, 'b'})},
134 {"a//b", string([]byte{'a', sep, sep, 'b'})},
135 }
136
137 func TestFromAndToSlash(t *testing.T) {
138 for _, test := range slashtests {
139 if s := filepath.FromSlash(test.path); s != test.result {
140 t.Errorf("FromSlash(%q) = %q, want %q", test.path, s, test.result)
141 }
142 if s := filepath.ToSlash(test.result); s != test.path {
143 t.Errorf("ToSlash(%q) = %q, want %q", test.result, s, test.path)
144 }
145 }
146 }
147
148 type SplitListTest struct {
149 list string
150 result []string
151 }
152
153 const lsep = filepath.ListSeparator
154
155 var splitlisttests = []SplitListTest{
156 {"", []string{}},
157 {string([]byte{'a', lsep, 'b'}), []string{"a", "b"}},
158 {string([]byte{lsep, 'a', lsep, 'b'}), []string{"", "a", "b"}},
159 }
160
161 func TestSplitList(t *testing.T) {
162 for _, test := range splitlisttests {
163 if l := filepath.SplitList(test.list); !reflect.DeepEqual(l, test.result) {
164 t.Errorf("SplitList(%q) = %s, want %s", test.list, l, test.result)
165 }
166 }
167 }
168
169 type SplitTest struct {
170 path, dir, file string
171 }
172
173 var unixsplittests = []SplitTest{
174 {"a/b", "a/", "b"},
175 {"a/b/", "a/b/", ""},
176 {"a/", "a/", ""},
177 {"a", "", "a"},
178 {"/", "/", ""},
179 }
180
181 var winsplittests = []SplitTest{
182 {`c:`, `c:`, ``},
183 {`c:/`, `c:/`, ``},
184 {`c:/foo`, `c:/`, `foo`},
185 {`c:/foo/bar`, `c:/foo/`, `bar`},
186 {`//host/share`, `//host/share`, ``},
187 {`//host/share/`, `//host/share/`, ``},
188 {`//host/share/foo`, `//host/share/`, `foo`},
189 {`\\host\share`, `\\host\share`, ``},
190 {`\\host\share\`, `\\host\share\`, ``},
191 {`\\host\share\foo`, `\\host\share\`, `foo`},
192 }
193
194 func TestSplit(t *testing.T) {
195 var splittests []SplitTest
196 splittests = unixsplittests
197 if runtime.GOOS == "windows" {
198 splittests = append(splittests, winsplittests...)
199 }
200 for _, test := range splittests {
201 if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
202 t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
203 }
204 }
205 }
206
207 type JoinTest struct {
208 elem []string
209 path string
210 }
211
212 var jointests = []JoinTest{
213 // zero parameters
214 {[]string{}, ""},
215
216 // one parameter
217 {[]string{""}, ""},
218 {[]string{"a"}, "a"},
219
220 // two parameters
221 {[]string{"a", "b"}, "a/b"},
222 {[]string{"a", ""}, "a"},
223 {[]string{"", "b"}, "b"},
224 {[]string{"/", "a"}, "/a"},
225 {[]string{"/", ""}, "/"},
226 {[]string{"a/", "b"}, "a/b"},
227 {[]string{"a/", ""}, "a"},
228 {[]string{"", ""}, ""},
229 }
230
231 var winjointests = []JoinTest{
232 {[]string{`directory`, `file`}, `directory\file`},
233 {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
234 {[]string{`C:\Windows\`, ``}, `C:\Windows`},
235 {[]string{`C:\`, `Windows`}, `C:\Windows`},
236 {[]string{`C:`, `Windows`}, `C:\Windows`},
237 {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
238 {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
239 }
240
241 // join takes a []string and passes it to Join.
242 func join(elem []string, args ...string) string {
243 args = elem
244 return filepath.Join(args...)
245 }
246
247 func TestJoin(t *testing.T) {
248 if runtime.GOOS == "windows" {
249 jointests = append(jointests, winjointests...)
250 }
251 for _, test := range jointests {
252 if p := join(test.elem); p != filepath.FromSlash(test.path) {
253 t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
254 }
255 }
256 }
257
258 type ExtTest struct {
259 path, ext string
260 }
261
262 var exttests = []ExtTest{
263 {"path.go", ".go"},
264 {"path.pb.go", ".go"},
265 {"a.dir/b", ""},
266 {"a.dir/b.go", ".go"},
267 {"a.dir/", ""},
268 }
269
270 func TestExt(t *testing.T) {
271 for _, test := range exttests {
272 if x := filepath.Ext(test.path); x != test.ext {
273 t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
274 }
275 }
276 }
277
278 type Node struct {
279 name string
280 entries []*Node // nil if the entry is a file
281 mark int
282 }
283
284 var tree = &Node{
285 "testdata",
286 []*Node{
287 {"a", nil, 0},
288 {"b", []*Node{}, 0},
289 {"c", nil, 0},
290 {
291 "d",
292 []*Node{
293 {"x", nil, 0},
294 {"y", []*Node{}, 0},
295 {
296 "z",
297 []*Node{
298 {"u", nil, 0},
299 {"v", nil, 0},
300 },
301 0,
302 },
303 },
304 0,
305 },
306 },
307 0,
308 }
309
310 func walkTree(n *Node, path string, f func(path string, n *Node)) {
311 f(path, n)
312 for _, e := range n.entries {
313 walkTree(e, filepath.Join(path, e.name), f)
314 }
315 }
316
317 func makeTree(t *testing.T) {
318 walkTree(tree, tree.name, func(path string, n *Node) {
319 if n.entries == nil {
320 fd, err := os.Create(path)
321 if err != nil {
322 t.Errorf("makeTree: %v", err)
323 return
324 }
325 fd.Close()
326 } else {
327 os.Mkdir(path, 0770)
328 }
329 })
330 }
331
332 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
333
334 func checkMarks(t *testing.T, report bool) {
335 walkTree(tree, tree.name, func(path string, n *Node) {
336 if n.mark != 1 && report {
337 t.Errorf("node %s mark = %d; expected 1", path, n.mark)
338 }
339 n.mark = 0
340 })
341 }
342
343 // Assumes that each node name is unique. Good enough for a test.
344 // If clear is true, any incoming error is cleared before return. The errors
345 // are always accumulated, though.
346 func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
347 if err != nil {
348 *errors = append(*errors, err)
349 if clear {
350 return nil
351 }
352 return err
353 }
354 name := info.Name()
355 walkTree(tree, tree.name, func(path string, n *Node) {
356 if n.name == name {
357 n.mark++
358 }
359 })
360 return nil
361 }
362
363 func TestWalk(t *testing.T) {
364 makeTree(t)
365 errors := make([]error, 0, 10)
366 clear := true
367 markFn := func(path string, info os.FileInfo, err error) error {
368 return mark(path, info, err, &errors, clear)
369 }
370 // Expect no errors.
371 err := filepath.Walk(tree.name, markFn)
372 if err != nil {
373 t.Fatalf("no error expected, found: %s", err)
374 }
375 if len(errors) != 0 {
376 t.Fatalf("unexpected errors: %s", errors)
377 }
378 checkMarks(t, true)
379 errors = errors[0:0]
380
381 // Test permission errors. Only possible if we're not root
382 // and only on some file systems (AFS, FAT). To avoid errors during
383 // all.bash on those file systems, skip during go test -short.
384 if os.Getuid() > 0 && !testing.Short() {
385 // introduce 2 errors: chmod top-level directories to 0
386 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
387 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
388
389 // 3) capture errors, expect two.
390 // mark respective subtrees manually
391 markTree(tree.entries[1])
392 markTree(tree.entries[3])
393 // correct double-marking of directory itself
394 tree.entries[1].mark--
395 tree.entries[3].mark--
396 err := filepath.Walk(tree.name, markFn)
397 if err != nil {
398 t.Fatalf("expected no error return from Walk, got %s", err)
399 }
400 if len(errors) != 2 {
401 t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
402 }
403 // the inaccessible subtrees were marked manually
404 checkMarks(t, true)
405 errors = errors[0:0]
406
407 // 4) capture errors, stop after first error.
408 // mark respective subtrees manually
409 markTree(tree.entries[1])
410 markTree(tree.entries[3])
411 // correct double-marking of directory itself
412 tree.entries[1].mark--
413 tree.entries[3].mark--
414 clear = false // error will stop processing
415 err = filepath.Walk(tree.name, markFn)
416 if err == nil {
417 t.Fatalf("expected error return from Walk")
418 }
419 if len(errors) != 1 {
420 t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
421 }
422 // the inaccessible subtrees were marked manually
423 checkMarks(t, false)
424 errors = errors[0:0]
425
426 // restore permissions
427 os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
428 os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
429 }
430
431 // cleanup
432 if err := os.RemoveAll(tree.name); err != nil {
433 t.Errorf("removeTree: %v", err)
434 }
435 }
436
437 var basetests = []PathTest{
438 {"", "."},
439 {".", "."},
440 {"/.", "."},
441 {"/", "/"},
442 {"////", "/"},
443 {"x/", "x"},
444 {"abc", "abc"},
445 {"abc/def", "def"},
446 {"a/b/.x", ".x"},
447 {"a/b/c.", "c."},
448 {"a/b/c.x", "c.x"},
449 }
450
451 var winbasetests = []PathTest{
452 {`c:\`, `\`},
453 {`c:.`, `.`},
454 {`c:\a\b`, `b`},
455 {`c:a\b`, `b`},
456 {`c:a\b\c`, `c`},
457 {`\\host\share\`, `\`},
458 {`\\host\share\a`, `a`},
459 {`\\host\share\a\b`, `b`},
460 }
461
462 func TestBase(t *testing.T) {
463 tests := basetests
464 if runtime.GOOS == "windows" {
465 // make unix tests work on windows
466 for i := range tests {
467 tests[i].result = filepath.Clean(tests[i].result)
468 }
469 // add windows specific tests
470 tests = append(tests, winbasetests...)
471 }
472 for _, test := range tests {
473 if s := filepath.Base(test.path); s != test.result {
474 t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
475 }
476 }
477 }
478
479 var dirtests = []PathTest{
480 {"", "."},
481 {".", "."},
482 {"/.", "/"},
483 {"/", "/"},
484 {"////", "/"},
485 {"/foo", "/"},
486 {"x/", "x"},
487 {"abc", "."},
488 {"abc/def", "abc"},
489 {"a/b/.x", "a/b"},
490 {"a/b/c.", "a/b"},
491 {"a/b/c.x", "a/b"},
492 }
493
494 var windirtests = []PathTest{
495 {`c:\`, `c:\`},
496 {`c:.`, `c:.`},
497 {`c:\a\b`, `c:\a`},
498 {`c:a\b`, `c:a`},
499 {`c:a\b\c`, `c:a\b`},
500 {`\\host\share\`, `\\host\share\`},
501 {`\\host\share\a`, `\\host\share\`},
502 {`\\host\share\a\b`, `\\host\share\a`},
503 }
504
505 func TestDir(t *testing.T) {
506 tests := dirtests
507 if runtime.GOOS == "windows" {
508 // make unix tests work on windows
509 for i := range tests {
510 tests[i].result = filepath.Clean(tests[i].result)
511 }
512 // add windows specific tests
513 tests = append(tests, windirtests...)
514 }
515 for _, test := range tests {
516 if s := filepath.Dir(test.path); s != test.result {
517 t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
518 }
519 }
520 }
521
522 type IsAbsTest struct {
523 path string
524 isAbs bool
525 }
526
527 var isabstests = []IsAbsTest{
528 {"", false},
529 {"/", true},
530 {"/usr/bin/gcc", true},
531 {"..", false},
532 {"/a/../bb", true},
533 {".", false},
534 {"./", false},
535 {"lala", false},
536 }
537
538 var winisabstests = []IsAbsTest{
539 {`C:\`, true},
540 {`c\`, false},
541 {`c::`, false},
542 {`c:`, false},
543 {`/`, false},
544 {`\`, false},
545 {`\Windows`, false},
546 {`c:a\b`, false},
547 {`\\host\share\foo`, true},
548 {`//host/share/foo/bar`, true},
549 }
550
551 func TestIsAbs(t *testing.T) {
552 var tests []IsAbsTest
553 if runtime.GOOS == "windows" {
554 tests = append(tests, winisabstests...)
555 // All non-windows tests should fail, because they have no volume letter.
556 for _, test := range isabstests {
557 tests = append(tests, IsAbsTest{test.path, false})
558 }
559 // All non-windows test should work as intended if prefixed with volume letter.
560 for _, test := range isabstests {
561 tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
562 }
563 } else {
564 tests = isabstests
565 }
566
567 for _, test := range tests {
568 if r := filepath.IsAbs(test.path); r != test.isAbs {
569 t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
570 }
571 }
572 }
573
574 type EvalSymlinksTest struct {
575 // If dest is empty, the path is created; otherwise the dest is symlinked to the path.
576 path, dest string
577 }
578
579 var EvalSymlinksTestDirs = []EvalSymlinksTest{
580 {"test", ""},
581 {"test/dir", ""},
582 {"test/dir/link3", "../../"},
583 {"test/link1", "../test"},
584 {"test/link2", "dir"},
585 {"test/linkabs", "/"},
586 }
587
588 var EvalSymlinksTests = []EvalSymlinksTest{
589 {"test", "test"},
590 {"test/dir", "test/dir"},
591 {"test/dir/../..", "."},
592 {"test/link1", "test"},
593 {"test/link2", "test/dir"},
594 {"test/link1/dir", "test/dir"},
595 {"test/link2/..", "test"},
596 {"test/dir/link3", "."},
597 {"test/link2/link3/test", "test"},
598 {"test/linkabs", "/"},
599 }
600
601 var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
602 {`c:\`, `c:\`},
603 }
604
605 // simpleJoin builds a file name from the directory and path.
606 // It does not use Join because we don't want ".." to be evaluated.
607 func simpleJoin(dir, path string) string {
608 return dir + string(filepath.Separator) + path
609 }
610
611 func TestEvalSymlinks(t *testing.T) {
612 tmpDir, err := ioutil.TempDir("", "evalsymlink")
613 if err != nil {
614 t.Fatal("creating temp dir:", err)
615 }
616 defer os.RemoveAll(tmpDir)
617
618 // /tmp may itself be a symlink! Avoid the confusion, although
619 // it means trusting the thing we're testing.
620 tmpDir, err = filepath.EvalSymlinks(tmpDir)
621 if err != nil {
622 t.Fatal("eval symlink for tmp dir:", err)
623 }
624
625 // Create the symlink farm using relative paths.
626 for _, d := range EvalSymlinksTestDirs {
627 var err error
628 path := simpleJoin(tmpDir, d.path)
629 if d.dest == "" {
630 err = os.Mkdir(path, 0755)
631 } else {
632 if runtime.GOOS != "windows" {
633 err = os.Symlink(d.dest, path)
634 }
635 }
636 if err != nil {
637 t.Fatal(err)
638 }
639 }
640
641 var tests []EvalSymlinksTest
642 if runtime.GOOS == "windows" {
643 for _, d := range EvalSymlinksTests {
644 if d.path == d.dest {
645 // will test only real files and directories
646 tests = append(tests, d)
647 // test "canonical" names
648 d2 := EvalSymlinksTest{
649 path: strings.ToUpper(d.path),
650 dest: d.dest,
651 }
652 tests = append(tests, d2)
653 }
654 }
655 } else {
656 tests = EvalSymlinksTests
657 }
658
659 // Evaluate the symlink farm.
660 for _, d := range tests {
661 path := simpleJoin(tmpDir, d.path)
662 dest := simpleJoin(tmpDir, d.dest)
663 if filepath.IsAbs(d.dest) {
664 dest = d.dest
665 }
666 if p, err := filepath.EvalSymlinks(path); err != nil {
667 t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
668 } else if filepath.Clean(p) != filepath.Clean(dest) {
669 t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
670 }
671 }
672 }
673
674 // Test directories relative to temporary directory.
675 // The tests are run in absTestDirs[0].
676 var absTestDirs = []string{
677 "a",
678 "a/b",
679 "a/b/c",
680 }
681
682 // Test paths relative to temporary directory. $ expands to the directory.
683 // The tests are run in absTestDirs[0].
684 // We create absTestDirs first.
685 var absTests = []string{
686 ".",
687 "b",
688 "../a",
689 "../a/b",
690 "../a/b/./c/../../.././a",
691 "$",
692 "$/.",
693 "$/a/../a/b",
694 "$/a/b/c/../../.././a",
695 }
696
697 func TestAbs(t *testing.T) {
698 oldwd, err := os.Getwd()
699 if err != nil {
700 t.Fatal("Getwd failed: ", err)
701 }
702 defer os.Chdir(oldwd)
703
704 root, err := ioutil.TempDir("", "TestAbs")
705 if err != nil {
706 t.Fatal("TempDir failed: ", err)
707 }
708 defer os.RemoveAll(root)
709
710 wd, err := os.Getwd()
711 if err != nil {
712 t.Fatal("getwd failed: ", err)
713 }
714 err = os.Chdir(root)
715 if err != nil {
716 t.Fatal("chdir failed: ", err)
717 }
718 defer os.Chdir(wd)
719
720 for _, dir := range absTestDirs {
721 err = os.Mkdir(dir, 0777)
722 if err != nil {
723 t.Fatal("Mkdir failed: ", err)
724 }
725 }
726
727 err = os.Chdir(absTestDirs[0])
728 if err != nil {
729 t.Fatal("chdir failed: ", err)
730 }
731
732 for _, path := range absTests {
733 path = strings.Replace(path, "$", root, -1)
734 info, err := os.Stat(path)
735 if err != nil {
736 t.Errorf("%s: %s", path, err)
737 continue
738 }
739
740 abspath, err := filepath.Abs(path)
741 if err != nil {
742 t.Errorf("Abs(%q) error: %v", path, err)
743 continue
744 }
745 absinfo, err := os.Stat(abspath)
746 if err != nil || !os.SameFile(absinfo, info) {
747 t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
748 }
749 if !filepath.IsAbs(abspath) {
750 t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
751 }
752 if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
753 t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
754 }
755 }
756 }
757
758 type RelTests struct {
759 root, path, want string
760 }
761
762 var reltests = []RelTests{
763 {"a/b", "a/b", "."},
764 {"a/b/.", "a/b", "."},
765 {"a/b", "a/b/.", "."},
766 {"./a/b", "a/b", "."},
767 {"a/b", "./a/b", "."},
768 {"ab/cd", "ab/cde", "../cde"},
769 {"ab/cd", "ab/c", "../c"},
770 {"a/b", "a/b/c/d", "c/d"},
771 {"a/b", "a/b/../c", "../c"},
772 {"a/b/../c", "a/b", "../b"},
773 {"a/b/c", "a/c/d", "../../c/d"},
774 {"a/b", "c/d", "../../c/d"},
775 {"a/b/c/d", "a/b", "../.."},
776 {"a/b/c/d", "a/b/", "../.."},
777 {"a/b/c/d/", "a/b", "../.."},
778 {"a/b/c/d/", "a/b/", "../.."},
779 {"../../a/b", "../../a/b/c/d", "c/d"},
780 {"/a/b", "/a/b", "."},
781 {"/a/b/.", "/a/b", "."},
782 {"/a/b", "/a/b/.", "."},
783 {"/ab/cd", "/ab/cde", "../cde"},
784 {"/ab/cd", "/ab/c", "../c"},
785 {"/a/b", "/a/b/c/d", "c/d"},
786 {"/a/b", "/a/b/../c", "../c"},
787 {"/a/b/../c", "/a/b", "../b"},
788 {"/a/b/c", "/a/c/d", "../../c/d"},
789 {"/a/b", "/c/d", "../../c/d"},
790 {"/a/b/c/d", "/a/b", "../.."},
791 {"/a/b/c/d", "/a/b/", "../.."},
792 {"/a/b/c/d/", "/a/b", "../.."},
793 {"/a/b/c/d/", "/a/b/", "../.."},
794 {"/../../a/b", "/../../a/b/c/d", "c/d"},
795 {".", "a/b", "a/b"},
796 {".", "..", ".."},
797
798 // can't do purely lexically
799 {"..", ".", "err"},
800 {"..", "a", "err"},
801 {"../..", "..", "err"},
802 {"a", "/a", "err"},
803 {"/a", "a", "err"},
804 }
805
806 var winreltests = []RelTests{
807 {`C:a\b\c`, `C:a/b/d`, `..\d`},
808 {`C:\`, `D:\`, `err`},
809 {`C:`, `D:`, `err`},
810 }
811
812 func TestRel(t *testing.T) {
813 tests := append([]RelTests{}, reltests...)
814 if runtime.GOOS == "windows" {
815 for i := range tests {
816 tests[i].want = filepath.FromSlash(tests[i].want)
817 }
818 tests = append(tests, winreltests...)
819 }
820 for _, test := range tests {
821 got, err := filepath.Rel(test.root, test.path)
822 if test.want == "err" {
823 if err == nil {
824 t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got)
825 }
826 continue
827 }
828 if err != nil {
829 t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err)
830 }
831 if got != test.want {
832 t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want)
833 }
834 }
835 }
836
837 type VolumeNameTest struct {
838 path string
839 vol string
840 }
841
842 var volumenametests = []VolumeNameTest{
843 {`c:/foo/bar`, `c:`},
844 {`c:`, `c:`},
845 {`2:`, ``},
846 {``, ``},
847 {`\\\host`, ``},
848 {`\\\host\`, ``},
849 {`\\\host\share`, ``},
850 {`\\\host\\share`, ``},
851 {`\\host`, ``},
852 {`//host`, ``},
853 {`\\host\`, ``},
854 {`//host/`, ``},
855 {`\\host\share`, `\\host\share`},
856 {`//host/share`, `//host/share`},
857 {`\\host\share\`, `\\host\share`},
858 {`//host/share/`, `//host/share`},
859 {`\\host\share\foo`, `\\host\share`},
860 {`//host/share/foo`, `//host/share`},
861 {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
862 {`//host/share//foo///bar////baz`, `//host/share`},
863 {`\\host\share\foo\..\bar`, `\\host\share`},
864 {`//host/share/foo/../bar`, `//host/share`},
865 }
866
867 func TestVolumeName(t *testing.T) {
868 if runtime.GOOS != "windows" {
869 return
870 }
871 for _, v := range volumenametests {
872 if vol := filepath.VolumeName(v.path); vol != v.vol {
873 t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol)
874 }
875 }
876 }
877
878 func TestDriveLetterInEvalSymlinks(t *testing.T) {
879 if runtime.GOOS != "windows" {
880 return
881 }
882 wd, _ := os.Getwd()
883 if len(wd) < 3 {
884 t.Errorf("Current directory path %q is too short", wd)
885 }
886 lp := strings.ToLower(wd)
887 up := strings.ToUpper(wd)
888 flp, err := filepath.EvalSymlinks(lp)
889 if err != nil {
890 t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err)
891 }
892 fup, err := filepath.EvalSymlinks(up)
893 if err != nil {
894 t.Fatalf("EvalSymlinks(%q) failed: %q", up, err)
895 }
896 if flp != fup {
897 t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup)
898 }
899 }
900
901 /* This test does not work gccgo, since the sources are arranged
902 differently.
903
904 func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
905 root, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
906 if err != nil {
907 t.Fatal(err)
908 }
909 lib := filepath.Join(root, "lib")
910 src := filepath.Join(root, "src")
911 seenSrc := false
912 filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
913 if err != nil {
914 t.Fatal(err)
915 }
916
917 switch pth {
918 case lib:
919 return filepath.SkipDir
920 case src:
921 seenSrc = true
922 }
923 return nil
924 })
925 if !seenSrc {
926 t.Fatalf("%q not seen", src)
927 }
928 }
929
930 */