...

Source file src/os/stat_test.go

Documentation: os

		 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 := t.TempDir()
	 189  	dir := filepath.Join(tmpdir, "dir")
	 190  	if err := os.Mkdir(dir, 0777); err != nil {
	 191  		t.Fatal(err)
	 192  	}
	 193  	testDirStats(t, dir)
	 194  
	 195  	dirlink := filepath.Join(tmpdir, "link")
	 196  	if err := os.Symlink(dir, dirlink); err != nil {
	 197  		t.Fatal(err)
	 198  	}
	 199  	testSymlinkStats(t, dirlink, true)
	 200  	testSymlinkSameFile(t, dir, dirlink)
	 201  
	 202  	linklink := filepath.Join(tmpdir, "linklink")
	 203  	if err := os.Symlink(dirlink, linklink); err != nil {
	 204  		t.Fatal(err)
	 205  	}
	 206  	testSymlinkStats(t, linklink, true)
	 207  	testSymlinkSameFile(t, dir, linklink)
	 208  }
	 209  
	 210  func TestFileAndSymlinkStats(t *testing.T) {
	 211  	testenv.MustHaveSymlink(t)
	 212  
	 213  	tmpdir := t.TempDir()
	 214  	file := filepath.Join(tmpdir, "file")
	 215  	if err := os.WriteFile(file, []byte(""), 0644); err != nil {
	 216  		t.Fatal(err)
	 217  	}
	 218  	testFileStats(t, file)
	 219  
	 220  	filelink := filepath.Join(tmpdir, "link")
	 221  	if err := os.Symlink(file, filelink); err != nil {
	 222  		t.Fatal(err)
	 223  	}
	 224  	testSymlinkStats(t, filelink, false)
	 225  	testSymlinkSameFile(t, file, filelink)
	 226  
	 227  	linklink := filepath.Join(tmpdir, "linklink")
	 228  	if err := os.Symlink(filelink, linklink); err != nil {
	 229  		t.Fatal(err)
	 230  	}
	 231  	testSymlinkStats(t, linklink, false)
	 232  	testSymlinkSameFile(t, file, linklink)
	 233  }
	 234  
	 235  // see issue 27225 for details
	 236  func TestSymlinkWithTrailingSlash(t *testing.T) {
	 237  	testenv.MustHaveSymlink(t)
	 238  
	 239  	tmpdir := t.TempDir()
	 240  	dir := filepath.Join(tmpdir, "dir")
	 241  	if err := os.Mkdir(dir, 0777); err != nil {
	 242  		t.Fatal(err)
	 243  	}
	 244  	dirlink := filepath.Join(tmpdir, "link")
	 245  	if err := os.Symlink(dir, dirlink); err != nil {
	 246  		t.Fatal(err)
	 247  	}
	 248  	dirlinkWithSlash := dirlink + string(os.PathSeparator)
	 249  
	 250  	if runtime.GOOS == "windows" {
	 251  		testSymlinkStats(t, dirlinkWithSlash, true)
	 252  	} else {
	 253  		testDirStats(t, dirlinkWithSlash)
	 254  	}
	 255  
	 256  	fi1, err := os.Stat(dir)
	 257  	if err != nil {
	 258  		t.Error(err)
	 259  		return
	 260  	}
	 261  	fi2, err := os.Stat(dirlinkWithSlash)
	 262  	if err != nil {
	 263  		t.Error(err)
	 264  		return
	 265  	}
	 266  	if !os.SameFile(fi1, fi2) {
	 267  		t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", dir, dirlinkWithSlash)
	 268  	}
	 269  }
	 270  

View as plain text