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  	const nonesuch = "dir/nonesuch"
    54  	_, err := fs.ReadLink(fsys, nonesuch)
    55  	if err == nil {
    56  		t.Fatal("fs.ReadLink of nonexistent file succeeded")
    57  	}
    58  	pe, ok := err.(*PathError)
    59  	if !ok {
    60  		t.Fatalf("fs.ReadLink error type = %T; want *PathError", err)
    61  	}
    62  	if pe.Path != nonesuch {
    63  		t.Errorf("fs.ReadLink(%q) error path = %q; want %q", nonesuch, pe.Path, nonesuch)
    64  	}
    65  }
    66  
    67  func TestDirFSLstat(t *testing.T) {
    68  	testenv.MustHaveSymlink(t)
    69  
    70  	root := t.TempDir()
    71  	subdir := filepath.Join(root, "dir")
    72  	if err := Mkdir(subdir, 0o777); err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	fsys := DirFS(root)
    80  	want := map[string]fs.FileMode{
    81  		"link": fs.ModeSymlink,
    82  		"dir":  fs.ModeDir,
    83  	}
    84  	for name, want := range want {
    85  		info, err := fs.Lstat(fsys, name)
    86  		var got fs.FileMode
    87  		if info != nil {
    88  			got = info.Mode().Type()
    89  		}
    90  		if got != want || err != nil {
    91  			t.Errorf("fs.Lstat(fsys, %q).Mode().Type() = %v, %v; want %v, <nil>", name, got, err, want)
    92  		}
    93  	}
    94  
    95  	const nonesuch = "dir/nonesuch"
    96  	_, err := fs.Lstat(fsys, nonesuch)
    97  	if err == nil {
    98  		t.Fatal("fs.Lstat of nonexistent file succeeded")
    99  	}
   100  	pe, ok := err.(*PathError)
   101  	if !ok {
   102  		t.Fatalf("fs.Lstat error type = %T; want *PathError", err)
   103  	}
   104  	if pe.Path != nonesuch {
   105  		t.Errorf("fs.Lstat(%q) error path = %q; want %q", nonesuch, pe.Path, nonesuch)
   106  	}
   107  }
   108  
   109  func TestDirFSWalkDir(t *testing.T) {
   110  	testenv.MustHaveSymlink(t)
   111  
   112  	root := t.TempDir()
   113  	subdir := filepath.Join(root, "dir")
   114  	if err := Mkdir(subdir, 0o777); err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	if err := Symlink("dir", filepath.Join(root, "link")); err != nil {
   118  		t.Fatal(err)
   119  	}
   120  	if err := WriteFile(filepath.Join(root, "dir", "a"), nil, 0o666); err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	fsys := DirFS(root)
   124  
   125  	t.Run("SymlinkRoot", func(t *testing.T) {
   126  		wantTypes := map[string]fs.FileMode{
   127  			"link":   fs.ModeDir,
   128  			"link/a": 0,
   129  		}
   130  		marks := make(map[string]int)
   131  		err := fs.WalkDir(fsys, "link", func(path string, entry fs.DirEntry, err error) error {
   132  			marks[path]++
   133  			if want, ok := wantTypes[path]; !ok {
   134  				t.Errorf("Unexpected path %q in walk", path)
   135  			} else if got := entry.Type(); got != want {
   136  				t.Errorf("%s entry type = %v; want %v", path, got, want)
   137  			}
   138  			if err != nil {
   139  				t.Errorf("%s: %v", path, err)
   140  			}
   141  			return nil
   142  		})
   143  		if err != nil {
   144  			t.Fatal(err)
   145  		}
   146  		for path := range wantTypes {
   147  			if got := marks[path]; got != 1 {
   148  				t.Errorf("%s visited %d times; expected 1", path, got)
   149  			}
   150  		}
   151  	})
   152  
   153  	t.Run("SymlinkPresent", func(t *testing.T) {
   154  		wantTypes := map[string]fs.FileMode{
   155  			".":     fs.ModeDir,
   156  			"dir":   fs.ModeDir,
   157  			"dir/a": 0,
   158  			"link":  fs.ModeSymlink,
   159  		}
   160  		marks := make(map[string]int)
   161  		err := fs.WalkDir(fsys, ".", func(path string, entry fs.DirEntry, err error) error {
   162  			marks[path]++
   163  			if want, ok := wantTypes[path]; !ok {
   164  				t.Errorf("Unexpected path %q in walk", path)
   165  			} else if got := entry.Type(); got != want {
   166  				t.Errorf("%s entry type = %v; want %v", path, got, want)
   167  			}
   168  			if err != nil {
   169  				t.Errorf("%s: %v", path, err)
   170  			}
   171  			return nil
   172  		})
   173  		if err != nil {
   174  			t.Fatal(err)
   175  		}
   176  		for path := range wantTypes {
   177  			if got := marks[path]; got != 1 {
   178  				t.Errorf("%s visited %d times; expected 1", path, got)
   179  			}
   180  		}
   181  	})
   182  }
   183  

View as plain text