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.
31 func TestMain(m
*testing
.M
) {
32 if Getenv("GO_OS_TEST_DRAIN_STDIN") == "1" {
34 io
.Copy(io
.Discard
, os
.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",
118 func size(name
string, t
*testing
.T
) int64 {
119 file
, err
:= Open(name
)
121 t
.Fatal("open failed:", err
)
124 if err
:= file
.Close(); err
!= nil {
128 n
, err
:= io
.Copy(io
.Discard
, file
)
135 func equal(name1
, name2
string) (r
bool) {
136 switch runtime
.GOOS
{
138 r
= strings
.ToLower(name1
) == strings
.ToLower(name2
)
145 // localTmp returns a local temporary directory not on NFS.
146 func localTmp() string {
147 switch runtime
.GOOS
{
148 case "android", "ios", "windows":
154 func newFile(testName
string, t
*testing
.T
) (f
*File
) {
155 f
, err
:= os
.CreateTemp(localTmp(), "_Go_"+testName
)
157 t
.Fatalf("TempFile %s: %s", testName
, err
)
162 func newDir(testName
string, t
*testing
.T
) (name
string) {
163 name
, err
:= os
.MkdirTemp(localTmp(), "_Go_"+testName
)
165 t
.Fatalf("TempDir %s: %s", testName
, err
)
170 var sfdir
= sysdir
.name
171 var sfname
= sysdir
.files
[0]
173 func TestStat(t
*testing
.T
) {
174 path
:= sfdir
+ "/" + sfname
175 dir
, err
:= Stat(path
)
177 t
.Fatal("stat failed:", err
)
179 if !equal(sfname
, dir
.Name()) {
180 t
.Error("name should be ", sfname
, "; is", dir
.Name())
182 filesize
:= size(path
, t
)
183 if dir
.Size() != filesize
{
184 t
.Error("size should be", filesize
, "; is", dir
.Size())
188 func TestStatError(t
*testing
.T
) {
191 path
:= "no-such-file"
193 fi
, err
:= Stat(path
)
195 t
.Fatal("got nil, want error")
198 t
.Errorf("got %v, want nil", fi
)
200 if perr
, ok
:= err
.(*PathError
); !ok
{
201 t
.Errorf("got %T, want %T", err
, perr
)
204 testenv
.MustHaveSymlink(t
)
207 err
= Symlink(path
, link
)
214 t
.Fatal("got nil, want error")
217 t
.Errorf("got %v, want nil", fi
)
219 if perr
, ok
:= err
.(*PathError
); !ok
{
220 t
.Errorf("got %T, want %T", err
, perr
)
224 func TestFstat(t
*testing
.T
) {
225 path
:= sfdir
+ "/" + sfname
226 file
, err1
:= Open(path
)
228 t
.Fatal("open failed:", err1
)
231 dir
, err2
:= file
.Stat()
233 t
.Fatal("fstat failed:", err2
)
235 if !equal(sfname
, dir
.Name()) {
236 t
.Error("name should be ", sfname
, "; is", dir
.Name())
238 filesize
:= size(path
, t
)
239 if dir
.Size() != filesize
{
240 t
.Error("size should be", filesize
, "; is", dir
.Size())
244 func TestLstat(t
*testing
.T
) {
245 path
:= sfdir
+ "/" + sfname
246 dir
, err
:= Lstat(path
)
248 t
.Fatal("lstat failed:", err
)
250 if !equal(sfname
, dir
.Name()) {
251 t
.Error("name should be ", sfname
, "; is", dir
.Name())
253 filesize
:= size(path
, t
)
254 if dir
.Size() != filesize
{
255 t
.Error("size should be", filesize
, "; is", dir
.Size())
259 // Read with length 0 should not return EOF.
260 func TestRead0(t
*testing
.T
) {
261 path
:= sfdir
+ "/" + sfname
264 t
.Fatal("open failed:", err
)
270 if n
!= 0 || err
!= nil {
271 t
.Errorf("Read(0) = %d, %v, want 0, nil", n
, err
)
273 b
= make([]byte, 100)
275 if n
<= 0 || err
!= nil {
276 t
.Errorf("Read(100) = %d, %v, want >0, nil", n
, err
)
280 // Reading a closed file should return ErrClosed error
281 func TestReadClosed(t
*testing
.T
) {
282 path
:= sfdir
+ "/" + sfname
283 file
, err
:= Open(path
)
285 t
.Fatal("open failed:", err
)
287 file
.Close() // close immediately
289 b
:= make([]byte, 100)
290 _
, err
= file
.Read(b
)
292 e
, ok
:= err
.(*PathError
)
294 t
.Fatalf("Read: %T(%v), want PathError", e
, e
)
297 if e
.Err
!= ErrClosed
{
298 t
.Errorf("Read: %v, want PathError(ErrClosed)", e
)
302 func testReaddirnames(dir
string, contents
[]string, t
*testing
.T
) {
303 file
, err
:= Open(dir
)
305 t
.Fatalf("open %q failed: %v", dir
, err
)
308 s
, err2
:= file
.Readdirnames(-1)
310 t
.Fatalf("Readdirnames %q failed: %v", dir
, err2
)
312 for _
, m
:= range contents
{
314 for _
, n
:= range s
{
315 if n
== "." || n
== ".." {
316 t
.Errorf("got %q in directory", n
)
322 t
.Error("present twice:", m
)
327 t
.Error("could not find", m
)
331 t
.Error("Readdirnames returned nil instead of empty slice")
335 func testReaddir(dir
string, contents
[]string, t
*testing
.T
) {
336 file
, err
:= Open(dir
)
338 t
.Fatalf("open %q failed: %v", dir
, err
)
341 s
, err2
:= file
.Readdir(-1)
343 t
.Fatalf("Readdir %q failed: %v", dir
, err2
)
345 for _
, m
:= range contents
{
347 for _
, n
:= range s
{
348 if n
.Name() == "." || n
.Name() == ".." {
349 t
.Errorf("got %q in directory", n
.Name())
351 if !equal(m
, n
.Name()) {
355 t
.Error("present twice:", m
)
360 t
.Error("could not find", m
)
364 t
.Error("Readdir returned nil instead of empty slice")
368 func testReadDir(dir
string, contents
[]string, t
*testing
.T
) {
369 file
, err
:= Open(dir
)
371 t
.Fatalf("open %q failed: %v", dir
, err
)
374 s
, err2
:= file
.ReadDir(-1)
376 t
.Fatalf("ReadDir %q failed: %v", dir
, err2
)
378 for _
, m
:= range contents
{
380 for _
, n
:= range s
{
381 if n
.Name() == "." || n
.Name() == ".." {
382 t
.Errorf("got %q in directory", n
)
384 if !equal(m
, n
.Name()) {
388 t
.Error("present twice:", m
)
391 lstat
, err
:= Lstat(dir
+ "/" + m
)
395 if n
.IsDir() != lstat
.IsDir() {
396 t
.Errorf("%s: IsDir=%v, want %v", m
, n
.IsDir(), lstat
.IsDir())
398 if n
.Type() != lstat
.Mode().Type() {
399 t
.Errorf("%s: IsDir=%v, want %v", m
, n
.Type(), lstat
.Mode().Type())
401 info
, err
:= n
.Info()
403 t
.Errorf("%s: Info: %v", m
, err
)
406 if !SameFile(info
, lstat
) {
407 t
.Errorf("%s: Info: SameFile(info, lstat) = false", m
)
411 t
.Error("could not find", m
)
415 t
.Error("ReadDir returned nil instead of empty slice")
419 func TestFileReaddirnames(t
*testing
.T
) {
420 testReaddirnames(".", dot
, t
)
421 testReaddirnames(sysdir
.name
, sysdir
.files
, t
)
422 testReaddirnames(t
.TempDir(), nil, t
)
425 func TestFileReaddir(t
*testing
.T
) {
426 testReaddir(".", dot
, t
)
427 testReaddir(sysdir
.name
, sysdir
.files
, t
)
428 testReaddir(t
.TempDir(), nil, t
)
431 func TestFileReadDir(t
*testing
.T
) {
432 testReadDir(".", dot
, t
)
433 testReadDir(sysdir
.name
, sysdir
.files
, t
)
434 testReadDir(t
.TempDir(), nil, t
)
437 func benchmarkReaddirname(path
string, b
*testing
.B
) {
439 for i
:= 0; i
< b
.N
; i
++ {
442 b
.Fatalf("open %q failed: %v", path
, err
)
444 ns
, err
:= f
.Readdirnames(-1)
447 b
.Fatalf("readdirnames %q failed: %v", path
, err
)
451 b
.Logf("benchmarkReaddirname %q: %d entries", path
, nentries
)
454 func benchmarkReaddir(path
string, b
*testing
.B
) {
456 for i
:= 0; i
< b
.N
; i
++ {
459 b
.Fatalf("open %q failed: %v", path
, err
)
461 fs
, err
:= f
.Readdir(-1)
464 b
.Fatalf("readdir %q failed: %v", path
, err
)
468 b
.Logf("benchmarkReaddir %q: %d entries", path
, nentries
)
471 func benchmarkReadDir(path
string, b
*testing
.B
) {
473 for i
:= 0; i
< b
.N
; i
++ {
476 b
.Fatalf("open %q failed: %v", path
, err
)
478 fs
, err
:= f
.ReadDir(-1)
481 b
.Fatalf("readdir %q failed: %v", path
, err
)
485 b
.Logf("benchmarkReadDir %q: %d entries", path
, nentries
)
488 func BenchmarkReaddirname(b
*testing
.B
) {
489 benchmarkReaddirname(".", b
)
492 func BenchmarkReaddir(b
*testing
.B
) {
493 benchmarkReaddir(".", b
)
496 func BenchmarkReadDir(b
*testing
.B
) {
497 benchmarkReadDir(".", b
)
500 func benchmarkStat(b
*testing
.B
, path
string) {
502 for i
:= 0; i
< b
.N
; i
++ {
505 b
.Fatalf("Stat(%q) failed: %v", path
, err
)
510 func benchmarkLstat(b
*testing
.B
, path
string) {
512 for i
:= 0; i
< b
.N
; i
++ {
513 _
, err
:= Lstat(path
)
515 b
.Fatalf("Lstat(%q) failed: %v", path
, err
)
520 func BenchmarkStatDot(b
*testing
.B
) {
521 benchmarkStat(b
, ".")
524 func BenchmarkStatFile(b
*testing
.B
) {
525 benchmarkStat(b
, filepath
.Join(runtime
.GOROOT(), "src/os/os_test.go"))
528 func BenchmarkStatDir(b
*testing
.B
) {
529 benchmarkStat(b
, filepath
.Join(runtime
.GOROOT(), "src/os"))
532 func BenchmarkLstatDot(b
*testing
.B
) {
533 benchmarkLstat(b
, ".")
536 func BenchmarkLstatFile(b
*testing
.B
) {
537 benchmarkLstat(b
, filepath
.Join(runtime
.GOROOT(), "src/os/os_test.go"))
540 func BenchmarkLstatDir(b
*testing
.B
) {
541 benchmarkLstat(b
, filepath
.Join(runtime
.GOROOT(), "src/os"))
544 // Read the directory one entry at a time.
545 func smallReaddirnames(file
*File
, length
int, t
*testing
.T
) []string {
546 names
:= make([]string, length
)
549 d
, err
:= file
.Readdirnames(1)
554 t
.Fatalf("readdirnames %q failed: %v", file
.Name(), err
)
557 t
.Fatalf("readdirnames %q returned empty slice and no error", file
.Name())
562 return names
[0:count
]
565 // Check that reading a directory one entry at a time gives the same result
566 // as reading it all at once.
567 func TestReaddirnamesOneAtATime(t
*testing
.T
) {
568 // big directory that doesn't change often.
570 switch runtime
.GOOS
{
582 dir
= Getenv("SystemRoot") + "\\system32"
584 file
, err
:= Open(dir
)
586 t
.Fatalf("open %q failed: %v", dir
, err
)
589 all
, err1
:= file
.Readdirnames(-1)
591 t
.Fatalf("readdirnames %q failed: %v", dir
, err1
)
593 file1
, err2
:= Open(dir
)
595 t
.Fatalf("open %q failed: %v", dir
, err2
)
598 small
:= smallReaddirnames(file1
, len(all
)+100, t
) // +100 in case we screw up
599 if len(small
) < len(all
) {
600 t
.Fatalf("len(small) is %d, less than %d", len(small
), len(all
))
602 for i
, n
:= range all
{
604 t
.Errorf("small read %q mismatch: %v", small
[i
], n
)
609 func TestReaddirNValues(t
*testing
.T
) {
611 t
.Skip("test.short; skipping")
614 for i
:= 1; i
<= 105; i
++ {
615 f
, err
:= Create(filepath
.Join(dir
, fmt
.Sprintf("%d", i
)))
617 t
.Fatalf("Create: %v", err
)
619 f
.Write([]byte(strings
.Repeat("X", i
)))
628 t
.Fatalf("Open directory: %v", err
)
632 readdirExpect
:= func(n
, want
int, wantErr error
) {
634 fi
, err
:= d
.Readdir(n
)
636 t
.Fatalf("Readdir of %d got error %v, want %v", n
, err
, wantErr
)
638 if g
, e
:= len(fi
), want
; g
!= e
{
639 t
.Errorf("Readdir of %d got %d files, want %d", n
, g
, e
)
643 readDirExpect
:= func(n
, want
int, wantErr error
) {
645 de
, err
:= d
.ReadDir(n
)
647 t
.Fatalf("ReadDir of %d got error %v, want %v", n
, err
, wantErr
)
649 if g
, e
:= len(de
), want
; g
!= e
{
650 t
.Errorf("ReadDir of %d got %d files, want %d", n
, g
, e
)
654 readdirnamesExpect
:= func(n
, want
int, wantErr error
) {
656 fi
, err
:= d
.Readdirnames(n
)
658 t
.Fatalf("Readdirnames of %d got error %v, want %v", n
, err
, wantErr
)
660 if g
, e
:= len(fi
), want
; g
!= e
{
661 t
.Errorf("Readdirnames of %d got %d files, want %d", n
, g
, e
)
665 for _
, fn
:= range []func(int, int, error
){readdirExpect
, readdirnamesExpect
, readDirExpect
} {
666 // Test the slurp case
672 // Slurp with -1 instead
679 // Test the bounded case
683 fn(105, 102, nil) // and tests buffer >100 case
689 func touch(t
*testing
.T
, name
string) {
690 f
, err
:= Create(name
)
694 if err
:= f
.Close(); err
!= nil {
699 func TestReaddirStatFailures(t
*testing
.T
) {
700 switch runtime
.GOOS
{
701 case "windows", "plan9":
702 // Windows and Plan 9 already do this correctly,
703 // but are structured with different syscalls such
704 // that they don't use Lstat, so the hook below for
705 // testing it wouldn't work.
706 t
.Skipf("skipping test on %v", runtime
.GOOS
)
709 touch(t
, filepath
.Join(dir
, "good1"))
710 touch(t
, filepath
.Join(dir
, "x")) // will disappear or have an error
711 touch(t
, filepath
.Join(dir
, "good2"))
715 var xerr error
// error to return for x
716 *LstatP
= func(path
string) (FileInfo
, error
) {
717 if xerr
!= nil && strings
.HasSuffix(path
, "x") {
722 readDir
:= func() ([]FileInfo
, error
) {
730 mustReadDir
:= func(testName
string) []FileInfo
{
731 fis
, err
:= readDir()
733 t
.Fatalf("%s: Readdir: %v", testName
, err
)
737 names
:= func(fis
[]FileInfo
) []string {
738 s
:= make([]string, len(fis
))
739 for i
, fi
:= range fis
{
746 if got
, want
:= names(mustReadDir("initial readdir")),
747 []string{"good1", "good2", "x"}; !reflect
.DeepEqual(got
, want
) {
748 t
.Errorf("initial readdir got %q; want %q", got
, want
)
752 if got
, want
:= names(mustReadDir("with x disappearing")),
753 []string{"good1", "good2"}; !reflect
.DeepEqual(got
, want
) {
754 t
.Errorf("with x disappearing, got %q; want %q", got
, want
)
757 xerr
= errors
.New("some real error")
758 if _
, err
:= readDir(); err
!= xerr
{
759 t
.Errorf("with a non-ErrNotExist error, got error %v; want %v", err
, xerr
)
763 // Readdir on a regular file should fail.
764 func TestReaddirOfFile(t
*testing
.T
) {
765 f
, err
:= os
.CreateTemp("", "_Go_ReaddirOfFile")
769 defer Remove(f
.Name())
770 f
.Write([]byte("foo"))
772 reg
, err
:= Open(f
.Name())
778 names
, err
:= reg
.Readdirnames(-1)
780 t
.Error("Readdirnames succeeded; want non-nil error")
783 if !errors
.As(err
, &pe
) || pe
.Path
!= f
.Name() {
784 t
.Errorf("Readdirnames returned %q; want a PathError with path %q", err
, f
.Name())
787 t
.Errorf("unexpected dir names in regular file: %q", names
)
791 func TestHardLink(t
*testing
.T
) {
792 testenv
.MustHaveLink(t
)
795 from
, to
:= "hardlinktestfrom", "hardlinktestto"
796 file
, err
:= Create(to
)
798 t
.Fatalf("open %q failed: %v", to
, err
)
800 if err
= file
.Close(); err
!= nil {
801 t
.Errorf("close %q failed: %v", to
, err
)
805 t
.Fatalf("link %q, %q failed: %v", to
, from
, err
)
808 none
:= "hardlinktestnone"
809 err
= Link(none
, none
)
810 // Check the returned error is well-formed.
811 if lerr
, ok
:= err
.(*LinkError
); !ok || lerr
.Error() == "" {
812 t
.Errorf("link %q, %q failed to return a valid error", none
, none
)
815 tostat
, err
:= Stat(to
)
817 t
.Fatalf("stat %q failed: %v", to
, err
)
819 fromstat
, err
:= Stat(from
)
821 t
.Fatalf("stat %q failed: %v", from
, err
)
823 if !SameFile(tostat
, fromstat
) {
824 t
.Errorf("link %q, %q did not create hard link", to
, from
)
826 // We should not be able to perform the same Link() a second time
828 switch err
:= err
.(type) {
830 if err
.Op
!= "link" {
831 t
.Errorf("Link(%q, %q) err.Op = %q; want %q", to
, from
, err
.Op
, "link")
834 t
.Errorf("Link(%q, %q) err.Old = %q; want %q", to
, from
, err
.Old
, to
)
837 t
.Errorf("Link(%q, %q) err.New = %q; want %q", to
, from
, err
.New
, from
)
839 if !IsExist(err
.Err
) {
840 t
.Errorf("Link(%q, %q) err.Err = %q; want %q", to
, from
, err
.Err
, "file exists error")
843 t
.Errorf("link %q, %q: expected error, got nil", from
, to
)
845 t
.Errorf("link %q, %q: expected %T, got %T %v", from
, to
, new(LinkError
), err
, err
)
849 // chtmpdir changes the working directory to a new temporary directory and
850 // provides a cleanup function.
851 func chtmpdir(t
*testing
.T
) func() {
852 oldwd
, err
:= Getwd()
854 t
.Fatalf("chtmpdir: %v", err
)
856 d
, err
:= os
.MkdirTemp("", "test")
858 t
.Fatalf("chtmpdir: %v", err
)
860 if err
:= Chdir(d
); err
!= nil {
861 t
.Fatalf("chtmpdir: %v", err
)
864 if err
:= Chdir(oldwd
); err
!= nil {
865 t
.Fatalf("chtmpdir: %v", err
)
871 func TestSymlink(t
*testing
.T
) {
872 testenv
.MustHaveSymlink(t
)
875 from
, to
:= "symlinktestfrom", "symlinktestto"
876 file
, err
:= Create(to
)
878 t
.Fatalf("Create(%q) failed: %v", to
, err
)
880 if err
= file
.Close(); err
!= nil {
881 t
.Errorf("Close(%q) failed: %v", to
, err
)
883 err
= Symlink(to
, from
)
885 t
.Fatalf("Symlink(%q, %q) failed: %v", to
, from
, err
)
887 tostat
, err
:= Lstat(to
)
889 t
.Fatalf("Lstat(%q) failed: %v", to
, err
)
891 if tostat
.Mode()&ModeSymlink
!= 0 {
892 t
.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to
, tostat
.Mode()&ModeSymlink
)
894 fromstat
, err
:= Stat(from
)
896 t
.Fatalf("Stat(%q) failed: %v", from
, err
)
898 if !SameFile(tostat
, fromstat
) {
899 t
.Errorf("Symlink(%q, %q) did not create symlink", to
, from
)
901 fromstat
, err
= Lstat(from
)
903 t
.Fatalf("Lstat(%q) failed: %v", from
, err
)
905 if fromstat
.Mode()&ModeSymlink
== 0 {
906 t
.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from
, ModeSymlink
)
908 fromstat
, err
= Stat(from
)
910 t
.Fatalf("Stat(%q) failed: %v", from
, err
)
912 if fromstat
.Name() != from
{
913 t
.Errorf("Stat(%q).Name() = %q, want %q", from
, fromstat
.Name(), from
)
915 if fromstat
.Mode()&ModeSymlink
!= 0 {
916 t
.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from
, fromstat
.Mode()&ModeSymlink
)
918 s
, err
:= Readlink(from
)
920 t
.Fatalf("Readlink(%q) failed: %v", from
, err
)
923 t
.Fatalf("Readlink(%q) = %q, want %q", from
, s
, to
)
925 file
, err
= Open(from
)
927 t
.Fatalf("Open(%q) failed: %v", from
, err
)
932 func TestLongSymlink(t
*testing
.T
) {
933 testenv
.MustHaveSymlink(t
)
936 s
:= "0123456789abcdef"
937 // Long, but not too long: a common limit is 255.
938 s
= s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
+ s
939 from
:= "longsymlinktestfrom"
940 err
:= Symlink(s
, from
)
942 t
.Fatalf("symlink %q, %q failed: %v", s
, from
, err
)
944 r
, err
:= Readlink(from
)
946 t
.Fatalf("readlink %q failed: %v", from
, err
)
949 t
.Fatalf("after symlink %q != %q", r
, s
)
953 func TestRename(t
*testing
.T
) {
955 from
, to
:= "renamefrom", "renameto"
957 file
, err
:= Create(from
)
959 t
.Fatalf("open %q failed: %v", from
, err
)
961 if err
= file
.Close(); err
!= nil {
962 t
.Errorf("close %q failed: %v", from
, err
)
964 err
= Rename(from
, to
)
966 t
.Fatalf("rename %q, %q failed: %v", to
, from
, err
)
970 t
.Errorf("stat %q failed: %v", to
, err
)
974 func TestRenameOverwriteDest(t
*testing
.T
) {
976 from
, to
:= "renamefrom", "renameto"
978 toData
:= []byte("to")
979 fromData
:= []byte("from")
981 err
:= os
.WriteFile(to
, toData
, 0777)
983 t
.Fatalf("write file %q failed: %v", to
, err
)
986 err
= os
.WriteFile(from
, fromData
, 0777)
988 t
.Fatalf("write file %q failed: %v", from
, err
)
990 err
= Rename(from
, to
)
992 t
.Fatalf("rename %q, %q failed: %v", to
, from
, err
)
997 t
.Errorf("from file %q still exists", from
)
999 if err
!= nil && !IsNotExist(err
) {
1000 t
.Fatalf("stat from: %v", err
)
1002 toFi
, err
:= Stat(to
)
1004 t
.Fatalf("stat %q failed: %v", to
, err
)
1006 if toFi
.Size() != int64(len(fromData
)) {
1007 t
.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi
.Size(), len(fromData
))
1011 func TestRenameFailed(t
*testing
.T
) {
1013 from
, to
:= "renamefrom", "renameto"
1015 err
:= Rename(from
, to
)
1016 switch err
:= err
.(type) {
1018 if err
.Op
!= "rename" {
1019 t
.Errorf("rename %q, %q: err.Op: want %q, got %q", from
, to
, "rename", err
.Op
)
1021 if err
.Old
!= from
{
1022 t
.Errorf("rename %q, %q: err.Old: want %q, got %q", from
, to
, from
, err
.Old
)
1025 t
.Errorf("rename %q, %q: err.New: want %q, got %q", from
, to
, to
, err
.New
)
1028 t
.Errorf("rename %q, %q: expected error, got nil", from
, to
)
1030 t
.Errorf("rename %q, %q: expected %T, got %T %v", from
, to
, new(LinkError
), err
, err
)
1034 func TestRenameNotExisting(t
*testing
.T
) {
1036 from
, to
:= "doesnt-exist", "dest"
1040 if err
:= Rename(from
, to
); !IsNotExist(err
) {
1041 t
.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from
, to
, err
)
1045 func TestRenameToDirFailed(t
*testing
.T
) {
1047 from
, to
:= "renamefrom", "renameto"
1052 err
:= Rename(from
, to
)
1053 switch err
:= err
.(type) {
1055 if err
.Op
!= "rename" {
1056 t
.Errorf("rename %q, %q: err.Op: want %q, got %q", from
, to
, "rename", err
.Op
)
1058 if err
.Old
!= from
{
1059 t
.Errorf("rename %q, %q: err.Old: want %q, got %q", from
, to
, from
, err
.Old
)
1062 t
.Errorf("rename %q, %q: err.New: want %q, got %q", from
, to
, to
, err
.New
)
1065 t
.Errorf("rename %q, %q: expected error, got nil", from
, to
)
1067 t
.Errorf("rename %q, %q: expected %T, got %T %v", from
, to
, new(LinkError
), err
, err
)
1071 func TestRenameCaseDifference(pt
*testing
.T
) {
1072 from
, to
:= "renameFROM", "RENAMEfrom"
1077 {"dir", func() error
{
1078 return Mkdir(from
, 0777)
1080 {"file", func() error
{
1081 fd
, err
:= Create(from
)
1089 for _
, test
:= range tests
{
1090 pt
.Run(test
.name
, func(t
*testing
.T
) {
1093 if err
:= test
.create(); err
!= nil {
1094 t
.Fatalf("failed to create test file: %s", err
)
1097 if _
, err
:= Stat(to
); err
!= nil {
1098 // Sanity check that the underlying filesystem is not case sensitive.
1099 if IsNotExist(err
) {
1100 t
.Skipf("case sensitive filesystem")
1102 t
.Fatalf("stat %q, got: %q", to
, err
)
1105 if err
:= Rename(from
, to
); err
!= nil {
1106 t
.Fatalf("unexpected error when renaming from %q to %q: %s", from
, to
, err
)
1109 fd
, err
:= Open(".")
1111 t
.Fatalf("Open .: %s", err
)
1114 // Stat does not return the real case of the file (it returns what the called asked for)
1115 // So we have to use readdir to get the real name of the file.
1116 dirNames
, err
:= fd
.Readdirnames(-1)
1118 t
.Fatalf("readdirnames: %s", err
)
1121 if dirNamesLen
:= len(dirNames
); dirNamesLen
!= 1 {
1122 t
.Fatalf("unexpected dirNames len, got %q, want %q", dirNamesLen
, 1)
1125 if dirNames
[0] != to
{
1126 t
.Errorf("unexpected name, got %q, want %q", dirNames
[0], to
)
1132 func exec(t
*testing
.T
, dir
, cmd
string, args
[]string, expect
string) {
1135 t
.Fatalf("Pipe: %v", err
)
1138 attr
:= &ProcAttr
{Dir
: dir
, Files
: []*File
{nil, w
, Stderr
}}
1139 p
, err
:= StartProcess(cmd
, args
, attr
)
1141 t
.Fatalf("StartProcess: %v", err
)
1147 output
:= b
.String()
1149 fi1
, _
:= Stat(strings
.TrimSpace(output
))
1150 fi2
, _
:= Stat(expect
)
1151 if !SameFile(fi1
, fi2
) {
1152 t
.Errorf("exec %q returned %q wanted %q",
1153 strings
.Join(append([]string{cmd
}, args
...), " "), output
, expect
)
1158 func TestStartProcess(t
*testing
.T
) {
1159 testenv
.MustHaveExec(t
)
1163 switch runtime
.GOOS
{
1165 t
.Skip("android doesn't have /bin/pwd")
1167 cmd
= Getenv("COMSPEC")
1168 dir
= Getenv("SystemRoot")
1169 args
= []string{"/c", "cd"}
1172 cmd
, err
= osexec
.LookPath("pwd")
1174 t
.Fatalf("Can't find pwd: %v", err
)
1178 t
.Logf("Testing with %v", cmd
)
1180 cmddir
, cmdbase
:= filepath
.Split(cmd
)
1181 args
= append([]string{cmdbase
}, args
...)
1182 // Test absolute executable path.
1183 exec(t
, dir
, cmd
, args
, dir
)
1184 // Test relative executable path.
1185 exec(t
, cmddir
, cmdbase
, args
, cmddir
)
1188 func checkMode(t
*testing
.T
, path
string, mode FileMode
) {
1189 dir
, err
:= Stat(path
)
1191 t
.Fatalf("Stat %q (looking for mode %#o): %s", path
, mode
, err
)
1193 if dir
.Mode()&ModePerm
!= mode
{
1194 t
.Errorf("Stat %q: mode %#o want %#o", path
, dir
.Mode(), mode
)
1198 func TestChmod(t
*testing
.T
) {
1199 f
:= newFile("TestChmod", t
)
1200 defer Remove(f
.Name())
1202 // Creation mode is read write
1204 fm
:= FileMode(0456)
1205 if runtime
.GOOS
== "windows" {
1206 fm
= FileMode(0444) // read-only file
1208 if err
:= Chmod(f
.Name(), fm
); err
!= nil {
1209 t
.Fatalf("chmod %s %#o: %s", f
.Name(), fm
, err
)
1211 checkMode(t
, f
.Name(), fm
)
1214 if runtime
.GOOS
== "windows" {
1215 fm
= FileMode(0666) // read-write file
1217 if err
:= f
.Chmod(fm
); err
!= nil {
1218 t
.Fatalf("chmod %s %#o: %s", f
.Name(), fm
, err
)
1220 checkMode(t
, f
.Name(), fm
)
1223 func checkSize(t
*testing
.T
, f
*File
, size
int64) {
1225 dir
, err
:= f
.Stat()
1227 t
.Fatalf("Stat %q (looking for size %d): %s", f
.Name(), size
, err
)
1229 if dir
.Size() != size
{
1230 t
.Errorf("Stat %q: size %d want %d", f
.Name(), dir
.Size(), size
)
1234 func TestFTruncate(t
*testing
.T
) {
1235 f
:= newFile("TestFTruncate", t
)
1236 defer Remove(f
.Name())
1240 f
.Write([]byte("hello, world\n"))
1245 checkSize(t
, f
, 1024)
1248 _
, err
:= f
.Write([]byte("surprise!"))
1250 checkSize(t
, f
, 13+9) // wrote at offset past where hello, world was.
1254 func TestTruncate(t
*testing
.T
) {
1255 f
:= newFile("TestTruncate", t
)
1256 defer Remove(f
.Name())
1260 f
.Write([]byte("hello, world\n"))
1262 Truncate(f
.Name(), 10)
1264 Truncate(f
.Name(), 1024)
1265 checkSize(t
, f
, 1024)
1266 Truncate(f
.Name(), 0)
1268 _
, err
:= f
.Write([]byte("surprise!"))
1270 checkSize(t
, f
, 13+9) // wrote at offset past where hello, world was.
1274 // Use TempDir (via newFile) to make sure we're on a local file system,
1275 // so that timings are not distorted by latency and caching.
1276 // On NFS, timings can be off due to caching of meta-data on
1277 // NFS servers (Issue 848).
1278 func TestChtimes(t
*testing
.T
) {
1279 f
:= newFile("TestChtimes", t
)
1280 defer Remove(f
.Name())
1282 f
.Write([]byte("hello, world\n"))
1285 testChtimes(t
, f
.Name())
1288 // Use TempDir (via newDir) to make sure we're on a local file system,
1289 // so that timings are not distorted by latency and caching.
1290 // On NFS, timings can be off due to caching of meta-data on
1291 // NFS servers (Issue 848).
1292 func TestChtimesDir(t
*testing
.T
) {
1293 name
:= newDir("TestChtimes", t
)
1294 defer RemoveAll(name
)
1296 testChtimes(t
, name
)
1299 func testChtimes(t
*testing
.T
, name
string) {
1300 st
, err
:= Stat(name
)
1302 t
.Fatalf("Stat %s: %s", name
, err
)
1306 // Move access and modification time back a second
1307 at
:= Atime(preStat
)
1308 mt
:= preStat
.ModTime()
1309 err
= Chtimes(name
, at
.Add(-time
.Second
), mt
.Add(-time
.Second
))
1311 t
.Fatalf("Chtimes %s: %s", name
, err
)
1314 st
, err
= Stat(name
)
1316 t
.Fatalf("second Stat %s: %s", name
, err
)
1320 pat
:= Atime(postStat
)
1321 pmt
:= postStat
.ModTime()
1322 if !pat
.Before(at
) {
1323 switch runtime
.GOOS
{
1325 // Mtime is the time of the last change of
1326 // content. Similarly, atime is set whenever
1327 // the contents are accessed; also, it is set
1328 // whenever mtime is set.
1330 mounts
, _
:= os
.ReadFile("/proc/mounts")
1331 if strings
.Contains(string(mounts
), "noatime") {
1332 t
.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.")
1334 t
.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at
, pat
)
1337 t
.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at
, pat
)
1341 if !pmt
.Before(mt
) {
1342 t
.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt
, pmt
)
1346 func TestFileChdir(t
*testing
.T
) {
1347 // TODO(brainman): file.Chdir() is not implemented on windows.
1348 if runtime
.GOOS
== "windows" {
1354 t
.Fatalf("Getwd: %s", err
)
1358 fd
, err
:= Open(".")
1360 t
.Fatalf("Open .: %s", err
)
1364 if err
:= Chdir("/"); err
!= nil {
1365 t
.Fatalf("Chdir /: %s", err
)
1368 if err
:= fd
.Chdir(); err
!= nil {
1369 t
.Fatalf("fd.Chdir: %s", err
)
1372 wdNew
, err
:= Getwd()
1374 t
.Fatalf("Getwd: %s", err
)
1377 t
.Fatalf("fd.Chdir failed, got %s, want %s", wdNew
, wd
)
1381 func TestChdirAndGetwd(t
*testing
.T
) {
1382 // TODO(brainman): file.Chdir() is not implemented on windows.
1383 if runtime
.GOOS
== "windows" {
1386 fd
, err
:= Open(".")
1388 t
.Fatalf("Open .: %s", err
)
1390 // These are chosen carefully not to be symlinks on a Mac
1391 // (unlike, say, /var, /etc), except /tmp, which we handle below.
1392 dirs
:= []string{"/", "/usr/bin", "/tmp"}
1393 // /usr/bin does not usually exist on Plan 9 or Android.
1394 switch runtime
.GOOS
{
1396 dirs
= []string{"/system/bin"}
1398 dirs
= []string{"/", "/usr"}
1401 for _
, d
:= range []string{"d1", "d2"} {
1402 dir
, err
:= os
.MkdirTemp("", d
)
1404 t
.Fatalf("TempDir: %v", err
)
1406 // Expand symlinks so path equality tests work.
1407 dir
, err
= filepath
.EvalSymlinks(dir
)
1409 t
.Fatalf("EvalSymlinks: %v", err
)
1411 dirs
= append(dirs
, dir
)
1414 oldwd
:= Getenv("PWD")
1415 for mode
:= 0; mode
< 2; mode
++ {
1416 for _
, d
:= range dirs
{
1420 fd1
, err1
:= Open(d
)
1422 t
.Errorf("Open %s: %s", d
, err1
)
1429 Setenv("PWD", "/tmp")
1431 pwd
, err1
:= Getwd()
1432 Setenv("PWD", oldwd
)
1435 // We changed the current directory and cannot go back.
1436 // Don't let the tests continue; they'll scribble
1437 // all over some other directory.
1438 fmt
.Fprintf(Stderr
, "fchdir back to dot failed: %s\n", err2
)
1443 t
.Fatalf("Chdir %s: %s", d
, err
)
1447 t
.Fatalf("Getwd in %s: %s", d
, err1
)
1451 t
.Fatalf("Getwd returned %q want %q", pwd
, d
)
1458 // Test that Chdir+Getwd is program-wide.
1459 func TestProgWideChdir(t
*testing
.T
) {
1461 const ErrPwd
= "Error!"
1462 c
:= make(chan bool)
1463 cpwd
:= make(chan string, N
)
1464 for i
:= 0; i
< N
; i
++ {
1466 // Lock half the goroutines in their own operating system
1467 // thread to exercise more scheduler possibilities.
1469 // On Plan 9, after calling LockOSThread, the goroutines
1470 // run on different processes which don't share the working
1471 // directory. This used to be an issue because Go expects
1472 // the working directory to be program-wide.
1474 runtime
.LockOSThread()
1476 hasErr
, closed := <-c
1477 if !closed && hasErr
{
1483 t
.Errorf("Getwd on goroutine %d: %v", i
, err
)
1490 oldwd
, err
:= Getwd()
1493 t
.Fatalf("Getwd: %v", err
)
1495 d
, err
:= os
.MkdirTemp("", "test")
1498 t
.Fatalf("TempDir: %v", err
)
1501 if err
:= Chdir(oldwd
); err
!= nil {
1502 t
.Fatalf("Chdir: %v", err
)
1506 if err
:= Chdir(d
); err
!= nil {
1508 t
.Fatalf("Chdir: %v", err
)
1510 // OS X sets TMPDIR to a symbolic link.
1511 // So we resolve our working directory again before the test.
1515 t
.Fatalf("Getwd: %v", err
)
1518 for i
:= 0; i
< N
; i
++ {
1524 t
.Errorf("Getwd returned %q; want %q", pwd
, d
)
1529 func TestSeek(t
*testing
.T
) {
1530 f
:= newFile("TestSeek", t
)
1531 defer Remove(f
.Name())
1534 const data
= "hello, world\n"
1535 io
.WriteString(f
, data
)
1543 {0, io
.SeekCurrent
, int64(len(data
))},
1544 {0, io
.SeekStart
, 0},
1545 {5, io
.SeekStart
, 5},
1546 {0, io
.SeekEnd
, int64(len(data
))},
1547 {0, io
.SeekStart
, 0},
1548 {-1, io
.SeekEnd
, int64(len(data
)) - 1},
1549 {1 << 33, io
.SeekStart
, 1 << 33},
1550 {1 << 33, io
.SeekEnd
, 1<<33 + int64(len(data
))},
1552 // Issue 21681, Windows 4G-1, etc:
1553 {1<<32 - 1, io
.SeekStart
, 1<<32 - 1},
1554 {0, io
.SeekCurrent
, 1<<32 - 1},
1555 {2<<32 - 1, io
.SeekStart
, 2<<32 - 1},
1556 {0, io
.SeekCurrent
, 2<<32 - 1},
1558 for i
, tt
:= range tests
{
1559 if runtime
.GOOS
== "hurd" && tt
.out
> 1<<32 {
1560 t
.Logf("skipping test case #%d on Hurd: file too large", i
)
1563 off
, err
:= f
.Seek(tt
.in
, tt
.whence
)
1564 if off
!= tt
.out || err
!= nil {
1565 if e
, ok
:= err
.(*PathError
); ok
&& e
.Err
== syscall
.EINVAL
&& tt
.out
> 1<<32 && runtime
.GOOS
== "linux" {
1566 mounts
, _
:= os
.ReadFile("/proc/mounts")
1567 if strings
.Contains(string(mounts
), "reiserfs") {
1568 // Reiserfs rejects the big seeks.
1569 t
.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91")
1572 t
.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i
, tt
.in
, tt
.whence
, off
, err
, tt
.out
)
1577 func TestSeekError(t
*testing
.T
) {
1578 switch runtime
.GOOS
{
1580 t
.Skipf("skipping test on %v", runtime
.GOOS
)
1587 _
, err
= r
.Seek(0, 0)
1589 t
.Fatal("Seek on pipe should fail")
1591 if perr
, ok
:= err
.(*PathError
); !ok || perr
.Err
!= syscall
.ESPIPE
{
1592 t
.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err
)
1594 _
, err
= w
.Seek(0, 0)
1596 t
.Fatal("Seek on pipe should fail")
1598 if perr
, ok
:= err
.(*PathError
); !ok || perr
.Err
!= syscall
.ESPIPE
{
1599 t
.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err
)
1603 type openErrorTest
struct {
1609 var openErrorTests
= []openErrorTest
{
1611 sfdir
+ "/no-such-file",
1621 sfdir
+ "/" + sfname
+ "/no-such-file",
1627 func TestOpenError(t
*testing
.T
) {
1628 for _
, tt
:= range openErrorTests
{
1629 f
, err
:= OpenFile(tt
.path
, tt
.mode
, 0)
1631 t
.Errorf("Open(%q, %d) succeeded", tt
.path
, tt
.mode
)
1635 perr
, ok
:= err
.(*PathError
)
1637 t
.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt
.path
, tt
.mode
, err
)
1639 if perr
.Err
!= tt
.error
{
1640 if runtime
.GOOS
== "plan9" {
1641 syscallErrStr
:= perr
.Err
.Error()
1642 expectedErrStr
:= strings
.Replace(tt
.error
.Error(), "file ", "", 1)
1643 if !strings
.HasSuffix(syscallErrStr
, expectedErrStr
) {
1644 // Some Plan 9 file servers incorrectly return
1645 // EACCES rather than EISDIR when a directory is
1646 // opened for write.
1647 if tt
.error
== syscall
.EISDIR
&& strings
.HasSuffix(syscallErrStr
, syscall
.EACCES
.Error()) {
1650 t
.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt
.path
, tt
.mode
, syscallErrStr
, expectedErrStr
)
1654 if runtime
.GOOS
== "dragonfly" {
1655 // DragonFly incorrectly returns EACCES rather
1656 // EISDIR when a directory is opened for write.
1657 if tt
.error
== syscall
.EISDIR
&& perr
.Err
== syscall
.EACCES
{
1661 t
.Errorf("Open(%q, %d) = _, %q; want %q", tt
.path
, tt
.mode
, perr
.Err
.Error(), tt
.error
.Error())
1666 func TestOpenNoName(t
*testing
.T
) {
1670 t
.Fatal(`Open("") succeeded`)
1674 func runBinHostname(t
*testing
.T
) string {
1675 // Run /bin/hostname and collect output.
1681 const path
= "/bin/hostname"
1682 argv
:= []string{"hostname"}
1683 if runtime
.GOOS
== "aix" {
1684 argv
= []string{"hostname", "-s"}
1686 p
, err
:= StartProcess(path
, argv
, &ProcAttr
{Files
: []*File
{nil, w
, Stderr
}})
1688 if _
, err
:= Stat(path
); IsNotExist(err
) {
1689 t
.Skipf("skipping test; test requires %s but it does not exist", path
)
1699 t
.Fatalf("run hostname Wait: %v", err
)
1703 t
.Errorf("expected an error from Kill running 'hostname'")
1705 output
:= b
.String()
1706 if n
:= len(output
); n
> 0 && output
[n
-1] == '\n' {
1707 output
= output
[0 : n
-1]
1710 t
.Fatalf("/bin/hostname produced no output")
1716 func testWindowsHostname(t
*testing
.T
, hostname
string) {
1717 cmd
:= osexec
.Command("hostname")
1718 out
, err
:= cmd
.CombinedOutput()
1720 t
.Fatalf("Failed to execute hostname command: %v %s", err
, out
)
1722 want
:= strings
.Trim(string(out
), "\r\n")
1723 if hostname
!= want
{
1724 t
.Fatalf("Hostname() = %q != system hostname of %q", hostname
, want
)
1728 func TestHostname(t
*testing
.T
) {
1729 hostname
, err
:= Hostname()
1734 t
.Fatal("Hostname returned empty string and no error")
1736 if strings
.Contains(hostname
, "\x00") {
1737 t
.Fatalf("unexpected zero byte in hostname: %q", hostname
)
1740 // There is no other way to fetch hostname on windows, but via winapi.
1741 // On Plan 9 it can be taken from #c/sysname as Hostname() does.
1742 switch runtime
.GOOS
{
1743 case "android", "plan9":
1744 // No /bin/hostname to verify against.
1747 testWindowsHostname(t
, hostname
)
1751 testenv
.MustHaveExec(t
)
1753 // Check internal Hostname() against the output of /bin/hostname.
1754 // Allow that the internal Hostname returns a Fully Qualified Domain Name
1755 // and the /bin/hostname only returns the first component
1756 want
:= runBinHostname(t
)
1757 if hostname
!= want
{
1758 host
, _
, ok
:= strings
.Cut(hostname
, ".")
1759 if !ok || host
!= want
{
1760 t
.Errorf("Hostname() = %q, want %q", hostname
, want
)
1765 func TestReadAt(t
*testing
.T
) {
1766 f
:= newFile("TestReadAt", t
)
1767 defer Remove(f
.Name())
1770 const data
= "hello, world\n"
1771 io
.WriteString(f
, data
)
1773 b
:= make([]byte, 5)
1774 n
, err
:= f
.ReadAt(b
, 7)
1775 if err
!= nil || n
!= len(b
) {
1776 t
.Fatalf("ReadAt 7: %d, %v", n
, err
)
1778 if string(b
) != "world" {
1779 t
.Fatalf("ReadAt 7: have %q want %q", string(b
), "world")
1783 // Verify that ReadAt doesn't affect seek offset.
1784 // In the Plan 9 kernel, there used to be a bug in the implementation of
1785 // the pread syscall, where the channel offset was erroneously updated after
1786 // calling pread on a file.
1787 func TestReadAtOffset(t
*testing
.T
) {
1788 f
:= newFile("TestReadAtOffset", t
)
1789 defer Remove(f
.Name())
1792 const data
= "hello, world\n"
1793 io
.WriteString(f
, data
)
1796 b
:= make([]byte, 5)
1798 n
, err
:= f
.ReadAt(b
, 7)
1799 if err
!= nil || n
!= len(b
) {
1800 t
.Fatalf("ReadAt 7: %d, %v", n
, err
)
1802 if string(b
) != "world" {
1803 t
.Fatalf("ReadAt 7: have %q want %q", string(b
), "world")
1807 if err
!= nil || n
!= len(b
) {
1808 t
.Fatalf("Read: %d, %v", n
, err
)
1810 if string(b
) != "hello" {
1811 t
.Fatalf("Read: have %q want %q", string(b
), "hello")
1815 // Verify that ReadAt doesn't allow negative offset.
1816 func TestReadAtNegativeOffset(t
*testing
.T
) {
1817 f
:= newFile("TestReadAtNegativeOffset", t
)
1818 defer Remove(f
.Name())
1821 const data
= "hello, world\n"
1822 io
.WriteString(f
, data
)
1825 b
:= make([]byte, 5)
1827 n
, err
:= f
.ReadAt(b
, -10)
1829 const wantsub
= "negative offset"
1830 if !strings
.Contains(fmt
.Sprint(err
), wantsub
) || n
!= 0 {
1831 t
.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n
, err
, wantsub
)
1835 func TestWriteAt(t
*testing
.T
) {
1836 f
:= newFile("TestWriteAt", t
)
1837 defer Remove(f
.Name())
1840 const data
= "hello, world\n"
1841 io
.WriteString(f
, data
)
1843 n
, err
:= f
.WriteAt([]byte("WORLD"), 7)
1844 if err
!= nil || n
!= 5 {
1845 t
.Fatalf("WriteAt 7: %d, %v", n
, err
)
1848 b
, err
:= os
.ReadFile(f
.Name())
1850 t
.Fatalf("ReadFile %s: %v", f
.Name(), err
)
1852 if string(b
) != "hello, WORLD\n" {
1853 t
.Fatalf("after write: have %q want %q", string(b
), "hello, WORLD\n")
1857 // Verify that WriteAt doesn't allow negative offset.
1858 func TestWriteAtNegativeOffset(t
*testing
.T
) {
1859 f
:= newFile("TestWriteAtNegativeOffset", t
)
1860 defer Remove(f
.Name())
1863 n
, err
:= f
.WriteAt([]byte("WORLD"), -10)
1865 const wantsub
= "negative offset"
1866 if !strings
.Contains(fmt
.Sprint(err
), wantsub
) || n
!= 0 {
1867 t
.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n
, err
, wantsub
)
1871 // Verify that WriteAt doesn't work in append mode.
1872 func TestWriteAtInAppendMode(t
*testing
.T
) {
1874 f
, err
:= OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE
, 0666)
1876 t
.Fatalf("OpenFile: %v", err
)
1880 _
, err
= f
.WriteAt([]byte(""), 1)
1881 if err
!= ErrWriteAtInAppendMode
{
1882 t
.Fatalf("f.WriteAt returned %v, expected %v", err
, ErrWriteAtInAppendMode
)
1886 func writeFile(t
*testing
.T
, fname
string, flag
int, text
string) string {
1887 f
, err
:= OpenFile(fname
, flag
, 0666)
1889 t
.Fatalf("Open: %v", err
)
1891 n
, err
:= io
.WriteString(f
, text
)
1893 t
.Fatalf("WriteString: %d, %v", n
, err
)
1896 data
, err
:= os
.ReadFile(fname
)
1898 t
.Fatalf("ReadFile: %v", err
)
1903 func TestAppend(t
*testing
.T
) {
1905 const f
= "append.txt"
1906 s
:= writeFile(t
, f
, O_CREATE|O_TRUNC|O_RDWR
, "new")
1908 t
.Fatalf("writeFile: have %q want %q", s
, "new")
1910 s
= writeFile(t
, f
, O_APPEND|O_RDWR
, "|append")
1911 if s
!= "new|append" {
1912 t
.Fatalf("writeFile: have %q want %q", s
, "new|append")
1914 s
= writeFile(t
, f
, O_CREATE|O_APPEND|O_RDWR
, "|append")
1915 if s
!= "new|append|append" {
1916 t
.Fatalf("writeFile: have %q want %q", s
, "new|append|append")
1920 t
.Fatalf("Remove: %v", err
)
1922 s
= writeFile(t
, f
, O_CREATE|O_APPEND|O_RDWR
, "new&append")
1923 if s
!= "new&append" {
1924 t
.Fatalf("writeFile: after append have %q want %q", s
, "new&append")
1926 s
= writeFile(t
, f
, O_CREATE|O_RDWR
, "old")
1927 if s
!= "old&append" {
1928 t
.Fatalf("writeFile: after create have %q want %q", s
, "old&append")
1930 s
= writeFile(t
, f
, O_CREATE|O_TRUNC|O_RDWR
, "new")
1932 t
.Fatalf("writeFile: after truncate have %q want %q", s
, "new")
1936 func TestStatDirWithTrailingSlash(t
*testing
.T
) {
1937 // Create new temporary directory and arrange to clean it up.
1940 // Stat of path should succeed.
1941 if _
, err
:= Stat(path
); err
!= nil {
1942 t
.Fatalf("stat %s failed: %s", path
, err
)
1945 // Stat of path+"/" should succeed too.
1947 if _
, err
:= Stat(path
); err
!= nil {
1948 t
.Fatalf("stat %s failed: %s", path
, err
)
1952 func TestNilProcessStateString(t
*testing
.T
) {
1953 var ps
*ProcessState
1956 t
.Errorf("(*ProcessState)(nil).String() = %q, want %q", s
, "<nil>")
1960 func TestSameFile(t
*testing
.T
) {
1962 fa
, err
:= Create("a")
1964 t
.Fatalf("Create(a): %v", err
)
1967 fb
, err
:= Create("b")
1969 t
.Fatalf("Create(b): %v", err
)
1973 ia1
, err
:= Stat("a")
1975 t
.Fatalf("Stat(a): %v", err
)
1977 ia2
, err
:= Stat("a")
1979 t
.Fatalf("Stat(a): %v", err
)
1981 if !SameFile(ia1
, ia2
) {
1982 t
.Errorf("files should be same")
1985 ib
, err
:= Stat("b")
1987 t
.Fatalf("Stat(b): %v", err
)
1989 if SameFile(ia1
, ib
) {
1990 t
.Errorf("files should be different")
1994 func testDevNullFileInfo(t
*testing
.T
, statname
, devNullName
string, fi FileInfo
, ignoreCase
bool) {
1995 pre
:= fmt
.Sprintf("%s(%q): ", statname
, devNullName
)
1996 name
:= filepath
.Base(devNullName
)
1998 if strings
.ToUpper(fi
.Name()) != strings
.ToUpper(name
) {
1999 t
.Errorf(pre
+"wrong file name have %v want %v", fi
.Name(), name
)
2002 if fi
.Name() != name
{
2003 t
.Errorf(pre
+"wrong file name have %v want %v", fi
.Name(), name
)
2007 t
.Errorf(pre
+"wrong file size have %d want 0", fi
.Size())
2009 if fi
.Mode()&ModeDevice
== 0 {
2010 t
.Errorf(pre
+"wrong file mode %q: ModeDevice is not set", fi
.Mode())
2012 if fi
.Mode()&ModeCharDevice
== 0 {
2013 t
.Errorf(pre
+"wrong file mode %q: ModeCharDevice is not set", fi
.Mode())
2015 if fi
.Mode().IsRegular() {
2016 t
.Errorf(pre
+"wrong file mode %q: IsRegular returns true", fi
.Mode())
2020 func testDevNullFile(t
*testing
.T
, devNullName
string, ignoreCase
bool) {
2021 f
, err
:= Open(devNullName
)
2023 t
.Fatalf("Open(%s): %v", devNullName
, err
)
2029 t
.Fatalf("Stat(%s): %v", devNullName
, err
)
2031 testDevNullFileInfo(t
, "f.Stat", devNullName
, fi
, ignoreCase
)
2033 fi
, err
= Stat(devNullName
)
2035 t
.Fatalf("Stat(%s): %v", devNullName
, err
)
2037 testDevNullFileInfo(t
, "Stat", devNullName
, fi
, ignoreCase
)
2040 func TestDevNullFile(t
*testing
.T
) {
2041 testDevNullFile(t
, DevNull
, false)
2044 var testLargeWrite
= flag
.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
2046 func TestLargeWriteToConsole(t
*testing
.T
) {
2047 if !*testLargeWrite
{
2048 t
.Skip("skipping console-flooding test; enable with -large_write")
2050 b
:= make([]byte, 32000)
2055 n
, err
:= Stdout
.Write(b
)
2057 t
.Fatalf("Write to os.Stdout failed: %v", err
)
2060 t
.Errorf("Write to os.Stdout should return %d; got %d", len(b
), n
)
2062 n
, err
= Stderr
.Write(b
)
2064 t
.Fatalf("Write to os.Stderr failed: %v", err
)
2067 t
.Errorf("Write to os.Stderr should return %d; got %d", len(b
), n
)
2071 func TestStatDirModeExec(t
*testing
.T
) {
2075 if err
:= Chmod(path
, 0777); err
!= nil {
2076 t
.Fatalf("Chmod %q 0777: %v", path
, err
)
2079 dir
, err
:= Stat(path
)
2081 t
.Fatalf("Stat %q (looking for mode %#o): %s", path
, mode
, err
)
2083 if dir
.Mode()&mode
!= mode
{
2084 t
.Errorf("Stat %q: mode %#o want %#o", path
, dir
.Mode()&mode
, mode
)
2088 func TestStatStdin(t
*testing
.T
) {
2089 switch runtime
.GOOS
{
2090 case "android", "plan9":
2091 t
.Skipf("%s doesn't have /bin/sh", runtime
.GOOS
)
2094 testenv
.MustHaveExec(t
)
2096 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2097 st
, err
:= Stdin
.Stat()
2099 t
.Fatalf("Stat failed: %v", err
)
2101 fmt
.Println(st
.Mode() & ModeNamedPipe
)
2105 fi
, err
:= Stdin
.Stat()
2109 switch mode
:= fi
.Mode(); {
2110 case mode
&ModeCharDevice
!= 0 && mode
&ModeDevice
!= 0:
2111 case mode
&ModeNamedPipe
!= 0:
2113 t
.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode
)
2117 if runtime
.GOOS
== "windows" {
2118 cmd
= osexec
.Command("cmd", "/c", "echo output | "+Args
[0]+" -test.run=TestStatStdin")
2120 cmd
= osexec
.Command("/bin/sh", "-c", "echo output | "+Args
[0]+" -test.run=TestStatStdin")
2122 cmd
.Env
= append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2124 output
, err
:= cmd
.CombinedOutput()
2126 t
.Fatalf("Failed to spawn child process: %v %q", err
, string(output
))
2129 // result will be like "prw-rw-rw"
2130 if len(output
) < 1 || output
[0] != 'p' {
2131 t
.Fatalf("Child process reports stdin is not pipe '%v'", string(output
))
2135 func TestStatRelativeSymlink(t
*testing
.T
) {
2136 testenv
.MustHaveSymlink(t
)
2138 tmpdir
:= t
.TempDir()
2139 target
:= filepath
.Join(tmpdir
, "target")
2140 f
, err
:= Create(target
)
2151 link
:= filepath
.Join(tmpdir
, "link")
2152 err
= Symlink(filepath
.Base(target
), link
)
2157 st1
, err
:= Stat(link
)
2162 if !SameFile(st
, st1
) {
2163 t
.Error("Stat doesn't follow relative symlink")
2166 if runtime
.GOOS
== "windows" {
2168 err
= Symlink(target
[len(filepath
.VolumeName(target
)):], link
)
2173 st1
, err
:= Stat(link
)
2178 if !SameFile(st
, st1
) {
2179 t
.Error("Stat doesn't follow relative symlink")
2184 func TestReadAtEOF(t
*testing
.T
) {
2185 f
:= newFile("TestReadAtEOF", t
)
2186 defer Remove(f
.Name())
2189 _
, err
:= f
.ReadAt(make([]byte, 10), 0)
2194 t
.Fatalf("ReadAt succeeded")
2196 t
.Fatalf("ReadAt failed: %s", err
)
2200 func TestLongPath(t
*testing
.T
) {
2201 tmpdir
:= newDir("TestLongPath", t
)
2202 defer func(d
string) {
2203 if err
:= RemoveAll(d
); err
!= nil {
2204 t
.Fatalf("RemoveAll failed: %v", err
)
2208 // Test the boundary of 247 and fewer bytes (normal) and 248 and more bytes (adjusted).
2209 sizes
:= []int{247, 248, 249, 400}
2210 for len(tmpdir
) < 400 {
2211 tmpdir
+= "/dir3456789"
2213 for _
, sz
:= range sizes
{
2214 t
.Run(fmt
.Sprintf("length=%d", sz
), func(t
*testing
.T
) {
2215 sizedTempDir
:= tmpdir
[:sz
-1] + "x" // Ensure it does not end with a slash.
2217 // The various sized runs are for this call to trigger the boundary
2219 if err
:= MkdirAll(sizedTempDir
, 0755); err
!= nil {
2220 t
.Fatalf("MkdirAll failed: %v", err
)
2222 data
:= []byte("hello world\n")
2223 if err
:= os
.WriteFile(sizedTempDir
+"/foo.txt", data
, 0644); err
!= nil {
2224 t
.Fatalf("os.WriteFile() failed: %v", err
)
2226 if err
:= Rename(sizedTempDir
+"/foo.txt", sizedTempDir
+"/bar.txt"); err
!= nil {
2227 t
.Fatalf("Rename failed: %v", err
)
2229 mtime
:= time
.Now().Truncate(time
.Minute
)
2230 if err
:= Chtimes(sizedTempDir
+"/bar.txt", mtime
, mtime
); err
!= nil {
2231 t
.Fatalf("Chtimes failed: %v", err
)
2233 names
:= []string{"bar.txt"}
2234 if testenv
.HasSymlink() {
2235 if err
:= Symlink(sizedTempDir
+"/bar.txt", sizedTempDir
+"/symlink.txt"); err
!= nil {
2236 t
.Fatalf("Symlink failed: %v", err
)
2238 names
= append(names
, "symlink.txt")
2240 if testenv
.HasLink() {
2241 if err
:= Link(sizedTempDir
+"/bar.txt", sizedTempDir
+"/link.txt"); err
!= nil {
2242 t
.Fatalf("Link failed: %v", err
)
2244 names
= append(names
, "link.txt")
2246 for _
, wantSize
:= range []int64{int64(len(data
)), 0} {
2247 for _
, name
:= range names
{
2248 path
:= sizedTempDir
+ "/" + name
2249 dir
, err
:= Stat(path
)
2251 t
.Fatalf("Stat(%q) failed: %v", path
, err
)
2253 filesize
:= size(path
, t
)
2254 if dir
.Size() != filesize || filesize
!= wantSize
{
2255 t
.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path
, dir
.Size(), filesize
, wantSize
)
2257 err
= Chmod(path
, dir
.Mode())
2259 t
.Fatalf("Chmod(%q) failed: %v", path
, err
)
2262 if err
:= Truncate(sizedTempDir
+"/bar.txt", 0); err
!= nil {
2263 t
.Fatalf("Truncate failed: %v", err
)
2270 func testKillProcess(t
*testing
.T
, processKiller
func(p
*Process
)) {
2271 testenv
.MustHaveExec(t
)
2274 // Re-exec the test binary to start a process that hangs until stdin is closed.
2275 cmd
:= osexec
.Command(Args
[0])
2276 cmd
.Env
= append(os
.Environ(), "GO_OS_TEST_DRAIN_STDIN=1")
2277 stdout
, err
:= cmd
.StdoutPipe()
2281 stdin
, err
:= cmd
.StdinPipe()
2287 t
.Fatalf("Failed to start test process: %v", err
)
2291 if err
:= cmd
.Wait(); err
== nil {
2292 t
.Errorf("Test process succeeded, but expected to fail")
2294 stdin
.Close() // Keep stdin alive until the process has finished dying.
2297 // Wait for the process to be started.
2298 // (It will close its stdout when it reaches TestMain.)
2299 io
.Copy(io
.Discard
, stdout
)
2301 processKiller(cmd
.Process
)
2304 func TestKillStartProcess(t
*testing
.T
) {
2305 testKillProcess(t
, func(p
*Process
) {
2308 t
.Fatalf("Failed to kill test process: %v", err
)
2313 func TestGetppid(t
*testing
.T
) {
2314 if runtime
.GOOS
== "plan9" {
2315 // TODO: golang.org/issue/8206
2316 t
.Skipf("skipping test on plan9; see issue 8206")
2319 testenv
.MustHaveExec(t
)
2321 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2322 fmt
.Print(Getppid())
2326 cmd
:= osexec
.Command(Args
[0], "-test.run=TestGetppid")
2327 cmd
.Env
= append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2329 // verify that Getppid() from the forked process reports our process id
2330 output
, err
:= cmd
.CombinedOutput()
2332 t
.Fatalf("Failed to spawn child process: %v %q", err
, string(output
))
2335 childPpid
:= string(output
)
2336 ourPid
:= fmt
.Sprintf("%d", Getpid())
2337 if childPpid
!= ourPid
{
2338 t
.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid
, ourPid
)
2342 func TestKillFindProcess(t
*testing
.T
) {
2343 testKillProcess(t
, func(p
*Process
) {
2344 p2
, err
:= FindProcess(p
.Pid
)
2346 t
.Fatalf("Failed to find test process: %v", err
)
2350 t
.Fatalf("Failed to kill test process: %v", err
)
2355 var nilFileMethodTests
= []struct {
2359 {"Chdir", func(f
*File
) error
{ return f
.Chdir() }},
2360 {"Close", func(f
*File
) error
{ return f
.Close() }},
2361 {"Chmod", func(f
*File
) error
{ return f
.Chmod(0) }},
2362 {"Chown", func(f
*File
) error
{ return f
.Chown(0, 0) }},
2363 {"Read", func(f
*File
) error
{ _
, err
:= f
.Read(make([]byte, 0)); return err
}},
2364 {"ReadAt", func(f
*File
) error
{ _
, err
:= f
.ReadAt(make([]byte, 0), 0); return err
}},
2365 {"Readdir", func(f
*File
) error
{ _
, err
:= f
.Readdir(1); return err
}},
2366 {"Readdirnames", func(f
*File
) error
{ _
, err
:= f
.Readdirnames(1); return err
}},
2367 {"Seek", func(f
*File
) error
{ _
, err
:= f
.Seek(0, io
.SeekStart
); return err
}},
2368 {"Stat", func(f
*File
) error
{ _
, err
:= f
.Stat(); return err
}},
2369 {"Sync", func(f
*File
) error
{ return f
.Sync() }},
2370 {"Truncate", func(f
*File
) error
{ return f
.Truncate(0) }},
2371 {"Write", func(f
*File
) error
{ _
, err
:= f
.Write(make([]byte, 0)); return err
}},
2372 {"WriteAt", func(f
*File
) error
{ _
, err
:= f
.WriteAt(make([]byte, 0), 0); return err
}},
2373 {"WriteString", func(f
*File
) error
{ _
, err
:= f
.WriteString(""); return err
}},
2376 // Test that all File methods give ErrInvalid if the receiver is nil.
2377 func TestNilFileMethods(t
*testing
.T
) {
2378 for _
, tt
:= range nilFileMethodTests
{
2381 if got
!= ErrInvalid
{
2382 t
.Errorf("%v should fail when f is nil; got %v", tt
.name
, got
)
2387 func mkdirTree(t
*testing
.T
, root
string, level
, max
int) {
2392 for i
:= 'a'; i
< 'c'; i
++ {
2393 dir
:= filepath
.Join(root
, string(i
))
2394 if err
:= Mkdir(dir
, 0700); err
!= nil {
2397 mkdirTree(t
, dir
, level
, max
)
2401 // Test that simultaneous RemoveAll do not report an error.
2402 // As long as it gets removed, we should be happy.
2403 func TestRemoveAllRace(t
*testing
.T
) {
2404 if runtime
.GOOS
== "windows" {
2405 // Windows has very strict rules about things like
2406 // removing directories while someone else has
2407 // them open. The racing doesn't work out nicely
2408 // like it does on Unix.
2409 t
.Skip("skipping on windows")
2412 n
:= runtime
.GOMAXPROCS(16)
2413 defer runtime
.GOMAXPROCS(n
)
2414 root
, err
:= os
.MkdirTemp("", "issue")
2418 mkdirTree(t
, root
, 1, 6)
2419 hold
:= make(chan struct{})
2420 var wg sync
.WaitGroup
2421 for i
:= 0; i
< 4; i
++ {
2426 err
:= RemoveAll(root
)
2428 t
.Errorf("unexpected error: %T, %q", err
, err
)
2432 close(hold
) // let workers race to remove root
2436 // Test that reading from a pipe doesn't use up a thread.
2437 func TestPipeThreads(t
*testing
.T
) {
2438 switch runtime
.GOOS
{
2439 case "illumos", "solaris":
2440 t
.Skip("skipping on Solaris and illumos; issue 19111")
2442 t
.Skip("skipping on Windows; issue 19098")
2444 t
.Skip("skipping on Plan 9; does not support runtime poller")
2446 t
.Skip("skipping on js; no support for os.Pipe")
2451 // OpenBSD has a low default for max number of files.
2452 if runtime
.GOOS
== "openbsd" {
2456 r
:= make([]*File
, threads
)
2457 w
:= make([]*File
, threads
)
2458 for i
:= 0; i
< threads
; i
++ {
2459 rp
, wp
, err
:= Pipe()
2461 for j
:= 0; j
< i
; j
++ {
2471 defer debug
.SetMaxThreads(debug
.SetMaxThreads(threads
/ 2))
2473 creading
:= make(chan bool, threads
)
2474 cdone
:= make(chan bool, threads
)
2475 for i
:= 0; i
< threads
; i
++ {
2479 if _
, err
:= r
[i
].Read(b
[:]); err
!= nil {
2482 if err
:= r
[i
].Close(); err
!= nil {
2489 for i
:= 0; i
< threads
; i
++ {
2493 // If we are still alive, it means that the 100 goroutines did
2494 // not require 100 threads.
2496 for i
:= 0; i
< threads
; i
++ {
2497 if _
, err
:= w
[i
].Write([]byte{0}); err
!= nil {
2500 if err
:= w
[i
].Close(); err
!= nil {
2507 func testDoubleCloseError(t
*testing
.T
, path
string) {
2508 file
, err
:= Open(path
)
2512 if err
:= file
.Close(); err
!= nil {
2513 t
.Fatalf("unexpected error from Close: %v", err
)
2515 if err
:= file
.Close(); err
== nil {
2516 t
.Error("second Close did not fail")
2517 } else if pe
, ok
:= err
.(*PathError
); !ok
{
2518 t
.Errorf("second Close returned unexpected error type %T; expected fs.PathError", pe
)
2519 } else if pe
.Err
!= ErrClosed
{
2520 t
.Errorf("second Close returned %q, wanted %q", err
, ErrClosed
)
2522 t
.Logf("second close returned expected error %q", err
)
2526 func TestDoubleCloseError(t
*testing
.T
) {
2527 testDoubleCloseError(t
, filepath
.Join(sfdir
, sfname
))
2528 testDoubleCloseError(t
, sfdir
)
2531 func TestUserHomeDir(t
*testing
.T
) {
2532 dir
, err
:= UserHomeDir()
2533 if dir
== "" && err
== nil {
2534 t
.Fatal("UserHomeDir returned an empty string but no error")
2537 t
.Skipf("UserHomeDir failed: %v", err
)
2539 fi
, err
:= Stat(dir
)
2544 t
.Fatalf("dir %s is not directory; type = %v", dir
, fi
.Mode())
2548 func TestDirSeek(t
*testing
.T
) {
2549 if runtime
.GOOS
== "windows" {
2550 testenv
.SkipFlaky(t
, 36019)
2560 dirnames1
, err
:= f
.Readdirnames(0)
2565 ret
, err
:= f
.Seek(0, 0)
2570 t
.Fatalf("seek result not zero: %d", ret
)
2573 dirnames2
, err
:= f
.Readdirnames(0)
2579 if len(dirnames1
) != len(dirnames2
) {
2580 t
.Fatalf("listings have different lengths: %d and %d\n", len(dirnames1
), len(dirnames2
))
2582 for i
, n1
:= range dirnames1
{
2585 t
.Fatalf("different name i=%d n1=%s n2=%s\n", i
, n1
, n2
)
2590 func TestReaddirSmallSeek(t
*testing
.T
) {
2591 // See issue 37161. Read only one entry from a directory,
2592 // seek to the beginning, and read again. We should not see
2593 // duplicate entries.
2594 if runtime
.GOOS
== "windows" {
2595 testenv
.SkipFlaky(t
, 36019)
2601 df
, err
:= Open(filepath
.Join(wd
, "testdata", "issue37161"))
2605 names1
, err
:= df
.Readdirnames(1)
2609 if _
, err
= df
.Seek(0, 0); err
!= nil {
2612 names2
, err
:= df
.Readdirnames(0)
2616 if len(names2
) != 3 {
2617 t
.Fatalf("first names: %v, second names: %v", names1
, names2
)
2621 // isDeadlineExceeded reports whether err is or wraps os.ErrDeadlineExceeded.
2622 // We also check that the error has a Timeout method that returns true.
2623 func isDeadlineExceeded(err error
) bool {
2624 if !IsTimeout(err
) {
2627 if !errors
.Is(err
, ErrDeadlineExceeded
) {
2633 // Test that opening a file does not change its permissions. Issue 38225.
2634 func TestOpenFileKeepsPermissions(t
*testing
.T
) {
2637 name
:= filepath
.Join(dir
, "x")
2638 f
, err
:= Create(name
)
2642 if err
:= f
.Close(); err
!= nil {
2645 f
, err
= OpenFile(name
, O_WRONLY|O_CREATE|O_TRUNC
, 0)
2649 if fi
, err
:= f
.Stat(); err
!= nil {
2651 } else if fi
.Mode()&0222 == 0 {
2652 t
.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi
.Mode())
2654 if err
:= f
.Close(); err
!= nil {
2657 if fi
, err
:= Stat(name
); err
!= nil {
2659 } else if fi
.Mode()&0222 == 0 {
2660 t
.Errorf("Stat after OpenFile is %v, should be writable", fi
.Mode())
2664 func TestDirFS(t
*testing
.T
) {
2665 // On Windows, we force the MFT to update by reading the actual metadata from GetFileInformationByHandle and then
2666 // explicitly setting that. Otherwise it might get out of sync with FindFirstFile. See golang.org/issues/42637.
2667 if runtime
.GOOS
== "windows" {
2668 if err
:= filepath
.WalkDir("./testdata/dirfs", func(path
string, d fs
.DirEntry
, err error
) error
{
2672 info
, err
:= d
.Info()
2676 stat
, err
:= Stat(path
) // This uses GetFileInformationByHandle internally.
2680 if stat
.ModTime() == info
.ModTime() {
2683 if err
:= Chtimes(path
, stat
.ModTime(), stat
.ModTime()); err
!= nil {
2684 t
.Log(err
) // We only log, not die, in case the test directory is not writable.
2691 if err
:= fstest
.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err
!= nil {
2695 // Test that Open does not accept backslash as separator.
2697 _
, err
:= d
.Open(`testdata\dirfs`)
2699 t
.Fatalf(`Open testdata\dirfs succeeded`)
2703 func TestDirFSPathsValid(t
*testing
.T
) {
2704 if runtime
.GOOS
== "windows" {
2705 t
.Skipf("skipping on Windows")
2709 if err
:= os
.WriteFile(filepath
.Join(d
, "control.txt"), []byte(string("Hello, world!")), 0644); err
!= nil {
2712 if err
:= os
.WriteFile(filepath
.Join(d
, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err
!= nil {
2717 err
:= fs
.WalkDir(fsys
, ".", func(path
string, e fs
.DirEntry
, err error
) error
{
2718 if fs
.ValidPath(e
.Name()) {
2719 t
.Logf("%q ok", e
.Name())
2721 t
.Errorf("%q INVALID", e
.Name())
2730 func TestReadFileProc(t
*testing
.T
) {
2731 // Linux files in /proc report 0 size,
2732 // but then if ReadFile reads just a single byte at offset 0,
2733 // the read at offset 1 returns EOF instead of more data.
2734 // ReadFile has a minimum read size of 512 to work around this,
2735 // but test explicitly that it's working.
2736 name
:= "/proc/sys/fs/pipe-max-size"
2737 if _
, err
:= Stat(name
); err
!= nil {
2740 data
, err
:= ReadFile(name
)
2744 if len(data
) == 0 || data
[len(data
)-1] != '\n' {
2745 t
.Fatalf("read %s: not newline-terminated: %q", name
, data
)
2749 func TestWriteStringAlloc(t
*testing
.T
) {
2750 if runtime
.GOOS
== "js" {
2751 t
.Skip("js allocates a lot during File.WriteString")
2754 f
, err
:= Create(filepath
.Join(d
, "whiteboard.txt"))
2759 allocs
:= testing
.AllocsPerRun(100, func() {
2760 f
.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
2763 t
.Errorf("expected 0 allocs for File.WriteString, got %v", allocs
)