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.
34 var sysdir = func() (sd *sysDir) {
38 Getenv("SystemRoot") + "\\system32\\drivers\\etc",
67 func size(name string, t *testing.T) int64 {
68 file, err := Open(name)
71 t.Fatal("open failed:", err)
76 n, e := file.Read(buf[0:])
82 t.Fatal("read failed:", err)
88 func equal(name1, name2 string) (r bool) {
91 r = strings.ToLower(name1) == strings.ToLower(name2)
98 func newFile(testName string, t *testing.T) (f *File) {
99 // Use a local file system, not NFS.
100 // On Unix, override $TMPDIR in case the user
101 // has it set to an NFS-mounted directory.
103 if syscall.OS != "windows" {
106 f, err := ioutil.TempFile(dir, "_Go_"+testName)
108 t.Fatalf("open %s: %s", testName, err)
113 var sfdir = sysdir.name
114 var sfname = sysdir.files[0]
116 func TestStat(t *testing.T) {
117 path := sfdir + "/" + sfname
118 dir, err := Stat(path)
120 t.Fatal("stat failed:", err)
122 if !equal(sfname, dir.Name) {
123 t.Error("name should be ", sfname, "; is", dir.Name)
125 filesize := size(path, t)
126 if dir.Size != filesize {
127 t.Error("size should be", filesize, "; is", dir.Size)
131 func TestFstat(t *testing.T) {
132 path := sfdir + "/" + sfname
133 file, err1 := Open(path)
136 t.Fatal("open failed:", err1)
138 dir, err2 := file.Stat()
140 t.Fatal("fstat failed:", err2)
142 if !equal(sfname, dir.Name) {
143 t.Error("name should be ", sfname, "; is", dir.Name)
145 filesize := size(path, t)
146 if dir.Size != filesize {
147 t.Error("size should be", filesize, "; is", dir.Size)
151 func TestLstat(t *testing.T) {
152 path := sfdir + "/" + sfname
153 dir, err := Lstat(path)
155 t.Fatal("lstat failed:", err)
157 if !equal(sfname, dir.Name) {
158 t.Error("name should be ", sfname, "; is", dir.Name)
160 filesize := size(path, t)
161 if dir.Size != filesize {
162 t.Error("size should be", filesize, "; is", dir.Size)
166 func testReaddirnames(dir string, contents []string, t *testing.T) {
167 file, err := Open(dir)
170 t.Fatalf("open %q failed: %v", dir, err)
172 s, err2 := file.Readdirnames(-1)
174 t.Fatalf("readdirnames %q failed: %v", dir, err2)
176 for _, m := range contents {
178 for _, n := range s {
179 if n == "." || n == ".." {
180 t.Errorf("got %s in directory", n)
184 t.Error("present twice:", m)
190 t.Error("could not find", m)
195 func testReaddir(dir string, contents []string, t *testing.T) {
196 file, err := Open(dir)
199 t.Fatalf("open %q failed: %v", dir, err)
201 s, err2 := file.Readdir(-1)
203 t.Fatalf("readdir %q failed: %v", dir, err2)
205 for _, m := range contents {
207 for _, n := range s {
208 if equal(m, n.Name) {
210 t.Error("present twice:", m)
216 t.Error("could not find", m)
221 func TestReaddirnames(t *testing.T) {
222 testReaddirnames(".", dot, t)
223 testReaddirnames(sysdir.name, sysdir.files, t)
226 func TestReaddir(t *testing.T) {
227 testReaddir(".", dot, t)
228 testReaddir(sysdir.name, sysdir.files, t)
231 // Read the directory one entry at a time.
232 func smallReaddirnames(file *File, length int, t *testing.T) []string {
233 names := make([]string, length)
236 d, err := file.Readdirnames(1)
238 t.Fatalf("readdir %q failed: %v", file.Name(), err)
246 return names[0:count]
249 // Check that reading a directory one entry at a time gives the same result
250 // as reading it all at once.
251 func TestReaddirnamesOneAtATime(t *testing.T) {
252 // big directory that doesn't change often.
256 dir = Getenv("SystemRoot") + "\\system32"
260 file, err := Open(dir)
263 t.Fatalf("open %q failed: %v", dir, err)
265 all, err1 := file.Readdirnames(-1)
267 t.Fatalf("readdirnames %q failed: %v", dir, err1)
269 file1, err2 := Open(dir)
271 t.Fatalf("open %q failed: %v", dir, err2)
273 small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
274 if len(small) < len(all) {
275 t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
277 for i, n := range all {
279 t.Errorf("small read %q mismatch: %v", small[i], n)
284 func TestHardLink(t *testing.T) {
285 // Hardlinks are not supported under windows.
286 if syscall.OS == "windows" {
289 from, to := "hardlinktestfrom", "hardlinktestto"
290 Remove(from) // Just in case.
291 file, err := Create(to)
293 t.Fatalf("open %q failed: %v", to, err)
296 if err = file.Close(); err != nil {
297 t.Errorf("close %q failed: %v", to, err)
301 t.Fatalf("link %q, %q failed: %v", to, from, err)
304 tostat, err := Stat(to)
306 t.Fatalf("stat %q failed: %v", to, err)
308 fromstat, err := Stat(from)
310 t.Fatalf("stat %q failed: %v", from, err)
312 if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
313 t.Errorf("link %q, %q did not create hard link", to, from)
317 func TestSymLink(t *testing.T) {
318 // Symlinks are not supported under windows.
319 if syscall.OS == "windows" {
322 from, to := "symlinktestfrom", "symlinktestto"
323 Remove(from) // Just in case.
324 file, err := Create(to)
326 t.Fatalf("open %q failed: %v", to, err)
329 if err = file.Close(); err != nil {
330 t.Errorf("close %q failed: %v", to, err)
332 err = Symlink(to, from)
334 t.Fatalf("symlink %q, %q failed: %v", to, from, err)
337 tostat, err := Stat(to)
339 t.Fatalf("stat %q failed: %v", to, err)
341 if tostat.FollowedSymlink {
342 t.Fatalf("stat %q claims to have followed a symlink", to)
344 fromstat, err := Stat(from)
346 t.Fatalf("stat %q failed: %v", from, err)
348 if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
349 t.Errorf("symlink %q, %q did not create symlink", to, from)
351 fromstat, err = Lstat(from)
353 t.Fatalf("lstat %q failed: %v", from, err)
355 if !fromstat.IsSymlink() {
356 t.Fatalf("symlink %q, %q did not create symlink", to, from)
358 fromstat, err = Stat(from)
360 t.Fatalf("stat %q failed: %v", from, err)
362 if !fromstat.FollowedSymlink {
363 t.Fatalf("stat %q did not follow symlink", from)
365 s, err := Readlink(from)
367 t.Fatalf("readlink %q failed: %v", from, err)
370 t.Fatalf("after symlink %q != %q", s, to)
372 file, err = Open(from)
374 t.Fatalf("open %q failed: %v", from, err)
379 func TestLongSymlink(t *testing.T) {
380 // Symlinks are not supported under windows.
381 if syscall.OS == "windows" {
384 s := "0123456789abcdef"
385 // Long, but not too long: a common limit is 255.
386 s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
387 from := "longsymlinktestfrom"
388 Remove(from) // Just in case.
389 err := Symlink(s, from)
391 t.Fatalf("symlink %q, %q failed: %v", s, from, err)
394 r, err := Readlink(from)
396 t.Fatalf("readlink %q failed: %v", from, err)
399 t.Fatalf("after symlink %q != %q", r, s)
403 func TestRename(t *testing.T) {
404 from, to := "renamefrom", "renameto"
405 Remove(to) // Just in case.
406 file, err := Create(from)
408 t.Fatalf("open %q failed: %v", to, err)
410 if err = file.Close(); err != nil {
411 t.Errorf("close %q failed: %v", to, err)
413 err = Rename(from, to)
415 t.Fatalf("rename %q, %q failed: %v", to, from, err)
420 t.Errorf("stat %q failed: %v", to, err)
424 func exec(t *testing.T, dir, cmd string, args []string, expect string) {
427 t.Fatalf("Pipe: %v", err)
429 attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
430 p, err := StartProcess(cmd, args, attr)
432 t.Fatalf("StartProcess: %v", err)
440 if output != expect {
441 t.Errorf("exec %q returned %q wanted %q",
442 strings.Join(append([]string{cmd}, args...), " "), output, expect)
447 func TestStartProcess(t *testing.T) {
448 var dir, cmd, le string
450 if syscall.OS == "windows" {
452 cmd = Getenv("COMSPEC")
453 dir = Getenv("SystemRoot")
454 args = []string{"/c", "cd"}
461 cmddir, cmdbase := filepath.Split(cmd)
462 args = append([]string{cmdbase}, args...)
463 // Test absolute executable path.
464 exec(t, dir, cmd, args, dir+le)
465 // Test relative executable path.
466 exec(t, cmddir, cmdbase, args, filepath.Clean(cmddir)+le)
469 func checkMode(t *testing.T, path string, mode uint32) {
470 dir, err := Stat(path)
472 t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
474 if dir.Mode&0777 != mode {
475 t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
479 func TestChmod(t *testing.T) {
480 // Chmod is not supported under windows.
481 if syscall.OS == "windows" {
484 f := newFile("TestChmod", t)
485 defer Remove(f.Name())
488 if err := Chmod(f.Name(), 0456); err != nil {
489 t.Fatalf("chmod %s 0456: %s", f.Name(), err)
491 checkMode(t, f.Name(), 0456)
493 if err := f.Chmod(0123); err != nil {
494 t.Fatalf("chmod %s 0123: %s", f.Name(), err)
496 checkMode(t, f.Name(), 0123)
499 func checkUidGid(t *testing.T, path string, uid, gid int) {
500 dir, err := Stat(path)
502 t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
505 t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
508 t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
512 func TestChown(t *testing.T) {
513 // Chown is not supported under windows.
514 if syscall.OS == "windows" {
517 // Use TempDir() to make sure we're on a local file system,
518 // so that the group ids returned by Getgroups will be allowed
519 // on the file. On NFS, the Getgroups groups are
520 // basically useless.
521 f := newFile("TestChown", t)
522 defer Remove(f.Name())
526 t.Fatalf("stat %s: %s", f.Name(), err)
529 // Can't change uid unless root, but can try
530 // changing the group id. First try our current group.
533 if err = Chown(f.Name(), -1, gid); err != nil {
534 t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
536 checkUidGid(t, f.Name(), dir.Uid, gid)
538 // Then try all the auxiliary groups.
539 groups, err := Getgroups()
541 t.Fatalf("getgroups: %s", err)
543 t.Log("groups: ", groups)
544 for _, g := range groups {
545 if err = Chown(f.Name(), -1, g); err != nil {
546 t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
548 checkUidGid(t, f.Name(), dir.Uid, g)
550 // change back to gid to test fd.Chown
551 if err = f.Chown(-1, gid); err != nil {
552 t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
554 checkUidGid(t, f.Name(), dir.Uid, gid)
558 func checkSize(t *testing.T, f *File, size int64) {
561 t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
563 if dir.Size != size {
564 t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
568 func TestFTruncate(t *testing.T) {
569 f := newFile("TestFTruncate", t)
570 defer Remove(f.Name())
574 f.Write([]byte("hello, world\n"))
579 checkSize(t, f, 1024)
582 f.Write([]byte("surprise!"))
583 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
586 func TestTruncate(t *testing.T) {
587 f := newFile("TestTruncate", t)
588 defer Remove(f.Name())
592 f.Write([]byte("hello, world\n"))
594 Truncate(f.Name(), 10)
596 Truncate(f.Name(), 1024)
597 checkSize(t, f, 1024)
598 Truncate(f.Name(), 0)
600 f.Write([]byte("surprise!"))
601 checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
604 // Use TempDir() to make sure we're on a local file system,
605 // so that timings are not distorted by latency and caching.
606 // On NFS, timings can be off due to caching of meta-data on
607 // NFS servers (Issue 848).
608 func TestChtimes(t *testing.T) {
609 f := newFile("TestChtimes", t)
610 defer Remove(f.Name())
613 f.Write([]byte("hello, world\n"))
616 preStat, err := Stat(f.Name())
618 t.Fatalf("Stat %s: %s", f.Name(), err)
621 // Move access and modification time back a second
622 const OneSecond = 1e9 // in nanoseconds
623 err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
625 t.Fatalf("Chtimes %s: %s", f.Name(), err)
628 postStat, err := Stat(f.Name())
630 t.Fatalf("second Stat %s: %s", f.Name(), err)
633 if postStat.Atime_ns >= preStat.Atime_ns {
634 t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
639 if postStat.Mtime_ns >= preStat.Mtime_ns {
640 t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
646 func TestChdirAndGetwd(t *testing.T) {
647 // TODO(brainman): file.Chdir() is not implemented on windows.
648 if syscall.OS == "windows" {
653 t.Fatalf("Open .: %s", err)
655 // These are chosen carefully not to be symlinks on a Mac
656 // (unlike, say, /var, /etc, and /tmp).
657 dirs := []string{"/", "/usr/bin"}
658 for mode := 0; mode < 2; mode++ {
659 for _, d := range dirs {
665 t.Errorf("Open %s: %s", d, err)
674 // We changed the current directory and cannot go back.
675 // Don't let the tests continue; they'll scribble
676 // all over some other directory.
677 fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
682 t.Fatalf("Chdir %s: %s", d, err)
686 t.Fatalf("Getwd in %s: %s", d, err1)
690 t.Fatalf("Getwd returned %q want %q", pwd, d)
697 func TestTime(t *testing.T) {
698 // Just want to check that Time() is getting something.
699 // A common failure mode on Darwin is to get 0, 0,
700 // because it returns the time in registers instead of
701 // filling in the structure passed to the system call.
702 // Too bad the compiler doesn't know that
703 // 365.24*86400 is an integer.
704 sec, nsec, err := Time()
705 if sec < (2009-1970)*36524*864 {
706 t.Errorf("Time() = %d, %d, %s; not plausible", sec, nsec, err)
710 func TestSeek(t *testing.T) {
711 f := newFile("TestSeek", t)
712 defer Remove(f.Name())
715 const data = "hello, world\n"
716 io.WriteString(f, data)
724 {0, 1, int64(len(data))},
727 {0, 2, int64(len(data))},
729 {-1, 2, int64(len(data)) - 1},
730 {1 << 33, 0, 1 << 33},
731 {1 << 33, 2, 1<<33 + int64(len(data))},
733 for i, tt := range tests {
734 off, err := f.Seek(tt.in, tt.whence)
735 if off != tt.out || err != nil {
736 if e, ok := err.(*PathError); ok && e.Error == EINVAL && tt.out > 1<<32 {
737 // Reiserfs rejects the big seeks.
738 // http://code.google.com/p/go/issues/detail?id=91
741 t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
746 type openErrorTest struct {
752 var openErrorTests = []openErrorTest{
754 sfdir + "/no-such-file",
764 sfdir + "/" + sfname + "/no-such-file",
770 func TestOpenError(t *testing.T) {
771 for _, tt := range openErrorTests {
772 f, err := OpenFile(tt.path, tt.mode, 0)
774 t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
778 perr, ok := err.(*PathError)
780 t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
782 if perr.Error != tt.error {
783 t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
788 func run(t *testing.T, cmd []string) string {
789 // Run /bin/hostname and collect output.
794 p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
805 if n := len(output); n > 0 && output[n-1] == '\n' {
806 output = output[0 : n-1]
809 t.Fatalf("%v produced no output", cmd)
816 func TestHostname(t *testing.T) {
817 // There is no other way to fetch hostname on windows, but via winapi.
818 if syscall.OS == "windows" {
821 // Check internal Hostname() against the output of /bin/hostname.
822 // Allow that the internal Hostname returns a Fully Qualified Domain Name
823 // and the /bin/hostname only returns the first component
824 hostname, err := Hostname()
828 want := run(t, []string{"/bin/hostname"})
829 if hostname != want {
830 i := strings.Index(hostname, ".")
831 if i < 0 || hostname[0:i] != want {
832 t.Errorf("Hostname() = %q, want %q", hostname, want)
837 func TestReadAt(t *testing.T) {
838 f := newFile("TestReadAt", t)
839 defer Remove(f.Name())
842 const data = "hello, world\n"
843 io.WriteString(f, data)
846 n, err := f.ReadAt(b, 7)
847 if err != nil || n != len(b) {
848 t.Fatalf("ReadAt 7: %d, %r", n, err)
850 if string(b) != "world" {
851 t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
855 func TestWriteAt(t *testing.T) {
856 f := newFile("TestWriteAt", t)
857 defer Remove(f.Name())
860 const data = "hello, world\n"
861 io.WriteString(f, data)
863 n, err := f.WriteAt([]byte("WORLD"), 7)
864 if err != nil || n != 5 {
865 t.Fatalf("WriteAt 7: %d, %v", n, err)
868 b, err := ioutil.ReadFile(f.Name())
870 t.Fatalf("ReadFile %s: %v", f.Name(), err)
872 if string(b) != "hello, WORLD\n" {
873 t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
877 func writeFile(t *testing.T, fname string, flag int, text string) string {
878 f, err := OpenFile(fname, flag, 0666)
880 t.Fatalf("Open: %v", err)
882 n, err := io.WriteString(f, text)
884 t.Fatalf("WriteString: %d, %v", n, err)
887 data, err := ioutil.ReadFile(fname)
889 t.Fatalf("ReadFile: %v", err)
894 func TestAppend(t *testing.T) {
895 const f = "append.txt"
897 s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
899 t.Fatalf("writeFile: have %q want %q", s, "new")
901 s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
902 if s != "new|append" {
903 t.Fatalf("writeFile: have %q want %q", s, "new|append")
905 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
906 if s != "new|append|append" {
907 t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
911 t.Fatalf("Remove: %v", err)
913 s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
914 if s != "new&append" {
915 t.Fatalf("writeFile: have %q want %q", s, "new&append")
919 func TestStatDirWithTrailingSlash(t *testing.T) {
920 // Create new dir, in _test so it will get
921 // cleaned up by make if not by us.
922 path := "_test/_TestStatDirWithSlash_"
923 err := MkdirAll(path, 0777)
925 t.Fatalf("MkdirAll %q: %s", path, err)
927 defer RemoveAll(path)
929 // Stat of path should succeed.
932 t.Fatal("stat failed:", err)
935 // Stat of path+"/" should succeed too.
936 _, err = Stat(path + "/")
938 t.Fatal("stat failed:", err)