github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/io/fs/walk_test.go (about) 1 // Copyright 2020 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 fs_test 6 7 import ( 8 . "io/fs" 9 "os" 10 pathpkg "path" 11 "path/filepath" 12 "reflect" 13 "testing" 14 "testing/fstest" 15 ) 16 17 type Node struct { 18 name string 19 entries []*Node // nil if the entry is a file 20 mark int 21 } 22 23 var tree = &Node{ 24 "testdata", 25 []*Node{ 26 {"a", nil, 0}, 27 {"b", []*Node{}, 0}, 28 {"c", nil, 0}, 29 { 30 "d", 31 []*Node{ 32 {"x", nil, 0}, 33 {"y", []*Node{}, 0}, 34 { 35 "z", 36 []*Node{ 37 {"u", nil, 0}, 38 {"v", nil, 0}, 39 }, 40 0, 41 }, 42 }, 43 0, 44 }, 45 }, 46 0, 47 } 48 49 func walkTree(n *Node, path string, f func(path string, n *Node)) { 50 f(path, n) 51 for _, e := range n.entries { 52 walkTree(e, pathpkg.Join(path, e.name), f) 53 } 54 } 55 56 func makeTree(t *testing.T) FS { 57 fsys := fstest.MapFS{} 58 walkTree(tree, tree.name, func(path string, n *Node) { 59 if n.entries == nil { 60 fsys[path] = &fstest.MapFile{} 61 } else { 62 fsys[path] = &fstest.MapFile{Mode: ModeDir} 63 } 64 }) 65 return fsys 66 } 67 68 func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } 69 70 func checkMarks(t *testing.T, report bool) { 71 walkTree(tree, tree.name, func(path string, n *Node) { 72 if n.mark != 1 && report { 73 t.Errorf("node %s mark = %d; expected 1", path, n.mark) 74 } 75 n.mark = 0 76 }) 77 } 78 79 // Assumes that each node name is unique. Good enough for a test. 80 // If clear is true, any incoming error is cleared before return. The errors 81 // are always accumulated, though. 82 func mark(entry DirEntry, err error, errors *[]error, clear bool) error { 83 name := entry.Name() 84 walkTree(tree, tree.name, func(path string, n *Node) { 85 if n.name == name { 86 n.mark++ 87 } 88 }) 89 if err != nil { 90 *errors = append(*errors, err) 91 if clear { 92 return nil 93 } 94 return err 95 } 96 return nil 97 } 98 99 func TestWalkDir(t *testing.T) { 100 tmpDir := t.TempDir() 101 102 origDir, err := os.Getwd() 103 if err != nil { 104 t.Fatal("finding working dir:", err) 105 } 106 if err = os.Chdir(tmpDir); err != nil { 107 t.Fatal("entering temp dir:", err) 108 } 109 defer os.Chdir(origDir) 110 111 fsys := makeTree(t) 112 errors := make([]error, 0, 10) 113 clear := true 114 markFn := func(path string, entry DirEntry, err error) error { 115 return mark(entry, err, &errors, clear) 116 } 117 // Expect no errors. 118 err = WalkDir(fsys, ".", markFn) 119 if err != nil { 120 t.Fatalf("no error expected, found: %s", err) 121 } 122 if len(errors) != 0 { 123 t.Fatalf("unexpected errors: %s", errors) 124 } 125 checkMarks(t, true) 126 } 127 128 func TestIssue51617(t *testing.T) { 129 dir := t.TempDir() 130 for _, sub := range []string{"a", filepath.Join("a", "bad"), filepath.Join("a", "next")} { 131 if err := os.Mkdir(filepath.Join(dir, sub), 0755); err != nil { 132 t.Fatal(err) 133 } 134 } 135 bad := filepath.Join(dir, "a", "bad") 136 if err := os.Chmod(bad, 0); err != nil { 137 t.Fatal(err) 138 } 139 defer os.Chmod(bad, 0700) // avoid errors on cleanup 140 var saw []string 141 err := WalkDir(os.DirFS(dir), ".", func(path string, d DirEntry, err error) error { 142 if err != nil { 143 return filepath.SkipDir 144 } 145 if d.IsDir() { 146 saw = append(saw, path) 147 } 148 return nil 149 }) 150 if err != nil { 151 t.Fatal(err) 152 } 153 want := []string{".", "a", "a/bad", "a/next"} 154 if !reflect.DeepEqual(saw, want) { 155 t.Errorf("got directories %v, want %v", saw, want) 156 } 157 }