| // 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 fs_test |
| |
| import ( |
| "os" |
| "path/filepath" |
| "runtime" |
| "testing" |
| |
| "github.com/kr/fs" |
| ) |
| |
| type PathTest struct { |
| path, result string |
| } |
| |
| type Node struct { |
| name string |
| entries []*Node // nil if the entry is a file |
| mark int |
| } |
| |
| var tree = &Node{ |
| "testdata", |
| []*Node{ |
| {"a", nil, 0}, |
| {"b", []*Node{}, 0}, |
| {"c", nil, 0}, |
| { |
| "d", |
| []*Node{ |
| {"x", nil, 0}, |
| {"y", []*Node{}, 0}, |
| { |
| "z", |
| []*Node{ |
| {"u", nil, 0}, |
| {"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, filepath.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.Create(path) |
| if err != nil { |
| t.Errorf("makeTree: %v", err) |
| return |
| } |
| 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, report bool) { |
| walkTree(tree, tree.name, func(path string, n *Node) { |
| if n.mark != 1 && report { |
| 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. |
| // If clear is true, any incoming error is cleared before return. The errors |
| // are always accumulated, though. |
| func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error { |
| if err != nil { |
| *errors = append(*errors, err) |
| if clear { |
| return nil |
| } |
| return err |
| } |
| name := info.Name() |
| walkTree(tree, tree.name, func(path string, n *Node) { |
| if n.name == name { |
| n.mark++ |
| } |
| }) |
| return nil |
| } |
| |
| func TestWalk(t *testing.T) { |
| makeTree(t) |
| errors := make([]error, 0, 10) |
| clear := true |
| markFn := func(walker *fs.Walker) (err error) { |
| for walker.Step() { |
| err = mark(walker.Path(), walker.Stat(), walker.Err(), &errors, clear) |
| if err != nil { |
| break |
| } |
| } |
| return err |
| } |
| // Expect no errors. |
| err := markFn(fs.Walk(tree.name)) |
| if err != nil { |
| t.Fatalf("no error expected, found: %s", err) |
| } |
| if len(errors) != 0 { |
| t.Fatalf("unexpected errors: %s", errors) |
| } |
| checkMarks(t, true) |
| errors = errors[0:0] |
| |
| // Test permission errors. Only possible if we're not root |
| // and only on some file systems (AFS, FAT). To avoid errors during |
| // all.bash on those file systems, skip during go test -short. |
| if os.Getuid() > 0 && !testing.Short() { |
| // introduce 2 errors: chmod top-level directories to 0 |
| os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0) |
| os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0) |
| |
| // 3) capture errors, expect two. |
| // 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-- |
| err := markFn(fs.Walk(tree.name)) |
| if err != nil { |
| t.Fatalf("expected no error return from Walk, got %s", err) |
| } |
| if len(errors) != 2 { |
| t.Errorf("expected 2 errors, got %d: %s", len(errors), errors) |
| } |
| // the inaccessible subtrees were marked manually |
| checkMarks(t, true) |
| errors = errors[0:0] |
| |
| // 4) capture errors, stop after first error. |
| // 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-- |
| clear = false // error will stop processing |
| err = markFn(fs.Walk(tree.name)) |
| if err == nil { |
| t.Fatalf("expected error return from Walk") |
| } |
| if len(errors) != 1 { |
| t.Errorf("expected 1 error, got %d: %s", len(errors), errors) |
| } |
| // the inaccessible subtrees were marked manually |
| checkMarks(t, false) |
| errors = errors[0:0] |
| |
| // restore permissions |
| os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770) |
| os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770) |
| } |
| |
| // cleanup |
| if err := os.RemoveAll(tree.name); err != nil { |
| t.Errorf("removeTree: %v", err) |
| } |
| } |
| |
| func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486 |
| root, err := filepath.EvalSymlinks(runtime.GOROOT()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| lib := filepath.Join(root, "lib") |
| src := filepath.Join(root, "src") |
| seenSrc := false |
| walker := fs.Walk(root) |
| for walker.Step() { |
| if walker.Err() != nil { |
| t.Fatal(walker.Err()) |
| } |
| |
| switch walker.Path() { |
| case lib: |
| walker.SkipDir() |
| case src: |
| seenSrc = true |
| } |
| } |
| if !seenSrc { |
| t.Fatalf("%q not seen", src) |
| } |
| } |