1 // Copyright 2009 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.
29 func TestMain(m *testing.M) {
30 if Getenv("GO_OS_TEST_DRAIN_STDIN") == "1" {
32 io.Copy(io.Discard, Stdin)
55 var sysdir = func() *sysDir {
66 wd, err := syscall.Getwd()
71 filepath.Join(wd, "..", ".."),
73 "ResourceRules.plist",
78 for _, f := range sd.files {
79 path := filepath.Join(sd.name, f)
80 if _, err := Stat(path); err != nil {
88 // In a self-hosted iOS build the above files might
89 // not exist. Look for system files instead below.
92 Getenv("SystemRoot") + "\\system32\\drivers\\etc",
108 // wasmtime has issues resolving symbolic links that are often present
109 // in directories like /etc/group below (e.g. private/etc/group on OSX).
110 // For this reason we use files in the Go source tree instead.
130 func size(name string, t *testing.T) int64 {
131 file, err := Open(name)
133 t.Fatal("open failed:", err)
136 if err := file.Close(); err != nil {
140 n, err := io.Copy(io.Discard, file)
147 func equal(name1, name2 string) (r bool) {
148 switch runtime.GOOS {
150 r = strings.ToLower(name1) == strings.ToLower(name2)
157 // localTmp returns a local temporary directory not on NFS.
158 func localTmp() string {
159 switch runtime.GOOS {
160 case "android", "ios", "windows":
166 func newFile(testName string, t *testing.T) (f *File) {
167 f, err := CreateTemp(localTmp(), "_Go_"+testName)
169 t.Fatalf("TempFile %s: %s", testName, err)
174 func newDir(testName string, t *testing.T) (name string) {
175 name, err := MkdirTemp(localTmp(), "_Go_"+testName)
177 t.Fatalf("TempDir %s: %s", testName, err)
182 var sfdir = sysdir.name
183 var sfname = sysdir.files[0]
185 func TestStat(t *testing.T) {
188 path := sfdir + "/" + sfname
189 dir, err := Stat(path)
191 t.Fatal("stat failed:", err)
193 if !equal(sfname, dir.Name()) {
194 t.Error("name should be ", sfname, "; is", dir.Name())
196 filesize := size(path, t)
197 if dir.Size() != filesize {
198 t.Error("size should be", filesize, "; is", dir.Size())
202 func TestStatError(t *testing.T) {
205 path := "no-such-file"
207 fi, err := Stat(path)
209 t.Fatal("got nil, want error")
212 t.Errorf("got %v, want nil", fi)
214 if perr, ok := err.(*PathError); !ok {
215 t.Errorf("got %T, want %T", err, perr)
218 testenv.MustHaveSymlink(t)
221 err = Symlink(path, link)
228 t.Fatal("got nil, want error")
231 t.Errorf("got %v, want nil", fi)
233 if perr, ok := err.(*PathError); !ok {
234 t.Errorf("got %T, want %T", err, perr)
238 func TestStatSymlinkLoop(t *testing.T) {
239 testenv.MustHaveSymlink(t)
243 err := Symlink("x", "y")
249 err = Symlink("y", "x")
256 if _, ok := err.(*fs.PathError); !ok {
257 t.Errorf("expected *PathError, got %T: %v\n", err, err)
261 func TestFstat(t *testing.T) {
264 path := sfdir + "/" + sfname
265 file, err1 := Open(path)
267 t.Fatal("open failed:", err1)
270 dir, err2 := file.Stat()
272 t.Fatal("fstat failed:", err2)
274 if !equal(sfname, dir.Name()) {
275 t.Error("name should be ", sfname, "; is", dir.Name())
277 filesize := size(path, t)
278 if dir.Size() != filesize {
279 t.Error("size should be", filesize, "; is", dir.Size())
283 func TestLstat(t *testing.T) {
286 path := sfdir + "/" + sfname
287 dir, err := Lstat(path)
289 t.Fatal("lstat failed:", err)
291 if !equal(sfname, dir.Name()) {
292 t.Error("name should be ", sfname, "; is", dir.Name())
294 if dir.Mode()&ModeSymlink == 0 {
295 filesize := size(path, t)
296 if dir.Size() != filesize {
297 t.Error("size should be", filesize, "; is", dir.Size())
302 // Read with length 0 should not return EOF.
303 func TestRead0(t *testing.T) {
306 path := sfdir + "/" + sfname
309 t.Fatal("open failed:", err)
315 if n != 0 || err != nil {
316 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
318 b = make([]byte, 100)
320 if n <= 0 || err != nil {
321 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
325 // Reading a closed file should return ErrClosed error
326 func TestReadClosed(t *testing.T) {
329 path := sfdir + "/" + sfname
330 file, err := Open(path)
332 t.Fatal("open failed:", err)
334 file.Close() // close immediately
336 b := make([]byte, 100)
337 _, err = file.Read(b)
339 e, ok := err.(*PathError)
340 if !ok || e.Err != ErrClosed {
341 t.Fatalf("Read: got %T(%v), want %T(%v)", err, err, e, ErrClosed)
345 func testReaddirnames(dir string, contents []string) func(*testing.T) {
346 return func(t *testing.T) {
349 file, err := Open(dir)
351 t.Fatalf("open %q failed: %v", dir, err)
354 s, err2 := file.Readdirnames(-1)
356 t.Fatalf("Readdirnames %q failed: %v", dir, err2)
358 for _, m := range contents {
360 for _, n := range s {
361 if n == "." || n == ".." {
362 t.Errorf("got %q in directory", n)
368 t.Error("present twice:", m)
373 t.Error("could not find", m)
377 t.Error("Readdirnames returned nil instead of empty slice")
382 func testReaddir(dir string, contents []string) func(*testing.T) {
383 return func(t *testing.T) {
386 file, err := Open(dir)
388 t.Fatalf("open %q failed: %v", dir, err)
391 s, err2 := file.Readdir(-1)
393 t.Fatalf("Readdir %q failed: %v", dir, err2)
395 for _, m := range contents {
397 for _, n := range s {
398 if n.Name() == "." || n.Name() == ".." {
399 t.Errorf("got %q in directory", n.Name())
401 if !equal(m, n.Name()) {
405 t.Error("present twice:", m)
410 t.Error("could not find", m)
414 t.Error("Readdir returned nil instead of empty slice")
419 func testReadDir(dir string, contents []string) func(*testing.T) {
420 return func(t *testing.T) {
423 file, err := Open(dir)
425 t.Fatalf("open %q failed: %v", dir, err)
428 s, err2 := file.ReadDir(-1)
430 t.Fatalf("ReadDir %q failed: %v", dir, err2)
432 for _, m := range contents {
434 for _, n := range s {
435 if n.Name() == "." || n.Name() == ".." {
436 t.Errorf("got %q in directory", n)
438 if !equal(m, n.Name()) {
442 t.Error("present twice:", m)
445 lstat, err := Lstat(dir + "/" + m)
449 if n.IsDir() != lstat.IsDir() {
450 t.Errorf("%s: IsDir=%v, want %v", m, n.IsDir(), lstat.IsDir())
452 if n.Type() != lstat.Mode().Type() {
453 t.Errorf("%s: IsDir=%v, want %v", m, n.Type(), lstat.Mode().Type())
455 info, err := n.Info()
457 t.Errorf("%s: Info: %v", m, err)
460 if !SameFile(info, lstat) {
461 t.Errorf("%s: Info: SameFile(info, lstat) = false", m)
465 t.Error("could not find", m)
469 t.Error("ReadDir returned nil instead of empty slice")
474 func TestFileReaddirnames(t *testing.T) {
477 t.Run(".", testReaddirnames(".", dot))
478 t.Run("sysdir", testReaddirnames(sysdir.name, sysdir.files))
479 t.Run("TempDir", testReaddirnames(t.TempDir(), nil))
482 func TestFileReaddir(t *testing.T) {
485 t.Run(".", testReaddir(".", dot))
486 t.Run("sysdir", testReaddir(sysdir.name, sysdir.files))
487 t.Run("TempDir", testReaddir(t.TempDir(), nil))
490 func TestFileReadDir(t *testing.T) {
493 t.Run(".", testReadDir(".", dot))
494 t.Run("sysdir", testReadDir(sysdir.name, sysdir.files))
495 t.Run("TempDir", testReadDir(t.TempDir(), nil))
498 func benchmarkReaddirname(path string, b *testing.B) {
500 for i := 0; i < b.N; i++ {
503 b.Fatalf("open %q failed: %v", path, err)
505 ns, err := f.Readdirnames(-1)
508 b.Fatalf("readdirnames %q failed: %v", path, err)
512 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries)
515 func benchmarkReaddir(path string, b *testing.B) {
517 for i := 0; i < b.N; i++ {
520 b.Fatalf("open %q failed: %v", path, err)
522 fs, err := f.Readdir(-1)
525 b.Fatalf("readdir %q failed: %v", path, err)
529 b.Logf("benchmarkReaddir %q: %d entries", path, nentries)
532 func benchmarkReadDir(path string, b *testing.B) {
534 for i := 0; i < b.N; i++ {
537 b.Fatalf("open %q failed: %v", path, err)
539 fs, err := f.ReadDir(-1)
542 b.Fatalf("readdir %q failed: %v", path, err)
546 b.Logf("benchmarkReadDir %q: %d entries", path, nentries)
549 func BenchmarkReaddirname(b *testing.B) {
550 benchmarkReaddirname(".", b)
553 func BenchmarkReaddir(b *testing.B) {
554 benchmarkReaddir(".", b)
557 func BenchmarkReadDir(b *testing.B) {
558 benchmarkReadDir(".", b)
561 func benchmarkStat(b *testing.B, path string) {
563 for i := 0; i < b.N; i++ {
566 b.Fatalf("Stat(%q) failed: %v", path, err)
571 func benchmarkLstat(b *testing.B, path string) {
573 for i := 0; i < b.N; i++ {
574 _, err := Lstat(path)
576 b.Fatalf("Lstat(%q) failed: %v", path, err)
581 func BenchmarkStatDot(b *testing.B) {
582 benchmarkStat(b, ".")
585 func BenchmarkStatFile(b *testing.B) {
586 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
589 func BenchmarkStatDir(b *testing.B) {
590 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
593 func BenchmarkLstatDot(b *testing.B) {
594 benchmarkLstat(b, ".")
597 func BenchmarkLstatFile(b *testing.B) {
598 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
601 func BenchmarkLstatDir(b *testing.B) {
602 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
605 // Read the directory one entry at a time.
606 func smallReaddirnames(file *File, length int, t *testing.T) []string {
607 names := make([]string, length)
610 d, err := file.Readdirnames(1)
615 t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
618 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
623 return names[0:count]
626 // Check that reading a directory one entry at a time gives the same result
627 // as reading it all at once.
628 func TestReaddirnamesOneAtATime(t *testing.T) {
631 // big directory that doesn't change often.
633 switch runtime.GOOS {
636 case "ios", "wasip1":
645 dir = Getenv("SystemRoot") + "\\system32"
647 file, err := Open(dir)
649 t.Fatalf("open %q failed: %v", dir, err)
652 all, err1 := file.Readdirnames(-1)
654 t.Fatalf("readdirnames %q failed: %v", dir, err1)
656 file1, err2 := Open(dir)
658 t.Fatalf("open %q failed: %v", dir, err2)
661 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
662 if len(small) < len(all) {
663 t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
665 for i, n := range all {
667 t.Errorf("small read %q mismatch: %v", small[i], n)
672 func TestReaddirNValues(t *testing.T) {
674 t.Skip("test.short; skipping")
679 for i := 1; i <= 105; i++ {
680 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
682 t.Fatalf("Create: %v", err)
684 f.Write([]byte(strings.Repeat("X", i)))
693 t.Fatalf("Open directory: %v", err)
697 readdirExpect := func(n, want int, wantErr error) {
699 fi, err := d.Readdir(n)
701 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
703 if g, e := len(fi), want; g != e {
704 t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
708 readDirExpect := func(n, want int, wantErr error) {
710 de, err := d.ReadDir(n)
712 t.Fatalf("ReadDir of %d got error %v, want %v", n, err, wantErr)
714 if g, e := len(de), want; g != e {
715 t.Errorf("ReadDir of %d got %d files, want %d", n, g, e)
719 readdirnamesExpect := func(n, want int, wantErr error) {
721 fi, err := d.Readdirnames(n)
723 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
725 if g, e := len(fi), want; g != e {
726 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
730 for _, fn := range []func(int, int, error){readdirExpect, readdirnamesExpect, readDirExpect} {
731 // Test the slurp case
737 // Slurp with -1 instead
744 // Test the bounded case
748 fn(105, 102, nil) // and tests buffer >100 case
754 func touch(t *testing.T, name string) {
755 f, err := Create(name)
759 if err := f.Close(); err != nil {
764 func TestReaddirStatFailures(t *testing.T) {
765 switch runtime.GOOS {
766 case "windows", "plan9":
767 // Windows and Plan 9 already do this correctly,
768 // but are structured with different syscalls such
769 // that they don't use Lstat, so the hook below for
770 // testing it wouldn't work.
771 t.Skipf("skipping test on %v", runtime.GOOS)
774 var xerr error // error to return for x
775 *LstatP = func(path string) (FileInfo, error) {
776 if xerr != nil && strings.HasSuffix(path, "x") {
781 defer func() { *LstatP = Lstat }()
784 touch(t, filepath.Join(dir, "good1"))
785 touch(t, filepath.Join(dir, "x")) // will disappear or have an error
786 touch(t, filepath.Join(dir, "good2"))
787 readDir := func() ([]FileInfo, error) {
795 mustReadDir := func(testName string) []FileInfo {
796 fis, err := readDir()
798 t.Fatalf("%s: Readdir: %v", testName, err)
802 names := func(fis []FileInfo) []string {
803 s := make([]string, len(fis))
804 for i, fi := range fis {
811 if got, want := names(mustReadDir("initial readdir")),
812 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
813 t.Errorf("initial readdir got %q; want %q", got, want)
817 if got, want := names(mustReadDir("with x disappearing")),
818 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
819 t.Errorf("with x disappearing, got %q; want %q", got, want)
822 xerr = errors.New("some real error")
823 if _, err := readDir(); err != xerr {
824 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
828 // Readdir on a regular file should fail.
829 func TestReaddirOfFile(t *testing.T) {
832 f, err := CreateTemp(t.TempDir(), "_Go_ReaddirOfFile")
836 f.Write([]byte("foo"))
838 reg, err := Open(f.Name())
844 names, err := reg.Readdirnames(-1)
846 t.Error("Readdirnames succeeded; want non-nil error")
849 if !errors.As(err, &pe) || pe.Path != f.Name() {
850 t.Errorf("Readdirnames returned %q; want a PathError with path %q", err, f.Name())
853 t.Errorf("unexpected dir names in regular file: %q", names)
857 func TestHardLink(t *testing.T) {
858 testenv.MustHaveLink(t)
861 from, to := "hardlinktestfrom", "hardlinktestto"
862 file, err := Create(to)
864 t.Fatalf("open %q failed: %v", to, err)
866 if err = file.Close(); err != nil {
867 t.Errorf("close %q failed: %v", to, err)
871 t.Fatalf("link %q, %q failed: %v", to, from, err)
874 none := "hardlinktestnone"
875 err = Link(none, none)
876 // Check the returned error is well-formed.
877 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
878 t.Errorf("link %q, %q failed to return a valid error", none, none)
881 tostat, err := Stat(to)
883 t.Fatalf("stat %q failed: %v", to, err)
885 fromstat, err := Stat(from)
887 t.Fatalf("stat %q failed: %v", from, err)
889 if !SameFile(tostat, fromstat) {
890 t.Errorf("link %q, %q did not create hard link", to, from)
892 // We should not be able to perform the same Link() a second time
894 switch err := err.(type) {
896 if err.Op != "link" {
897 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link")
900 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to)
903 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from)
905 if !IsExist(err.Err) {
906 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error")
909 t.Errorf("link %q, %q: expected error, got nil", from, to)
911 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
915 // chtmpdir changes the working directory to a new temporary directory and
916 // provides a cleanup function.
917 func chtmpdir(t *testing.T) func() {
918 oldwd, err := Getwd()
920 t.Fatalf("chtmpdir: %v", err)
922 d, err := MkdirTemp("", "test")
924 t.Fatalf("chtmpdir: %v", err)
926 if err := Chdir(d); err != nil {
927 t.Fatalf("chtmpdir: %v", err)
930 if err := Chdir(oldwd); err != nil {
931 t.Fatalf("chtmpdir: %v", err)
937 func TestSymlink(t *testing.T) {
938 testenv.MustHaveSymlink(t)
941 from, to := "symlinktestfrom", "symlinktestto"
942 file, err := Create(to)
944 t.Fatalf("Create(%q) failed: %v", to, err)
946 if err = file.Close(); err != nil {
947 t.Errorf("Close(%q) failed: %v", to, err)
949 err = Symlink(to, from)
951 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
953 tostat, err := Lstat(to)
955 t.Fatalf("Lstat(%q) failed: %v", to, err)
957 if tostat.Mode()&ModeSymlink != 0 {
958 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink)
960 fromstat, err := Stat(from)
962 t.Fatalf("Stat(%q) failed: %v", from, err)
964 if !SameFile(tostat, fromstat) {
965 t.Errorf("Symlink(%q, %q) did not create symlink", to, from)
967 fromstat, err = Lstat(from)
969 t.Fatalf("Lstat(%q) failed: %v", from, err)
971 if fromstat.Mode()&ModeSymlink == 0 {
972 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink)
974 fromstat, err = Stat(from)
976 t.Fatalf("Stat(%q) failed: %v", from, err)
978 if fromstat.Name() != from {
979 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from)
981 if fromstat.Mode()&ModeSymlink != 0 {
982 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink)
984 s, err := Readlink(from)
986 t.Fatalf("Readlink(%q) failed: %v", from, err)
989 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to)
991 file, err = Open(from)
993 t.Fatalf("Open(%q) failed: %v", from, err)
998 func TestLongSymlink(t *testing.T) {
999 testenv.MustHaveSymlink(t)
1002 s := "0123456789abcdef"
1003 // Long, but not too long: a common limit is 255.
1004 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
1005 from := "longsymlinktestfrom"
1006 err := Symlink(s, from)
1008 t.Fatalf("symlink %q, %q failed: %v", s, from, err)
1010 r, err := Readlink(from)
1012 t.Fatalf("readlink %q failed: %v", from, err)
1015 t.Fatalf("after symlink %q != %q", r, s)
1019 func TestRename(t *testing.T) {
1021 from, to := "renamefrom", "renameto"
1023 file, err := Create(from)
1025 t.Fatalf("open %q failed: %v", from, err)
1027 if err = file.Close(); err != nil {
1028 t.Errorf("close %q failed: %v", from, err)
1030 err = Rename(from, to)
1032 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1036 t.Errorf("stat %q failed: %v", to, err)
1040 func TestRenameOverwriteDest(t *testing.T) {
1042 from, to := "renamefrom", "renameto"
1044 toData := []byte("to")
1045 fromData := []byte("from")
1047 err := WriteFile(to, toData, 0777)
1049 t.Fatalf("write file %q failed: %v", to, err)
1052 err = WriteFile(from, fromData, 0777)
1054 t.Fatalf("write file %q failed: %v", from, err)
1056 err = Rename(from, to)
1058 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1063 t.Errorf("from file %q still exists", from)
1065 if err != nil && !IsNotExist(err) {
1066 t.Fatalf("stat from: %v", err)
1068 toFi, err := Stat(to)
1070 t.Fatalf("stat %q failed: %v", to, err)
1072 if toFi.Size() != int64(len(fromData)) {
1073 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
1077 func TestRenameFailed(t *testing.T) {
1079 from, to := "renamefrom", "renameto"
1081 err := Rename(from, to)
1082 switch err := err.(type) {
1084 if err.Op != "rename" {
1085 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1087 if err.Old != from {
1088 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1091 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1094 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1096 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1100 func TestRenameNotExisting(t *testing.T) {
1102 from, to := "doesnt-exist", "dest"
1106 if err := Rename(from, to); !IsNotExist(err) {
1107 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
1111 func TestRenameToDirFailed(t *testing.T) {
1113 from, to := "renamefrom", "renameto"
1118 err := Rename(from, to)
1119 switch err := err.(type) {
1121 if err.Op != "rename" {
1122 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1124 if err.Old != from {
1125 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1128 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1131 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1133 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1137 func TestRenameCaseDifference(pt *testing.T) {
1138 from, to := "renameFROM", "RENAMEfrom"
1143 {"dir", func() error {
1144 return Mkdir(from, 0777)
1146 {"file", func() error {
1147 fd, err := Create(from)
1155 for _, test := range tests {
1156 pt.Run(test.name, func(t *testing.T) {
1159 if err := test.create(); err != nil {
1160 t.Fatalf("failed to create test file: %s", err)
1163 if _, err := Stat(to); err != nil {
1164 // Sanity check that the underlying filesystem is not case sensitive.
1165 if IsNotExist(err) {
1166 t.Skipf("case sensitive filesystem")
1168 t.Fatalf("stat %q, got: %q", to, err)
1171 if err := Rename(from, to); err != nil {
1172 t.Fatalf("unexpected error when renaming from %q to %q: %s", from, to, err)
1175 fd, err := Open(".")
1177 t.Fatalf("Open .: %s", err)
1180 // Stat does not return the real case of the file (it returns what the called asked for)
1181 // So we have to use readdir to get the real name of the file.
1182 dirNames, err := fd.Readdirnames(-1)
1184 t.Fatalf("readdirnames: %s", err)
1187 if dirNamesLen := len(dirNames); dirNamesLen != 1 {
1188 t.Fatalf("unexpected dirNames len, got %q, want %q", dirNamesLen, 1)
1191 if dirNames[0] != to {
1192 t.Errorf("unexpected name, got %q, want %q", dirNames[0], to)
1198 func testStartProcess(dir, cmd string, args []string, expect string) func(t *testing.T) {
1199 return func(t *testing.T) {
1204 t.Fatalf("Pipe: %v", err)
1207 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
1208 p, err := StartProcess(cmd, args, attr)
1210 t.Fatalf("StartProcess: %v", err)
1214 var b strings.Builder
1216 output := b.String()
1218 fi1, _ := Stat(strings.TrimSpace(output))
1219 fi2, _ := Stat(expect)
1220 if !SameFile(fi1, fi2) {
1221 t.Errorf("exec %q returned %q wanted %q",
1222 strings.Join(append([]string{cmd}, args...), " "), output, expect)
1228 func TestStartProcess(t *testing.T) {
1229 testenv.MustHaveExec(t)
1234 switch runtime.GOOS {
1236 t.Skip("android doesn't have /bin/pwd")
1238 cmd = Getenv("COMSPEC")
1239 dir = Getenv("SystemRoot")
1240 args = []string{"/c", "cd"}
1243 cmd, err = exec.LookPath("pwd")
1245 t.Fatalf("Can't find pwd: %v", err)
1249 t.Logf("Testing with %v", cmd)
1251 cmddir, cmdbase := filepath.Split(cmd)
1252 args = append([]string{cmdbase}, args...)
1253 t.Run("absolute", testStartProcess(dir, cmd, args, dir))
1254 t.Run("relative", testStartProcess(cmddir, cmdbase, args, cmddir))
1257 func checkMode(t *testing.T, path string, mode FileMode) {
1258 dir, err := Stat(path)
1260 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
1262 if dir.Mode()&ModePerm != mode {
1263 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
1267 func TestChmod(t *testing.T) {
1268 // Chmod is not supported on wasip1.
1269 if runtime.GOOS == "wasip1" {
1270 t.Skip("Chmod is not supported on " + runtime.GOOS)
1274 f := newFile("TestChmod", t)
1275 defer Remove(f.Name())
1277 // Creation mode is read write
1279 fm := FileMode(0456)
1280 if runtime.GOOS == "windows" {
1281 fm = FileMode(0444) // read-only file
1283 if err := Chmod(f.Name(), fm); err != nil {
1284 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1286 checkMode(t, f.Name(), fm)
1289 if runtime.GOOS == "windows" {
1290 fm = FileMode(0666) // read-write file
1292 if err := f.Chmod(fm); err != nil {
1293 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1295 checkMode(t, f.Name(), fm)
1298 func checkSize(t *testing.T, f *File, size int64) {
1300 dir, err := f.Stat()
1302 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
1304 if dir.Size() != size {
1305 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
1309 func TestFTruncate(t *testing.T) {
1312 f := newFile("TestFTruncate", t)
1313 defer Remove(f.Name())
1317 f.Write([]byte("hello, world\n"))
1322 checkSize(t, f, 1024)
1325 _, err := f.Write([]byte("surprise!"))
1327 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
1331 func TestTruncate(t *testing.T) {
1334 f := newFile("TestTruncate", t)
1335 defer Remove(f.Name())
1339 f.Write([]byte("hello, world\n"))
1341 Truncate(f.Name(), 10)
1343 Truncate(f.Name(), 1024)
1344 checkSize(t, f, 1024)
1345 Truncate(f.Name(), 0)
1347 _, err := f.Write([]byte("surprise!"))
1349 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
1353 func TestTruncateNonexistentFile(t *testing.T) {
1356 assertPathError := func(t testing.TB, path string, err error) {
1358 if pe, ok := err.(*PathError); !ok || !IsNotExist(err) || pe.Path != path {
1359 t.Errorf("got error: %v\nwant an ErrNotExist PathError with path %q", err, path)
1363 path := filepath.Join(t.TempDir(), "nonexistent")
1365 err := Truncate(path, 1)
1366 assertPathError(t, path, err)
1368 // Truncate shouldn't create any new file.
1370 assertPathError(t, path, err)
1373 // Use TempDir (via newFile) to make sure we're on a local file system,
1374 // so that timings are not distorted by latency and caching.
1375 // On NFS, timings can be off due to caching of meta-data on
1376 // NFS servers (Issue 848).
1377 func TestChtimes(t *testing.T) {
1380 f := newFile("TestChtimes", t)
1381 defer Remove(f.Name())
1383 f.Write([]byte("hello, world\n"))
1386 testChtimes(t, f.Name())
1389 func TestChtimesWithZeroTimes(t *testing.T) {
1390 file := newFile("chtimes-with-zero", t)
1391 _, err := file.Write([]byte("hello, world\n"))
1393 t.Fatalf("Write: %s", err)
1395 fName := file.Name()
1396 defer Remove(file.Name())
1401 fs, err := Stat(fName)
1405 startAtime := Atime(fs)
1406 startMtime := fs.ModTime()
1407 switch runtime.GOOS {
1409 startAtime = startAtime.Truncate(time.Second)
1410 startMtime = startMtime.Truncate(time.Second)
1414 t0 := startMtime.Truncate(time.Second).Add(1 * time.Hour)
1425 wantATime: startAtime,
1426 wantMTime: startMtime,
1429 aTime: t0.Add(200 * time.Second),
1431 wantATime: t0.Add(200 * time.Second),
1432 wantMTime: startMtime,
1436 mTime: t0.Add(100 * time.Second),
1437 wantATime: t0.Add(200 * time.Second),
1438 wantMTime: t0.Add(100 * time.Second),
1441 aTime: t0.Add(300 * time.Second),
1442 mTime: t0.Add(100 * time.Second),
1443 wantATime: t0.Add(300 * time.Second),
1444 wantMTime: t0.Add(100 * time.Second),
1448 for _, tt := range tests {
1449 // Now change the times accordingly.
1450 if err := Chtimes(fName, tt.aTime, tt.mTime); err != nil {
1454 // Finally verify the expectations.
1455 fs, err = Stat(fName)
1462 if got, want := at0, tt.wantATime; !got.Equal(want) {
1463 errormsg := fmt.Sprintf("AccessTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
1464 switch runtime.GOOS {
1466 // Mtime is the time of the last change of
1467 // content. Similarly, atime is set whenever
1468 // the contents are accessed; also, it is set
1469 // whenever mtime is set.
1473 if got, want := at0, tt.wantATime; !got.Equal(want) {
1474 mounts, err := ReadFile("/bin/mounts")
1476 mounts, err = ReadFile("/etc/mtab")
1478 if strings.Contains(string(mounts), "noatime") {
1480 t.Log("A filesystem is mounted with noatime; ignoring.")
1482 switch runtime.GOOS {
1483 case "netbsd", "dragonfly":
1484 // On a 64-bit implementation, birth time is generally supported and cannot be changed.
1485 // When supported, atime update is restricted and depends on the file system and on the
1486 // OS configuration.
1487 if strings.Contains(runtime.GOARCH, "64") {
1489 t.Log("Filesystem might not support atime changes; ignoring.")
1498 if got, want := mt0, tt.wantMTime; !got.Equal(want) {
1499 errormsg := fmt.Sprintf("ModTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
1500 switch runtime.GOOS {
1503 t.Log("Mtime is always updated; ignoring.")
1511 // Use TempDir (via newDir) to make sure we're on a local file system,
1512 // so that timings are not distorted by latency and caching.
1513 // On NFS, timings can be off due to caching of meta-data on
1514 // NFS servers (Issue 848).
1515 func TestChtimesDir(t *testing.T) {
1518 name := newDir("TestChtimes", t)
1519 defer RemoveAll(name)
1521 testChtimes(t, name)
1524 func testChtimes(t *testing.T, name string) {
1525 st, err := Stat(name)
1527 t.Fatalf("Stat %s: %s", name, err)
1531 // Move access and modification time back a second
1532 at := Atime(preStat)
1533 mt := preStat.ModTime()
1534 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
1536 t.Fatalf("Chtimes %s: %s", name, err)
1539 st, err = Stat(name)
1541 t.Fatalf("second Stat %s: %s", name, err)
1545 pat := Atime(postStat)
1546 pmt := postStat.ModTime()
1547 if !pat.Before(at) {
1548 switch runtime.GOOS {
1550 // Mtime is the time of the last change of
1551 // content. Similarly, atime is set whenever
1552 // the contents are accessed; also, it is set
1553 // whenever mtime is set.
1555 mounts, _ := ReadFile("/proc/mounts")
1556 if strings.Contains(string(mounts), "noatime") {
1557 t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.")
1559 t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat)
1562 t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
1566 if !pmt.Before(mt) {
1567 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt)
1571 func TestChtimesToUnixZero(t *testing.T) {
1572 file := newFile("chtimes-to-unix-zero", t)
1575 if _, err := file.Write([]byte("hi")); err != nil {
1578 if err := file.Close(); err != nil {
1582 unixZero := time.Unix(0, 0)
1583 if err := Chtimes(fn, unixZero, unixZero); err != nil {
1584 t.Fatalf("Chtimes failed: %v", err)
1592 if mt := st.ModTime(); mt != unixZero {
1593 t.Errorf("mtime is %v, want %v", mt, unixZero)
1597 func TestFileChdir(t *testing.T) {
1600 t.Fatalf("Getwd: %s", err)
1604 fd, err := Open(".")
1606 t.Fatalf("Open .: %s", err)
1610 if err := Chdir("/"); err != nil {
1611 t.Fatalf("Chdir /: %s", err)
1614 if err := fd.Chdir(); err != nil {
1615 t.Fatalf("fd.Chdir: %s", err)
1618 wdNew, err := Getwd()
1620 t.Fatalf("Getwd: %s", err)
1622 if !equal(wdNew, wd) {
1623 t.Fatalf("fd.Chdir failed, got %s, want %s", wdNew, wd)
1627 func TestChdirAndGetwd(t *testing.T) {
1628 fd, err := Open(".")
1630 t.Fatalf("Open .: %s", err)
1632 // These are chosen carefully not to be symlinks on a Mac
1633 // (unlike, say, /var, /etc), except /tmp, which we handle below.
1634 dirs := []string{"/", "/usr/bin", "/tmp"}
1635 // /usr/bin does not usually exist on Plan 9 or Android.
1636 switch runtime.GOOS {
1638 dirs = []string{"/system/bin"}
1640 dirs = []string{"/", "/usr"}
1641 case "ios", "windows", "wasip1":
1643 for _, dir := range []string{t.TempDir(), t.TempDir()} {
1644 // Expand symlinks so path equality tests work.
1645 dir, err = filepath.EvalSymlinks(dir)
1647 t.Fatalf("EvalSymlinks: %v", err)
1649 dirs = append(dirs, dir)
1652 oldwd := Getenv("PWD")
1653 for mode := 0; mode < 2; mode++ {
1654 for _, d := range dirs {
1658 fd1, err1 := Open(d)
1660 t.Errorf("Open %s: %s", d, err1)
1667 Setenv("PWD", "/tmp")
1669 pwd, err1 := Getwd()
1670 Setenv("PWD", oldwd)
1673 // We changed the current directory and cannot go back.
1674 // Don't let the tests continue; they'll scribble
1675 // all over some other directory.
1676 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
1681 t.Fatalf("Chdir %s: %s", d, err)
1685 t.Fatalf("Getwd in %s: %s", d, err1)
1689 t.Fatalf("Getwd returned %q want %q", pwd, d)
1696 // Test that Chdir+Getwd is program-wide.
1697 func TestProgWideChdir(t *testing.T) {
1699 var wg sync.WaitGroup
1700 hold := make(chan struct{})
1701 done := make(chan struct{})
1704 oldwd, err := Getwd()
1706 t.Fatalf("Getwd: %v", err)
1709 if err := Chdir(oldwd); err != nil {
1710 // It's not safe to continue with tests if we can't get back to
1711 // the original working directory.
1716 // Note the deferred Wait must be called after the deferred close(done),
1717 // to ensure the N goroutines have been released even if the main goroutine
1718 // calls Fatalf. It must be called before the Chdir back to the original
1719 // directory, and before the deferred deletion implied by TempDir,
1720 // so as not to interfere while the N goroutines are still running.
1724 for i := 0; i < N; i++ {
1728 // Lock half the goroutines in their own operating system
1729 // thread to exercise more scheduler possibilities.
1731 // On Plan 9, after calling LockOSThread, the goroutines
1732 // run on different processes which don't share the working
1733 // directory. This used to be an issue because Go expects
1734 // the working directory to be program-wide.
1736 runtime.LockOSThread()
1743 // Getwd might be wrong
1744 f0, err := Stat(".")
1751 t.Errorf("Getwd: %v", err)
1755 t.Errorf("Getwd() = %q, want %q", pwd, d)
1758 f1, err := Stat(pwd)
1763 if !SameFile(f0, f1) {
1764 t.Errorf(`Samefile(Stat("."), Getwd()) reports false (%s != %s)`, f0.Name(), f1.Name())
1769 if err = Chdir(d); err != nil {
1770 t.Fatalf("Chdir: %v", err)
1772 // OS X sets TMPDIR to a symbolic link.
1773 // So we resolve our working directory again before the test.
1776 t.Fatalf("Getwd: %v", err)
1782 func TestSeek(t *testing.T) {
1785 f := newFile("TestSeek", t)
1786 defer Remove(f.Name())
1789 const data = "hello, world\n"
1790 io.WriteString(f, data)
1798 {0, io.SeekCurrent, int64(len(data))},
1799 {0, io.SeekStart, 0},
1800 {5, io.SeekStart, 5},
1801 {0, io.SeekEnd, int64(len(data))},
1802 {0, io.SeekStart, 0},
1803 {-1, io.SeekEnd, int64(len(data)) - 1},
1804 {1 << 33, io.SeekStart, 1 << 33},
1805 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
1807 // Issue 21681, Windows 4G-1, etc:
1808 {1<<32 - 1, io.SeekStart, 1<<32 - 1},
1809 {0, io.SeekCurrent, 1<<32 - 1},
1810 {2<<32 - 1, io.SeekStart, 2<<32 - 1},
1811 {0, io.SeekCurrent, 2<<32 - 1},
1813 for i, tt := range tests {
1814 off, err := f.Seek(tt.in, tt.whence)
1815 if off != tt.out || err != nil {
1816 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" {
1817 mounts, _ := ReadFile("/proc/mounts")
1818 if strings.Contains(string(mounts), "reiserfs") {
1819 // Reiserfs rejects the big seeks.
1820 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91")
1823 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
1828 func TestSeekError(t *testing.T) {
1829 switch runtime.GOOS {
1830 case "js", "plan9", "wasip1":
1831 t.Skipf("skipping test on %v", runtime.GOOS)
1839 _, err = r.Seek(0, 0)
1841 t.Fatal("Seek on pipe should fail")
1843 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1844 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1846 _, err = w.Seek(0, 0)
1848 t.Fatal("Seek on pipe should fail")
1850 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1851 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1855 type openErrorTest struct {
1861 var openErrorTests = []openErrorTest{
1863 sfdir + "/no-such-file",
1873 sfdir + "/" + sfname + "/no-such-file",
1879 func TestOpenError(t *testing.T) {
1882 for _, tt := range openErrorTests {
1883 f, err := OpenFile(tt.path, tt.mode, 0)
1885 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
1889 perr, ok := err.(*PathError)
1891 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
1893 if perr.Err != tt.error {
1894 if runtime.GOOS == "plan9" {
1895 syscallErrStr := perr.Err.Error()
1896 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
1897 if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
1898 // Some Plan 9 file servers incorrectly return
1899 // EACCES rather than EISDIR when a directory is
1900 // opened for write.
1901 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
1904 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
1908 if runtime.GOOS == "dragonfly" {
1909 // DragonFly incorrectly returns EACCES rather
1910 // EISDIR when a directory is opened for write.
1911 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES {
1915 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
1920 func TestOpenNoName(t *testing.T) {
1924 t.Fatal(`Open("") succeeded`)
1928 func runBinHostname(t *testing.T) string {
1929 // Run /bin/hostname and collect output.
1936 path, err := exec.LookPath("hostname")
1938 if errors.Is(err, exec.ErrNotFound) {
1939 t.Skip("skipping test; test requires hostname but it does not exist")
1944 argv := []string{"hostname"}
1945 if runtime.GOOS == "aix" {
1946 argv = []string{"hostname", "-s"}
1948 p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}})
1954 var b strings.Builder
1958 t.Fatalf("run hostname Wait: %v", err)
1962 t.Errorf("expected an error from Kill running 'hostname'")
1964 output := b.String()
1965 if n := len(output); n > 0 && output[n-1] == '\n' {
1966 output = output[0 : n-1]
1969 t.Fatalf("/bin/hostname produced no output")
1975 func testWindowsHostname(t *testing.T, hostname string) {
1976 cmd := testenv.Command(t, "hostname")
1977 out, err := cmd.Output()
1979 t.Fatalf("Failed to execute hostname command: %v %s", err, out)
1981 want := strings.Trim(string(out), "\r\n")
1982 if hostname != want {
1983 t.Fatalf("Hostname() = %q != system hostname of %q", hostname, want)
1987 func TestHostname(t *testing.T) {
1990 hostname, err := Hostname()
1995 t.Fatal("Hostname returned empty string and no error")
1997 if strings.Contains(hostname, "\x00") {
1998 t.Fatalf("unexpected zero byte in hostname: %q", hostname)
2001 // There is no other way to fetch hostname on windows, but via winapi.
2002 // On Plan 9 it can be taken from #c/sysname as Hostname() does.
2003 switch runtime.GOOS {
2004 case "android", "plan9":
2005 // No /bin/hostname to verify against.
2008 testWindowsHostname(t, hostname)
2012 testenv.MustHaveExec(t)
2014 // Check internal Hostname() against the output of /bin/hostname.
2015 // Allow that the internal Hostname returns a Fully Qualified Domain Name
2016 // and the /bin/hostname only returns the first component
2017 want := runBinHostname(t)
2018 if hostname != want {
2019 host, _, ok := strings.Cut(hostname, ".")
2020 if !ok || host != want {
2021 t.Errorf("Hostname() = %q, want %q", hostname, want)
2026 func TestReadAt(t *testing.T) {
2029 f := newFile("TestReadAt", t)
2030 defer Remove(f.Name())
2033 const data = "hello, world\n"
2034 io.WriteString(f, data)
2036 b := make([]byte, 5)
2037 n, err := f.ReadAt(b, 7)
2038 if err != nil || n != len(b) {
2039 t.Fatalf("ReadAt 7: %d, %v", n, err)
2041 if string(b) != "world" {
2042 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2046 // Verify that ReadAt doesn't affect seek offset.
2047 // In the Plan 9 kernel, there used to be a bug in the implementation of
2048 // the pread syscall, where the channel offset was erroneously updated after
2049 // calling pread on a file.
2050 func TestReadAtOffset(t *testing.T) {
2053 f := newFile("TestReadAtOffset", t)
2054 defer Remove(f.Name())
2057 const data = "hello, world\n"
2058 io.WriteString(f, data)
2061 b := make([]byte, 5)
2063 n, err := f.ReadAt(b, 7)
2064 if err != nil || n != len(b) {
2065 t.Fatalf("ReadAt 7: %d, %v", n, err)
2067 if string(b) != "world" {
2068 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2072 if err != nil || n != len(b) {
2073 t.Fatalf("Read: %d, %v", n, err)
2075 if string(b) != "hello" {
2076 t.Fatalf("Read: have %q want %q", string(b), "hello")
2080 // Verify that ReadAt doesn't allow negative offset.
2081 func TestReadAtNegativeOffset(t *testing.T) {
2084 f := newFile("TestReadAtNegativeOffset", t)
2085 defer Remove(f.Name())
2088 const data = "hello, world\n"
2089 io.WriteString(f, data)
2092 b := make([]byte, 5)
2094 n, err := f.ReadAt(b, -10)
2096 const wantsub = "negative offset"
2097 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2098 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2102 func TestWriteAt(t *testing.T) {
2105 f := newFile("TestWriteAt", t)
2106 defer Remove(f.Name())
2109 const data = "hello, world\n"
2110 io.WriteString(f, data)
2112 n, err := f.WriteAt([]byte("WORLD"), 7)
2113 if err != nil || n != 5 {
2114 t.Fatalf("WriteAt 7: %d, %v", n, err)
2117 b, err := ReadFile(f.Name())
2119 t.Fatalf("ReadFile %s: %v", f.Name(), err)
2121 if string(b) != "hello, WORLD\n" {
2122 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
2126 // Verify that WriteAt doesn't allow negative offset.
2127 func TestWriteAtNegativeOffset(t *testing.T) {
2130 f := newFile("TestWriteAtNegativeOffset", t)
2131 defer Remove(f.Name())
2134 n, err := f.WriteAt([]byte("WORLD"), -10)
2136 const wantsub = "negative offset"
2137 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2138 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2142 // Verify that WriteAt doesn't work in append mode.
2143 func TestWriteAtInAppendMode(t *testing.T) {
2145 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE, 0666)
2147 t.Fatalf("OpenFile: %v", err)
2151 _, err = f.WriteAt([]byte(""), 1)
2152 if err != ErrWriteAtInAppendMode {
2153 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode)
2157 func writeFile(t *testing.T, fname string, flag int, text string) string {
2158 f, err := OpenFile(fname, flag, 0666)
2160 t.Fatalf("Open: %v", err)
2162 n, err := io.WriteString(f, text)
2164 t.Fatalf("WriteString: %d, %v", n, err)
2167 data, err := ReadFile(fname)
2169 t.Fatalf("ReadFile: %v", err)
2174 func TestAppend(t *testing.T) {
2176 const f = "append.txt"
2177 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2179 t.Fatalf("writeFile: have %q want %q", s, "new")
2181 s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
2182 if s != "new|append" {
2183 t.Fatalf("writeFile: have %q want %q", s, "new|append")
2185 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
2186 if s != "new|append|append" {
2187 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
2191 t.Fatalf("Remove: %v", err)
2193 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
2194 if s != "new&append" {
2195 t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
2197 s = writeFile(t, f, O_CREATE|O_RDWR, "old")
2198 if s != "old&append" {
2199 t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
2201 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2203 t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
2207 func TestStatDirWithTrailingSlash(t *testing.T) {
2210 // Create new temporary directory and arrange to clean it up.
2213 // Stat of path should succeed.
2214 if _, err := Stat(path); err != nil {
2215 t.Fatalf("stat %s failed: %s", path, err)
2218 // Stat of path+"/" should succeed too.
2220 if _, err := Stat(path); err != nil {
2221 t.Fatalf("stat %s failed: %s", path, err)
2225 func TestNilProcessStateString(t *testing.T) {
2226 var ps *ProcessState
2229 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
2233 func TestSameFile(t *testing.T) {
2235 fa, err := Create("a")
2237 t.Fatalf("Create(a): %v", err)
2240 fb, err := Create("b")
2242 t.Fatalf("Create(b): %v", err)
2246 ia1, err := Stat("a")
2248 t.Fatalf("Stat(a): %v", err)
2250 ia2, err := Stat("a")
2252 t.Fatalf("Stat(a): %v", err)
2254 if !SameFile(ia1, ia2) {
2255 t.Errorf("files should be same")
2258 ib, err := Stat("b")
2260 t.Fatalf("Stat(b): %v", err)
2262 if SameFile(ia1, ib) {
2263 t.Errorf("files should be different")
2267 func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo) {
2268 pre := fmt.Sprintf("%s(%q): ", statname, devNullName)
2270 t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
2272 if fi.Mode()&ModeDevice == 0 {
2273 t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
2275 if fi.Mode()&ModeCharDevice == 0 {
2276 t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
2278 if fi.Mode().IsRegular() {
2279 t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
2283 func testDevNullFile(t *testing.T, devNullName string) {
2284 f, err := Open(devNullName)
2286 t.Fatalf("Open(%s): %v", devNullName, err)
2292 t.Fatalf("Stat(%s): %v", devNullName, err)
2294 testDevNullFileInfo(t, "f.Stat", devNullName, fi)
2296 fi, err = Stat(devNullName)
2298 t.Fatalf("Stat(%s): %v", devNullName, err)
2300 testDevNullFileInfo(t, "Stat", devNullName, fi)
2303 func TestDevNullFile(t *testing.T) {
2306 testDevNullFile(t, DevNull)
2307 if runtime.GOOS == "windows" {
2308 testDevNullFile(t, "./nul")
2309 testDevNullFile(t, "//./nul")
2313 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
2315 func TestLargeWriteToConsole(t *testing.T) {
2316 if !*testLargeWrite {
2317 t.Skip("skipping console-flooding test; enable with -large_write")
2319 b := make([]byte, 32000)
2324 n, err := Stdout.Write(b)
2326 t.Fatalf("Write to os.Stdout failed: %v", err)
2329 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
2331 n, err = Stderr.Write(b)
2333 t.Fatalf("Write to os.Stderr failed: %v", err)
2336 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
2340 func TestStatDirModeExec(t *testing.T) {
2341 if runtime.GOOS == "wasip1" {
2342 t.Skip("Chmod is not supported on " + runtime.GOOS)
2349 if err := Chmod(path, 0777); err != nil {
2350 t.Fatalf("Chmod %q 0777: %v", path, err)
2353 dir, err := Stat(path)
2355 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
2357 if dir.Mode()&mode != mode {
2358 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
2362 func TestStatStdin(t *testing.T) {
2363 switch runtime.GOOS {
2364 case "android", "plan9":
2365 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
2368 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2369 st, err := Stdin.Stat()
2371 t.Fatalf("Stat failed: %v", err)
2373 fmt.Println(st.Mode() & ModeNamedPipe)
2377 testenv.MustHaveExec(t)
2380 fi, err := Stdin.Stat()
2384 switch mode := fi.Mode(); {
2385 case mode&ModeCharDevice != 0 && mode&ModeDevice != 0:
2386 case mode&ModeNamedPipe != 0:
2388 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode)
2392 if runtime.GOOS == "windows" {
2393 cmd = testenv.Command(t, "cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
2395 cmd = testenv.Command(t, "/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
2397 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2399 output, err := cmd.CombinedOutput()
2401 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2404 // result will be like "prw-rw-rw"
2405 if len(output) < 1 || output[0] != 'p' {
2406 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
2410 func TestStatRelativeSymlink(t *testing.T) {
2411 testenv.MustHaveSymlink(t)
2414 tmpdir := t.TempDir()
2415 target := filepath.Join(tmpdir, "target")
2416 f, err := Create(target)
2427 link := filepath.Join(tmpdir, "link")
2428 err = Symlink(filepath.Base(target), link)
2433 st1, err := Stat(link)
2438 if !SameFile(st, st1) {
2439 t.Error("Stat doesn't follow relative symlink")
2442 if runtime.GOOS == "windows" {
2444 err = Symlink(target[len(filepath.VolumeName(target)):], link)
2449 st1, err := Stat(link)
2454 if !SameFile(st, st1) {
2455 t.Error("Stat doesn't follow relative symlink")
2460 func TestReadAtEOF(t *testing.T) {
2463 f := newFile("TestReadAtEOF", t)
2464 defer Remove(f.Name())
2467 _, err := f.ReadAt(make([]byte, 10), 0)
2472 t.Fatalf("ReadAt succeeded")
2474 t.Fatalf("ReadAt failed: %s", err)
2478 func TestLongPath(t *testing.T) {
2481 tmpdir := newDir("TestLongPath", t)
2482 defer func(d string) {
2483 if err := RemoveAll(d); err != nil {
2484 t.Fatalf("RemoveAll failed: %v", err)
2488 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted).
2489 sizes := []int{247, 248, 249, 400}
2490 for len(tmpdir) < 400 {
2491 tmpdir += "/dir3456789"
2493 for _, sz := range sizes {
2494 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
2495 sizedTempDir := tmpdir[:sz-1] + "x" // Ensure it does not end with a slash.
2497 // The various sized runs are for this call to trigger the boundary
2499 if err := MkdirAll(sizedTempDir, 0755); err != nil {
2500 t.Fatalf("MkdirAll failed: %v", err)
2502 data := []byte("hello world\n")
2503 if err := WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
2504 t.Fatalf("os.WriteFile() failed: %v", err)
2506 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
2507 t.Fatalf("Rename failed: %v", err)
2509 mtime := time.Now().Truncate(time.Minute)
2510 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
2511 t.Fatalf("Chtimes failed: %v", err)
2513 names := []string{"bar.txt"}
2514 if testenv.HasSymlink() {
2515 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
2516 t.Fatalf("Symlink failed: %v", err)
2518 names = append(names, "symlink.txt")
2520 if testenv.HasLink() {
2521 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
2522 t.Fatalf("Link failed: %v", err)
2524 names = append(names, "link.txt")
2526 for _, wantSize := range []int64{int64(len(data)), 0} {
2527 for _, name := range names {
2528 path := sizedTempDir + "/" + name
2529 dir, err := Stat(path)
2531 t.Fatalf("Stat(%q) failed: %v", path, err)
2533 filesize := size(path, t)
2534 if dir.Size() != filesize || filesize != wantSize {
2535 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
2537 if runtime.GOOS != "wasip1" { // Chmod is not supported on wasip1
2538 err = Chmod(path, dir.Mode())
2540 t.Fatalf("Chmod(%q) failed: %v", path, err)
2544 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
2545 t.Fatalf("Truncate failed: %v", err)
2552 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
2553 testenv.MustHaveExec(t)
2556 // Re-exec the test binary to start a process that hangs until stdin is closed.
2557 cmd := testenv.Command(t, Args[0])
2558 cmd.Env = append(cmd.Environ(), "GO_OS_TEST_DRAIN_STDIN=1")
2559 stdout, err := cmd.StdoutPipe()
2563 stdin, err := cmd.StdinPipe()
2569 t.Fatalf("Failed to start test process: %v", err)
2573 if err := cmd.Wait(); err == nil {
2574 t.Errorf("Test process succeeded, but expected to fail")
2576 stdin.Close() // Keep stdin alive until the process has finished dying.
2579 // Wait for the process to be started.
2580 // (It will close its stdout when it reaches TestMain.)
2581 io.Copy(io.Discard, stdout)
2583 processKiller(cmd.Process)
2586 func TestKillStartProcess(t *testing.T) {
2587 testKillProcess(t, func(p *Process) {
2590 t.Fatalf("Failed to kill test process: %v", err)
2595 func TestGetppid(t *testing.T) {
2596 if runtime.GOOS == "plan9" {
2597 // TODO: golang.org/issue/8206
2598 t.Skipf("skipping test on plan9; see issue 8206")
2601 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2602 fmt.Print(Getppid())
2606 testenv.MustHaveExec(t)
2609 cmd := testenv.Command(t, Args[0], "-test.run=TestGetppid")
2610 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2612 // verify that Getppid() from the forked process reports our process id
2613 output, err := cmd.CombinedOutput()
2615 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2618 childPpid := string(output)
2619 ourPid := fmt.Sprintf("%d", Getpid())
2620 if childPpid != ourPid {
2621 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
2625 func TestKillFindProcess(t *testing.T) {
2626 testKillProcess(t, func(p *Process) {
2627 p2, err := FindProcess(p.Pid)
2629 t.Fatalf("Failed to find test process: %v", err)
2633 t.Fatalf("Failed to kill test process: %v", err)
2638 var nilFileMethodTests = []struct {
2642 {"Chdir", func(f *File) error { return f.Chdir() }},
2643 {"Close", func(f *File) error { return f.Close() }},
2644 {"Chmod", func(f *File) error { return f.Chmod(0) }},
2645 {"Chown", func(f *File) error { return f.Chown(0, 0) }},
2646 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
2647 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
2648 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
2649 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
2650 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
2651 {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
2652 {"Sync", func(f *File) error { return f.Sync() }},
2653 {"Truncate", func(f *File) error { return f.Truncate(0) }},
2654 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
2655 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
2656 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
2659 // Test that all File methods give ErrInvalid if the receiver is nil.
2660 func TestNilFileMethods(t *testing.T) {
2663 for _, tt := range nilFileMethodTests {
2666 if got != ErrInvalid {
2667 t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
2672 func mkdirTree(t *testing.T, root string, level, max int) {
2677 for i := 'a'; i < 'c'; i++ {
2678 dir := filepath.Join(root, string(i))
2679 if err := Mkdir(dir, 0700); err != nil {
2682 mkdirTree(t, dir, level, max)
2686 // Test that simultaneous RemoveAll do not report an error.
2687 // As long as it gets removed, we should be happy.
2688 func TestRemoveAllRace(t *testing.T) {
2689 if runtime.GOOS == "windows" {
2690 // Windows has very strict rules about things like
2691 // removing directories while someone else has
2692 // them open. The racing doesn't work out nicely
2693 // like it does on Unix.
2694 t.Skip("skipping on windows")
2696 if runtime.GOOS == "dragonfly" {
2697 testenv.SkipFlaky(t, 52301)
2700 n := runtime.GOMAXPROCS(16)
2701 defer runtime.GOMAXPROCS(n)
2702 root, err := MkdirTemp("", "issue")
2706 mkdirTree(t, root, 1, 6)
2707 hold := make(chan struct{})
2708 var wg sync.WaitGroup
2709 for i := 0; i < 4; i++ {
2714 err := RemoveAll(root)
2716 t.Errorf("unexpected error: %T, %q", err, err)
2720 close(hold) // let workers race to remove root
2724 // Test that reading from a pipe doesn't use up a thread.
2725 func TestPipeThreads(t *testing.T) {
2726 switch runtime.GOOS {
2727 case "illumos", "solaris":
2728 t.Skip("skipping on Solaris and illumos; issue 19111")
2730 t.Skip("skipping on Windows; issue 19098")
2732 t.Skip("skipping on Plan 9; does not support runtime poller")
2734 t.Skip("skipping on js; no support for os.Pipe")
2736 t.Skip("skipping on wasip1; no support for os.Pipe")
2741 // OpenBSD has a low default for max number of files.
2742 if runtime.GOOS == "openbsd" {
2746 r := make([]*File, threads)
2747 w := make([]*File, threads)
2748 for i := 0; i < threads; i++ {
2749 rp, wp, err := Pipe()
2751 for j := 0; j < i; j++ {
2761 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2))
2763 creading := make(chan bool, threads)
2764 cdone := make(chan bool, threads)
2765 for i := 0; i < threads; i++ {
2769 if _, err := r[i].Read(b[:]); err != nil {
2772 if err := r[i].Close(); err != nil {
2779 for i := 0; i < threads; i++ {
2783 // If we are still alive, it means that the 100 goroutines did
2784 // not require 100 threads.
2786 for i := 0; i < threads; i++ {
2787 if _, err := w[i].Write([]byte{0}); err != nil {
2790 if err := w[i].Close(); err != nil {
2797 func testDoubleCloseError(path string) func(*testing.T) {
2798 return func(t *testing.T) {
2801 file, err := Open(path)
2805 if err := file.Close(); err != nil {
2806 t.Fatalf("unexpected error from Close: %v", err)
2808 if err := file.Close(); err == nil {
2809 t.Error("second Close did not fail")
2810 } else if pe, ok := err.(*PathError); !ok {
2811 t.Errorf("second Close: got %T, want %T", err, pe)
2812 } else if pe.Err != ErrClosed {
2813 t.Errorf("second Close: got %q, want %q", pe.Err, ErrClosed)
2815 t.Logf("second close returned expected error %q", err)
2820 func TestDoubleCloseError(t *testing.T) {
2822 t.Run("file", testDoubleCloseError(filepath.Join(sfdir, sfname)))
2823 t.Run("dir", testDoubleCloseError(sfdir))
2826 func TestUserCacheDir(t *testing.T) {
2829 dir, err := UserCacheDir()
2831 t.Skipf("skipping: %v", err)
2834 t.Fatalf("UserCacheDir returned %q; want non-empty path or error", dir)
2837 if err := MkdirAll(dir, 0777); err != nil {
2838 t.Fatalf("could not create UserCacheDir: %v", err)
2840 d, err := MkdirTemp(dir, "TestUserCacheDir")
2842 t.Fatalf("could not create a directory in UserCacheDir: %v", err)
2844 if err := Remove(d); err != nil {
2849 func TestUserConfigDir(t *testing.T) {
2852 dir, err := UserConfigDir()
2854 t.Skipf("skipping: %v", err)
2857 t.Fatalf("UserConfigDir returned %q; want non-empty path or error", dir)
2860 if err := MkdirAll(dir, 0777); err != nil {
2861 t.Fatalf("could not create UserConfigDir: %v", err)
2864 d, err := MkdirTemp(dir, "TestUserConfigDir")
2866 t.Fatalf("could not create a directory in UserConfigDir: %v", err)
2868 if err := Remove(d); err != nil {
2873 func TestUserHomeDir(t *testing.T) {
2876 dir, err := UserHomeDir()
2877 if dir == "" && err == nil {
2878 t.Fatal("UserHomeDir returned an empty string but no error")
2881 // UserHomeDir may return a non-nil error if the environment variable
2882 // for the home directory is empty or unset in the environment.
2883 t.Skipf("skipping: %v", err)
2886 fi, err := Stat(dir)
2888 if IsNotExist(err) {
2889 // The user's home directory has a well-defined location, but does not
2890 // exist. (Maybe nothing has written to it yet? That could happen, for
2891 // example, on minimal VM images used for CI testing.)
2898 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2902 func TestDirSeek(t *testing.T) {
2913 dirnames1, err := f.Readdirnames(0)
2918 ret, err := f.Seek(0, 0)
2923 t.Fatalf("seek result not zero: %d", ret)
2926 dirnames2, err := f.Readdirnames(0)
2931 if len(dirnames1) != len(dirnames2) {
2932 t.Fatalf("listings have different lengths: %d and %d\n", len(dirnames1), len(dirnames2))
2934 for i, n1 := range dirnames1 {
2937 t.Fatalf("different name i=%d n1=%s n2=%s\n", i, n1, n2)
2942 func TestReaddirSmallSeek(t *testing.T) {
2943 // See issue 37161. Read only one entry from a directory,
2944 // seek to the beginning, and read again. We should not see
2945 // duplicate entries.
2952 df, err := Open(filepath.Join(wd, "testdata", "issue37161"))
2956 names1, err := df.Readdirnames(1)
2960 if _, err = df.Seek(0, 0); err != nil {
2963 names2, err := df.Readdirnames(0)
2967 if len(names2) != 3 {
2968 t.Fatalf("first names: %v, second names: %v", names1, names2)
2972 // isDeadlineExceeded reports whether err is or wraps ErrDeadlineExceeded.
2973 // We also check that the error has a Timeout method that returns true.
2974 func isDeadlineExceeded(err error) bool {
2975 if !IsTimeout(err) {
2978 if !errors.Is(err, ErrDeadlineExceeded) {
2984 // Test that opening a file does not change its permissions. Issue 38225.
2985 func TestOpenFileKeepsPermissions(t *testing.T) {
2989 name := filepath.Join(dir, "x")
2990 f, err := Create(name)
2994 if err := f.Close(); err != nil {
2997 f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
3001 if fi, err := f.Stat(); err != nil {
3003 } else if fi.Mode()&0222 == 0 {
3004 t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
3006 if err := f.Close(); err != nil {
3009 if fi, err := Stat(name); err != nil {
3011 } else if fi.Mode()&0222 == 0 {
3012 t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
3016 func TestDirFS(t *testing.T) {
3019 // On Windows, we force the MFT to update by reading the actual metadata from GetFileInformationByHandle and then
3020 // explicitly setting that. Otherwise it might get out of sync with FindFirstFile. See golang.org/issues/42637.
3021 if runtime.GOOS == "windows" {
3022 if err := filepath.WalkDir("./testdata/dirfs", func(path string, d fs.DirEntry, err error) error {
3026 info, err := d.Info()
3030 stat, err := Stat(path) // This uses GetFileInformationByHandle internally.
3034 if stat.ModTime() == info.ModTime() {
3037 if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
3038 t.Log(err) // We only log, not die, in case the test directory is not writable.
3045 fsys := DirFS("./testdata/dirfs")
3046 if err := fstest.TestFS(fsys, "a", "b", "dir/x"); err != nil {
3050 rdfs, ok := fsys.(fs.ReadDirFS)
3052 t.Error("expected DirFS result to implement fs.ReadDirFS")
3054 if _, err := rdfs.ReadDir("nonexistent"); err == nil {
3055 t.Error("fs.ReadDir of nonexistent directory succeeded")
3058 // Test that the error message does not contain a backslash,
3059 // and does not contain the DirFS argument.
3060 const nonesuch = "dir/nonesuch"
3061 _, err := fsys.Open(nonesuch)
3063 t.Error("fs.Open of nonexistent file succeeded")
3065 if !strings.Contains(err.Error(), nonesuch) {
3066 t.Errorf("error %q does not contain %q", err, nonesuch)
3068 if strings.Contains(err.(*PathError).Path, "testdata") {
3069 t.Errorf("error %q contains %q", err, "testdata")
3073 // Test that Open does not accept backslash as separator.
3075 _, err = d.Open(`testdata\dirfs`)
3077 t.Fatalf(`Open testdata\dirfs succeeded`)
3080 // Test that Open does not open Windows device files.
3081 _, err = d.Open(`NUL`)
3083 t.Errorf(`Open NUL succeeded`)
3087 func TestDirFSRootDir(t *testing.T) {
3094 cwd = cwd[len(filepath.VolumeName(cwd)):] // trim volume prefix (C:) on Windows
3095 cwd = filepath.ToSlash(cwd) // convert \ to /
3096 cwd = strings.TrimPrefix(cwd, "/") // trim leading /
3098 // Test that Open can open a path starting at /.
3100 f, err := d.Open(cwd + "/testdata/dirfs/a")
3107 func TestDirFSEmptyDir(t *testing.T) {
3112 for _, path := range []string{
3113 "testdata/dirfs/a", // not DirFS(".")
3114 filepath.ToSlash(cwd) + "/testdata/dirfs/a", // not DirFS("/")
3116 _, err := d.Open(path)
3118 t.Fatalf(`DirFS("").Open(%q) succeeded`, path)
3123 func TestDirFSPathsValid(t *testing.T) {
3124 if runtime.GOOS == "windows" {
3125 t.Skipf("skipping on Windows")
3130 if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
3133 if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
3138 err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
3139 if fs.ValidPath(e.Name()) {
3140 t.Logf("%q ok", e.Name())
3142 t.Errorf("%q INVALID", e.Name())
3151 func TestReadFileProc(t *testing.T) {
3154 // Linux files in /proc report 0 size,
3155 // but then if ReadFile reads just a single byte at offset 0,
3156 // the read at offset 1 returns EOF instead of more data.
3157 // ReadFile has a minimum read size of 512 to work around this,
3158 // but test explicitly that it's working.
3159 name := "/proc/sys/fs/pipe-max-size"
3160 if _, err := Stat(name); err != nil {
3163 data, err := ReadFile(name)
3167 if len(data) == 0 || data[len(data)-1] != '\n' {
3168 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3172 func TestDirFSReadFileProc(t *testing.T) {
3176 name := "proc/sys/fs/pipe-max-size"
3177 if _, err := fs.Stat(fsys, name); err != nil {
3180 data, err := fs.ReadFile(fsys, name)
3184 if len(data) == 0 || data[len(data)-1] != '\n' {
3185 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3189 func TestWriteStringAlloc(t *testing.T) {
3190 if runtime.GOOS == "js" {
3191 t.Skip("js allocates a lot during File.WriteString")
3194 f, err := Create(filepath.Join(d, "whiteboard.txt"))
3199 allocs := testing.AllocsPerRun(100, func() {
3200 f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
3203 t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs)
3207 // Test that it's OK to have parallel I/O and Close on a pipe.
3208 func TestPipeIOCloseRace(t *testing.T) {
3209 // Skip on wasm, which doesn't have pipes.
3210 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3211 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3220 var wg sync.WaitGroup
3226 n, err := w.Write([]byte("hi"))
3228 // We look at error strings as the
3229 // expected errors are OS-specific.
3231 case errors.Is(err, ErrClosed),
3232 strings.Contains(err.Error(), "broken pipe"),
3233 strings.Contains(err.Error(), "pipe is being closed"),
3234 strings.Contains(err.Error(), "hungup channel"):
3235 // Ignore an expected error.
3237 // Unexpected error.
3243 t.Errorf("wrote %d bytes, expected 2", n)
3253 n, err := r.Read(buf[:])
3255 if err != io.EOF && !errors.Is(err, ErrClosed) {
3261 t.Errorf("read %d bytes, want 2", n)
3269 // Let the other goroutines start. This is just to get
3270 // a better test, the test will still pass if they
3272 time.Sleep(time.Millisecond)
3274 if err := r.Close(); err != nil {
3277 if err := w.Close(); err != nil {
3285 // Test that it's OK to call Close concurrently on a pipe.
3286 func TestPipeCloseRace(t *testing.T) {
3287 // Skip on wasm, which doesn't have pipes.
3288 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3289 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3297 var wg sync.WaitGroup
3298 c := make(chan error, 4)
3308 for i := 0; i < 4; i++ {
3316 if nils != 2 || errs != 2 {
3317 t.Errorf("got nils %d errs %d, want 2 2", nils, errs)