| // Copyright 2020 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 ( |
| . "io/fs" |
| "io/ioutil" |
| "os" |
| pathpkg "path" |
| "runtime" |
| "testing" |
| "testing/fstest" |
| ) |
| |
| 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, pathpkg.Join(path, e.name), f) |
| } |
| } |
| |
| func makeTree(t *testing.T) FS { |
| fsys := fstest.MapFS{} |
| walkTree(tree, tree.name, func(path string, n *Node) { |
| if n.entries == nil { |
| fsys[path] = &fstest.MapFile{} |
| } else { |
| fsys[path] = &fstest.MapFile{Mode: ModeDir} |
| } |
| }) |
| return fsys |
| } |
| |
| 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(entry DirEntry, err error, errors *[]error, clear bool) error { |
| name := entry.Name() |
| walkTree(tree, tree.name, func(path string, n *Node) { |
| if n.name == name { |
| n.mark++ |
| } |
| }) |
| if err != nil { |
| *errors = append(*errors, err) |
| if clear { |
| return nil |
| } |
| return err |
| } |
| return nil |
| } |
| |
| func chtmpdir(t *testing.T) (restore func()) { |
| oldwd, err := os.Getwd() |
| if err != nil { |
| t.Fatalf("chtmpdir: %v", err) |
| } |
| d, err := ioutil.TempDir("", "test") |
| if err != nil { |
| t.Fatalf("chtmpdir: %v", err) |
| } |
| if err := os.Chdir(d); err != nil { |
| t.Fatalf("chtmpdir: %v", err) |
| } |
| return func() { |
| if err := os.Chdir(oldwd); err != nil { |
| t.Fatalf("chtmpdir: %v", err) |
| } |
| os.RemoveAll(d) |
| } |
| } |
| |
| func TestWalkDir(t *testing.T) { |
| if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { |
| restore := chtmpdir(t) |
| defer restore() |
| } |
| |
| tmpDir, err := ioutil.TempDir("", "TestWalk") |
| if err != nil { |
| t.Fatal("creating temp dir:", err) |
| } |
| defer os.RemoveAll(tmpDir) |
| |
| origDir, err := os.Getwd() |
| if err != nil { |
| t.Fatal("finding working dir:", err) |
| } |
| if err = os.Chdir(tmpDir); err != nil { |
| t.Fatal("entering temp dir:", err) |
| } |
| defer os.Chdir(origDir) |
| |
| fsys := makeTree(t) |
| errors := make([]error, 0, 10) |
| clear := true |
| markFn := func(path string, entry DirEntry, err error) error { |
| return mark(entry, err, &errors, clear) |
| } |
| // Expect no errors. |
| err = WalkDir(fsys, ".", markFn) |
| if err != nil { |
| t.Fatalf("no error expected, found: %s", err) |
| } |
| if len(errors) != 0 { |
| t.Fatalf("unexpected errors: %s", errors) |
| } |
| checkMarks(t, true) |
| } |