Source file src/io/fs/walk_test.go

     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  	"slices"
    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() 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  // Assumes that each node name is unique. Good enough for a test.
    69  // If clear is true, any incoming error is cleared before return. The errors
    70  // are always accumulated, though.
    71  func mark(entry DirEntry, err error, errors *[]error, clear bool) error {
    72  	name := entry.Name()
    73  	walkTree(tree, tree.name, func(path string, n *Node) {
    74  		if n.name == name {
    75  			n.mark++
    76  		}
    77  	})
    78  	if err != nil {
    79  		*errors = append(*errors, err)
    80  		if clear {
    81  			return nil
    82  		}
    83  		return err
    84  	}
    85  	return nil
    86  }
    87  
    88  func TestWalkDir(t *testing.T) {
    89  	t.Chdir(t.TempDir())
    90  
    91  	fsys := makeTree()
    92  	errors := make([]error, 0, 10)
    93  	clear := true
    94  	markFn := func(path string, entry DirEntry, err error) error {
    95  		return mark(entry, err, &errors, clear)
    96  	}
    97  	// Expect no errors.
    98  	err := WalkDir(fsys, ".", markFn)
    99  	if err != nil {
   100  		t.Fatalf("no error expected, found: %s", err)
   101  	}
   102  	if len(errors) != 0 {
   103  		t.Fatalf("unexpected errors: %s", errors)
   104  	}
   105  	walkTree(tree, tree.name, func(path string, n *Node) {
   106  		if n.mark != 1 {
   107  			t.Errorf("node %s mark = %d; expected 1", path, n.mark)
   108  		}
   109  		n.mark = 0
   110  	})
   111  }
   112  
   113  func TestIssue51617(t *testing.T) {
   114  	dir := t.TempDir()
   115  	for _, sub := range []string{"a", filepath.Join("a", "bad"), filepath.Join("a", "next")} {
   116  		if err := os.Mkdir(filepath.Join(dir, sub), 0755); err != nil {
   117  			t.Fatal(err)
   118  		}
   119  	}
   120  	bad := filepath.Join(dir, "a", "bad")
   121  	if err := os.Chmod(bad, 0); err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	defer os.Chmod(bad, 0700) // avoid errors on cleanup
   125  	var saw []string
   126  	err := WalkDir(os.DirFS(dir), ".", func(path string, d DirEntry, err error) error {
   127  		if err != nil {
   128  			return filepath.SkipDir
   129  		}
   130  		if d.IsDir() {
   131  			saw = append(saw, path)
   132  		}
   133  		return nil
   134  	})
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  	want := []string{".", "a", "a/bad", "a/next"}
   139  	if !slices.Equal(saw, want) {
   140  		t.Errorf("got directories %v, want %v", saw, want)
   141  	}
   142  }
   143  

View as plain text