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  	"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() 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  	tmpDir := t.TempDir()
    90  
    91  	origDir, err := os.Getwd()
    92  	if err != nil {
    93  		t.Fatal("finding working dir:", err)
    94  	}
    95  	if err = os.Chdir(tmpDir); err != nil {
    96  		t.Fatal("entering temp dir:", err)
    97  	}
    98  	defer os.Chdir(origDir)
    99  
   100  	fsys := makeTree()
   101  	errors := make([]error, 0, 10)
   102  	clear := true
   103  	markFn := func(path string, entry DirEntry, err error) error {
   104  		return mark(entry, err, &errors, clear)
   105  	}
   106  	// Expect no errors.
   107  	err = WalkDir(fsys, ".", markFn)
   108  	if err != nil {
   109  		t.Fatalf("no error expected, found: %s", err)
   110  	}
   111  	if len(errors) != 0 {
   112  		t.Fatalf("unexpected errors: %s", errors)
   113  	}
   114  	walkTree(tree, tree.name, func(path string, n *Node) {
   115  		if n.mark != 1 {
   116  			t.Errorf("node %s mark = %d; expected 1", path, n.mark)
   117  		}
   118  		n.mark = 0
   119  	})
   120  }
   121  
   122  func TestIssue51617(t *testing.T) {
   123  	dir := t.TempDir()
   124  	for _, sub := range []string{"a", filepath.Join("a", "bad"), filepath.Join("a", "next")} {
   125  		if err := os.Mkdir(filepath.Join(dir, sub), 0755); err != nil {
   126  			t.Fatal(err)
   127  		}
   128  	}
   129  	bad := filepath.Join(dir, "a", "bad")
   130  	if err := os.Chmod(bad, 0); err != nil {
   131  		t.Fatal(err)
   132  	}
   133  	defer os.Chmod(bad, 0700) // avoid errors on cleanup
   134  	var saw []string
   135  	err := WalkDir(os.DirFS(dir), ".", func(path string, d DirEntry, err error) error {
   136  		if err != nil {
   137  			return filepath.SkipDir
   138  		}
   139  		if d.IsDir() {
   140  			saw = append(saw, path)
   141  		}
   142  		return nil
   143  	})
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  	want := []string{".", "a", "a/bad", "a/next"}
   148  	if !reflect.DeepEqual(saw, want) {
   149  		t.Errorf("got directories %v, want %v", saw, want)
   150  	}
   151  }
   152  

View as plain text