github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/os/stat_test.go (about)

     1  // Copyright 2018 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  	"runtime"
    13  	"testing"
    14  )
    15  
    16  // testStatAndLstat verifies that all os.Stat, os.Lstat os.File.Stat and os.Readdir work.
    17  func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, fs.FileInfo)) {
    18  	// test os.Stat
    19  	sfi, err := os.Stat(path)
    20  	if err != nil {
    21  		t.Error(err)
    22  		return
    23  	}
    24  	statCheck(t, path, sfi)
    25  
    26  	// test os.Lstat
    27  	lsfi, err := os.Lstat(path)
    28  	if err != nil {
    29  		t.Error(err)
    30  		return
    31  	}
    32  	lstatCheck(t, path, lsfi)
    33  
    34  	if isLink {
    35  		if os.SameFile(sfi, lsfi) {
    36  			t.Errorf("stat and lstat of %q should not be the same", path)
    37  		}
    38  	} else {
    39  		if !os.SameFile(sfi, lsfi) {
    40  			t.Errorf("stat and lstat of %q should be the same", path)
    41  		}
    42  	}
    43  
    44  	// test os.File.Stat
    45  	f, err := os.Open(path)
    46  	if err != nil {
    47  		t.Error(err)
    48  		return
    49  	}
    50  	defer f.Close()
    51  
    52  	sfi2, err := f.Stat()
    53  	if err != nil {
    54  		t.Error(err)
    55  		return
    56  	}
    57  	statCheck(t, path, sfi2)
    58  
    59  	if !os.SameFile(sfi, sfi2) {
    60  		t.Errorf("stat of open %q file and stat of %q should be the same", path, path)
    61  	}
    62  
    63  	if isLink {
    64  		if os.SameFile(sfi2, lsfi) {
    65  			t.Errorf("stat of opened %q file and lstat of %q should not be the same", path, path)
    66  		}
    67  	} else {
    68  		if !os.SameFile(sfi2, lsfi) {
    69  			t.Errorf("stat of opened %q file and lstat of %q should be the same", path, path)
    70  		}
    71  	}
    72  
    73  	// test fs.FileInfo returned by os.Readdir
    74  	if len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
    75  		// skip os.Readdir test of directories with slash at the end
    76  		return
    77  	}
    78  	parentdir := filepath.Dir(path)
    79  	parent, err := os.Open(parentdir)
    80  	if err != nil {
    81  		t.Error(err)
    82  		return
    83  	}
    84  	defer parent.Close()
    85  
    86  	fis, err := parent.Readdir(-1)
    87  	if err != nil {
    88  		t.Error(err)
    89  		return
    90  	}
    91  	var lsfi2 fs.FileInfo
    92  	base := filepath.Base(path)
    93  	for _, fi2 := range fis {
    94  		if fi2.Name() == base {
    95  			lsfi2 = fi2
    96  			break
    97  		}
    98  	}
    99  	if lsfi2 == nil {
   100  		t.Errorf("failed to find %q in its parent", path)
   101  		return
   102  	}
   103  	lstatCheck(t, path, lsfi2)
   104  
   105  	if !os.SameFile(lsfi, lsfi2) {
   106  		t.Errorf("lstat of %q file in %q directory and %q should be the same", lsfi2.Name(), parentdir, path)
   107  	}
   108  }
   109  
   110  // testIsDir verifies that fi refers to directory.
   111  func testIsDir(t *testing.T, path string, fi fs.FileInfo) {
   112  	t.Helper()
   113  	if !fi.IsDir() {
   114  		t.Errorf("%q should be a directory", path)
   115  	}
   116  	if fi.Mode()&fs.ModeSymlink != 0 {
   117  		t.Errorf("%q should not be a symlink", path)
   118  	}
   119  }
   120  
   121  // testIsSymlink verifies that fi refers to symlink.
   122  func testIsSymlink(t *testing.T, path string, fi fs.FileInfo) {
   123  	t.Helper()
   124  	if fi.IsDir() {
   125  		t.Errorf("%q should not be a directory", path)
   126  	}
   127  	if fi.Mode()&fs.ModeSymlink == 0 {
   128  		t.Errorf("%q should be a symlink", path)
   129  	}
   130  }
   131  
   132  // testIsFile verifies that fi refers to file.
   133  func testIsFile(t *testing.T, path string, fi fs.FileInfo) {
   134  	t.Helper()
   135  	if fi.IsDir() {
   136  		t.Errorf("%q should not be a directory", path)
   137  	}
   138  	if fi.Mode()&fs.ModeSymlink != 0 {
   139  		t.Errorf("%q should not be a symlink", path)
   140  	}
   141  }
   142  
   143  func testDirStats(t *testing.T, path string) {
   144  	testStatAndLstat(t, path, false, testIsDir, testIsDir)
   145  }
   146  
   147  func testFileStats(t *testing.T, path string) {
   148  	testStatAndLstat(t, path, false, testIsFile, testIsFile)
   149  }
   150  
   151  func testSymlinkStats(t *testing.T, path string, isdir bool) {
   152  	if isdir {
   153  		testStatAndLstat(t, path, true, testIsDir, testIsSymlink)
   154  	} else {
   155  		testStatAndLstat(t, path, true, testIsFile, testIsSymlink)
   156  	}
   157  }
   158  
   159  func testSymlinkSameFile(t *testing.T, path, link string) {
   160  	pathfi, err := os.Stat(path)
   161  	if err != nil {
   162  		t.Error(err)
   163  		return
   164  	}
   165  
   166  	linkfi, err := os.Stat(link)
   167  	if err != nil {
   168  		t.Error(err)
   169  		return
   170  	}
   171  	if !os.SameFile(pathfi, linkfi) {
   172  		t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", path, link)
   173  	}
   174  
   175  	linkfi, err = os.Lstat(link)
   176  	if err != nil {
   177  		t.Error(err)
   178  		return
   179  	}
   180  	if os.SameFile(pathfi, linkfi) {
   181  		t.Errorf("os.Stat(%q) and os.Lstat(%q) are the same file", path, link)
   182  	}
   183  }
   184  
   185  func TestDirAndSymlinkStats(t *testing.T) {
   186  	testenv.MustHaveSymlink(t)
   187  
   188  	tmpdir, err := os.MkdirTemp("", "TestDirAndSymlinkStats")
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  	defer os.RemoveAll(tmpdir)
   193  
   194  	dir := filepath.Join(tmpdir, "dir")
   195  	err = os.Mkdir(dir, 0777)
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	testDirStats(t, dir)
   200  
   201  	dirlink := filepath.Join(tmpdir, "link")
   202  	err = os.Symlink(dir, dirlink)
   203  	if err != nil {
   204  		t.Fatal(err)
   205  	}
   206  	testSymlinkStats(t, dirlink, true)
   207  	testSymlinkSameFile(t, dir, dirlink)
   208  
   209  	linklink := filepath.Join(tmpdir, "linklink")
   210  	err = os.Symlink(dirlink, linklink)
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	testSymlinkStats(t, linklink, true)
   215  	testSymlinkSameFile(t, dir, linklink)
   216  }
   217  
   218  func TestFileAndSymlinkStats(t *testing.T) {
   219  	testenv.MustHaveSymlink(t)
   220  
   221  	tmpdir, err := os.MkdirTemp("", "TestFileAndSymlinkStats")
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  	defer os.RemoveAll(tmpdir)
   226  
   227  	file := filepath.Join(tmpdir, "file")
   228  	err = os.WriteFile(file, []byte(""), 0644)
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	testFileStats(t, file)
   233  
   234  	filelink := filepath.Join(tmpdir, "link")
   235  	err = os.Symlink(file, filelink)
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	testSymlinkStats(t, filelink, false)
   240  	testSymlinkSameFile(t, file, filelink)
   241  
   242  	linklink := filepath.Join(tmpdir, "linklink")
   243  	err = os.Symlink(filelink, linklink)
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	testSymlinkStats(t, linklink, false)
   248  	testSymlinkSameFile(t, file, linklink)
   249  }
   250  
   251  // see issue 27225 for details
   252  func TestSymlinkWithTrailingSlash(t *testing.T) {
   253  	testenv.MustHaveSymlink(t)
   254  
   255  	tmpdir, err := os.MkdirTemp("", "TestSymlinkWithTrailingSlash")
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	defer os.RemoveAll(tmpdir)
   260  
   261  	dir := filepath.Join(tmpdir, "dir")
   262  	err = os.Mkdir(dir, 0777)
   263  	if err != nil {
   264  		t.Fatal(err)
   265  	}
   266  	dirlink := filepath.Join(tmpdir, "link")
   267  	err = os.Symlink(dir, dirlink)
   268  	if err != nil {
   269  		t.Fatal(err)
   270  	}
   271  	dirlinkWithSlash := dirlink + string(os.PathSeparator)
   272  
   273  	if runtime.GOOS == "windows" {
   274  		testSymlinkStats(t, dirlinkWithSlash, true)
   275  	} else {
   276  		testDirStats(t, dirlinkWithSlash)
   277  	}
   278  
   279  	fi1, err := os.Stat(dir)
   280  	if err != nil {
   281  		t.Error(err)
   282  		return
   283  	}
   284  	fi2, err := os.Stat(dirlinkWithSlash)
   285  	if err != nil {
   286  		t.Error(err)
   287  		return
   288  	}
   289  	if !os.SameFile(fi1, fi2) {
   290  		t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", dir, dirlinkWithSlash)
   291  	}
   292  }