Source file
src/os/os_test.go
Documentation: os
1
2
3
4
5 package os_test
6
7 import (
8 "errors"
9 "flag"
10 "fmt"
11 "internal/testenv"
12 "io"
13 "io/fs"
14 "log"
15 . "os"
16 "os/exec"
17 "path/filepath"
18 "reflect"
19 "runtime"
20 "runtime/debug"
21 "sort"
22 "strings"
23 "sync"
24 "syscall"
25 "testing"
26 "testing/fstest"
27 "time"
28 )
29
30 func TestMain(m *testing.M) {
31 if Getenv("GO_OS_TEST_DRAIN_STDIN") == "1" {
32 Stdout.Close()
33 io.Copy(io.Discard, Stdin)
34 Exit(0)
35 }
36
37 log.SetFlags(log.LstdFlags | log.Lshortfile)
38
39 Exit(m.Run())
40 }
41
42 var dot = []string{
43 "dir_unix.go",
44 "env.go",
45 "error.go",
46 "file.go",
47 "os_test.go",
48 "types.go",
49 "stat_darwin.go",
50 "stat_linux.go",
51 }
52
53 type sysDir struct {
54 name string
55 files []string
56 }
57
58 var sysdir = func() *sysDir {
59 switch runtime.GOOS {
60 case "android":
61 return &sysDir{
62 "/system/lib",
63 []string{
64 "libmedia.so",
65 "libpowermanager.so",
66 },
67 }
68 case "ios":
69 wd, err := syscall.Getwd()
70 if err != nil {
71 wd = err.Error()
72 }
73 sd := &sysDir{
74 filepath.Join(wd, "..", ".."),
75 []string{
76 "ResourceRules.plist",
77 "Info.plist",
78 },
79 }
80 found := true
81 for _, f := range sd.files {
82 path := filepath.Join(sd.name, f)
83 if _, err := Stat(path); err != nil {
84 found = false
85 break
86 }
87 }
88 if found {
89 return sd
90 }
91
92
93 case "windows":
94 return &sysDir{
95 Getenv("SystemRoot") + "\\system32\\drivers\\etc",
96 []string{
97 "networks",
98 "protocol",
99 "services",
100 },
101 }
102 case "plan9":
103 return &sysDir{
104 "/lib/ndb",
105 []string{
106 "common",
107 "local",
108 },
109 }
110 case "wasip1":
111
112
113
114 return &sysDir{
115 runtime.GOROOT(),
116 []string{
117 "go.env",
118 "LICENSE",
119 "CONTRIBUTING.md",
120 },
121 }
122 }
123 return &sysDir{
124 "/etc",
125 []string{
126 "group",
127 "hosts",
128 "passwd",
129 },
130 }
131 }()
132
133 func size(name string, t *testing.T) int64 {
134 file, err := Open(name)
135 if err != nil {
136 t.Fatal("open failed:", err)
137 }
138 defer func() {
139 if err := file.Close(); err != nil {
140 t.Error(err)
141 }
142 }()
143 n, err := io.Copy(io.Discard, file)
144 if err != nil {
145 t.Fatal(err)
146 }
147 return n
148 }
149
150 func equal(name1, name2 string) (r bool) {
151 switch runtime.GOOS {
152 case "windows":
153 r = strings.EqualFold(name1, name2)
154 default:
155 r = name1 == name2
156 }
157 return
158 }
159
160
161 func localTmp() string {
162 switch runtime.GOOS {
163 case "android", "ios", "windows":
164 return TempDir()
165 }
166 return "/tmp"
167 }
168
169 func newFile(testName string, t *testing.T) (f *File) {
170 f, err := CreateTemp(localTmp(), "_Go_"+testName)
171 if err != nil {
172 t.Fatalf("TempFile %s: %s", testName, err)
173 }
174 return
175 }
176
177 func newDir(testName string, t *testing.T) (name string) {
178 name, err := MkdirTemp(localTmp(), "_Go_"+testName)
179 if err != nil {
180 t.Fatalf("TempDir %s: %s", testName, err)
181 }
182 return
183 }
184
185 var sfdir = sysdir.name
186 var sfname = sysdir.files[0]
187
188 func TestStat(t *testing.T) {
189 t.Parallel()
190
191 path := sfdir + "/" + sfname
192 dir, err := Stat(path)
193 if err != nil {
194 t.Fatal("stat failed:", err)
195 }
196 if !equal(sfname, dir.Name()) {
197 t.Error("name should be ", sfname, "; is", dir.Name())
198 }
199 filesize := size(path, t)
200 if dir.Size() != filesize {
201 t.Error("size should be", filesize, "; is", dir.Size())
202 }
203 }
204
205 func TestStatError(t *testing.T) {
206 defer chtmpdir(t)()
207
208 path := "no-such-file"
209
210 fi, err := Stat(path)
211 if err == nil {
212 t.Fatal("got nil, want error")
213 }
214 if fi != nil {
215 t.Errorf("got %v, want nil", fi)
216 }
217 if perr, ok := err.(*PathError); !ok {
218 t.Errorf("got %T, want %T", err, perr)
219 }
220
221 testenv.MustHaveSymlink(t)
222
223 link := "symlink"
224 err = Symlink(path, link)
225 if err != nil {
226 t.Fatal(err)
227 }
228
229 fi, err = Stat(link)
230 if err == nil {
231 t.Fatal("got nil, want error")
232 }
233 if fi != nil {
234 t.Errorf("got %v, want nil", fi)
235 }
236 if perr, ok := err.(*PathError); !ok {
237 t.Errorf("got %T, want %T", err, perr)
238 }
239 }
240
241 func TestStatSymlinkLoop(t *testing.T) {
242 testenv.MustHaveSymlink(t)
243
244 defer chtmpdir(t)()
245
246 err := Symlink("x", "y")
247 if err != nil {
248 t.Fatal(err)
249 }
250 defer Remove("y")
251
252 err = Symlink("y", "x")
253 if err != nil {
254 t.Fatal(err)
255 }
256 defer Remove("x")
257
258 _, err = Stat("x")
259 if _, ok := err.(*fs.PathError); !ok {
260 t.Errorf("expected *PathError, got %T: %v\n", err, err)
261 }
262 }
263
264 func TestFstat(t *testing.T) {
265 t.Parallel()
266
267 path := sfdir + "/" + sfname
268 file, err1 := Open(path)
269 if err1 != nil {
270 t.Fatal("open failed:", err1)
271 }
272 defer file.Close()
273 dir, err2 := file.Stat()
274 if err2 != nil {
275 t.Fatal("fstat failed:", err2)
276 }
277 if !equal(sfname, dir.Name()) {
278 t.Error("name should be ", sfname, "; is", dir.Name())
279 }
280 filesize := size(path, t)
281 if dir.Size() != filesize {
282 t.Error("size should be", filesize, "; is", dir.Size())
283 }
284 }
285
286 func TestLstat(t *testing.T) {
287 t.Parallel()
288
289 path := sfdir + "/" + sfname
290 dir, err := Lstat(path)
291 if err != nil {
292 t.Fatal("lstat failed:", err)
293 }
294 if !equal(sfname, dir.Name()) {
295 t.Error("name should be ", sfname, "; is", dir.Name())
296 }
297 if dir.Mode()&ModeSymlink == 0 {
298 filesize := size(path, t)
299 if dir.Size() != filesize {
300 t.Error("size should be", filesize, "; is", dir.Size())
301 }
302 }
303 }
304
305
306 func TestRead0(t *testing.T) {
307 t.Parallel()
308
309 path := sfdir + "/" + sfname
310 f, err := Open(path)
311 if err != nil {
312 t.Fatal("open failed:", err)
313 }
314 defer f.Close()
315
316 b := make([]byte, 0)
317 n, err := f.Read(b)
318 if n != 0 || err != nil {
319 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
320 }
321 b = make([]byte, 100)
322 n, err = f.Read(b)
323 if n <= 0 || err != nil {
324 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
325 }
326 }
327
328
329 func TestReadClosed(t *testing.T) {
330 t.Parallel()
331
332 path := sfdir + "/" + sfname
333 file, err := Open(path)
334 if err != nil {
335 t.Fatal("open failed:", err)
336 }
337 file.Close()
338
339 b := make([]byte, 100)
340 _, err = file.Read(b)
341
342 e, ok := err.(*PathError)
343 if !ok || e.Err != ErrClosed {
344 t.Fatalf("Read: got %T(%v), want %T(%v)", err, err, e, ErrClosed)
345 }
346 }
347
348 func testReaddirnames(dir string, contents []string) func(*testing.T) {
349 return func(t *testing.T) {
350 t.Parallel()
351
352 file, err := Open(dir)
353 if err != nil {
354 t.Fatalf("open %q failed: %v", dir, err)
355 }
356 defer file.Close()
357 s, err2 := file.Readdirnames(-1)
358 if err2 != nil {
359 t.Fatalf("Readdirnames %q failed: %v", dir, err2)
360 }
361 for _, m := range contents {
362 found := false
363 for _, n := range s {
364 if n == "." || n == ".." {
365 t.Errorf("got %q in directory", n)
366 }
367 if !equal(m, n) {
368 continue
369 }
370 if found {
371 t.Error("present twice:", m)
372 }
373 found = true
374 }
375 if !found {
376 t.Error("could not find", m)
377 }
378 }
379 if s == nil {
380 t.Error("Readdirnames returned nil instead of empty slice")
381 }
382 }
383 }
384
385 func testReaddir(dir string, contents []string) func(*testing.T) {
386 return func(t *testing.T) {
387 t.Parallel()
388
389 file, err := Open(dir)
390 if err != nil {
391 t.Fatalf("open %q failed: %v", dir, err)
392 }
393 defer file.Close()
394 s, err2 := file.Readdir(-1)
395 if err2 != nil {
396 t.Fatalf("Readdir %q failed: %v", dir, err2)
397 }
398 for _, m := range contents {
399 found := false
400 for _, n := range s {
401 if n.Name() == "." || n.Name() == ".." {
402 t.Errorf("got %q in directory", n.Name())
403 }
404 if !equal(m, n.Name()) {
405 continue
406 }
407 if found {
408 t.Error("present twice:", m)
409 }
410 found = true
411 }
412 if !found {
413 t.Error("could not find", m)
414 }
415 }
416 if s == nil {
417 t.Error("Readdir returned nil instead of empty slice")
418 }
419 }
420 }
421
422 func testReadDir(dir string, contents []string) func(*testing.T) {
423 return func(t *testing.T) {
424 t.Parallel()
425
426 file, err := Open(dir)
427 if err != nil {
428 t.Fatalf("open %q failed: %v", dir, err)
429 }
430 defer file.Close()
431 s, err2 := file.ReadDir(-1)
432 if err2 != nil {
433 t.Fatalf("ReadDir %q failed: %v", dir, err2)
434 }
435 for _, m := range contents {
436 found := false
437 for _, n := range s {
438 if n.Name() == "." || n.Name() == ".." {
439 t.Errorf("got %q in directory", n)
440 }
441 if !equal(m, n.Name()) {
442 continue
443 }
444 if found {
445 t.Error("present twice:", m)
446 }
447 found = true
448 lstat, err := Lstat(dir + "/" + m)
449 if err != nil {
450 t.Fatal(err)
451 }
452 if n.IsDir() != lstat.IsDir() {
453 t.Errorf("%s: IsDir=%v, want %v", m, n.IsDir(), lstat.IsDir())
454 }
455 if n.Type() != lstat.Mode().Type() {
456 t.Errorf("%s: IsDir=%v, want %v", m, n.Type(), lstat.Mode().Type())
457 }
458 info, err := n.Info()
459 if err != nil {
460 t.Errorf("%s: Info: %v", m, err)
461 continue
462 }
463 if !SameFile(info, lstat) {
464 t.Errorf("%s: Info: SameFile(info, lstat) = false", m)
465 }
466 }
467 if !found {
468 t.Error("could not find", m)
469 }
470 }
471 if s == nil {
472 t.Error("ReadDir returned nil instead of empty slice")
473 }
474 }
475 }
476
477 func TestFileReaddirnames(t *testing.T) {
478 t.Parallel()
479
480 t.Run(".", testReaddirnames(".", dot))
481 t.Run("sysdir", testReaddirnames(sysdir.name, sysdir.files))
482 t.Run("TempDir", testReaddirnames(t.TempDir(), nil))
483 }
484
485 func TestFileReaddir(t *testing.T) {
486 t.Parallel()
487
488 t.Run(".", testReaddir(".", dot))
489 t.Run("sysdir", testReaddir(sysdir.name, sysdir.files))
490 t.Run("TempDir", testReaddir(t.TempDir(), nil))
491 }
492
493 func TestFileReadDir(t *testing.T) {
494 t.Parallel()
495
496 t.Run(".", testReadDir(".", dot))
497 t.Run("sysdir", testReadDir(sysdir.name, sysdir.files))
498 t.Run("TempDir", testReadDir(t.TempDir(), nil))
499 }
500
501 func benchmarkReaddirname(path string, b *testing.B) {
502 var nentries int
503 for i := 0; i < b.N; i++ {
504 f, err := Open(path)
505 if err != nil {
506 b.Fatalf("open %q failed: %v", path, err)
507 }
508 ns, err := f.Readdirnames(-1)
509 f.Close()
510 if err != nil {
511 b.Fatalf("readdirnames %q failed: %v", path, err)
512 }
513 nentries = len(ns)
514 }
515 b.Logf("benchmarkReaddirname %q: %d entries", path, nentries)
516 }
517
518 func benchmarkReaddir(path string, b *testing.B) {
519 var nentries int
520 for i := 0; i < b.N; i++ {
521 f, err := Open(path)
522 if err != nil {
523 b.Fatalf("open %q failed: %v", path, err)
524 }
525 fs, err := f.Readdir(-1)
526 f.Close()
527 if err != nil {
528 b.Fatalf("readdir %q failed: %v", path, err)
529 }
530 nentries = len(fs)
531 }
532 b.Logf("benchmarkReaddir %q: %d entries", path, nentries)
533 }
534
535 func benchmarkReadDir(path string, b *testing.B) {
536 var nentries int
537 for i := 0; i < b.N; i++ {
538 f, err := Open(path)
539 if err != nil {
540 b.Fatalf("open %q failed: %v", path, err)
541 }
542 fs, err := f.ReadDir(-1)
543 f.Close()
544 if err != nil {
545 b.Fatalf("readdir %q failed: %v", path, err)
546 }
547 nentries = len(fs)
548 }
549 b.Logf("benchmarkReadDir %q: %d entries", path, nentries)
550 }
551
552 func BenchmarkReaddirname(b *testing.B) {
553 benchmarkReaddirname(".", b)
554 }
555
556 func BenchmarkReaddir(b *testing.B) {
557 benchmarkReaddir(".", b)
558 }
559
560 func BenchmarkReadDir(b *testing.B) {
561 benchmarkReadDir(".", b)
562 }
563
564 func benchmarkStat(b *testing.B, path string) {
565 b.ResetTimer()
566 for i := 0; i < b.N; i++ {
567 _, err := Stat(path)
568 if err != nil {
569 b.Fatalf("Stat(%q) failed: %v", path, err)
570 }
571 }
572 }
573
574 func benchmarkLstat(b *testing.B, path string) {
575 b.ResetTimer()
576 for i := 0; i < b.N; i++ {
577 _, err := Lstat(path)
578 if err != nil {
579 b.Fatalf("Lstat(%q) failed: %v", path, err)
580 }
581 }
582 }
583
584 func BenchmarkStatDot(b *testing.B) {
585 benchmarkStat(b, ".")
586 }
587
588 func BenchmarkStatFile(b *testing.B) {
589 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
590 }
591
592 func BenchmarkStatDir(b *testing.B) {
593 benchmarkStat(b, filepath.Join(runtime.GOROOT(), "src/os"))
594 }
595
596 func BenchmarkLstatDot(b *testing.B) {
597 benchmarkLstat(b, ".")
598 }
599
600 func BenchmarkLstatFile(b *testing.B) {
601 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os/os_test.go"))
602 }
603
604 func BenchmarkLstatDir(b *testing.B) {
605 benchmarkLstat(b, filepath.Join(runtime.GOROOT(), "src/os"))
606 }
607
608
609 func smallReaddirnames(file *File, length int, t *testing.T) []string {
610 names := make([]string, length)
611 count := 0
612 for {
613 d, err := file.Readdirnames(1)
614 if err == io.EOF {
615 break
616 }
617 if err != nil {
618 t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
619 }
620 if len(d) == 0 {
621 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
622 }
623 names[count] = d[0]
624 count++
625 }
626 return names[0:count]
627 }
628
629
630
631 func TestReaddirnamesOneAtATime(t *testing.T) {
632 t.Parallel()
633
634
635 dir := "/usr/bin"
636 switch runtime.GOOS {
637 case "android":
638 dir = "/system/bin"
639 case "ios", "wasip1":
640 wd, err := Getwd()
641 if err != nil {
642 t.Fatal(err)
643 }
644 dir = wd
645 case "plan9":
646 dir = "/bin"
647 case "windows":
648 dir = Getenv("SystemRoot") + "\\system32"
649 }
650 file, err := Open(dir)
651 if err != nil {
652 t.Fatalf("open %q failed: %v", dir, err)
653 }
654 defer file.Close()
655 all, err1 := file.Readdirnames(-1)
656 if err1 != nil {
657 t.Fatalf("readdirnames %q failed: %v", dir, err1)
658 }
659 file1, err2 := Open(dir)
660 if err2 != nil {
661 t.Fatalf("open %q failed: %v", dir, err2)
662 }
663 defer file1.Close()
664 small := smallReaddirnames(file1, len(all)+100, t)
665 if len(small) < len(all) {
666 t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
667 }
668 for i, n := range all {
669 if small[i] != n {
670 t.Errorf("small read %q mismatch: %v", small[i], n)
671 }
672 }
673 }
674
675 func TestReaddirNValues(t *testing.T) {
676 if testing.Short() {
677 t.Skip("test.short; skipping")
678 }
679 t.Parallel()
680
681 dir := t.TempDir()
682 for i := 1; i <= 105; i++ {
683 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
684 if err != nil {
685 t.Fatalf("Create: %v", err)
686 }
687 f.Write([]byte(strings.Repeat("X", i)))
688 f.Close()
689 }
690
691 var d *File
692 openDir := func() {
693 var err error
694 d, err = Open(dir)
695 if err != nil {
696 t.Fatalf("Open directory: %v", err)
697 }
698 }
699
700 readdirExpect := func(n, want int, wantErr error) {
701 t.Helper()
702 fi, err := d.Readdir(n)
703 if err != wantErr {
704 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
705 }
706 if g, e := len(fi), want; g != e {
707 t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
708 }
709 }
710
711 readDirExpect := func(n, want int, wantErr error) {
712 t.Helper()
713 de, err := d.ReadDir(n)
714 if err != wantErr {
715 t.Fatalf("ReadDir of %d got error %v, want %v", n, err, wantErr)
716 }
717 if g, e := len(de), want; g != e {
718 t.Errorf("ReadDir of %d got %d files, want %d", n, g, e)
719 }
720 }
721
722 readdirnamesExpect := func(n, want int, wantErr error) {
723 t.Helper()
724 fi, err := d.Readdirnames(n)
725 if err != wantErr {
726 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
727 }
728 if g, e := len(fi), want; g != e {
729 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
730 }
731 }
732
733 for _, fn := range []func(int, int, error){readdirExpect, readdirnamesExpect, readDirExpect} {
734
735 openDir()
736 fn(0, 105, nil)
737 fn(0, 0, nil)
738 d.Close()
739
740
741 openDir()
742 fn(-1, 105, nil)
743 fn(-2, 0, nil)
744 fn(0, 0, nil)
745 d.Close()
746
747
748 openDir()
749 fn(1, 1, nil)
750 fn(2, 2, nil)
751 fn(105, 102, nil)
752 fn(3, 0, io.EOF)
753 d.Close()
754 }
755 }
756
757 func touch(t *testing.T, name string) {
758 f, err := Create(name)
759 if err != nil {
760 t.Fatal(err)
761 }
762 if err := f.Close(); err != nil {
763 t.Fatal(err)
764 }
765 }
766
767 func TestReaddirStatFailures(t *testing.T) {
768 switch runtime.GOOS {
769 case "windows", "plan9":
770
771
772
773
774 t.Skipf("skipping test on %v", runtime.GOOS)
775 }
776
777 var xerr error
778 *LstatP = func(path string) (FileInfo, error) {
779 if xerr != nil && strings.HasSuffix(path, "x") {
780 return nil, xerr
781 }
782 return Lstat(path)
783 }
784 defer func() { *LstatP = Lstat }()
785
786 dir := t.TempDir()
787 touch(t, filepath.Join(dir, "good1"))
788 touch(t, filepath.Join(dir, "x"))
789 touch(t, filepath.Join(dir, "good2"))
790 readDir := func() ([]FileInfo, error) {
791 d, err := Open(dir)
792 if err != nil {
793 t.Fatal(err)
794 }
795 defer d.Close()
796 return d.Readdir(-1)
797 }
798 mustReadDir := func(testName string) []FileInfo {
799 fis, err := readDir()
800 if err != nil {
801 t.Fatalf("%s: Readdir: %v", testName, err)
802 }
803 return fis
804 }
805 names := func(fis []FileInfo) []string {
806 s := make([]string, len(fis))
807 for i, fi := range fis {
808 s[i] = fi.Name()
809 }
810 sort.Strings(s)
811 return s
812 }
813
814 if got, want := names(mustReadDir("initial readdir")),
815 []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
816 t.Errorf("initial readdir got %q; want %q", got, want)
817 }
818
819 xerr = ErrNotExist
820 if got, want := names(mustReadDir("with x disappearing")),
821 []string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
822 t.Errorf("with x disappearing, got %q; want %q", got, want)
823 }
824
825 xerr = errors.New("some real error")
826 if _, err := readDir(); err != xerr {
827 t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
828 }
829 }
830
831
832 func TestReaddirOfFile(t *testing.T) {
833 t.Parallel()
834
835 f, err := CreateTemp(t.TempDir(), "_Go_ReaddirOfFile")
836 if err != nil {
837 t.Fatal(err)
838 }
839 f.Write([]byte("foo"))
840 f.Close()
841 reg, err := Open(f.Name())
842 if err != nil {
843 t.Fatal(err)
844 }
845 defer reg.Close()
846
847 names, err := reg.Readdirnames(-1)
848 if err == nil {
849 t.Error("Readdirnames succeeded; want non-nil error")
850 }
851 var pe *PathError
852 if !errors.As(err, &pe) || pe.Path != f.Name() {
853 t.Errorf("Readdirnames returned %q; want a PathError with path %q", err, f.Name())
854 }
855 if len(names) > 0 {
856 t.Errorf("unexpected dir names in regular file: %q", names)
857 }
858 }
859
860 func TestHardLink(t *testing.T) {
861 testenv.MustHaveLink(t)
862
863 defer chtmpdir(t)()
864 from, to := "hardlinktestfrom", "hardlinktestto"
865 file, err := Create(to)
866 if err != nil {
867 t.Fatalf("open %q failed: %v", to, err)
868 }
869 if err = file.Close(); err != nil {
870 t.Errorf("close %q failed: %v", to, err)
871 }
872 err = Link(to, from)
873 if err != nil {
874 t.Fatalf("link %q, %q failed: %v", to, from, err)
875 }
876
877 none := "hardlinktestnone"
878 err = Link(none, none)
879
880 if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
881 t.Errorf("link %q, %q failed to return a valid error", none, none)
882 }
883
884 tostat, err := Stat(to)
885 if err != nil {
886 t.Fatalf("stat %q failed: %v", to, err)
887 }
888 fromstat, err := Stat(from)
889 if err != nil {
890 t.Fatalf("stat %q failed: %v", from, err)
891 }
892 if !SameFile(tostat, fromstat) {
893 t.Errorf("link %q, %q did not create hard link", to, from)
894 }
895
896 err = Link(to, from)
897 switch err := err.(type) {
898 case *LinkError:
899 if err.Op != "link" {
900 t.Errorf("Link(%q, %q) err.Op = %q; want %q", to, from, err.Op, "link")
901 }
902 if err.Old != to {
903 t.Errorf("Link(%q, %q) err.Old = %q; want %q", to, from, err.Old, to)
904 }
905 if err.New != from {
906 t.Errorf("Link(%q, %q) err.New = %q; want %q", to, from, err.New, from)
907 }
908 if !IsExist(err.Err) {
909 t.Errorf("Link(%q, %q) err.Err = %q; want %q", to, from, err.Err, "file exists error")
910 }
911 case nil:
912 t.Errorf("link %q, %q: expected error, got nil", from, to)
913 default:
914 t.Errorf("link %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
915 }
916 }
917
918
919
920 func chtmpdir(t *testing.T) func() {
921 oldwd, err := Getwd()
922 if err != nil {
923 t.Fatalf("chtmpdir: %v", err)
924 }
925 d, err := MkdirTemp("", "test")
926 if err != nil {
927 t.Fatalf("chtmpdir: %v", err)
928 }
929 if err := Chdir(d); err != nil {
930 t.Fatalf("chtmpdir: %v", err)
931 }
932 return func() {
933 if err := Chdir(oldwd); err != nil {
934 t.Fatalf("chtmpdir: %v", err)
935 }
936 RemoveAll(d)
937 }
938 }
939
940 func TestSymlink(t *testing.T) {
941 testenv.MustHaveSymlink(t)
942
943 defer chtmpdir(t)()
944 from, to := "symlinktestfrom", "symlinktestto"
945 file, err := Create(to)
946 if err != nil {
947 t.Fatalf("Create(%q) failed: %v", to, err)
948 }
949 if err = file.Close(); err != nil {
950 t.Errorf("Close(%q) failed: %v", to, err)
951 }
952 err = Symlink(to, from)
953 if err != nil {
954 t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
955 }
956 tostat, err := Lstat(to)
957 if err != nil {
958 t.Fatalf("Lstat(%q) failed: %v", to, err)
959 }
960 if tostat.Mode()&ModeSymlink != 0 {
961 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = %v, want 0", to, tostat.Mode()&ModeSymlink)
962 }
963 fromstat, err := Stat(from)
964 if err != nil {
965 t.Fatalf("Stat(%q) failed: %v", from, err)
966 }
967 if !SameFile(tostat, fromstat) {
968 t.Errorf("Symlink(%q, %q) did not create symlink", to, from)
969 }
970 fromstat, err = Lstat(from)
971 if err != nil {
972 t.Fatalf("Lstat(%q) failed: %v", from, err)
973 }
974 if fromstat.Mode()&ModeSymlink == 0 {
975 t.Fatalf("Lstat(%q).Mode()&ModeSymlink = 0, want %v", from, ModeSymlink)
976 }
977 fromstat, err = Stat(from)
978 if err != nil {
979 t.Fatalf("Stat(%q) failed: %v", from, err)
980 }
981 if fromstat.Name() != from {
982 t.Errorf("Stat(%q).Name() = %q, want %q", from, fromstat.Name(), from)
983 }
984 if fromstat.Mode()&ModeSymlink != 0 {
985 t.Fatalf("Stat(%q).Mode()&ModeSymlink = %v, want 0", from, fromstat.Mode()&ModeSymlink)
986 }
987 s, err := Readlink(from)
988 if err != nil {
989 t.Fatalf("Readlink(%q) failed: %v", from, err)
990 }
991 if s != to {
992 t.Fatalf("Readlink(%q) = %q, want %q", from, s, to)
993 }
994 file, err = Open(from)
995 if err != nil {
996 t.Fatalf("Open(%q) failed: %v", from, err)
997 }
998 file.Close()
999 }
1000
1001 func TestLongSymlink(t *testing.T) {
1002 testenv.MustHaveSymlink(t)
1003
1004 defer chtmpdir(t)()
1005 s := "0123456789abcdef"
1006
1007 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
1008 from := "longsymlinktestfrom"
1009 err := Symlink(s, from)
1010 if err != nil {
1011 t.Fatalf("symlink %q, %q failed: %v", s, from, err)
1012 }
1013 r, err := Readlink(from)
1014 if err != nil {
1015 t.Fatalf("readlink %q failed: %v", from, err)
1016 }
1017 if r != s {
1018 t.Fatalf("after symlink %q != %q", r, s)
1019 }
1020 }
1021
1022 func TestRename(t *testing.T) {
1023 defer chtmpdir(t)()
1024 from, to := "renamefrom", "renameto"
1025
1026 file, err := Create(from)
1027 if err != nil {
1028 t.Fatalf("open %q failed: %v", from, err)
1029 }
1030 if err = file.Close(); err != nil {
1031 t.Errorf("close %q failed: %v", from, err)
1032 }
1033 err = Rename(from, to)
1034 if err != nil {
1035 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1036 }
1037 _, err = Stat(to)
1038 if err != nil {
1039 t.Errorf("stat %q failed: %v", to, err)
1040 }
1041 }
1042
1043 func TestRenameOverwriteDest(t *testing.T) {
1044 defer chtmpdir(t)()
1045 from, to := "renamefrom", "renameto"
1046
1047 toData := []byte("to")
1048 fromData := []byte("from")
1049
1050 err := WriteFile(to, toData, 0777)
1051 if err != nil {
1052 t.Fatalf("write file %q failed: %v", to, err)
1053 }
1054
1055 err = WriteFile(from, fromData, 0777)
1056 if err != nil {
1057 t.Fatalf("write file %q failed: %v", from, err)
1058 }
1059 err = Rename(from, to)
1060 if err != nil {
1061 t.Fatalf("rename %q, %q failed: %v", to, from, err)
1062 }
1063
1064 _, err = Stat(from)
1065 if err == nil {
1066 t.Errorf("from file %q still exists", from)
1067 }
1068 if err != nil && !IsNotExist(err) {
1069 t.Fatalf("stat from: %v", err)
1070 }
1071 toFi, err := Stat(to)
1072 if err != nil {
1073 t.Fatalf("stat %q failed: %v", to, err)
1074 }
1075 if toFi.Size() != int64(len(fromData)) {
1076 t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
1077 }
1078 }
1079
1080 func TestRenameFailed(t *testing.T) {
1081 defer chtmpdir(t)()
1082 from, to := "renamefrom", "renameto"
1083
1084 err := Rename(from, to)
1085 switch err := err.(type) {
1086 case *LinkError:
1087 if err.Op != "rename" {
1088 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1089 }
1090 if err.Old != from {
1091 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1092 }
1093 if err.New != to {
1094 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1095 }
1096 case nil:
1097 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1098 default:
1099 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1100 }
1101 }
1102
1103 func TestRenameNotExisting(t *testing.T) {
1104 defer chtmpdir(t)()
1105 from, to := "doesnt-exist", "dest"
1106
1107 Mkdir(to, 0777)
1108
1109 if err := Rename(from, to); !IsNotExist(err) {
1110 t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
1111 }
1112 }
1113
1114 func TestRenameToDirFailed(t *testing.T) {
1115 defer chtmpdir(t)()
1116 from, to := "renamefrom", "renameto"
1117
1118 Mkdir(from, 0777)
1119 Mkdir(to, 0777)
1120
1121 err := Rename(from, to)
1122 switch err := err.(type) {
1123 case *LinkError:
1124 if err.Op != "rename" {
1125 t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
1126 }
1127 if err.Old != from {
1128 t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
1129 }
1130 if err.New != to {
1131 t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
1132 }
1133 case nil:
1134 t.Errorf("rename %q, %q: expected error, got nil", from, to)
1135 default:
1136 t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
1137 }
1138 }
1139
1140 func TestRenameCaseDifference(pt *testing.T) {
1141 from, to := "renameFROM", "RENAMEfrom"
1142 tests := []struct {
1143 name string
1144 create func() error
1145 }{
1146 {"dir", func() error {
1147 return Mkdir(from, 0777)
1148 }},
1149 {"file", func() error {
1150 fd, err := Create(from)
1151 if err != nil {
1152 return err
1153 }
1154 return fd.Close()
1155 }},
1156 }
1157
1158 for _, test := range tests {
1159 pt.Run(test.name, func(t *testing.T) {
1160 defer chtmpdir(t)()
1161
1162 if err := test.create(); err != nil {
1163 t.Fatalf("failed to create test file: %s", err)
1164 }
1165
1166 if _, err := Stat(to); err != nil {
1167
1168 if IsNotExist(err) {
1169 t.Skipf("case sensitive filesystem")
1170 }
1171 t.Fatalf("stat %q, got: %q", to, err)
1172 }
1173
1174 if err := Rename(from, to); err != nil {
1175 t.Fatalf("unexpected error when renaming from %q to %q: %s", from, to, err)
1176 }
1177
1178 fd, err := Open(".")
1179 if err != nil {
1180 t.Fatalf("Open .: %s", err)
1181 }
1182
1183
1184
1185 dirNames, err := fd.Readdirnames(-1)
1186 fd.Close()
1187 if err != nil {
1188 t.Fatalf("readdirnames: %s", err)
1189 }
1190
1191 if dirNamesLen := len(dirNames); dirNamesLen != 1 {
1192 t.Fatalf("unexpected dirNames len, got %q, want %q", dirNamesLen, 1)
1193 }
1194
1195 if dirNames[0] != to {
1196 t.Errorf("unexpected name, got %q, want %q", dirNames[0], to)
1197 }
1198 })
1199 }
1200 }
1201
1202 func testStartProcess(dir, cmd string, args []string, expect string) func(t *testing.T) {
1203 return func(t *testing.T) {
1204 t.Parallel()
1205
1206 r, w, err := Pipe()
1207 if err != nil {
1208 t.Fatalf("Pipe: %v", err)
1209 }
1210 defer r.Close()
1211 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
1212 p, err := StartProcess(cmd, args, attr)
1213 if err != nil {
1214 t.Fatalf("StartProcess: %v", err)
1215 }
1216 w.Close()
1217
1218 var b strings.Builder
1219 io.Copy(&b, r)
1220 output := b.String()
1221
1222 fi1, _ := Stat(strings.TrimSpace(output))
1223 fi2, _ := Stat(expect)
1224 if !SameFile(fi1, fi2) {
1225 t.Errorf("exec %q returned %q wanted %q",
1226 strings.Join(append([]string{cmd}, args...), " "), output, expect)
1227 }
1228 p.Wait()
1229 }
1230 }
1231
1232 func TestStartProcess(t *testing.T) {
1233 testenv.MustHaveExec(t)
1234 t.Parallel()
1235
1236 var dir, cmd string
1237 var args []string
1238 switch runtime.GOOS {
1239 case "android":
1240 t.Skip("android doesn't have /bin/pwd")
1241 case "windows":
1242 cmd = Getenv("COMSPEC")
1243 dir = Getenv("SystemRoot")
1244 args = []string{"/c", "cd"}
1245 default:
1246 var err error
1247 cmd, err = exec.LookPath("pwd")
1248 if err != nil {
1249 t.Fatalf("Can't find pwd: %v", err)
1250 }
1251 dir = "/"
1252 args = []string{}
1253 t.Logf("Testing with %v", cmd)
1254 }
1255 cmddir, cmdbase := filepath.Split(cmd)
1256 args = append([]string{cmdbase}, args...)
1257 t.Run("absolute", testStartProcess(dir, cmd, args, dir))
1258 t.Run("relative", testStartProcess(cmddir, cmdbase, args, cmddir))
1259 }
1260
1261 func checkMode(t *testing.T, path string, mode FileMode) {
1262 dir, err := Stat(path)
1263 if err != nil {
1264 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
1265 }
1266 if dir.Mode()&ModePerm != mode {
1267 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
1268 }
1269 }
1270
1271 func TestChmod(t *testing.T) {
1272
1273 if runtime.GOOS == "wasip1" {
1274 t.Skip("Chmod is not supported on " + runtime.GOOS)
1275 }
1276 t.Parallel()
1277
1278 f := newFile("TestChmod", t)
1279 defer Remove(f.Name())
1280 defer f.Close()
1281
1282
1283 fm := FileMode(0456)
1284 if runtime.GOOS == "windows" {
1285 fm = FileMode(0444)
1286 }
1287 if err := Chmod(f.Name(), fm); err != nil {
1288 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1289 }
1290 checkMode(t, f.Name(), fm)
1291
1292 fm = FileMode(0123)
1293 if runtime.GOOS == "windows" {
1294 fm = FileMode(0666)
1295 }
1296 if err := f.Chmod(fm); err != nil {
1297 t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1298 }
1299 checkMode(t, f.Name(), fm)
1300 }
1301
1302 func checkSize(t *testing.T, f *File, size int64) {
1303 t.Helper()
1304 dir, err := f.Stat()
1305 if err != nil {
1306 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
1307 }
1308 if dir.Size() != size {
1309 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
1310 }
1311 }
1312
1313 func TestFTruncate(t *testing.T) {
1314 t.Parallel()
1315
1316 f := newFile("TestFTruncate", t)
1317 defer Remove(f.Name())
1318 defer f.Close()
1319
1320 checkSize(t, f, 0)
1321 f.Write([]byte("hello, world\n"))
1322 checkSize(t, f, 13)
1323 f.Truncate(10)
1324 checkSize(t, f, 10)
1325 f.Truncate(1024)
1326 checkSize(t, f, 1024)
1327 f.Truncate(0)
1328 checkSize(t, f, 0)
1329 _, err := f.Write([]byte("surprise!"))
1330 if err == nil {
1331 checkSize(t, f, 13+9)
1332 }
1333 }
1334
1335 func TestTruncate(t *testing.T) {
1336 t.Parallel()
1337
1338 f := newFile("TestTruncate", t)
1339 defer Remove(f.Name())
1340 defer f.Close()
1341
1342 checkSize(t, f, 0)
1343 f.Write([]byte("hello, world\n"))
1344 checkSize(t, f, 13)
1345 Truncate(f.Name(), 10)
1346 checkSize(t, f, 10)
1347 Truncate(f.Name(), 1024)
1348 checkSize(t, f, 1024)
1349 Truncate(f.Name(), 0)
1350 checkSize(t, f, 0)
1351 _, err := f.Write([]byte("surprise!"))
1352 if err == nil {
1353 checkSize(t, f, 13+9)
1354 }
1355 }
1356
1357 func TestTruncateNonexistentFile(t *testing.T) {
1358 t.Parallel()
1359
1360 assertPathError := func(t testing.TB, path string, err error) {
1361 t.Helper()
1362 if pe, ok := err.(*PathError); !ok || !IsNotExist(err) || pe.Path != path {
1363 t.Errorf("got error: %v\nwant an ErrNotExist PathError with path %q", err, path)
1364 }
1365 }
1366
1367 path := filepath.Join(t.TempDir(), "nonexistent")
1368
1369 err := Truncate(path, 1)
1370 assertPathError(t, path, err)
1371
1372
1373 _, err = Stat(path)
1374 assertPathError(t, path, err)
1375 }
1376
1377
1378
1379
1380
1381 func TestChtimes(t *testing.T) {
1382 t.Parallel()
1383
1384 f := newFile("TestChtimes", t)
1385 defer Remove(f.Name())
1386
1387 f.Write([]byte("hello, world\n"))
1388 f.Close()
1389
1390 testChtimes(t, f.Name())
1391 }
1392
1393 func TestChtimesWithZeroTimes(t *testing.T) {
1394 file := newFile("chtimes-with-zero", t)
1395 _, err := file.Write([]byte("hello, world\n"))
1396 if err != nil {
1397 t.Fatalf("Write: %s", err)
1398 }
1399 fName := file.Name()
1400 defer Remove(file.Name())
1401 err = file.Close()
1402 if err != nil {
1403 t.Errorf("%v", err)
1404 }
1405 fs, err := Stat(fName)
1406 if err != nil {
1407 t.Fatal(err)
1408 }
1409 startAtime := Atime(fs)
1410 startMtime := fs.ModTime()
1411 switch runtime.GOOS {
1412 case "js":
1413 startAtime = startAtime.Truncate(time.Second)
1414 startMtime = startMtime.Truncate(time.Second)
1415 }
1416 at0 := startAtime
1417 mt0 := startMtime
1418 t0 := startMtime.Truncate(time.Second).Add(1 * time.Hour)
1419
1420 tests := []struct {
1421 aTime time.Time
1422 mTime time.Time
1423 wantATime time.Time
1424 wantMTime time.Time
1425 }{
1426 {
1427 aTime: time.Time{},
1428 mTime: time.Time{},
1429 wantATime: startAtime,
1430 wantMTime: startMtime,
1431 },
1432 {
1433 aTime: t0.Add(200 * time.Second),
1434 mTime: time.Time{},
1435 wantATime: t0.Add(200 * time.Second),
1436 wantMTime: startMtime,
1437 },
1438 {
1439 aTime: time.Time{},
1440 mTime: t0.Add(100 * time.Second),
1441 wantATime: t0.Add(200 * time.Second),
1442 wantMTime: t0.Add(100 * time.Second),
1443 },
1444 {
1445 aTime: t0.Add(300 * time.Second),
1446 mTime: t0.Add(100 * time.Second),
1447 wantATime: t0.Add(300 * time.Second),
1448 wantMTime: t0.Add(100 * time.Second),
1449 },
1450 }
1451
1452 for _, tt := range tests {
1453
1454 if err := Chtimes(fName, tt.aTime, tt.mTime); err != nil {
1455 t.Error(err)
1456 }
1457
1458
1459 fs, err = Stat(fName)
1460 if err != nil {
1461 t.Error(err)
1462 }
1463 at0 = Atime(fs)
1464 mt0 = fs.ModTime()
1465
1466 if got, want := at0, tt.wantATime; !got.Equal(want) {
1467 errormsg := fmt.Sprintf("AccessTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
1468 switch runtime.GOOS {
1469 case "plan9":
1470
1471
1472
1473
1474 case "windows":
1475 t.Error(errormsg)
1476 default:
1477 if got, want := at0, tt.wantATime; !got.Equal(want) {
1478 mounts, err := ReadFile("/bin/mounts")
1479 if err != nil {
1480 mounts, err = ReadFile("/etc/mtab")
1481 }
1482 if strings.Contains(string(mounts), "noatime") {
1483 t.Log(errormsg)
1484 t.Log("A filesystem is mounted with noatime; ignoring.")
1485 } else {
1486 switch runtime.GOOS {
1487 case "netbsd", "dragonfly":
1488
1489
1490
1491 if strings.Contains(runtime.GOARCH, "64") {
1492 t.Log(errormsg)
1493 t.Log("Filesystem might not support atime changes; ignoring.")
1494 }
1495 default:
1496 t.Error(errormsg)
1497 }
1498 }
1499 }
1500 }
1501 }
1502 if got, want := mt0, tt.wantMTime; !got.Equal(want) {
1503 errormsg := fmt.Sprintf("ModTime mismatch with values ATime:%q-MTime:%q\ngot: %q\nwant: %q", tt.aTime, tt.mTime, got, want)
1504 switch runtime.GOOS {
1505 case "dragonfly":
1506 t.Log(errormsg)
1507 t.Log("Mtime is always updated; ignoring.")
1508 default:
1509 t.Error(errormsg)
1510 }
1511 }
1512 }
1513 }
1514
1515
1516
1517
1518
1519 func TestChtimesDir(t *testing.T) {
1520 t.Parallel()
1521
1522 name := newDir("TestChtimes", t)
1523 defer RemoveAll(name)
1524
1525 testChtimes(t, name)
1526 }
1527
1528 func testChtimes(t *testing.T, name string) {
1529 st, err := Stat(name)
1530 if err != nil {
1531 t.Fatalf("Stat %s: %s", name, err)
1532 }
1533 preStat := st
1534
1535
1536 at := Atime(preStat)
1537 mt := preStat.ModTime()
1538 err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
1539 if err != nil {
1540 t.Fatalf("Chtimes %s: %s", name, err)
1541 }
1542
1543 st, err = Stat(name)
1544 if err != nil {
1545 t.Fatalf("second Stat %s: %s", name, err)
1546 }
1547 postStat := st
1548
1549 pat := Atime(postStat)
1550 pmt := postStat.ModTime()
1551 if !pat.Before(at) {
1552 switch runtime.GOOS {
1553 case "plan9":
1554
1555
1556
1557
1558 case "netbsd":
1559 mounts, _ := ReadFile("/proc/mounts")
1560 if strings.Contains(string(mounts), "noatime") {
1561 t.Logf("AccessTime didn't go backwards, but see a filesystem mounted noatime; ignoring. Issue 19293.")
1562 } else {
1563 t.Logf("AccessTime didn't go backwards; was=%v, after=%v (Ignoring on NetBSD, assuming noatime, Issue 19293)", at, pat)
1564 }
1565 default:
1566 t.Errorf("AccessTime didn't go backwards; was=%v, after=%v", at, pat)
1567 }
1568 }
1569
1570 if !pmt.Before(mt) {
1571 t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt)
1572 }
1573 }
1574
1575 func TestChtimesToUnixZero(t *testing.T) {
1576 file := newFile("chtimes-to-unix-zero", t)
1577 fn := file.Name()
1578 defer Remove(fn)
1579 if _, err := file.Write([]byte("hi")); err != nil {
1580 t.Fatal(err)
1581 }
1582 if err := file.Close(); err != nil {
1583 t.Fatal(err)
1584 }
1585
1586 unixZero := time.Unix(0, 0)
1587 if err := Chtimes(fn, unixZero, unixZero); err != nil {
1588 t.Fatalf("Chtimes failed: %v", err)
1589 }
1590
1591 st, err := Stat(fn)
1592 if err != nil {
1593 t.Fatal(err)
1594 }
1595
1596 if mt := st.ModTime(); mt != unixZero {
1597 t.Errorf("mtime is %v, want %v", mt, unixZero)
1598 }
1599 }
1600
1601 func TestFileChdir(t *testing.T) {
1602 wd, err := Getwd()
1603 if err != nil {
1604 t.Fatalf("Getwd: %s", err)
1605 }
1606 defer Chdir(wd)
1607
1608 fd, err := Open(".")
1609 if err != nil {
1610 t.Fatalf("Open .: %s", err)
1611 }
1612 defer fd.Close()
1613
1614 if err := Chdir("/"); err != nil {
1615 t.Fatalf("Chdir /: %s", err)
1616 }
1617
1618 if err := fd.Chdir(); err != nil {
1619 t.Fatalf("fd.Chdir: %s", err)
1620 }
1621
1622 wdNew, err := Getwd()
1623 if err != nil {
1624 t.Fatalf("Getwd: %s", err)
1625 }
1626
1627 wdInfo, err := fd.Stat()
1628 if err != nil {
1629 t.Fatal(err)
1630 }
1631 newInfo, err := Stat(wdNew)
1632 if err != nil {
1633 t.Fatal(err)
1634 }
1635 if !SameFile(wdInfo, newInfo) {
1636 t.Fatalf("fd.Chdir failed: got %s, want %s", wdNew, wd)
1637 }
1638 }
1639
1640 func TestChdirAndGetwd(t *testing.T) {
1641 fd, err := Open(".")
1642 if err != nil {
1643 t.Fatalf("Open .: %s", err)
1644 }
1645
1646
1647 dirs := []string{"/", "/usr/bin", "/tmp"}
1648
1649 switch runtime.GOOS {
1650 case "android":
1651 dirs = []string{"/system/bin"}
1652 case "plan9":
1653 dirs = []string{"/", "/usr"}
1654 case "ios", "windows", "wasip1":
1655 dirs = nil
1656 for _, dir := range []string{t.TempDir(), t.TempDir()} {
1657
1658 dir, err = filepath.EvalSymlinks(dir)
1659 if err != nil {
1660 t.Fatalf("EvalSymlinks: %v", err)
1661 }
1662 dirs = append(dirs, dir)
1663 }
1664 }
1665 oldwd := Getenv("PWD")
1666 for mode := 0; mode < 2; mode++ {
1667 for _, d := range dirs {
1668 if mode == 0 {
1669 err = Chdir(d)
1670 } else {
1671 fd1, err1 := Open(d)
1672 if err1 != nil {
1673 t.Errorf("Open %s: %s", d, err1)
1674 continue
1675 }
1676 err = fd1.Chdir()
1677 fd1.Close()
1678 }
1679 if d == "/tmp" {
1680 Setenv("PWD", "/tmp")
1681 }
1682 pwd, err1 := Getwd()
1683 Setenv("PWD", oldwd)
1684 err2 := fd.Chdir()
1685 if err2 != nil {
1686
1687
1688
1689 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
1690 Exit(1)
1691 }
1692 if err != nil {
1693 fd.Close()
1694 t.Fatalf("Chdir %s: %s", d, err)
1695 }
1696 if err1 != nil {
1697 fd.Close()
1698 t.Fatalf("Getwd in %s: %s", d, err1)
1699 }
1700 if !equal(pwd, d) {
1701 fd.Close()
1702 t.Fatalf("Getwd returned %q want %q", pwd, d)
1703 }
1704 }
1705 }
1706 fd.Close()
1707 }
1708
1709
1710 func TestProgWideChdir(t *testing.T) {
1711 const N = 10
1712 var wg sync.WaitGroup
1713 hold := make(chan struct{})
1714 done := make(chan struct{})
1715
1716 d := t.TempDir()
1717 oldwd, err := Getwd()
1718 if err != nil {
1719 t.Fatalf("Getwd: %v", err)
1720 }
1721 defer func() {
1722 if err := Chdir(oldwd); err != nil {
1723
1724
1725 panic(err)
1726 }
1727 }()
1728
1729
1730
1731
1732
1733
1734 defer wg.Wait()
1735 defer close(done)
1736
1737 for i := 0; i < N; i++ {
1738 wg.Add(1)
1739 go func(i int) {
1740 defer wg.Done()
1741
1742
1743 if i%2 == 1 {
1744
1745
1746
1747
1748
1749 runtime.LockOSThread()
1750 }
1751 select {
1752 case <-done:
1753 return
1754 case <-hold:
1755 }
1756
1757 f0, err := Stat(".")
1758 if err != nil {
1759 t.Error(err)
1760 return
1761 }
1762 pwd, err := Getwd()
1763 if err != nil {
1764 t.Errorf("Getwd: %v", err)
1765 return
1766 }
1767 if pwd != d {
1768 t.Errorf("Getwd() = %q, want %q", pwd, d)
1769 return
1770 }
1771 f1, err := Stat(pwd)
1772 if err != nil {
1773 t.Error(err)
1774 return
1775 }
1776 if !SameFile(f0, f1) {
1777 t.Errorf(`Samefile(Stat("."), Getwd()) reports false (%s != %s)`, f0.Name(), f1.Name())
1778 return
1779 }
1780 }(i)
1781 }
1782 if err = Chdir(d); err != nil {
1783 t.Fatalf("Chdir: %v", err)
1784 }
1785
1786
1787 d, err = Getwd()
1788 if err != nil {
1789 t.Fatalf("Getwd: %v", err)
1790 }
1791 close(hold)
1792 wg.Wait()
1793 }
1794
1795 func TestSeek(t *testing.T) {
1796 t.Parallel()
1797
1798 f := newFile("TestSeek", t)
1799 defer Remove(f.Name())
1800 defer f.Close()
1801
1802 const data = "hello, world\n"
1803 io.WriteString(f, data)
1804
1805 type test struct {
1806 in int64
1807 whence int
1808 out int64
1809 }
1810 var tests = []test{
1811 {0, io.SeekCurrent, int64(len(data))},
1812 {0, io.SeekStart, 0},
1813 {5, io.SeekStart, 5},
1814 {0, io.SeekEnd, int64(len(data))},
1815 {0, io.SeekStart, 0},
1816 {-1, io.SeekEnd, int64(len(data)) - 1},
1817 {1 << 33, io.SeekStart, 1 << 33},
1818 {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
1819
1820
1821 {1<<32 - 1, io.SeekStart, 1<<32 - 1},
1822 {0, io.SeekCurrent, 1<<32 - 1},
1823 {2<<32 - 1, io.SeekStart, 2<<32 - 1},
1824 {0, io.SeekCurrent, 2<<32 - 1},
1825 }
1826 for i, tt := range tests {
1827 off, err := f.Seek(tt.in, tt.whence)
1828 if off != tt.out || err != nil {
1829 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" {
1830 mounts, _ := ReadFile("/proc/mounts")
1831 if strings.Contains(string(mounts), "reiserfs") {
1832
1833 t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91")
1834 }
1835 }
1836 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
1837 }
1838 }
1839 }
1840
1841 func TestSeekError(t *testing.T) {
1842 switch runtime.GOOS {
1843 case "js", "plan9", "wasip1":
1844 t.Skipf("skipping test on %v", runtime.GOOS)
1845 }
1846 t.Parallel()
1847
1848 r, w, err := Pipe()
1849 if err != nil {
1850 t.Fatal(err)
1851 }
1852 _, err = r.Seek(0, 0)
1853 if err == nil {
1854 t.Fatal("Seek on pipe should fail")
1855 }
1856 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1857 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1858 }
1859 _, err = w.Seek(0, 0)
1860 if err == nil {
1861 t.Fatal("Seek on pipe should fail")
1862 }
1863 if perr, ok := err.(*PathError); !ok || perr.Err != syscall.ESPIPE {
1864 t.Errorf("Seek returned error %v, want &PathError{Err: syscall.ESPIPE}", err)
1865 }
1866 }
1867
1868 type openErrorTest struct {
1869 path string
1870 mode int
1871 error error
1872 }
1873
1874 var openErrorTests = []openErrorTest{
1875 {
1876 sfdir + "/no-such-file",
1877 O_RDONLY,
1878 syscall.ENOENT,
1879 },
1880 {
1881 sfdir,
1882 O_WRONLY,
1883 syscall.EISDIR,
1884 },
1885 {
1886 sfdir + "/" + sfname + "/no-such-file",
1887 O_WRONLY,
1888 syscall.ENOTDIR,
1889 },
1890 }
1891
1892 func TestOpenError(t *testing.T) {
1893 t.Parallel()
1894
1895 for _, tt := range openErrorTests {
1896 f, err := OpenFile(tt.path, tt.mode, 0)
1897 if err == nil {
1898 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
1899 f.Close()
1900 continue
1901 }
1902 perr, ok := err.(*PathError)
1903 if !ok {
1904 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
1905 }
1906 if perr.Err != tt.error {
1907 if runtime.GOOS == "plan9" {
1908 syscallErrStr := perr.Err.Error()
1909 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
1910 if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
1911
1912
1913
1914 if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
1915 continue
1916 }
1917 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
1918 }
1919 continue
1920 }
1921 if runtime.GOOS == "dragonfly" {
1922
1923
1924 if tt.error == syscall.EISDIR && perr.Err == syscall.EACCES {
1925 continue
1926 }
1927 }
1928 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
1929 }
1930 }
1931 }
1932
1933 func TestOpenNoName(t *testing.T) {
1934 f, err := Open("")
1935 if err == nil {
1936 f.Close()
1937 t.Fatal(`Open("") succeeded`)
1938 }
1939 }
1940
1941 func runBinHostname(t *testing.T) string {
1942
1943 r, w, err := Pipe()
1944 if err != nil {
1945 t.Fatal(err)
1946 }
1947 defer r.Close()
1948
1949 path, err := exec.LookPath("hostname")
1950 if err != nil {
1951 if errors.Is(err, exec.ErrNotFound) {
1952 t.Skip("skipping test; test requires hostname but it does not exist")
1953 }
1954 t.Fatal(err)
1955 }
1956
1957 argv := []string{"hostname"}
1958 if runtime.GOOS == "aix" {
1959 argv = []string{"hostname", "-s"}
1960 }
1961 p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}})
1962 if err != nil {
1963 t.Fatal(err)
1964 }
1965 w.Close()
1966
1967 var b strings.Builder
1968 io.Copy(&b, r)
1969 _, err = p.Wait()
1970 if err != nil {
1971 t.Fatalf("run hostname Wait: %v", err)
1972 }
1973 err = p.Kill()
1974 if err == nil {
1975 t.Errorf("expected an error from Kill running 'hostname'")
1976 }
1977 output := b.String()
1978 if n := len(output); n > 0 && output[n-1] == '\n' {
1979 output = output[0 : n-1]
1980 }
1981 if output == "" {
1982 t.Fatalf("/bin/hostname produced no output")
1983 }
1984
1985 return output
1986 }
1987
1988 func testWindowsHostname(t *testing.T, hostname string) {
1989 cmd := testenv.Command(t, "hostname")
1990 out, err := cmd.Output()
1991 if err != nil {
1992 t.Fatalf("Failed to execute hostname command: %v %s", err, out)
1993 }
1994 want := strings.Trim(string(out), "\r\n")
1995 if hostname != want {
1996 t.Fatalf("Hostname() = %q != system hostname of %q", hostname, want)
1997 }
1998 }
1999
2000 func TestHostname(t *testing.T) {
2001 t.Parallel()
2002
2003 hostname, err := Hostname()
2004 if err != nil {
2005 t.Fatal(err)
2006 }
2007 if hostname == "" {
2008 t.Fatal("Hostname returned empty string and no error")
2009 }
2010 if strings.Contains(hostname, "\x00") {
2011 t.Fatalf("unexpected zero byte in hostname: %q", hostname)
2012 }
2013
2014
2015
2016 switch runtime.GOOS {
2017 case "android", "plan9":
2018
2019 return
2020 case "windows":
2021 testWindowsHostname(t, hostname)
2022 return
2023 }
2024
2025 testenv.MustHaveExec(t)
2026
2027
2028
2029
2030 want := runBinHostname(t)
2031 if hostname != want {
2032 host, _, ok := strings.Cut(hostname, ".")
2033 if !ok || host != want {
2034 t.Errorf("Hostname() = %q, want %q", hostname, want)
2035 }
2036 }
2037 }
2038
2039 func TestReadAt(t *testing.T) {
2040 t.Parallel()
2041
2042 f := newFile("TestReadAt", t)
2043 defer Remove(f.Name())
2044 defer f.Close()
2045
2046 const data = "hello, world\n"
2047 io.WriteString(f, data)
2048
2049 b := make([]byte, 5)
2050 n, err := f.ReadAt(b, 7)
2051 if err != nil || n != len(b) {
2052 t.Fatalf("ReadAt 7: %d, %v", n, err)
2053 }
2054 if string(b) != "world" {
2055 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2056 }
2057 }
2058
2059
2060
2061
2062
2063 func TestReadAtOffset(t *testing.T) {
2064 t.Parallel()
2065
2066 f := newFile("TestReadAtOffset", t)
2067 defer Remove(f.Name())
2068 defer f.Close()
2069
2070 const data = "hello, world\n"
2071 io.WriteString(f, data)
2072
2073 f.Seek(0, 0)
2074 b := make([]byte, 5)
2075
2076 n, err := f.ReadAt(b, 7)
2077 if err != nil || n != len(b) {
2078 t.Fatalf("ReadAt 7: %d, %v", n, err)
2079 }
2080 if string(b) != "world" {
2081 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
2082 }
2083
2084 n, err = f.Read(b)
2085 if err != nil || n != len(b) {
2086 t.Fatalf("Read: %d, %v", n, err)
2087 }
2088 if string(b) != "hello" {
2089 t.Fatalf("Read: have %q want %q", string(b), "hello")
2090 }
2091 }
2092
2093
2094 func TestReadAtNegativeOffset(t *testing.T) {
2095 t.Parallel()
2096
2097 f := newFile("TestReadAtNegativeOffset", t)
2098 defer Remove(f.Name())
2099 defer f.Close()
2100
2101 const data = "hello, world\n"
2102 io.WriteString(f, data)
2103
2104 f.Seek(0, 0)
2105 b := make([]byte, 5)
2106
2107 n, err := f.ReadAt(b, -10)
2108
2109 const wantsub = "negative offset"
2110 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2111 t.Errorf("ReadAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2112 }
2113 }
2114
2115 func TestWriteAt(t *testing.T) {
2116 t.Parallel()
2117
2118 f := newFile("TestWriteAt", t)
2119 defer Remove(f.Name())
2120 defer f.Close()
2121
2122 const data = "hello, world\n"
2123 io.WriteString(f, data)
2124
2125 n, err := f.WriteAt([]byte("WORLD"), 7)
2126 if err != nil || n != 5 {
2127 t.Fatalf("WriteAt 7: %d, %v", n, err)
2128 }
2129
2130 b, err := ReadFile(f.Name())
2131 if err != nil {
2132 t.Fatalf("ReadFile %s: %v", f.Name(), err)
2133 }
2134 if string(b) != "hello, WORLD\n" {
2135 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
2136 }
2137 }
2138
2139
2140 func TestWriteAtNegativeOffset(t *testing.T) {
2141 t.Parallel()
2142
2143 f := newFile("TestWriteAtNegativeOffset", t)
2144 defer Remove(f.Name())
2145 defer f.Close()
2146
2147 n, err := f.WriteAt([]byte("WORLD"), -10)
2148
2149 const wantsub = "negative offset"
2150 if !strings.Contains(fmt.Sprint(err), wantsub) || n != 0 {
2151 t.Errorf("WriteAt(-10) = %v, %v; want 0, ...%q...", n, err, wantsub)
2152 }
2153 }
2154
2155
2156 func TestWriteAtInAppendMode(t *testing.T) {
2157 defer chtmpdir(t)()
2158 f, err := OpenFile("write_at_in_append_mode.txt", O_APPEND|O_CREATE, 0666)
2159 if err != nil {
2160 t.Fatalf("OpenFile: %v", err)
2161 }
2162 defer f.Close()
2163
2164 _, err = f.WriteAt([]byte(""), 1)
2165 if err != ErrWriteAtInAppendMode {
2166 t.Fatalf("f.WriteAt returned %v, expected %v", err, ErrWriteAtInAppendMode)
2167 }
2168 }
2169
2170 func writeFile(t *testing.T, fname string, flag int, text string) string {
2171 f, err := OpenFile(fname, flag, 0666)
2172 if err != nil {
2173 t.Fatalf("Open: %v", err)
2174 }
2175 n, err := io.WriteString(f, text)
2176 if err != nil {
2177 t.Fatalf("WriteString: %d, %v", n, err)
2178 }
2179 f.Close()
2180 data, err := ReadFile(fname)
2181 if err != nil {
2182 t.Fatalf("ReadFile: %v", err)
2183 }
2184 return string(data)
2185 }
2186
2187 func TestAppend(t *testing.T) {
2188 defer chtmpdir(t)()
2189 const f = "append.txt"
2190 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2191 if s != "new" {
2192 t.Fatalf("writeFile: have %q want %q", s, "new")
2193 }
2194 s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
2195 if s != "new|append" {
2196 t.Fatalf("writeFile: have %q want %q", s, "new|append")
2197 }
2198 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
2199 if s != "new|append|append" {
2200 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
2201 }
2202 err := Remove(f)
2203 if err != nil {
2204 t.Fatalf("Remove: %v", err)
2205 }
2206 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
2207 if s != "new&append" {
2208 t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
2209 }
2210 s = writeFile(t, f, O_CREATE|O_RDWR, "old")
2211 if s != "old&append" {
2212 t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
2213 }
2214 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
2215 if s != "new" {
2216 t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
2217 }
2218 }
2219
2220 func TestStatDirWithTrailingSlash(t *testing.T) {
2221 t.Parallel()
2222
2223
2224 path := t.TempDir()
2225
2226
2227 if _, err := Stat(path); err != nil {
2228 t.Fatalf("stat %s failed: %s", path, err)
2229 }
2230
2231
2232 path += "/"
2233 if _, err := Stat(path); err != nil {
2234 t.Fatalf("stat %s failed: %s", path, err)
2235 }
2236 }
2237
2238 func TestNilProcessStateString(t *testing.T) {
2239 var ps *ProcessState
2240 s := ps.String()
2241 if s != "<nil>" {
2242 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
2243 }
2244 }
2245
2246 func TestSameFile(t *testing.T) {
2247 defer chtmpdir(t)()
2248 fa, err := Create("a")
2249 if err != nil {
2250 t.Fatalf("Create(a): %v", err)
2251 }
2252 fa.Close()
2253 fb, err := Create("b")
2254 if err != nil {
2255 t.Fatalf("Create(b): %v", err)
2256 }
2257 fb.Close()
2258
2259 ia1, err := Stat("a")
2260 if err != nil {
2261 t.Fatalf("Stat(a): %v", err)
2262 }
2263 ia2, err := Stat("a")
2264 if err != nil {
2265 t.Fatalf("Stat(a): %v", err)
2266 }
2267 if !SameFile(ia1, ia2) {
2268 t.Errorf("files should be same")
2269 }
2270
2271 ib, err := Stat("b")
2272 if err != nil {
2273 t.Fatalf("Stat(b): %v", err)
2274 }
2275 if SameFile(ia1, ib) {
2276 t.Errorf("files should be different")
2277 }
2278 }
2279
2280 func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo) {
2281 pre := fmt.Sprintf("%s(%q): ", statname, devNullName)
2282 if fi.Size() != 0 {
2283 t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
2284 }
2285 if fi.Mode()&ModeDevice == 0 {
2286 t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
2287 }
2288 if fi.Mode()&ModeCharDevice == 0 {
2289 t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
2290 }
2291 if fi.Mode().IsRegular() {
2292 t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
2293 }
2294 }
2295
2296 func testDevNullFile(t *testing.T, devNullName string) {
2297 f, err := Open(devNullName)
2298 if err != nil {
2299 t.Fatalf("Open(%s): %v", devNullName, err)
2300 }
2301 defer f.Close()
2302
2303 fi, err := f.Stat()
2304 if err != nil {
2305 t.Fatalf("Stat(%s): %v", devNullName, err)
2306 }
2307 testDevNullFileInfo(t, "f.Stat", devNullName, fi)
2308
2309 fi, err = Stat(devNullName)
2310 if err != nil {
2311 t.Fatalf("Stat(%s): %v", devNullName, err)
2312 }
2313 testDevNullFileInfo(t, "Stat", devNullName, fi)
2314 }
2315
2316 func TestDevNullFile(t *testing.T) {
2317 t.Parallel()
2318
2319 testDevNullFile(t, DevNull)
2320 if runtime.GOOS == "windows" {
2321 testDevNullFile(t, "./nul")
2322 testDevNullFile(t, "//./nul")
2323 }
2324 }
2325
2326 var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
2327
2328 func TestLargeWriteToConsole(t *testing.T) {
2329 if !*testLargeWrite {
2330 t.Skip("skipping console-flooding test; enable with -large_write")
2331 }
2332 b := make([]byte, 32000)
2333 for i := range b {
2334 b[i] = '.'
2335 }
2336 b[len(b)-1] = '\n'
2337 n, err := Stdout.Write(b)
2338 if err != nil {
2339 t.Fatalf("Write to os.Stdout failed: %v", err)
2340 }
2341 if n != len(b) {
2342 t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
2343 }
2344 n, err = Stderr.Write(b)
2345 if err != nil {
2346 t.Fatalf("Write to os.Stderr failed: %v", err)
2347 }
2348 if n != len(b) {
2349 t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
2350 }
2351 }
2352
2353 func TestStatDirModeExec(t *testing.T) {
2354 if runtime.GOOS == "wasip1" {
2355 t.Skip("Chmod is not supported on " + runtime.GOOS)
2356 }
2357 t.Parallel()
2358
2359 const mode = 0111
2360
2361 path := t.TempDir()
2362 if err := Chmod(path, 0777); err != nil {
2363 t.Fatalf("Chmod %q 0777: %v", path, err)
2364 }
2365
2366 dir, err := Stat(path)
2367 if err != nil {
2368 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
2369 }
2370 if dir.Mode()&mode != mode {
2371 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
2372 }
2373 }
2374
2375 func TestStatStdin(t *testing.T) {
2376 switch runtime.GOOS {
2377 case "android", "plan9":
2378 t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
2379 }
2380
2381 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2382 st, err := Stdin.Stat()
2383 if err != nil {
2384 t.Fatalf("Stat failed: %v", err)
2385 }
2386 fmt.Println(st.Mode() & ModeNamedPipe)
2387 Exit(0)
2388 }
2389
2390 exe, err := Executable()
2391 if err != nil {
2392 t.Skipf("can't find executable: %v", err)
2393 }
2394
2395 testenv.MustHaveExec(t)
2396 t.Parallel()
2397
2398 fi, err := Stdin.Stat()
2399 if err != nil {
2400 t.Fatal(err)
2401 }
2402 switch mode := fi.Mode(); {
2403 case mode&ModeCharDevice != 0 && mode&ModeDevice != 0:
2404 case mode&ModeNamedPipe != 0:
2405 default:
2406 t.Fatalf("unexpected Stdin mode (%v), want ModeCharDevice or ModeNamedPipe", mode)
2407 }
2408
2409 cmd := testenv.Command(t, exe, "-test.run=^TestStatStdin$")
2410 cmd = testenv.CleanCmdEnv(cmd)
2411 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
2412
2413 cmd.Stdin = strings.NewReader("output")
2414
2415 output, err := cmd.CombinedOutput()
2416 if err != nil {
2417 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2418 }
2419
2420
2421 if len(output) < 1 || output[0] != 'p' {
2422 t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
2423 }
2424 }
2425
2426 func TestStatRelativeSymlink(t *testing.T) {
2427 testenv.MustHaveSymlink(t)
2428 t.Parallel()
2429
2430 tmpdir := t.TempDir()
2431 target := filepath.Join(tmpdir, "target")
2432 f, err := Create(target)
2433 if err != nil {
2434 t.Fatal(err)
2435 }
2436 defer f.Close()
2437
2438 st, err := f.Stat()
2439 if err != nil {
2440 t.Fatal(err)
2441 }
2442
2443 link := filepath.Join(tmpdir, "link")
2444 err = Symlink(filepath.Base(target), link)
2445 if err != nil {
2446 t.Fatal(err)
2447 }
2448
2449 st1, err := Stat(link)
2450 if err != nil {
2451 t.Fatal(err)
2452 }
2453
2454 if !SameFile(st, st1) {
2455 t.Error("Stat doesn't follow relative symlink")
2456 }
2457
2458 if runtime.GOOS == "windows" {
2459 Remove(link)
2460 err = Symlink(target[len(filepath.VolumeName(target)):], link)
2461 if err != nil {
2462 t.Fatal(err)
2463 }
2464
2465 st1, err := Stat(link)
2466 if err != nil {
2467 t.Fatal(err)
2468 }
2469
2470 if !SameFile(st, st1) {
2471 t.Error("Stat doesn't follow relative symlink")
2472 }
2473 }
2474 }
2475
2476 func TestReadAtEOF(t *testing.T) {
2477 t.Parallel()
2478
2479 f := newFile("TestReadAtEOF", t)
2480 defer Remove(f.Name())
2481 defer f.Close()
2482
2483 _, err := f.ReadAt(make([]byte, 10), 0)
2484 switch err {
2485 case io.EOF:
2486
2487 case nil:
2488 t.Fatalf("ReadAt succeeded")
2489 default:
2490 t.Fatalf("ReadAt failed: %s", err)
2491 }
2492 }
2493
2494 func TestLongPath(t *testing.T) {
2495 t.Parallel()
2496
2497 tmpdir := newDir("TestLongPath", t)
2498 defer func(d string) {
2499 if err := RemoveAll(d); err != nil {
2500 t.Fatalf("RemoveAll failed: %v", err)
2501 }
2502 }(tmpdir)
2503
2504
2505 sizes := []int{247, 248, 249, 400}
2506 for len(tmpdir) < 400 {
2507 tmpdir += "/dir3456789"
2508 }
2509 for _, sz := range sizes {
2510 t.Run(fmt.Sprintf("length=%d", sz), func(t *testing.T) {
2511 sizedTempDir := tmpdir[:sz-1] + "x"
2512
2513
2514
2515 if err := MkdirAll(sizedTempDir, 0755); err != nil {
2516 t.Fatalf("MkdirAll failed: %v", err)
2517 }
2518 data := []byte("hello world\n")
2519 if err := WriteFile(sizedTempDir+"/foo.txt", data, 0644); err != nil {
2520 t.Fatalf("os.WriteFile() failed: %v", err)
2521 }
2522 if err := Rename(sizedTempDir+"/foo.txt", sizedTempDir+"/bar.txt"); err != nil {
2523 t.Fatalf("Rename failed: %v", err)
2524 }
2525 mtime := time.Now().Truncate(time.Minute)
2526 if err := Chtimes(sizedTempDir+"/bar.txt", mtime, mtime); err != nil {
2527 t.Fatalf("Chtimes failed: %v", err)
2528 }
2529 names := []string{"bar.txt"}
2530 if testenv.HasSymlink() {
2531 if err := Symlink(sizedTempDir+"/bar.txt", sizedTempDir+"/symlink.txt"); err != nil {
2532 t.Fatalf("Symlink failed: %v", err)
2533 }
2534 names = append(names, "symlink.txt")
2535 }
2536 if testenv.HasLink() {
2537 if err := Link(sizedTempDir+"/bar.txt", sizedTempDir+"/link.txt"); err != nil {
2538 t.Fatalf("Link failed: %v", err)
2539 }
2540 names = append(names, "link.txt")
2541 }
2542 for _, wantSize := range []int64{int64(len(data)), 0} {
2543 for _, name := range names {
2544 path := sizedTempDir + "/" + name
2545 dir, err := Stat(path)
2546 if err != nil {
2547 t.Fatalf("Stat(%q) failed: %v", path, err)
2548 }
2549 filesize := size(path, t)
2550 if dir.Size() != filesize || filesize != wantSize {
2551 t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
2552 }
2553 if runtime.GOOS != "wasip1" {
2554 err = Chmod(path, dir.Mode())
2555 if err != nil {
2556 t.Fatalf("Chmod(%q) failed: %v", path, err)
2557 }
2558 }
2559 }
2560 if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
2561 t.Fatalf("Truncate failed: %v", err)
2562 }
2563 }
2564 })
2565 }
2566 }
2567
2568 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
2569 testenv.MustHaveExec(t)
2570 t.Parallel()
2571
2572
2573 cmd := testenv.Command(t, Args[0])
2574 cmd.Env = append(cmd.Environ(), "GO_OS_TEST_DRAIN_STDIN=1")
2575 stdout, err := cmd.StdoutPipe()
2576 if err != nil {
2577 t.Fatal(err)
2578 }
2579 stdin, err := cmd.StdinPipe()
2580 if err != nil {
2581 t.Fatal(err)
2582 }
2583 err = cmd.Start()
2584 if err != nil {
2585 t.Fatalf("Failed to start test process: %v", err)
2586 }
2587
2588 defer func() {
2589 if err := cmd.Wait(); err == nil {
2590 t.Errorf("Test process succeeded, but expected to fail")
2591 }
2592 stdin.Close()
2593 }()
2594
2595
2596
2597 io.Copy(io.Discard, stdout)
2598
2599 processKiller(cmd.Process)
2600 }
2601
2602 func TestKillStartProcess(t *testing.T) {
2603 testKillProcess(t, func(p *Process) {
2604 err := p.Kill()
2605 if err != nil {
2606 t.Fatalf("Failed to kill test process: %v", err)
2607 }
2608 })
2609 }
2610
2611 func TestGetppid(t *testing.T) {
2612 if runtime.GOOS == "plan9" {
2613
2614 t.Skipf("skipping test on plan9; see issue 8206")
2615 }
2616
2617 if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
2618 fmt.Print(Getppid())
2619 Exit(0)
2620 }
2621
2622 testenv.MustHaveExec(t)
2623 t.Parallel()
2624
2625 cmd := testenv.Command(t, Args[0], "-test.run=^TestGetppid$")
2626 cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
2627
2628
2629 output, err := cmd.CombinedOutput()
2630 if err != nil {
2631 t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
2632 }
2633
2634 childPpid := string(output)
2635 ourPid := fmt.Sprintf("%d", Getpid())
2636 if childPpid != ourPid {
2637 t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
2638 }
2639 }
2640
2641 func TestKillFindProcess(t *testing.T) {
2642 testKillProcess(t, func(p *Process) {
2643 p2, err := FindProcess(p.Pid)
2644 if err != nil {
2645 t.Fatalf("Failed to find test process: %v", err)
2646 }
2647 err = p2.Kill()
2648 if err != nil {
2649 t.Fatalf("Failed to kill test process: %v", err)
2650 }
2651 })
2652 }
2653
2654 var nilFileMethodTests = []struct {
2655 name string
2656 f func(*File) error
2657 }{
2658 {"Chdir", func(f *File) error { return f.Chdir() }},
2659 {"Close", func(f *File) error { return f.Close() }},
2660 {"Chmod", func(f *File) error { return f.Chmod(0) }},
2661 {"Chown", func(f *File) error { return f.Chown(0, 0) }},
2662 {"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
2663 {"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
2664 {"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
2665 {"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
2666 {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
2667 {"Stat", func(f *File) error { _, err := f.Stat(); return err }},
2668 {"Sync", func(f *File) error { return f.Sync() }},
2669 {"Truncate", func(f *File) error { return f.Truncate(0) }},
2670 {"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
2671 {"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
2672 {"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
2673 }
2674
2675
2676 func TestNilFileMethods(t *testing.T) {
2677 t.Parallel()
2678
2679 for _, tt := range nilFileMethodTests {
2680 var file *File
2681 got := tt.f(file)
2682 if got != ErrInvalid {
2683 t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
2684 }
2685 }
2686 }
2687
2688 func mkdirTree(t *testing.T, root string, level, max int) {
2689 if level >= max {
2690 return
2691 }
2692 level++
2693 for i := 'a'; i < 'c'; i++ {
2694 dir := filepath.Join(root, string(i))
2695 if err := Mkdir(dir, 0700); err != nil {
2696 t.Fatal(err)
2697 }
2698 mkdirTree(t, dir, level, max)
2699 }
2700 }
2701
2702
2703
2704 func TestRemoveAllRace(t *testing.T) {
2705 if runtime.GOOS == "windows" {
2706
2707
2708
2709
2710 t.Skip("skipping on windows")
2711 }
2712 if runtime.GOOS == "dragonfly" {
2713 testenv.SkipFlaky(t, 52301)
2714 }
2715
2716 n := runtime.GOMAXPROCS(16)
2717 defer runtime.GOMAXPROCS(n)
2718 root, err := MkdirTemp("", "issue")
2719 if err != nil {
2720 t.Fatal(err)
2721 }
2722 mkdirTree(t, root, 1, 6)
2723 hold := make(chan struct{})
2724 var wg sync.WaitGroup
2725 for i := 0; i < 4; i++ {
2726 wg.Add(1)
2727 go func() {
2728 defer wg.Done()
2729 <-hold
2730 err := RemoveAll(root)
2731 if err != nil {
2732 t.Errorf("unexpected error: %T, %q", err, err)
2733 }
2734 }()
2735 }
2736 close(hold)
2737 wg.Wait()
2738 }
2739
2740
2741 func TestPipeThreads(t *testing.T) {
2742 switch runtime.GOOS {
2743 case "illumos", "solaris":
2744 t.Skip("skipping on Solaris and illumos; issue 19111")
2745 case "windows":
2746 t.Skip("skipping on Windows; issue 19098")
2747 case "plan9":
2748 t.Skip("skipping on Plan 9; does not support runtime poller")
2749 case "js":
2750 t.Skip("skipping on js; no support for os.Pipe")
2751 case "wasip1":
2752 t.Skip("skipping on wasip1; no support for os.Pipe")
2753 }
2754
2755 threads := 100
2756
2757
2758 if runtime.GOOS == "openbsd" {
2759 threads = 50
2760 }
2761
2762 r := make([]*File, threads)
2763 w := make([]*File, threads)
2764 for i := 0; i < threads; i++ {
2765 rp, wp, err := Pipe()
2766 if err != nil {
2767 for j := 0; j < i; j++ {
2768 r[j].Close()
2769 w[j].Close()
2770 }
2771 t.Fatal(err)
2772 }
2773 r[i] = rp
2774 w[i] = wp
2775 }
2776
2777 defer debug.SetMaxThreads(debug.SetMaxThreads(threads / 2))
2778
2779 creading := make(chan bool, threads)
2780 cdone := make(chan bool, threads)
2781 for i := 0; i < threads; i++ {
2782 go func(i int) {
2783 var b [1]byte
2784 creading <- true
2785 if _, err := r[i].Read(b[:]); err != nil {
2786 t.Error(err)
2787 }
2788 if err := r[i].Close(); err != nil {
2789 t.Error(err)
2790 }
2791 cdone <- true
2792 }(i)
2793 }
2794
2795 for i := 0; i < threads; i++ {
2796 <-creading
2797 }
2798
2799
2800
2801
2802 for i := 0; i < threads; i++ {
2803 if _, err := w[i].Write([]byte{0}); err != nil {
2804 t.Error(err)
2805 }
2806 if err := w[i].Close(); err != nil {
2807 t.Error(err)
2808 }
2809 <-cdone
2810 }
2811 }
2812
2813 func testDoubleCloseError(path string) func(*testing.T) {
2814 return func(t *testing.T) {
2815 t.Parallel()
2816
2817 file, err := Open(path)
2818 if err != nil {
2819 t.Fatal(err)
2820 }
2821 if err := file.Close(); err != nil {
2822 t.Fatalf("unexpected error from Close: %v", err)
2823 }
2824 if err := file.Close(); err == nil {
2825 t.Error("second Close did not fail")
2826 } else if pe, ok := err.(*PathError); !ok {
2827 t.Errorf("second Close: got %T, want %T", err, pe)
2828 } else if pe.Err != ErrClosed {
2829 t.Errorf("second Close: got %q, want %q", pe.Err, ErrClosed)
2830 } else {
2831 t.Logf("second close returned expected error %q", err)
2832 }
2833 }
2834 }
2835
2836 func TestDoubleCloseError(t *testing.T) {
2837 t.Parallel()
2838 t.Run("file", testDoubleCloseError(filepath.Join(sfdir, sfname)))
2839 t.Run("dir", testDoubleCloseError(sfdir))
2840 }
2841
2842 func TestUserCacheDir(t *testing.T) {
2843 t.Parallel()
2844
2845 dir, err := UserCacheDir()
2846 if err != nil {
2847 t.Skipf("skipping: %v", err)
2848 }
2849 if dir == "" {
2850 t.Fatalf("UserCacheDir returned %q; want non-empty path or error", dir)
2851 }
2852
2853 fi, err := Stat(dir)
2854 if err != nil {
2855 if IsNotExist(err) {
2856 t.Log(err)
2857 return
2858 }
2859 t.Fatal(err)
2860 }
2861 if !fi.IsDir() {
2862 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2863 }
2864 }
2865
2866 func TestUserConfigDir(t *testing.T) {
2867 t.Parallel()
2868
2869 dir, err := UserConfigDir()
2870 if err != nil {
2871 t.Skipf("skipping: %v", err)
2872 }
2873 if dir == "" {
2874 t.Fatalf("UserConfigDir returned %q; want non-empty path or error", dir)
2875 }
2876
2877 fi, err := Stat(dir)
2878 if err != nil {
2879 if IsNotExist(err) {
2880 t.Log(err)
2881 return
2882 }
2883 t.Fatal(err)
2884 }
2885 if !fi.IsDir() {
2886 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2887 }
2888 }
2889
2890 func TestUserHomeDir(t *testing.T) {
2891 t.Parallel()
2892
2893 dir, err := UserHomeDir()
2894 if dir == "" && err == nil {
2895 t.Fatal("UserHomeDir returned an empty string but no error")
2896 }
2897 if err != nil {
2898
2899
2900 t.Skipf("skipping: %v", err)
2901 }
2902
2903 fi, err := Stat(dir)
2904 if err != nil {
2905 if IsNotExist(err) {
2906
2907
2908
2909 t.Log(err)
2910 return
2911 }
2912 t.Fatal(err)
2913 }
2914 if !fi.IsDir() {
2915 t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
2916 }
2917 }
2918
2919 func TestDirSeek(t *testing.T) {
2920 t.Parallel()
2921
2922 wd, err := Getwd()
2923 if err != nil {
2924 t.Fatal(err)
2925 }
2926 f, err := Open(wd)
2927 if err != nil {
2928 t.Fatal(err)
2929 }
2930 dirnames1, err := f.Readdirnames(0)
2931 if err != nil {
2932 t.Fatal(err)
2933 }
2934
2935 ret, err := f.Seek(0, 0)
2936 if err != nil {
2937 t.Fatal(err)
2938 }
2939 if ret != 0 {
2940 t.Fatalf("seek result not zero: %d", ret)
2941 }
2942
2943 dirnames2, err := f.Readdirnames(0)
2944 if err != nil {
2945 t.Fatal(err)
2946 }
2947
2948 if len(dirnames1) != len(dirnames2) {
2949 t.Fatalf("listings have different lengths: %d and %d\n", len(dirnames1), len(dirnames2))
2950 }
2951 for i, n1 := range dirnames1 {
2952 n2 := dirnames2[i]
2953 if n1 != n2 {
2954 t.Fatalf("different name i=%d n1=%s n2=%s\n", i, n1, n2)
2955 }
2956 }
2957 }
2958
2959 func TestReaddirSmallSeek(t *testing.T) {
2960
2961
2962
2963 t.Parallel()
2964
2965 wd, err := Getwd()
2966 if err != nil {
2967 t.Fatal(err)
2968 }
2969 df, err := Open(filepath.Join(wd, "testdata", "issue37161"))
2970 if err != nil {
2971 t.Fatal(err)
2972 }
2973 names1, err := df.Readdirnames(1)
2974 if err != nil {
2975 t.Fatal(err)
2976 }
2977 if _, err = df.Seek(0, 0); err != nil {
2978 t.Fatal(err)
2979 }
2980 names2, err := df.Readdirnames(0)
2981 if err != nil {
2982 t.Fatal(err)
2983 }
2984 if len(names2) != 3 {
2985 t.Fatalf("first names: %v, second names: %v", names1, names2)
2986 }
2987 }
2988
2989
2990
2991 func isDeadlineExceeded(err error) bool {
2992 if !IsTimeout(err) {
2993 return false
2994 }
2995 if !errors.Is(err, ErrDeadlineExceeded) {
2996 return false
2997 }
2998 return true
2999 }
3000
3001
3002 func TestOpenFileKeepsPermissions(t *testing.T) {
3003 t.Parallel()
3004
3005 dir := t.TempDir()
3006 name := filepath.Join(dir, "x")
3007 f, err := Create(name)
3008 if err != nil {
3009 t.Fatal(err)
3010 }
3011 if err := f.Close(); err != nil {
3012 t.Error(err)
3013 }
3014 f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
3015 if err != nil {
3016 t.Fatal(err)
3017 }
3018 if fi, err := f.Stat(); err != nil {
3019 t.Error(err)
3020 } else if fi.Mode()&0222 == 0 {
3021 t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
3022 }
3023 if err := f.Close(); err != nil {
3024 t.Error(err)
3025 }
3026 if fi, err := Stat(name); err != nil {
3027 t.Error(err)
3028 } else if fi.Mode()&0222 == 0 {
3029 t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
3030 }
3031 }
3032
3033 func TestDirFS(t *testing.T) {
3034 t.Parallel()
3035
3036
3037
3038 if runtime.GOOS == "windows" {
3039 if err := filepath.WalkDir("./testdata/dirfs", func(path string, d fs.DirEntry, err error) error {
3040 if err != nil {
3041 t.Fatal(err)
3042 }
3043 info, err := d.Info()
3044 if err != nil {
3045 t.Fatal(err)
3046 }
3047 stat, err := Stat(path)
3048 if err != nil {
3049 t.Fatal(err)
3050 }
3051 if stat.ModTime() == info.ModTime() {
3052 return nil
3053 }
3054 if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
3055 t.Log(err)
3056 }
3057 return nil
3058 }); err != nil {
3059 t.Fatal(err)
3060 }
3061 }
3062 fsys := DirFS("./testdata/dirfs")
3063 if err := fstest.TestFS(fsys, "a", "b", "dir/x"); err != nil {
3064 t.Fatal(err)
3065 }
3066
3067 rdfs, ok := fsys.(fs.ReadDirFS)
3068 if !ok {
3069 t.Error("expected DirFS result to implement fs.ReadDirFS")
3070 }
3071 if _, err := rdfs.ReadDir("nonexistent"); err == nil {
3072 t.Error("fs.ReadDir of nonexistent directory succeeded")
3073 }
3074
3075
3076
3077 const nonesuch = "dir/nonesuch"
3078 _, err := fsys.Open(nonesuch)
3079 if err == nil {
3080 t.Error("fs.Open of nonexistent file succeeded")
3081 } else {
3082 if !strings.Contains(err.Error(), nonesuch) {
3083 t.Errorf("error %q does not contain %q", err, nonesuch)
3084 }
3085 if strings.Contains(err.(*PathError).Path, "testdata") {
3086 t.Errorf("error %q contains %q", err, "testdata")
3087 }
3088 }
3089
3090
3091 d := DirFS(".")
3092 _, err = d.Open(`testdata\dirfs`)
3093 if err == nil {
3094 t.Fatalf(`Open testdata\dirfs succeeded`)
3095 }
3096
3097
3098 _, err = d.Open(`NUL`)
3099 if err == nil {
3100 t.Errorf(`Open NUL succeeded`)
3101 }
3102 }
3103
3104 func TestDirFSRootDir(t *testing.T) {
3105 t.Parallel()
3106
3107 cwd, err := Getwd()
3108 if err != nil {
3109 t.Fatal(err)
3110 }
3111 cwd = cwd[len(filepath.VolumeName(cwd)):]
3112 cwd = filepath.ToSlash(cwd)
3113 cwd = strings.TrimPrefix(cwd, "/")
3114
3115
3116 d := DirFS("/")
3117 f, err := d.Open(cwd + "/testdata/dirfs/a")
3118 if err != nil {
3119 t.Fatal(err)
3120 }
3121 f.Close()
3122 }
3123
3124 func TestDirFSEmptyDir(t *testing.T) {
3125 t.Parallel()
3126
3127 d := DirFS("")
3128 cwd, _ := Getwd()
3129 for _, path := range []string{
3130 "testdata/dirfs/a",
3131 filepath.ToSlash(cwd) + "/testdata/dirfs/a",
3132 } {
3133 _, err := d.Open(path)
3134 if err == nil {
3135 t.Fatalf(`DirFS("").Open(%q) succeeded`, path)
3136 }
3137 }
3138 }
3139
3140 func TestDirFSPathsValid(t *testing.T) {
3141 if runtime.GOOS == "windows" {
3142 t.Skipf("skipping on Windows")
3143 }
3144 t.Parallel()
3145
3146 d := t.TempDir()
3147 if err := WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil {
3148 t.Fatal(err)
3149 }
3150 if err := WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil {
3151 t.Fatal(err)
3152 }
3153
3154 fsys := DirFS(d)
3155 err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error {
3156 if fs.ValidPath(e.Name()) {
3157 t.Logf("%q ok", e.Name())
3158 } else {
3159 t.Errorf("%q INVALID", e.Name())
3160 }
3161 return nil
3162 })
3163 if err != nil {
3164 t.Fatal(err)
3165 }
3166 }
3167
3168 func TestReadFileProc(t *testing.T) {
3169 t.Parallel()
3170
3171
3172
3173
3174
3175
3176 name := "/proc/sys/fs/pipe-max-size"
3177 if _, err := Stat(name); err != nil {
3178 t.Skip(err)
3179 }
3180 data, err := ReadFile(name)
3181 if err != nil {
3182 t.Fatal(err)
3183 }
3184 if len(data) == 0 || data[len(data)-1] != '\n' {
3185 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3186 }
3187 }
3188
3189 func TestDirFSReadFileProc(t *testing.T) {
3190 t.Parallel()
3191
3192 fsys := DirFS("/")
3193 name := "proc/sys/fs/pipe-max-size"
3194 if _, err := fs.Stat(fsys, name); err != nil {
3195 t.Skip()
3196 }
3197 data, err := fs.ReadFile(fsys, name)
3198 if err != nil {
3199 t.Fatal(err)
3200 }
3201 if len(data) == 0 || data[len(data)-1] != '\n' {
3202 t.Fatalf("read %s: not newline-terminated: %q", name, data)
3203 }
3204 }
3205
3206 func TestWriteStringAlloc(t *testing.T) {
3207 if runtime.GOOS == "js" {
3208 t.Skip("js allocates a lot during File.WriteString")
3209 }
3210 d := t.TempDir()
3211 f, err := Create(filepath.Join(d, "whiteboard.txt"))
3212 if err != nil {
3213 t.Fatal(err)
3214 }
3215 defer f.Close()
3216 allocs := testing.AllocsPerRun(100, func() {
3217 f.WriteString("I will not allocate when passed a string longer than 32 bytes.\n")
3218 })
3219 if allocs != 0 {
3220 t.Errorf("expected 0 allocs for File.WriteString, got %v", allocs)
3221 }
3222 }
3223
3224
3225 func TestPipeIOCloseRace(t *testing.T) {
3226
3227 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3228 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3229 }
3230 t.Parallel()
3231
3232 r, w, err := Pipe()
3233 if err != nil {
3234 t.Fatal(err)
3235 }
3236
3237 var wg sync.WaitGroup
3238 wg.Add(3)
3239
3240 go func() {
3241 defer wg.Done()
3242 for {
3243 n, err := w.Write([]byte("hi"))
3244 if err != nil {
3245
3246
3247 switch {
3248 case errors.Is(err, ErrClosed),
3249 strings.Contains(err.Error(), "broken pipe"),
3250 strings.Contains(err.Error(), "pipe is being closed"),
3251 strings.Contains(err.Error(), "hungup channel"):
3252
3253 default:
3254
3255 t.Error(err)
3256 }
3257 return
3258 }
3259 if n != 2 {
3260 t.Errorf("wrote %d bytes, expected 2", n)
3261 return
3262 }
3263 }
3264 }()
3265
3266 go func() {
3267 defer wg.Done()
3268 for {
3269 var buf [2]byte
3270 n, err := r.Read(buf[:])
3271 if err != nil {
3272 if err != io.EOF && !errors.Is(err, ErrClosed) {
3273 t.Error(err)
3274 }
3275 return
3276 }
3277 if n != 2 {
3278 t.Errorf("read %d bytes, want 2", n)
3279 }
3280 }
3281 }()
3282
3283 go func() {
3284 defer wg.Done()
3285
3286
3287
3288
3289 time.Sleep(time.Millisecond)
3290
3291 if err := r.Close(); err != nil {
3292 t.Error(err)
3293 }
3294 if err := w.Close(); err != nil {
3295 t.Error(err)
3296 }
3297 }()
3298
3299 wg.Wait()
3300 }
3301
3302
3303 func TestPipeCloseRace(t *testing.T) {
3304
3305 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
3306 t.Skipf("skipping on %s: no pipes", runtime.GOOS)
3307 }
3308 t.Parallel()
3309
3310 r, w, err := Pipe()
3311 if err != nil {
3312 t.Fatal(err)
3313 }
3314 var wg sync.WaitGroup
3315 c := make(chan error, 4)
3316 f := func() {
3317 defer wg.Done()
3318 c <- r.Close()
3319 c <- w.Close()
3320 }
3321 wg.Add(2)
3322 go f()
3323 go f()
3324 nils, errs := 0, 0
3325 for i := 0; i < 4; i++ {
3326 err := <-c
3327 if err == nil {
3328 nils++
3329 } else {
3330 errs++
3331 }
3332 }
3333 if nils != 2 || errs != 2 {
3334 t.Errorf("got nils %d errs %d, want 2 2", nils, errs)
3335 }
3336 }
3337
3338 func TestRandomLen(t *testing.T) {
3339 for range 5 {
3340 dir, err := MkdirTemp(t.TempDir(), "*")
3341 if err != nil {
3342 t.Fatal(err)
3343 }
3344 base := filepath.Base(dir)
3345 if len(base) > 10 {
3346 t.Errorf("MkdirTemp returned len %d: %s", len(base), base)
3347 }
3348 }
3349 for range 5 {
3350 f, err := CreateTemp(t.TempDir(), "*")
3351 if err != nil {
3352 t.Fatal(err)
3353 }
3354 base := filepath.Base(f.Name())
3355 f.Close()
3356 if len(base) > 10 {
3357 t.Errorf("CreateTemp returned len %d: %s", len(base), base)
3358 }
3359 }
3360 }
3361
View as plain text