github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/os/os_test.go (about)

     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.
     4  
     5  package os_test
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	. "os"
    14  	"path/filepath"
    15  	"runtime"
    16  	"strings"
    17  	"syscall"
    18  	"testing"
    19  	"time"
    20  )
    21  
    22  var dot = []string{
    23  	"dir_unix.go",
    24  	"env.go",
    25  	"error.go",
    26  	"file.go",
    27  	"os_test.go",
    28  	"types.go",
    29  	"stat_darwin.go",
    30  	"stat_linux.go",
    31  }
    32  
    33  type sysDir struct {
    34  	name  string
    35  	files []string
    36  }
    37  
    38  var sysdir = func() (sd *sysDir) {
    39  	switch runtime.GOOS {
    40  	case "windows":
    41  		sd = &sysDir{
    42  			Getenv("SystemRoot") + "\\system32\\drivers\\etc",
    43  			[]string{
    44  				"networks",
    45  				"protocol",
    46  				"services",
    47  			},
    48  		}
    49  	case "plan9":
    50  		sd = &sysDir{
    51  			"/lib/ndb",
    52  			[]string{
    53  				"common",
    54  				"local",
    55  			},
    56  		}
    57  	default:
    58  		sd = &sysDir{
    59  			"/etc",
    60  			[]string{
    61  				"group",
    62  				"hosts",
    63  				"passwd",
    64  			},
    65  		}
    66  	}
    67  	return
    68  }()
    69  
    70  func size(name string, t *testing.T) int64 {
    71  	file, err := Open(name)
    72  	if err != nil {
    73  		t.Fatal("open failed:", err)
    74  	}
    75  	defer file.Close()
    76  	var buf [100]byte
    77  	len := 0
    78  	for {
    79  		n, e := file.Read(buf[0:])
    80  		len += n
    81  		if e == io.EOF {
    82  			break
    83  		}
    84  		if e != nil {
    85  			t.Fatal("read failed:", err)
    86  		}
    87  	}
    88  	return int64(len)
    89  }
    90  
    91  func equal(name1, name2 string) (r bool) {
    92  	switch runtime.GOOS {
    93  	case "windows":
    94  		r = strings.ToLower(name1) == strings.ToLower(name2)
    95  	default:
    96  		r = name1 == name2
    97  	}
    98  	return
    99  }
   100  
   101  func newFile(testName string, t *testing.T) (f *File) {
   102  	// Use a local file system, not NFS.
   103  	// On Unix, override $TMPDIR in case the user
   104  	// has it set to an NFS-mounted directory.
   105  	dir := ""
   106  	if runtime.GOOS != "windows" {
   107  		dir = "/tmp"
   108  	}
   109  	f, err := ioutil.TempFile(dir, "_Go_"+testName)
   110  	if err != nil {
   111  		t.Fatalf("open %s: %s", testName, err)
   112  	}
   113  	return
   114  }
   115  
   116  var sfdir = sysdir.name
   117  var sfname = sysdir.files[0]
   118  
   119  func TestStat(t *testing.T) {
   120  	path := sfdir + "/" + sfname
   121  	dir, err := Stat(path)
   122  	if err != nil {
   123  		t.Fatal("stat failed:", err)
   124  	}
   125  	if !equal(sfname, dir.Name()) {
   126  		t.Error("name should be ", sfname, "; is", dir.Name())
   127  	}
   128  	filesize := size(path, t)
   129  	if dir.Size() != filesize {
   130  		t.Error("size should be", filesize, "; is", dir.Size())
   131  	}
   132  }
   133  
   134  func TestFstat(t *testing.T) {
   135  	path := sfdir + "/" + sfname
   136  	file, err1 := Open(path)
   137  	if err1 != nil {
   138  		t.Fatal("open failed:", err1)
   139  	}
   140  	defer file.Close()
   141  	dir, err2 := file.Stat()
   142  	if err2 != nil {
   143  		t.Fatal("fstat failed:", err2)
   144  	}
   145  	if !equal(sfname, dir.Name()) {
   146  		t.Error("name should be ", sfname, "; is", dir.Name())
   147  	}
   148  	filesize := size(path, t)
   149  	if dir.Size() != filesize {
   150  		t.Error("size should be", filesize, "; is", dir.Size())
   151  	}
   152  }
   153  
   154  func TestLstat(t *testing.T) {
   155  	path := sfdir + "/" + sfname
   156  	dir, err := Lstat(path)
   157  	if err != nil {
   158  		t.Fatal("lstat failed:", err)
   159  	}
   160  	if !equal(sfname, dir.Name()) {
   161  		t.Error("name should be ", sfname, "; is", dir.Name())
   162  	}
   163  	filesize := size(path, t)
   164  	if dir.Size() != filesize {
   165  		t.Error("size should be", filesize, "; is", dir.Size())
   166  	}
   167  }
   168  
   169  // Read with length 0 should not return EOF.
   170  func TestRead0(t *testing.T) {
   171  	path := sfdir + "/" + sfname
   172  	f, err := Open(path)
   173  	if err != nil {
   174  		t.Fatal("open failed:", err)
   175  	}
   176  	defer f.Close()
   177  
   178  	b := make([]byte, 0)
   179  	n, err := f.Read(b)
   180  	if n != 0 || err != nil {
   181  		t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
   182  	}
   183  	b = make([]byte, 100)
   184  	n, err = f.Read(b)
   185  	if n <= 0 || err != nil {
   186  		t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
   187  	}
   188  }
   189  
   190  func testReaddirnames(dir string, contents []string, t *testing.T) {
   191  	file, err := Open(dir)
   192  	if err != nil {
   193  		t.Fatalf("open %q failed: %v", dir, err)
   194  	}
   195  	defer file.Close()
   196  	s, err2 := file.Readdirnames(-1)
   197  	if err2 != nil {
   198  		t.Fatalf("readdirnames %q failed: %v", dir, err2)
   199  	}
   200  	for _, m := range contents {
   201  		found := false
   202  		for _, n := range s {
   203  			if n == "." || n == ".." {
   204  				t.Errorf("got %s in directory", n)
   205  			}
   206  			if equal(m, n) {
   207  				if found {
   208  					t.Error("present twice:", m)
   209  				}
   210  				found = true
   211  			}
   212  		}
   213  		if !found {
   214  			t.Error("could not find", m)
   215  		}
   216  	}
   217  }
   218  
   219  func testReaddir(dir string, contents []string, t *testing.T) {
   220  	file, err := Open(dir)
   221  	if err != nil {
   222  		t.Fatalf("open %q failed: %v", dir, err)
   223  	}
   224  	defer file.Close()
   225  	s, err2 := file.Readdir(-1)
   226  	if err2 != nil {
   227  		t.Fatalf("readdir %q failed: %v", dir, err2)
   228  	}
   229  	for _, m := range contents {
   230  		found := false
   231  		for _, n := range s {
   232  			if equal(m, n.Name()) {
   233  				if found {
   234  					t.Error("present twice:", m)
   235  				}
   236  				found = true
   237  			}
   238  		}
   239  		if !found {
   240  			t.Error("could not find", m)
   241  		}
   242  	}
   243  }
   244  
   245  func TestReaddirnames(t *testing.T) {
   246  	testReaddirnames(".", dot, t)
   247  	testReaddirnames(sysdir.name, sysdir.files, t)
   248  }
   249  
   250  func TestReaddir(t *testing.T) {
   251  	testReaddir(".", dot, t)
   252  	testReaddir(sysdir.name, sysdir.files, t)
   253  }
   254  
   255  // Read the directory one entry at a time.
   256  func smallReaddirnames(file *File, length int, t *testing.T) []string {
   257  	names := make([]string, length)
   258  	count := 0
   259  	for {
   260  		d, err := file.Readdirnames(1)
   261  		if err == io.EOF {
   262  			break
   263  		}
   264  		if err != nil {
   265  			t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
   266  		}
   267  		if len(d) == 0 {
   268  			t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
   269  		}
   270  		names[count] = d[0]
   271  		count++
   272  	}
   273  	return names[0:count]
   274  }
   275  
   276  // Check that reading a directory one entry at a time gives the same result
   277  // as reading it all at once.
   278  func TestReaddirnamesOneAtATime(t *testing.T) {
   279  	// big directory that doesn't change often.
   280  	dir := "/usr/bin"
   281  	switch runtime.GOOS {
   282  	case "windows":
   283  		dir = Getenv("SystemRoot") + "\\system32"
   284  	case "plan9":
   285  		dir = "/bin"
   286  	}
   287  	file, err := Open(dir)
   288  	if err != nil {
   289  		t.Fatalf("open %q failed: %v", dir, err)
   290  	}
   291  	defer file.Close()
   292  	all, err1 := file.Readdirnames(-1)
   293  	if err1 != nil {
   294  		t.Fatalf("readdirnames %q failed: %v", dir, err1)
   295  	}
   296  	file1, err2 := Open(dir)
   297  	if err2 != nil {
   298  		t.Fatalf("open %q failed: %v", dir, err2)
   299  	}
   300  	small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
   301  	if len(small) < len(all) {
   302  		t.Fatalf("len(small) is %d, less than %d", len(small), len(all))
   303  	}
   304  	for i, n := range all {
   305  		if small[i] != n {
   306  			t.Errorf("small read %q mismatch: %v", small[i], n)
   307  		}
   308  	}
   309  }
   310  
   311  func TestReaddirNValues(t *testing.T) {
   312  	if testing.Short() {
   313  		t.Skip("test.short; skipping")
   314  	}
   315  	dir, err := ioutil.TempDir("", "")
   316  	if err != nil {
   317  		t.Fatalf("TempDir: %v", err)
   318  	}
   319  	defer RemoveAll(dir)
   320  	for i := 1; i <= 105; i++ {
   321  		f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
   322  		if err != nil {
   323  			t.Fatalf("Create: %v", err)
   324  		}
   325  		f.Write([]byte(strings.Repeat("X", i)))
   326  		f.Close()
   327  	}
   328  
   329  	var d *File
   330  	openDir := func() {
   331  		var err error
   332  		d, err = Open(dir)
   333  		if err != nil {
   334  			t.Fatalf("Open directory: %v", err)
   335  		}
   336  	}
   337  
   338  	readDirExpect := func(n, want int, wantErr error) {
   339  		fi, err := d.Readdir(n)
   340  		if err != wantErr {
   341  			t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
   342  		}
   343  		if g, e := len(fi), want; g != e {
   344  			t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
   345  		}
   346  	}
   347  
   348  	readDirNamesExpect := func(n, want int, wantErr error) {
   349  		fi, err := d.Readdirnames(n)
   350  		if err != wantErr {
   351  			t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
   352  		}
   353  		if g, e := len(fi), want; g != e {
   354  			t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
   355  		}
   356  	}
   357  
   358  	for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} {
   359  		// Test the slurp case
   360  		openDir()
   361  		fn(0, 105, nil)
   362  		fn(0, 0, nil)
   363  		d.Close()
   364  
   365  		// Slurp with -1 instead
   366  		openDir()
   367  		fn(-1, 105, nil)
   368  		fn(-2, 0, nil)
   369  		fn(0, 0, nil)
   370  		d.Close()
   371  
   372  		// Test the bounded case
   373  		openDir()
   374  		fn(1, 1, nil)
   375  		fn(2, 2, nil)
   376  		fn(105, 102, nil) // and tests buffer >100 case
   377  		fn(3, 0, io.EOF)
   378  		d.Close()
   379  	}
   380  }
   381  
   382  func TestHardLink(t *testing.T) {
   383  	// Hardlinks are not supported under windows or Plan 9.
   384  	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   385  		return
   386  	}
   387  	from, to := "hardlinktestfrom", "hardlinktestto"
   388  	Remove(from) // Just in case.
   389  	file, err := Create(to)
   390  	if err != nil {
   391  		t.Fatalf("open %q failed: %v", to, err)
   392  	}
   393  	defer Remove(to)
   394  	if err = file.Close(); err != nil {
   395  		t.Errorf("close %q failed: %v", to, err)
   396  	}
   397  	err = Link(to, from)
   398  	if err != nil {
   399  		t.Fatalf("link %q, %q failed: %v", to, from, err)
   400  	}
   401  	defer Remove(from)
   402  	tostat, err := Stat(to)
   403  	if err != nil {
   404  		t.Fatalf("stat %q failed: %v", to, err)
   405  	}
   406  	fromstat, err := Stat(from)
   407  	if err != nil {
   408  		t.Fatalf("stat %q failed: %v", from, err)
   409  	}
   410  	if !SameFile(tostat, fromstat) {
   411  		t.Errorf("link %q, %q did not create hard link", to, from)
   412  	}
   413  }
   414  
   415  func TestSymLink(t *testing.T) {
   416  	// Symlinks are not supported under windows or Plan 9.
   417  	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   418  		return
   419  	}
   420  	from, to := "symlinktestfrom", "symlinktestto"
   421  	Remove(from) // Just in case.
   422  	file, err := Create(to)
   423  	if err != nil {
   424  		t.Fatalf("open %q failed: %v", to, err)
   425  	}
   426  	defer Remove(to)
   427  	if err = file.Close(); err != nil {
   428  		t.Errorf("close %q failed: %v", to, err)
   429  	}
   430  	err = Symlink(to, from)
   431  	if err != nil {
   432  		t.Fatalf("symlink %q, %q failed: %v", to, from, err)
   433  	}
   434  	defer Remove(from)
   435  	tostat, err := Lstat(to)
   436  	if err != nil {
   437  		t.Fatalf("stat %q failed: %v", to, err)
   438  	}
   439  	if tostat.Mode()&ModeSymlink != 0 {
   440  		t.Fatalf("stat %q claims to have found a symlink", to)
   441  	}
   442  	fromstat, err := Stat(from)
   443  	if err != nil {
   444  		t.Fatalf("stat %q failed: %v", from, err)
   445  	}
   446  	if !SameFile(tostat, fromstat) {
   447  		t.Errorf("symlink %q, %q did not create symlink", to, from)
   448  	}
   449  	fromstat, err = Lstat(from)
   450  	if err != nil {
   451  		t.Fatalf("lstat %q failed: %v", from, err)
   452  	}
   453  	if fromstat.Mode()&ModeSymlink == 0 {
   454  		t.Fatalf("symlink %q, %q did not create symlink", to, from)
   455  	}
   456  	fromstat, err = Stat(from)
   457  	if err != nil {
   458  		t.Fatalf("stat %q failed: %v", from, err)
   459  	}
   460  	if fromstat.Mode()&ModeSymlink != 0 {
   461  		t.Fatalf("stat %q did not follow symlink", from)
   462  	}
   463  	s, err := Readlink(from)
   464  	if err != nil {
   465  		t.Fatalf("readlink %q failed: %v", from, err)
   466  	}
   467  	if s != to {
   468  		t.Fatalf("after symlink %q != %q", s, to)
   469  	}
   470  	file, err = Open(from)
   471  	if err != nil {
   472  		t.Fatalf("open %q failed: %v", from, err)
   473  	}
   474  	file.Close()
   475  }
   476  
   477  func TestLongSymlink(t *testing.T) {
   478  	// Symlinks are not supported under windows or Plan 9.
   479  	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   480  		return
   481  	}
   482  	s := "0123456789abcdef"
   483  	// Long, but not too long: a common limit is 255.
   484  	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
   485  	from := "longsymlinktestfrom"
   486  	Remove(from) // Just in case.
   487  	err := Symlink(s, from)
   488  	if err != nil {
   489  		t.Fatalf("symlink %q, %q failed: %v", s, from, err)
   490  	}
   491  	defer Remove(from)
   492  	r, err := Readlink(from)
   493  	if err != nil {
   494  		t.Fatalf("readlink %q failed: %v", from, err)
   495  	}
   496  	if r != s {
   497  		t.Fatalf("after symlink %q != %q", r, s)
   498  	}
   499  }
   500  
   501  func TestRename(t *testing.T) {
   502  	from, to := "renamefrom", "renameto"
   503  	Remove(to) // Just in case.
   504  	file, err := Create(from)
   505  	if err != nil {
   506  		t.Fatalf("open %q failed: %v", to, err)
   507  	}
   508  	if err = file.Close(); err != nil {
   509  		t.Errorf("close %q failed: %v", to, err)
   510  	}
   511  	err = Rename(from, to)
   512  	if err != nil {
   513  		t.Fatalf("rename %q, %q failed: %v", to, from, err)
   514  	}
   515  	defer Remove(to)
   516  	_, err = Stat(to)
   517  	if err != nil {
   518  		t.Errorf("stat %q failed: %v", to, err)
   519  	}
   520  }
   521  
   522  func exec(t *testing.T, dir, cmd string, args []string, expect string) {
   523  	r, w, err := Pipe()
   524  	if err != nil {
   525  		t.Fatalf("Pipe: %v", err)
   526  	}
   527  	attr := &ProcAttr{Dir: dir, Files: []*File{nil, w, Stderr}}
   528  	p, err := StartProcess(cmd, args, attr)
   529  	if err != nil {
   530  		t.Fatalf("StartProcess: %v", err)
   531  	}
   532  	w.Close()
   533  
   534  	var b bytes.Buffer
   535  	io.Copy(&b, r)
   536  	output := b.String()
   537  
   538  	fi1, _ := Stat(strings.TrimSpace(output))
   539  	fi2, _ := Stat(expect)
   540  	if !SameFile(fi1, fi2) {
   541  		t.Errorf("exec %q returned %q wanted %q",
   542  			strings.Join(append([]string{cmd}, args...), " "), output, expect)
   543  	}
   544  	p.Wait()
   545  }
   546  
   547  func TestStartProcess(t *testing.T) {
   548  	var dir, cmd string
   549  	var args []string
   550  	if runtime.GOOS == "windows" {
   551  		cmd = Getenv("COMSPEC")
   552  		dir = Getenv("SystemRoot")
   553  		args = []string{"/c", "cd"}
   554  	} else {
   555  		cmd = "/bin/pwd"
   556  		dir = "/"
   557  		args = []string{}
   558  	}
   559  	cmddir, cmdbase := filepath.Split(cmd)
   560  	args = append([]string{cmdbase}, args...)
   561  	// Test absolute executable path.
   562  	exec(t, dir, cmd, args, dir)
   563  	// Test relative executable path.
   564  	exec(t, cmddir, cmdbase, args, cmddir)
   565  }
   566  
   567  func checkMode(t *testing.T, path string, mode FileMode) {
   568  	dir, err := Stat(path)
   569  	if err != nil {
   570  		t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
   571  	}
   572  	if dir.Mode()&0777 != mode {
   573  		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
   574  	}
   575  }
   576  
   577  func TestChmod(t *testing.T) {
   578  	// Chmod is not supported under windows.
   579  	if runtime.GOOS == "windows" {
   580  		return
   581  	}
   582  	f := newFile("TestChmod", t)
   583  	defer Remove(f.Name())
   584  	defer f.Close()
   585  
   586  	if err := Chmod(f.Name(), 0456); err != nil {
   587  		t.Fatalf("chmod %s 0456: %s", f.Name(), err)
   588  	}
   589  	checkMode(t, f.Name(), 0456)
   590  
   591  	if err := f.Chmod(0123); err != nil {
   592  		t.Fatalf("chmod %s 0123: %s", f.Name(), err)
   593  	}
   594  	checkMode(t, f.Name(), 0123)
   595  }
   596  
   597  func checkSize(t *testing.T, f *File, size int64) {
   598  	dir, err := f.Stat()
   599  	if err != nil {
   600  		t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
   601  	}
   602  	if dir.Size() != size {
   603  		t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
   604  	}
   605  }
   606  
   607  func TestFTruncate(t *testing.T) {
   608  	f := newFile("TestFTruncate", t)
   609  	defer Remove(f.Name())
   610  	defer f.Close()
   611  
   612  	checkSize(t, f, 0)
   613  	f.Write([]byte("hello, world\n"))
   614  	checkSize(t, f, 13)
   615  	f.Truncate(10)
   616  	checkSize(t, f, 10)
   617  	f.Truncate(1024)
   618  	checkSize(t, f, 1024)
   619  	f.Truncate(0)
   620  	checkSize(t, f, 0)
   621  	f.Write([]byte("surprise!"))
   622  	checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
   623  }
   624  
   625  func TestTruncate(t *testing.T) {
   626  	f := newFile("TestTruncate", t)
   627  	defer Remove(f.Name())
   628  	defer f.Close()
   629  
   630  	checkSize(t, f, 0)
   631  	f.Write([]byte("hello, world\n"))
   632  	checkSize(t, f, 13)
   633  	Truncate(f.Name(), 10)
   634  	checkSize(t, f, 10)
   635  	Truncate(f.Name(), 1024)
   636  	checkSize(t, f, 1024)
   637  	Truncate(f.Name(), 0)
   638  	checkSize(t, f, 0)
   639  	f.Write([]byte("surprise!"))
   640  	checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
   641  }
   642  
   643  // Use TempDir() to make sure we're on a local file system,
   644  // so that timings are not distorted by latency and caching.
   645  // On NFS, timings can be off due to caching of meta-data on
   646  // NFS servers (Issue 848).
   647  func TestChtimes(t *testing.T) {
   648  	f := newFile("TestChtimes", t)
   649  	defer Remove(f.Name())
   650  	defer f.Close()
   651  
   652  	f.Write([]byte("hello, world\n"))
   653  	f.Close()
   654  
   655  	st, err := Stat(f.Name())
   656  	if err != nil {
   657  		t.Fatalf("Stat %s: %s", f.Name(), err)
   658  	}
   659  	preStat := st
   660  
   661  	// Move access and modification time back a second
   662  	at := Atime(preStat)
   663  	mt := preStat.ModTime()
   664  	err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
   665  	if err != nil {
   666  		t.Fatalf("Chtimes %s: %s", f.Name(), err)
   667  	}
   668  
   669  	st, err = Stat(f.Name())
   670  	if err != nil {
   671  		t.Fatalf("second Stat %s: %s", f.Name(), err)
   672  	}
   673  	postStat := st
   674  
   675  	/* Plan 9:
   676  		Mtime is the time of the last change of content.  Similarly, atime is set whenever the
   677  	    contents are accessed; also, it is set whenever mtime is set.
   678  	*/
   679  	pat := Atime(postStat)
   680  	pmt := postStat.ModTime()
   681  	if !pat.Before(at) && runtime.GOOS != "plan9" {
   682  		t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
   683  	}
   684  
   685  	if !pmt.Before(mt) {
   686  		t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
   687  	}
   688  }
   689  
   690  func TestChdirAndGetwd(t *testing.T) {
   691  	// TODO(brainman): file.Chdir() is not implemented on windows.
   692  	if runtime.GOOS == "windows" {
   693  		return
   694  	}
   695  	fd, err := Open(".")
   696  	if err != nil {
   697  		t.Fatalf("Open .: %s", err)
   698  	}
   699  	// These are chosen carefully not to be symlinks on a Mac
   700  	// (unlike, say, /var, /etc, and /tmp).
   701  	dirs := []string{"/", "/usr/bin"}
   702  	// /usr/bin does not usually exist on Plan 9.
   703  	if runtime.GOOS == "plan9" {
   704  		dirs = []string{"/", "/usr"}
   705  	}
   706  	for mode := 0; mode < 2; mode++ {
   707  		for _, d := range dirs {
   708  			if mode == 0 {
   709  				err = Chdir(d)
   710  			} else {
   711  				fd1, err := Open(d)
   712  				if err != nil {
   713  					t.Errorf("Open %s: %s", d, err)
   714  					continue
   715  				}
   716  				err = fd1.Chdir()
   717  				fd1.Close()
   718  			}
   719  			pwd, err1 := Getwd()
   720  			err2 := fd.Chdir()
   721  			if err2 != nil {
   722  				// We changed the current directory and cannot go back.
   723  				// Don't let the tests continue; they'll scribble
   724  				// all over some other directory.
   725  				fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
   726  				Exit(1)
   727  			}
   728  			if err != nil {
   729  				fd.Close()
   730  				t.Fatalf("Chdir %s: %s", d, err)
   731  			}
   732  			if err1 != nil {
   733  				fd.Close()
   734  				t.Fatalf("Getwd in %s: %s", d, err1)
   735  			}
   736  			if pwd != d {
   737  				fd.Close()
   738  				t.Fatalf("Getwd returned %q want %q", pwd, d)
   739  			}
   740  		}
   741  	}
   742  	fd.Close()
   743  }
   744  
   745  func TestSeek(t *testing.T) {
   746  	f := newFile("TestSeek", t)
   747  	defer Remove(f.Name())
   748  	defer f.Close()
   749  
   750  	const data = "hello, world\n"
   751  	io.WriteString(f, data)
   752  
   753  	type test struct {
   754  		in     int64
   755  		whence int
   756  		out    int64
   757  	}
   758  	var tests = []test{
   759  		{0, 1, int64(len(data))},
   760  		{0, 0, 0},
   761  		{5, 0, 5},
   762  		{0, 2, int64(len(data))},
   763  		{0, 0, 0},
   764  		{-1, 2, int64(len(data)) - 1},
   765  		{1 << 33, 0, 1 << 33},
   766  		{1 << 33, 2, 1<<33 + int64(len(data))},
   767  	}
   768  	for i, tt := range tests {
   769  		off, err := f.Seek(tt.in, tt.whence)
   770  		if off != tt.out || err != nil {
   771  			if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
   772  				// Reiserfs rejects the big seeks.
   773  				// http://code.google.com/p/go/issues/detail?id=91
   774  				break
   775  			}
   776  			t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
   777  		}
   778  	}
   779  }
   780  
   781  type openErrorTest struct {
   782  	path  string
   783  	mode  int
   784  	error error
   785  }
   786  
   787  var openErrorTests = []openErrorTest{
   788  	{
   789  		sfdir + "/no-such-file",
   790  		O_RDONLY,
   791  		syscall.ENOENT,
   792  	},
   793  	{
   794  		sfdir,
   795  		O_WRONLY,
   796  		syscall.EISDIR,
   797  	},
   798  	{
   799  		sfdir + "/" + sfname + "/no-such-file",
   800  		O_WRONLY,
   801  		syscall.ENOTDIR,
   802  	},
   803  }
   804  
   805  func TestOpenError(t *testing.T) {
   806  	for _, tt := range openErrorTests {
   807  		f, err := OpenFile(tt.path, tt.mode, 0)
   808  		if err == nil {
   809  			t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
   810  			f.Close()
   811  			continue
   812  		}
   813  		perr, ok := err.(*PathError)
   814  		if !ok {
   815  			t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
   816  		}
   817  		if perr.Err != tt.error {
   818  			if runtime.GOOS == "plan9" {
   819  				syscallErrStr := perr.Err.Error()
   820  				expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
   821  				if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
   822  					t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
   823  				}
   824  			} else {
   825  				t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
   826  			}
   827  		}
   828  	}
   829  }
   830  
   831  func TestOpenNoName(t *testing.T) {
   832  	f, err := Open("")
   833  	if err == nil {
   834  		t.Fatal(`Open("") succeeded`)
   835  		f.Close()
   836  	}
   837  }
   838  
   839  func run(t *testing.T, cmd []string) string {
   840  	// Run /bin/hostname and collect output.
   841  	r, w, err := Pipe()
   842  	if err != nil {
   843  		t.Fatal(err)
   844  	}
   845  	p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
   846  	if err != nil {
   847  		t.Fatal(err)
   848  	}
   849  	w.Close()
   850  
   851  	var b bytes.Buffer
   852  	io.Copy(&b, r)
   853  	_, err = p.Wait()
   854  	if err != nil {
   855  		t.Fatalf("run hostname Wait: %v", err)
   856  	}
   857  	err = p.Kill()
   858  	if err == nil {
   859  		t.Errorf("expected an error from Kill running 'hostname'")
   860  	}
   861  	output := b.String()
   862  	if n := len(output); n > 0 && output[n-1] == '\n' {
   863  		output = output[0 : n-1]
   864  	}
   865  	if output == "" {
   866  		t.Fatalf("%v produced no output", cmd)
   867  	}
   868  
   869  	return output
   870  }
   871  
   872  func TestHostname(t *testing.T) {
   873  	// There is no other way to fetch hostname on windows, but via winapi.
   874  	// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
   875  	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
   876  		return
   877  	}
   878  
   879  	// Check internal Hostname() against the output of /bin/hostname.
   880  	// Allow that the internal Hostname returns a Fully Qualified Domain Name
   881  	// and the /bin/hostname only returns the first component
   882  	hostname, err := Hostname()
   883  	if err != nil {
   884  		t.Fatalf("%v", err)
   885  	}
   886  	want := run(t, []string{"/bin/hostname"})
   887  	if hostname != want {
   888  		i := strings.Index(hostname, ".")
   889  		if i < 0 || hostname[0:i] != want {
   890  			t.Errorf("Hostname() = %q, want %q", hostname, want)
   891  		}
   892  	}
   893  }
   894  
   895  func TestReadAt(t *testing.T) {
   896  	f := newFile("TestReadAt", t)
   897  	defer Remove(f.Name())
   898  	defer f.Close()
   899  
   900  	const data = "hello, world\n"
   901  	io.WriteString(f, data)
   902  
   903  	b := make([]byte, 5)
   904  	n, err := f.ReadAt(b, 7)
   905  	if err != nil || n != len(b) {
   906  		t.Fatalf("ReadAt 7: %d, %v", n, err)
   907  	}
   908  	if string(b) != "world" {
   909  		t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
   910  	}
   911  }
   912  
   913  func TestWriteAt(t *testing.T) {
   914  	f := newFile("TestWriteAt", t)
   915  	defer Remove(f.Name())
   916  	defer f.Close()
   917  
   918  	const data = "hello, world\n"
   919  	io.WriteString(f, data)
   920  
   921  	n, err := f.WriteAt([]byte("WORLD"), 7)
   922  	if err != nil || n != 5 {
   923  		t.Fatalf("WriteAt 7: %d, %v", n, err)
   924  	}
   925  
   926  	b, err := ioutil.ReadFile(f.Name())
   927  	if err != nil {
   928  		t.Fatalf("ReadFile %s: %v", f.Name(), err)
   929  	}
   930  	if string(b) != "hello, WORLD\n" {
   931  		t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
   932  	}
   933  }
   934  
   935  func writeFile(t *testing.T, fname string, flag int, text string) string {
   936  	f, err := OpenFile(fname, flag, 0666)
   937  	if err != nil {
   938  		t.Fatalf("Open: %v", err)
   939  	}
   940  	n, err := io.WriteString(f, text)
   941  	if err != nil {
   942  		t.Fatalf("WriteString: %d, %v", n, err)
   943  	}
   944  	f.Close()
   945  	data, err := ioutil.ReadFile(fname)
   946  	if err != nil {
   947  		t.Fatalf("ReadFile: %v", err)
   948  	}
   949  	return string(data)
   950  }
   951  
   952  func TestAppend(t *testing.T) {
   953  	const f = "append.txt"
   954  	defer Remove(f)
   955  	s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
   956  	if s != "new" {
   957  		t.Fatalf("writeFile: have %q want %q", s, "new")
   958  	}
   959  	s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
   960  	if s != "new|append" {
   961  		t.Fatalf("writeFile: have %q want %q", s, "new|append")
   962  	}
   963  	s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "|append")
   964  	if s != "new|append|append" {
   965  		t.Fatalf("writeFile: have %q want %q", s, "new|append|append")
   966  	}
   967  	err := Remove(f)
   968  	if err != nil {
   969  		t.Fatalf("Remove: %v", err)
   970  	}
   971  	s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
   972  	if s != "new&append" {
   973  		t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
   974  	}
   975  	s = writeFile(t, f, O_CREATE|O_RDWR, "old")
   976  	if s != "old&append" {
   977  		t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
   978  	}
   979  	s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
   980  	if s != "new" {
   981  		t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
   982  	}
   983  }
   984  
   985  func TestStatDirWithTrailingSlash(t *testing.T) {
   986  	// Create new temporary directory and arrange to clean it up.
   987  	path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_")
   988  	if err != nil {
   989  		t.Fatalf("TempDir: %s", err)
   990  	}
   991  	defer RemoveAll(path)
   992  
   993  	// Stat of path should succeed.
   994  	_, err = Stat(path)
   995  	if err != nil {
   996  		t.Fatalf("stat %s failed: %s", path, err)
   997  	}
   998  
   999  	// Stat of path+"/" should succeed too.
  1000  	path += "/"
  1001  	_, err = Stat(path)
  1002  	if err != nil {
  1003  		t.Fatalf("stat %s failed: %s", path, err)
  1004  	}
  1005  }
  1006  
  1007  func TestNilProcessStateString(t *testing.T) {
  1008  	var ps *ProcessState
  1009  	s := ps.String()
  1010  	if s != "<nil>" {
  1011  		t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
  1012  	}
  1013  }
  1014  
  1015  func TestSameFile(t *testing.T) {
  1016  	fa, err := Create("a")
  1017  	if err != nil {
  1018  		t.Fatalf("Create(a): %v", err)
  1019  	}
  1020  	defer Remove(fa.Name())
  1021  	fa.Close()
  1022  	fb, err := Create("b")
  1023  	if err != nil {
  1024  		t.Fatalf("Create(b): %v", err)
  1025  	}
  1026  	defer Remove(fb.Name())
  1027  	fb.Close()
  1028  
  1029  	ia1, err := Stat("a")
  1030  	if err != nil {
  1031  		t.Fatalf("Stat(a): %v", err)
  1032  	}
  1033  	ia2, err := Stat("a")
  1034  	if err != nil {
  1035  		t.Fatalf("Stat(a): %v", err)
  1036  	}
  1037  	if !SameFile(ia1, ia2) {
  1038  		t.Errorf("files should be same")
  1039  	}
  1040  
  1041  	ib, err := Stat("b")
  1042  	if err != nil {
  1043  		t.Fatalf("Stat(b): %v", err)
  1044  	}
  1045  	if SameFile(ia1, ib) {
  1046  		t.Errorf("files should be different")
  1047  	}
  1048  }
  1049  
  1050  func TestDevNullFile(t *testing.T) {
  1051  	f, err := Open(DevNull)
  1052  	if err != nil {
  1053  		t.Fatalf("Open(%s): %v", DevNull, err)
  1054  	}
  1055  	defer f.Close()
  1056  	fi, err := f.Stat()
  1057  	if err != nil {
  1058  		t.Fatalf("Stat(%s): %v", DevNull, err)
  1059  	}
  1060  	name := filepath.Base(DevNull)
  1061  	if fi.Name() != name {
  1062  		t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
  1063  	}
  1064  	if fi.Size() != 0 {
  1065  		t.Fatalf("wrong file size have %d want 0", fi.Size())
  1066  	}
  1067  }
  1068  
  1069  var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
  1070  
  1071  func TestLargeWriteToConsole(t *testing.T) {
  1072  	if !*testLargeWrite {
  1073  		t.Skip("skipping console-flooding test; enable with -large_write")
  1074  	}
  1075  	b := make([]byte, 32000)
  1076  	for i := range b {
  1077  		b[i] = '.'
  1078  	}
  1079  	b[len(b)-1] = '\n'
  1080  	n, err := Stdout.Write(b)
  1081  	if err != nil {
  1082  		t.Fatalf("Write to os.Stdout failed: %v", err)
  1083  	}
  1084  	if n != len(b) {
  1085  		t.Errorf("Write to os.Stdout should return %d; got %d", len(b), n)
  1086  	}
  1087  	n, err = Stderr.Write(b)
  1088  	if err != nil {
  1089  		t.Fatalf("Write to os.Stderr failed: %v", err)
  1090  	}
  1091  	if n != len(b) {
  1092  		t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
  1093  	}
  1094  }
  1095  
  1096  func TestStatDirModeExec(t *testing.T) {
  1097  	const mode = 0111
  1098  
  1099  	path, err := ioutil.TempDir("", "go-build")
  1100  	if err != nil {
  1101  		t.Fatalf("Failed to create temp directory: %v", err)
  1102  	}
  1103  	defer RemoveAll(path)
  1104  
  1105  	if err := Chmod(path, 0777); err != nil {
  1106  		t.Fatalf("Chmod %q 0777: %v", path, err)
  1107  	}
  1108  
  1109  	dir, err := Stat(path)
  1110  	if err != nil {
  1111  		t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
  1112  	}
  1113  	if dir.Mode()&mode != mode {
  1114  		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode()&mode, mode)
  1115  	}
  1116  }