2009-04-07 01:40:07 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package path
|
|
|
|
|
|
|
|
import (
|
2009-10-19 12:48:04 -06:00
|
|
|
"os";
|
2009-10-08 16:14:54 -06:00
|
|
|
"testing";
|
2009-04-07 01:40:07 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type CleanTest struct {
|
2009-10-08 16:14:54 -06:00
|
|
|
path, clean string;
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var cleantests = []CleanTest{
|
2009-04-07 01:40:07 -06:00
|
|
|
// Already clean
|
|
|
|
CleanTest{"", "."},
|
|
|
|
CleanTest{"abc", "abc"},
|
|
|
|
CleanTest{"abc/def", "abc/def"},
|
|
|
|
CleanTest{"a/b/c", "a/b/c"},
|
|
|
|
CleanTest{".", "."},
|
|
|
|
CleanTest{"..", ".."},
|
|
|
|
CleanTest{"../..", "../.."},
|
|
|
|
CleanTest{"../../abc", "../../abc"},
|
|
|
|
CleanTest{"/abc", "/abc"},
|
|
|
|
CleanTest{"/", "/"},
|
|
|
|
|
|
|
|
// Remove trailing slash
|
|
|
|
CleanTest{"abc/", "abc"},
|
|
|
|
CleanTest{"abc/def/", "abc/def"},
|
|
|
|
CleanTest{"a/b/c/", "a/b/c"},
|
|
|
|
CleanTest{"./", "."},
|
|
|
|
CleanTest{"../", ".."},
|
|
|
|
CleanTest{"../../", "../.."},
|
|
|
|
CleanTest{"/abc/", "/abc"},
|
|
|
|
|
|
|
|
// Remove doubled slash
|
|
|
|
CleanTest{"abc//def//ghi", "abc/def/ghi"},
|
|
|
|
CleanTest{"//abc", "/abc"},
|
|
|
|
CleanTest{"///abc", "/abc"},
|
|
|
|
CleanTest{"//abc//", "/abc"},
|
|
|
|
CleanTest{"abc//", "abc"},
|
|
|
|
|
|
|
|
// Remove . elements
|
|
|
|
CleanTest{"abc/./def", "abc/def"},
|
|
|
|
CleanTest{"/./abc/def", "/abc/def"},
|
|
|
|
CleanTest{"abc/.", "abc"},
|
|
|
|
|
|
|
|
// Remove .. elements
|
|
|
|
CleanTest{"abc/def/ghi/../jkl", "abc/def/jkl"},
|
|
|
|
CleanTest{"abc/def/../ghi/../jkl", "abc/jkl"},
|
|
|
|
CleanTest{"abc/def/..", "abc"},
|
|
|
|
CleanTest{"abc/def/../..", "."},
|
|
|
|
CleanTest{"/abc/def/../..", "/"},
|
|
|
|
CleanTest{"abc/def/../../..", ".."},
|
|
|
|
CleanTest{"/abc/def/../../..", "/"},
|
|
|
|
CleanTest{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
|
|
|
|
|
|
|
|
// Combinations
|
|
|
|
CleanTest{"abc/./../def", "def"},
|
|
|
|
CleanTest{"abc//./../def", "def"},
|
|
|
|
CleanTest{"abc/../../././../def", "../../def"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestClean(t *testing.T) {
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, test := range cleantests {
|
2009-04-07 01:40:07 -06:00
|
|
|
if s := Clean(test.path); s != test.clean {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type SplitTest struct {
|
2009-10-08 16:14:54 -06:00
|
|
|
path, dir, file string;
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var splittests = []SplitTest{
|
2009-04-07 01:40:07 -06:00
|
|
|
SplitTest{"a/b", "a/", "b"},
|
|
|
|
SplitTest{"a/b/", "a/b/", ""},
|
|
|
|
SplitTest{"a/", "a/", ""},
|
|
|
|
SplitTest{"a", "", "a"},
|
|
|
|
SplitTest{"/", "/", ""},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSplit(t *testing.T) {
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, test := range splittests {
|
2009-04-07 01:40:07 -06:00
|
|
|
if d, f := Split(test.path); d != test.dir || f != test.file {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type JoinTest struct {
|
2009-10-08 16:14:54 -06:00
|
|
|
dir, file, path string;
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var jointests = []JoinTest{
|
2009-04-07 01:40:07 -06:00
|
|
|
JoinTest{"a", "b", "a/b"},
|
2009-04-07 22:53:39 -06:00
|
|
|
JoinTest{"a", "", "a"},
|
2009-04-07 01:40:07 -06:00
|
|
|
JoinTest{"", "b", "b"},
|
|
|
|
JoinTest{"/", "a", "/a"},
|
|
|
|
JoinTest{"/", "", "/"},
|
|
|
|
JoinTest{"a/", "b", "a/b"},
|
2009-04-07 22:53:39 -06:00
|
|
|
JoinTest{"a/", "", "a"},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestJoin(t *testing.T) {
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, test := range jointests {
|
2009-04-07 22:53:39 -06:00
|
|
|
if p := Join(test.dir, test.file); p != test.path {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Join(%q, %q) = %q, want %q", test.dir, test.file, p, test.path)
|
2009-04-07 22:53:39 -06:00
|
|
|
}
|
|
|
|
}
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type ExtTest struct {
|
2009-10-08 16:14:54 -06:00
|
|
|
path, ext string;
|
2009-04-07 01:40:07 -06:00
|
|
|
}
|
|
|
|
|
2009-10-08 16:14:54 -06:00
|
|
|
var exttests = []ExtTest{
|
2009-04-07 01:40:07 -06:00
|
|
|
ExtTest{"path.go", ".go"},
|
|
|
|
ExtTest{"path.pb.go", ".go"},
|
|
|
|
ExtTest{"a.dir/b", ""},
|
|
|
|
ExtTest{"a.dir/b.go", ".go"},
|
|
|
|
ExtTest{"a.dir/", ""},
|
|
|
|
}
|
2009-04-07 22:53:39 -06:00
|
|
|
|
|
|
|
func TestExt(t *testing.T) {
|
2009-09-15 10:41:59 -06:00
|
|
|
for _, test := range exttests {
|
2009-04-07 22:53:39 -06:00
|
|
|
if x := Ext(test.path); x != test.ext {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
|
2009-04-07 22:53:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-19 12:48:04 -06:00
|
|
|
|
|
|
|
type Node struct {
|
2009-10-27 23:47:54 -06:00
|
|
|
name string;
|
|
|
|
entries []*Node; // nil if the entry is a file
|
|
|
|
mark int;
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
var tree = &Node{
|
|
|
|
"testdata",
|
|
|
|
[]*Node{
|
|
|
|
&Node{"a", nil, 0},
|
|
|
|
&Node{"b", []*Node{}, 0},
|
|
|
|
&Node{"c", nil, 0},
|
|
|
|
&Node{
|
|
|
|
"d",
|
|
|
|
[]*Node{
|
|
|
|
&Node{"x", nil, 0},
|
|
|
|
&Node{"y", []*Node{}, 0},
|
|
|
|
&Node{
|
|
|
|
"z",
|
|
|
|
[]*Node{
|
|
|
|
&Node{"u", nil, 0},
|
|
|
|
&Node{"v", nil, 0},
|
|
|
|
},
|
2009-10-27 23:47:54 -06:00
|
|
|
0,
|
|
|
|
},
|
2009-10-19 12:48:04 -06:00
|
|
|
},
|
2009-10-27 23:47:54 -06:00
|
|
|
0,
|
|
|
|
},
|
2009-10-19 12:48:04 -06:00
|
|
|
},
|
2009-10-27 23:47:54 -06:00
|
|
|
0,
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func walkTree(n *Node, path string, f func(path string, n *Node)) {
|
|
|
|
f(path, n);
|
|
|
|
for _, e := range n.entries {
|
2009-11-09 13:07:39 -07:00
|
|
|
walkTree(e, Join(path, e.name), f)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeTree(t *testing.T) {
|
|
|
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
|
|
|
if n.entries == nil {
|
|
|
|
fd, err := os.Open(path, os.O_CREAT, 0660);
|
|
|
|
if err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("makeTree: %v", err)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
fd.Close();
|
|
|
|
} else {
|
2009-11-09 13:07:39 -07:00
|
|
|
os.Mkdir(path, 0770)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
2009-11-09 13:07:39 -07:00
|
|
|
})
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
2009-11-06 15:24:38 -07:00
|
|
|
func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
|
2009-10-19 12:48:04 -06:00
|
|
|
|
|
|
|
func checkMarks(t *testing.T) {
|
|
|
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
|
|
|
if n.mark != 1 {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("node %s mark = %d; expected 1", path, n.mark)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
n.mark = 0;
|
2009-11-09 13:07:39 -07:00
|
|
|
})
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Assumes that each node name is unique. Good enough for a test.
|
|
|
|
func mark(name string) {
|
|
|
|
walkTree(tree, tree.name, func(path string, n *Node) {
|
|
|
|
if n.name == name {
|
2009-11-09 13:07:39 -07:00
|
|
|
n.mark++
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
2009-11-09 13:07:39 -07:00
|
|
|
})
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
2009-10-27 23:47:54 -06:00
|
|
|
type TestVisitor struct{}
|
2009-10-19 12:48:04 -06:00
|
|
|
|
|
|
|
func (v *TestVisitor) VisitDir(path string, d *os.Dir) bool {
|
|
|
|
mark(d.Name);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *TestVisitor) VisitFile(path string, d *os.Dir) {
|
2009-11-09 13:07:39 -07:00
|
|
|
mark(d.Name)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestWalk(t *testing.T) {
|
|
|
|
makeTree(t);
|
|
|
|
|
|
|
|
// 1) ignore error handling, expect none
|
|
|
|
v := &TestVisitor{};
|
|
|
|
Walk(tree.name, v, nil);
|
|
|
|
checkMarks(t);
|
|
|
|
|
|
|
|
// 2) handle errors, expect none
|
|
|
|
errors := make(chan os.Error, 64);
|
|
|
|
Walk(tree.name, v, errors);
|
|
|
|
if err, ok := <-errors; ok {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("no error expected, found: s", err)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
checkMarks(t);
|
|
|
|
|
2009-11-13 12:34:33 -07:00
|
|
|
if os.Getuid() != 0 {
|
|
|
|
// introduce 2 errors: chmod top-level directories to 0
|
|
|
|
os.Chmod(Join(tree.name, tree.entries[1].name), 0);
|
|
|
|
os.Chmod(Join(tree.name, tree.entries[3].name), 0);
|
|
|
|
// mark respective subtrees manually
|
|
|
|
markTree(tree.entries[1]);
|
|
|
|
markTree(tree.entries[3]);
|
|
|
|
// correct double-marking of directory itself
|
|
|
|
tree.entries[1].mark--;
|
|
|
|
tree.entries[3].mark--;
|
|
|
|
|
|
|
|
// 3) handle errors, expect two
|
|
|
|
errors = make(chan os.Error, 64);
|
|
|
|
os.Chmod(Join(tree.name, tree.entries[1].name), 0);
|
|
|
|
Walk(tree.name, v, errors);
|
|
|
|
for i := 1; i <= 2; i++ {
|
|
|
|
if _, ok := <-errors; !ok {
|
|
|
|
t.Errorf("%d. error expected, none found", i);
|
|
|
|
break;
|
|
|
|
}
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
2009-11-13 12:34:33 -07:00
|
|
|
if err, ok := <-errors; ok {
|
|
|
|
t.Errorf("only two errors expected, found 3rd: %v", err)
|
|
|
|
}
|
|
|
|
// the inaccessible subtrees were marked manually
|
|
|
|
checkMarks(t);
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
os.Chmod(Join(tree.name, tree.entries[1].name), 0770);
|
|
|
|
os.Chmod(Join(tree.name, tree.entries[3].name), 0770);
|
|
|
|
if err := os.RemoveAll(tree.name); err != nil {
|
2009-11-09 13:07:39 -07:00
|
|
|
t.Errorf("removeTree: %v", err)
|
2009-10-19 12:48:04 -06:00
|
|
|
}
|
|
|
|
}
|