mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
directory tree walk w/ visitor per rsc's suggestion
R=rsc,r DELTA=193 (191 added, 0 deleted, 2 changed) OCL=35849 CL=35877
This commit is contained in:
parent
e32883df01
commit
4adad657de
3 changed files with 193 additions and 2 deletions
|
|
@ -5,6 +5,7 @@
|
|||
package path
|
||||
|
||||
import (
|
||||
"os";
|
||||
"testing";
|
||||
)
|
||||
|
||||
|
|
@ -131,3 +132,141 @@ func TestExt(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
name string;
|
||||
entries []*Node; // nil if the entry is a file
|
||||
mark int;
|
||||
}
|
||||
|
||||
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},
|
||||
},
|
||||
0
|
||||
}
|
||||
},
|
||||
0
|
||||
}
|
||||
},
|
||||
0
|
||||
}
|
||||
|
||||
func walkTree(n *Node, path string, f func(path string, n *Node)) {
|
||||
f(path, n);
|
||||
for _, e := range n.entries {
|
||||
walkTree(e, Join(path, e.name), f);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Errorf("makeTree: %v", err);
|
||||
}
|
||||
fd.Close();
|
||||
} else {
|
||||
os.Mkdir(path, 0770);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
func markTree(n *Node) {
|
||||
walkTree(n, "", func(path string, n *Node) {
|
||||
n.mark++;
|
||||
});
|
||||
}
|
||||
|
||||
func checkMarks(t *testing.T) {
|
||||
walkTree(tree, tree.name, func(path string, n *Node) {
|
||||
if n.mark != 1 {
|
||||
t.Errorf("node %s mark = %d; expected 1", path, n.mark);
|
||||
}
|
||||
n.mark = 0;
|
||||
});
|
||||
}
|
||||
|
||||
// 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 {
|
||||
n.mark++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
type TestVisitor struct {}
|
||||
|
||||
func (v *TestVisitor) VisitDir(path string, d *os.Dir) bool {
|
||||
mark(d.Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
func (v *TestVisitor) VisitFile(path string, d *os.Dir) {
|
||||
mark(d.Name);
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Errorf("no error expected, found: s", err);
|
||||
}
|
||||
checkMarks(t);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
if err, ok := <-errors; ok {
|
||||
t.Errorf("only two errors expected, found 3rd: %v", err);
|
||||
}
|
||||
// the inaccessible subtrees were marked manually
|
||||
checkMarks(t);
|
||||
|
||||
// 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 {
|
||||
t.Errorf("removeTree: %v", err);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue