Source file src/os/file_test.go

     1  // Copyright 2023 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 os_test
     6  
     7  import (
     8  	"internal/testenv"
     9  	"io/fs"
    10  	. "os"
    11  	"path/filepath"
    12  	"testing"
    13  )
    14  
    15  func TestDirFSReadLink(t *testing.T) {
    16  	testenv.MustHaveSymlink(t)
    17  
    18  	root := t.TempDir()
    19  	subdir := filepath.Join(root, "dir")
    20  	if err := Mkdir(subdir, 0o777); err != nil {
    21  		t.Fatal(err)
    22  	}
    23  	links := map[string]string{
    24  		filepath.Join(root, "parent-link"):        filepath.Join("..", "foo"),
    25  		filepath.Join(root, "sneaky-parent-link"): filepath.Join("dir", "..", "..", "foo"),
    26  		filepath.Join(root, "abs-link"):           filepath.Join(root, "foo"),
    27  		filepath.Join(root, "rel-link"):           "foo",
    28  		filepath.Join(root, "rel-sub-link"):       filepath.Join("dir", "foo"),
    29  		filepath.Join(subdir, "parent-link"):      filepath.Join("..", "foo"),
    30  	}
    31  	for newname, oldname := range links {
    32  		if err := Symlink(oldname, newname); err != nil {
    33  			t.Fatal(err)
    34  		}
    35  	}
    36  
    37  	fsys := DirFS(root)
    38  	want := map[string]string{
    39  		"rel-link":           "foo",
    40  		"rel-sub-link":       filepath.Join("dir", "foo"),
    41  		"dir/parent-link":    filepath.Join("..", "foo"),
    42  		"parent-link":        filepath.Join("..", "foo"),
    43  		"sneaky-parent-link": filepath.Join("dir", "..", "..", "foo"),
    44  		"abs-link":           filepath.Join(root, "foo"),
    45  	}
    46  	for name, want := range want {
    47  		got, err := fs.ReadLink(fsys, name)
    48  		if got != want || err != nil {
    49  			t.Errorf("fs.ReadLink(fsys, %q) = %q, %v; want %q, <nil>", name, got, err, want)
    50  		}
    51  	}
    52  }
    53  
    54  func TestDirFSLstat(t *testing.T) {
    55  	testenv.MustHaveSymlink(t)
    56  
    57  	root := t.TempDir()
    58  	subdir := filepath.Join(root, "dir")
    59  	if err := Mkdir(subdir, 0o777); err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	fsys := DirFS(root)
    67  	want := map[string]fs.FileMode{
    68  		"link": fs.ModeSymlink,
    69  		"dir":  fs.ModeDir,
    70  	}
    71  	for name, want := range want {
    72  		info, err := fs.Lstat(fsys, name)
    73  		var got fs.FileMode
    74  		if info != nil {
    75  			got = info.Mode().Type()
    76  		}
    77  		if got != want || err != nil {
    78  			t.Errorf("fs.Lstat(fsys, %q).Mode().Type() = %v, %v; want %v, <nil>", name, got, err, want)
    79  		}
    80  	}
    81  }
    82  
    83  func TestDirFSWalkDir(t *testing.T) {
    84  	testenv.MustHaveSymlink(t)
    85  
    86  	root := t.TempDir()
    87  	subdir := filepath.Join(root, "dir")
    88  	if err := Mkdir(subdir, 0o777); err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	if err := WriteFile(filepath.Join(root, "dir", "a"), nil, 0o666); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	fsys := DirFS(root)
    98  
    99  	t.Run("SymlinkRoot", func(t *testing.T) {
   100  		wantTypes := map[string]fs.FileMode{
   101  			"link":   fs.ModeDir,
   102  			"link/a": 0,
   103  		}
   104  		marks := make(map[string]int)
   105  		err := fs.WalkDir(fsys, "link", func(path string, entry fs.DirEntry, err error) error {
   106  			marks[path]++
   107  			if want, ok := wantTypes[path]; !ok {
   108  				t.Errorf("Unexpected path %q in walk", path)
   109  			} else if got := entry.Type(); got != want {
   110  				t.Errorf("%s entry type = %v; want %v", path, got, want)
   111  			}
   112  			if err != nil {
   113  				t.Errorf("%s: %v", path, err)
   114  			}
   115  			return nil
   116  		})
   117  		if err != nil {
   118  			t.Fatal(err)
   119  		}
   120  		for path := range wantTypes {
   121  			if got := marks[path]; got != 1 {
   122  				t.Errorf("%s visited %d times; expected 1", path, got)
   123  			}
   124  		}
   125  	})
   126  
   127  	t.Run("SymlinkPresent", func(t *testing.T) {
   128  		wantTypes := map[string]fs.FileMode{
   129  			".":     fs.ModeDir,
   130  			"dir":   fs.ModeDir,
   131  			"dir/a": 0,
   132  			"link":  fs.ModeSymlink,
   133  		}
   134  		marks := make(map[string]int)
   135  		err := fs.WalkDir(fsys, ".", func(path string, entry fs.DirEntry, err error) error {
   136  			marks[path]++
   137  			if want, ok := wantTypes[path]; !ok {
   138  				t.Errorf("Unexpected path %q in walk", path)
   139  			} else if got := entry.Type(); got != want {
   140  				t.Errorf("%s entry type = %v; want %v", path, got, want)
   141  			}
   142  			if err != nil {
   143  				t.Errorf("%s: %v", path, err)
   144  			}
   145  			return nil
   146  		})
   147  		if err != nil {
   148  			t.Fatal(err)
   149  		}
   150  		for path := range wantTypes {
   151  			if got := marks[path]; got != 1 {
   152  				t.Errorf("%s visited %d times; expected 1", path, got)
   153  			}
   154  		}
   155  	})
   156  }
   157  

View as plain text