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  }