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.
35 var sysdir = func() (sd *sysDir) {
39 Getenv("SystemRoot") + "\\system32\\drivers\\etc",
68 func size(name string, t *testing.T) int64 {
69 file, err := Open(name)
71 t.Fatal("open failed:", err)
77 n, e := file.Read(buf[0:])
83 t.Fatal("read failed:", err)
89 func equal(name1, name2 string) (r bool) {
92 r = strings.ToLower(name1) == strings.ToLower(name2)
99 func newFile(testName string, t *testing.T) (f *File) {
100 // Use a local file system, not NFS.
101 // On Unix, override $TMPDIR in case the user
102 // has it set to an NFS-mounted directory.
104 if runtime.GOOS != "windows" {
107 f, err := ioutil.TempFile(dir, "_Go_"+testName)
109 t.Fatalf("open %s: %s", testName, err)
114 var sfdir = sysdir.name
115 var sfname = sysdir.files[0]
117 func TestStat(t *testing.T) {
118 path := sfdir + "/" + sfname
119 dir, err := Stat(path)
121 t.Fatal("stat failed:", err)
123 if !equal(sfname, dir.Name()) {
124 t.Error("name should be ", sfname, "; is", dir.Name())
126 filesize := size(path, t)
127 if dir.Size() != filesize {
128 t.Error("size should be", filesize, "; is", dir.Size())
132 func TestFstat(t *testing.T) {
133 path := sfdir + "/" + sfname
134 file, err1 := Open(path)
136 t.Fatal("open failed:", err1)
139 dir, err2 := file.Stat()
141 t.Fatal("fstat failed:", err2)
143 if !equal(sfname, dir.Name()) {
144 t.Error("name should be ", sfname, "; is", dir.Name())
146 filesize := size(path, t)
147 if dir.Size() != filesize {
148 t.Error("size should be", filesize, "; is", dir.Size())
152 func TestLstat(t *testing.T) {
153 path := sfdir + "/" + sfname
154 dir, err := Lstat(path)
156 t.Fatal("lstat failed:", err)
158 if !equal(sfname, dir.Name()) {
159 t.Error("name should be ", sfname, "; is", dir.Name())
161 filesize := size(path, t)
162 if dir.Size() != filesize {
163 t.Error("size should be", filesize, "; is", dir.Size())
167 // Read with length 0 should not return EOF.
168 func TestRead0(t *testing.T) {
169 path := sfdir + "/" + sfname
172 t.Fatal("open failed:", err)
178 if n != 0 || err != nil {
179 t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
181 b = make([]byte, 100)
183 if n <= 0 || err != nil {
184 t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
188 func testReaddirnames(dir string, contents []string, t *testing.T) {
189 file, err := Open(dir)
191 t.Fatalf("open %q failed: %v", dir, err)
194 s, err2 := file.Readdirnames(-1)
196 t.Fatalf("readdirnames %q failed: %v", dir, err2)
198 for _, m := range contents {
200 for _, n := range s {
201 if n == "." || n == ".." {
202 t.Errorf("got %s in directory", n)
206 t.Error("present twice:", m)
212 t.Error("could not find", m)
217 func testReaddir(dir string, contents []string, t *testing.T) {
218 file, err := Open(dir)
220 t.Fatalf("open %q failed: %v", dir, err)
223 s, err2 := file.Readdir(-1)
225 t.Fatalf("readdir %q failed: %v", dir, err2)
227 for _, m := range contents {
229 for _, n := range s {
230 if equal(m, n.Name()) {
232 t.Error("present twice:", m)
238 t.Error("could not find", m)
243 func TestReaddirnames(t *testing.T) {
244 testReaddirnames(".", dot, t)
245 testReaddirnames(sysdir.name, sysdir.files, t)
248 func TestReaddir(t *testing.T) {
249 testReaddir(".", dot, t)
250 testReaddir(sysdir.name, sysdir.files, t)
253 // Read the directory one entry at a time.
254 func smallReaddirnames(file *File, length int, t *testing.T) []string {
255 names := make([]string, length)
258 d, err := file.Readdirnames(1)
263 t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
266 t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
271 return names[0:count]
274 // Check that reading a directory one entry at a time gives the same result
275 // as reading it all at once.
276 func TestReaddirnamesOneAtATime(t *testing.T) {
277 // big directory that doesn't change often.
279 switch runtime.GOOS {
281 dir = Getenv("SystemRoot") + "\\system32"
285 file, err := Open(dir)
287 t.Fatalf("open %q failed: %v", dir, err)
290 all, err1 := file.Readdirnames(-1)
292 t.Fatalf("readdirnames %q failed: %v", dir, err1)
294 file1, err2 := Open(dir)
296 t.Fatalf("open %q failed: %v", dir, err2)
298 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
299 if len(small) < len(all) {
300 t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
302 for i, n := range all {
304 t.Errorf("small read %q mismatch: %v", small[i], n)
309 func TestReaddirNValues(t *testing.T) {
311 t.Logf("test.short; skipping")
314 dir, err := ioutil.TempDir("", "")
316 t.Fatalf("TempDir: %v", err)
319 for i := 1; i <= 105; i++ {
320 f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
322 t.Fatalf("Create: %v", err)
324 f.Write([]byte(strings.Repeat("X", i)))
333 t.Fatalf("Open directory: %v", err)
337 readDirExpect := func(n, want int, wantErr error) {
338 fi, err := d.Readdir(n)
340 t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
342 if g, e := len(fi), want; g != e {
343 t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
347 readDirNamesExpect := func(n, want int, wantErr error) {
348 fi, err := d.Readdirnames(n)
350 t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
352 if g, e := len(fi), want; g != e {
353 t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
357 for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} {
358 // Test the slurp case
364 // Slurp with -1 instead
371 // Test the bounded case
375 fn(105, 102, nil) // and tests buffer >100 case
381 func TestHardLink(t *testing.T) {
382 // Hardlinks are not supported under windows or Plan 9.
383 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
386 from, to := "hardlinktestfrom", "hardlinktestto"
387 Remove(from) // Just in case.
388 file, err := Create(to)
390 t.Fatalf("open %q failed: %v", to, err)
393 if err = file.Close(); err != nil {
394 t.Errorf("close %q failed: %v", to, err)
398 t.Fatalf("link %q, %q failed: %v", to, from, err)
401 tostat, err := Stat(to)
403 t.Fatalf("stat %q failed: %v", to, err)
405 fromstat, err := Stat(from)
407 t.Fatalf("stat %q failed: %v", from, err)
409 if !SameFile(tostat, fromstat) {
410 t.Errorf("link %q, %q did not create hard link", to, from)
414 func TestSymLink(t *testing.T) {
415 // Symlinks are not supported under windows or Plan 9.
416 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
419 from, to := "symlinktestfrom", "symlinktestto"
420 Remove(from) // Just in case.
421 file, err := Create(to)
423 t.Fatalf("open %q failed: %v", to, err)
426 if err = file.Close(); err != nil {
427 t.Errorf("close %q failed: %v", to, err)
429 err = Symlink(to, from)
431 t.Fatalf("symlink %q, %q failed: %v", to, from, err)
434 tostat, err := Lstat(to)
436 t.Fatalf("stat %q failed: %v", to, err)
438 if tostat.Mode()&ModeSymlink != 0 {
439 t.Fatalf("stat %q claims to have found a symlink", to)
441 fromstat, err := Stat(from)
443 t.Fatalf("stat %q failed: %v", from, err)
445 if !SameFile(tostat, fromstat) {
446 t.Errorf("symlink %q, %q did not create symlink", to, from)
448 fromstat, err = Lstat(from)
450 t.Fatalf("lstat %q failed: %v", from, err)
452 if fromstat.Mode()&ModeSymlink == 0 {
453 t.Fatalf("symlink %q, %q did not create symlink", to, from)
455 fromstat, err = Stat(from)
457 t.Fatalf("stat %q failed: %v", from, err)
459 if fromstat.Mode()&ModeSymlink != 0 {
460 t.Fatalf("stat %q did not follow symlink", from)
462 s, err := Readlink(from)
464 t.Fatalf("readlink %q failed: %v", from, err)
467 t.Fatalf("after symlink %q != %q", s, to)
469 file, err = Open(from)
471 t.Fatalf("open %q failed: %v", from, err)
476 func TestLongSymlink(t *testing.T) {
477 // Symlinks are not supported under windows or Plan 9.
478 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
481 s := "0123456789abcdef"
482 // Long, but not too long: a common limit is 255.
483 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
484 from := "longsymlinktestfrom"
485 Remove(from) // Just in case.
486 err := Symlink(s, from)
488 t.Fatalf("symlink %q, %q failed: %v", s, from, err)
491 r, err := Readlink(from)
493 t.Fatalf("readlink %q failed: %v", from, err)
496 t.Fatalf("after symlink %q != %q", r, s)
500 func TestRename(t *testing.T) {
501 from, to := "renamefrom", "renameto"
502 Remove(to) // Just in case.
503 file, err := Create(from)
505 t.Fatalf("open %q failed: %v", to, err)
507 if err = file.Close(); err != nil {
508 t.Errorf("close %q failed: %v", to, err)
510 err = Rename(from, to)
512 t.Fatalf("rename %q, %q failed: %v", to, from, err)
517 t.Errorf("stat %q failed: %v", to, err)
521 func exec(t *testing.T, dir, cmd string, args []string, expect string) {
524 t.Fatalf("Pipe: %v", err)
526 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
527 p, err := StartProcess(cmd, args, attr)
529 t.Fatalf("StartProcess: %v", err)
536 // Accept /usr prefix because Solaris /bin is symlinked to /usr/bin.
537 if output != expect && output != "/usr"+expect {
538 t.Errorf("exec %q returned %q wanted %q",
539 strings.Join(append([]string{cmd}, args...), " "), output, expect)
544 func TestStartProcess(t *testing.T) {
545 var dir, cmd, le string
547 if runtime.GOOS == "windows" {
549 cmd = Getenv("COMSPEC")
550 dir = Getenv("SystemRoot")
551 args = []string{"/c", "cd"}
558 cmddir, cmdbase := filepath.Split(cmd)
559 args = append([]string{cmdbase}, args...)
560 // Test absolute executable path.
561 exec(t, dir, cmd, args, dir+le)
562 // Test relative executable path.
563 exec(t, cmddir, cmdbase, args, filepath.Clean(cmddir)+le)
566 func checkMode(t *testing.T, path string, mode FileMode) {
567 dir, err := Stat(path)
569 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
571 if dir.Mode()&0777 != mode {
572 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
576 func TestChmod(t *testing.T) {
577 // Chmod is not supported under windows.
578 if runtime.GOOS == "windows" {
581 f := newFile("TestChmod", t)
582 defer Remove(f.Name())
585 if err := Chmod(f.Name(), 0456); err != nil {
586 t.Fatalf("chmod %s 0456: %s", f.Name(), err)
588 checkMode(t, f.Name(), 0456)
590 if err := f.Chmod(0123); err != nil {
591 t.Fatalf("chmod %s 0123: %s", f.Name(), err)
593 checkMode(t, f.Name(), 0123)
596 func checkSize(t *testing.T, f *File, size int64) {
599 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
601 if dir.Size() != size {
602 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
606 func TestFTruncate(t *testing.T) {
607 f := newFile("TestFTruncate", t)
608 defer Remove(f.Name())
612 f.Write([]byte("hello, world\n"))
617 checkSize(t, f, 1024)
620 f.Write([]byte("surprise!"))
621 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
624 func TestTruncate(t *testing.T) {
625 f := newFile("TestTruncate", t)
626 defer Remove(f.Name())
630 f.Write([]byte("hello, world\n"))
632 Truncate(f.Name(), 10)
634 Truncate(f.Name(), 1024)
635 checkSize(t, f, 1024)
636 Truncate(f.Name(), 0)
638 f.Write([]byte("surprise!"))
639 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
642 // Use TempDir() to make sure we're on a local file system,
643 // so that timings are not distorted by latency and caching.
644 // On NFS, timings can be off due to caching of meta-data on
645 // NFS servers (Issue 848).
646 func TestChtimes(t *testing.T) {
647 f := newFile("TestChtimes", t)
648 defer Remove(f.Name())
651 f.Write([]byte("hello, world\n"))
654 st, err := Stat(f.Name())
656 t.Fatalf("Stat %s: %s", f.Name(), err)
660 // Move access and modification time back a second
662 mt := preStat.ModTime()
663 err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
665 t.Fatalf("Chtimes %s: %s", f.Name(), err)
668 st, err = Stat(f.Name())
670 t.Fatalf("second Stat %s: %s", f.Name(), err)
675 Mtime is the time of the last change of content. Similarly, atime is set whenever the
676 contents are accessed; also, it is set whenever mtime is set.
678 pat := Atime(postStat)
679 pmt := postStat.ModTime()
680 if !pat.Before(at) && runtime.GOOS != "plan9" {
681 t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
685 t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
689 func TestChdirAndGetwd(t *testing.T) {
690 // TODO(brainman): file.Chdir() is not implemented on windows.
691 if runtime.GOOS == "windows" {
696 t.Fatalf("Open .: %s", err)
698 // These are chosen carefully not to be symlinks on a Mac
699 // (unlike, say, /var, /etc, and /tmp).
700 dirs := []string{"/", "/usr/bin"}
701 // /usr/bin does not usually exist on Plan 9.
702 if runtime.GOOS == "plan9" {
703 dirs = []string{"/", "/usr"}
705 for mode := 0; mode < 2; mode++ {
706 for _, d := range dirs {
712 t.Errorf("Open %s: %s", d, err)
721 // We changed the current directory and cannot go back.
722 // Don't let the tests continue; they'll scribble
723 // all over some other directory.
724 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
729 t.Fatalf("Chdir %s: %s", d, err)
733 t.Fatalf("Getwd in %s: %s", d, err1)
737 t.Fatalf("Getwd returned %q want %q", pwd, d)
744 func TestSeek(t *testing.T) {
745 f := newFile("TestSeek", t)
746 defer Remove(f.Name())
749 const data = "hello, world\n"
750 io.WriteString(f, data)
758 {0, 1, int64(len(data))},
761 {0, 2, int64(len(data))},
763 {-1, 2, int64(len(data)) - 1},
764 {1 << 33, 0, 1 << 33},
765 {1 << 33, 2, 1<<33 + int64(len(data))},
767 for i, tt := range tests {
768 off, err := f.Seek(tt.in, tt.whence)
769 if off != tt.out || err != nil {
770 if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
771 // Reiserfs rejects the big seeks.
772 // http://code.google.com/p/go/issues/detail?id=91
775 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
780 type openErrorTest struct {
786 var openErrorTests = []openErrorTest{
788 sfdir + "/no-such-file",
798 sfdir + "/" + sfname + "/no-such-file",
804 func TestOpenError(t *testing.T) {
805 for _, tt := range openErrorTests {
806 f, err := OpenFile(tt.path, tt.mode, 0)
808 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
812 perr, ok := err.(*PathError)
814 t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
816 if perr.Err != tt.error {
817 if runtime.GOOS == "plan9" {
818 syscallErrStr := perr.Err.Error()
819 expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
820 if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
821 t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
824 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
830 func TestOpenNoName(t *testing.T) {
833 t.Fatal(`Open("") succeeded`)
838 func run(t *testing.T, cmd []string) string {
839 // Run /bin/hostname and collect output.
844 p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
854 t.Fatalf("run hostname Wait: %v", err)
858 t.Errorf("expected an error from Kill running 'hostname'")
861 if n := len(output); n > 0 && output[n-1] == '\n' {
862 output = output[0 : n-1]
865 t.Fatalf("%v produced no output", cmd)
871 func TestHostname(t *testing.T) {
872 // There is no other way to fetch hostname on windows, but via winapi.
873 // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
874 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
878 // Check internal Hostname() against the output of /bin/hostname.
879 // Allow that the internal Hostname returns a Fully Qualified Domain Name
880 // and the /bin/hostname only returns the first component
881 hostname, err := Hostname()
885 want := run(t, []string{"/bin/hostname"})
886 if hostname != want {
887 i := strings.Index(hostname, ".")
888 if i < 0 || hostname[0:i] != want {
889 t.Errorf("Hostname() = %q, want %q", hostname, want)
894 func TestReadAt(t *testing.T) {
895 f := newFile("TestReadAt", t)
896 defer Remove(f.Name())
899 const data = "hello, world\n"
900 io.WriteString(f, data)
903 n, err := f.ReadAt(b, 7)
904 if err != nil || n != len(b) {
905 t.Fatalf("ReadAt 7: %d, %v", n, err)
907 if string(b) != "world" {
908 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
912 func TestWriteAt(t *testing.T) {
913 f := newFile("TestWriteAt", t)
914 defer Remove(f.Name())
917 const data = "hello, world\n"
918 io.WriteString(f, data)
920 n, err := f.WriteAt([]byte("WORLD"), 7)
921 if err != nil || n != 5 {
922 t.Fatalf("WriteAt 7: %d, %v", n, err)
925 b, err := ioutil.ReadFile(f.Name())
927 t.Fatalf("ReadFile %s: %v", f.Name(), err)
929 if string(b) != "hello, WORLD\n" {
930 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
934 func writeFile(t *testing.T, fname string, flag int, text string) string {
935 f, err := OpenFile(fname, flag, 0666)
937 t.Fatalf("Open: %v", err)
939 n, err := io.WriteString(f, text)
941 t.Fatalf("WriteString: %d, %v", n, err)
944 data, err := ioutil.ReadFile(fname)
946 t.Fatalf("ReadFile: %v", err)
951 func TestAppend(t *testing.T) {
952 const f = "append.txt"
954 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
956 t.Fatalf("writeFile: have %q want %q", s, "new")
958 s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
959 if s != "new|append" {
960 t.Fatalf("writeFile: have %q want %q", s, "new|append")
962 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
963 if s != "new|append|append" {
964 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
968 t.Fatalf("Remove: %v", err)
970 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
971 if s != "new&append" {
972 t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
974 s = writeFile(t, f, O_CREATE|O_RDWR, "old")
975 if s != "old&append" {
976 t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
978 s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
980 t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
984 func TestStatDirWithTrailingSlash(t *testing.T) {
985 // Create new temporary directory and arrange to clean it up.
986 path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_")
988 t.Fatalf("TempDir: %s", err)
990 defer RemoveAll(path)
992 // Stat of path should succeed.
995 t.Fatalf("stat %s failed: %s", path, err)
998 // Stat of path+"/" should succeed too.
1002 t.Fatalf("stat %s failed: %s", path, err)
1006 func TestNilProcessStateString(t *testing.T) {
1007 var ps *ProcessState
1010 t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
1014 func TestSameFile(t *testing.T) {
1015 fa, err := Create("a")
1017 t.Fatalf("Create(a): %v", err)
1019 defer Remove(fa.Name())
1021 fb, err := Create("b")
1023 t.Fatalf("Create(b): %v", err)
1025 defer Remove(fb.Name())
1028 ia1, err := Stat("a")
1030 t.Fatalf("Stat(a): %v", err)
1032 ia2, err := Stat("a")
1034 t.Fatalf("Stat(a): %v", err)
1036 if !SameFile(ia1, ia2) {
1037 t.Errorf("files should be same")
1040 ib, err := Stat("b")
1042 t.Fatalf("Stat(b): %v", err)
1044 if SameFile(ia1, ib) {
1045 t.Errorf("files should be different")
1049 func TestDevNullFile(t *testing.T) {
1050 f, err := Open(DevNull)
1052 t.Fatalf("Open(%s): %v", DevNull, err)
1057 t.Fatalf("Stat(%s): %v", DevNull, err)
1059 name := filepath.Base(DevNull)
1060 if fi.Name() != name {
1061 t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
1064 t.Fatalf("wrong file size have %d want 0", fi.Size())