diff options
Diffstat (limited to 'llgo/third_party/gofrontend/libgo/go/os/os_test.go')
| -rw-r--r-- | llgo/third_party/gofrontend/libgo/go/os/os_test.go | 400 |
1 files changed, 313 insertions, 87 deletions
diff --git a/llgo/third_party/gofrontend/libgo/go/os/os_test.go b/llgo/third_party/gofrontend/libgo/go/os/os_test.go index 7a86efac218..78201f2c27e 100644 --- a/llgo/third_party/gofrontend/libgo/go/os/os_test.go +++ b/llgo/third_party/gofrontend/libgo/go/os/os_test.go @@ -9,6 +9,7 @@ import ( "errors" "flag" "fmt" + "internal/testenv" "io" "io/ioutil" . "os" @@ -21,7 +22,6 @@ import ( "sync" "syscall" "testing" - "text/template" "time" ) @@ -41,18 +41,33 @@ type sysDir struct { files []string } -var sysdir = func() (sd *sysDir) { +var sysdir = func() *sysDir { switch runtime.GOOS { case "android": - sd = &sysDir{ + return &sysDir{ "/system/etc", []string{ "audio_policy.conf", "system_fonts.xml", }, } + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + wd, err := syscall.Getwd() + if err != nil { + wd = err.Error() + } + return &sysDir{ + filepath.Join(wd, "..", ".."), + []string{ + "ResourceRules.plist", + "Info.plist", + }, + } + } case "windows": - sd = &sysDir{ + return &sysDir{ Getenv("SystemRoot") + "\\system32\\drivers\\etc", []string{ "networks", @@ -61,24 +76,22 @@ var sysdir = func() (sd *sysDir) { }, } case "plan9": - sd = &sysDir{ + return &sysDir{ "/lib/ndb", []string{ "common", "local", }, } - default: - sd = &sysDir{ - "/etc", - []string{ - "group", - "hosts", - "passwd", - }, - } } - return + return &sysDir{ + "/etc", + []string{ + "group", + "hosts", + "passwd", + }, + } }() func size(name string, t *testing.T) int64 { @@ -112,15 +125,22 @@ func equal(name1, name2 string) (r bool) { return } -func newFile(testName string, t *testing.T) (f *File) { - // Use a local file system, not NFS. - // On Unix, override $TMPDIR in case the user - // has it set to an NFS-mounted directory. - dir := "" - if runtime.GOOS != "android" && runtime.GOOS != "windows" { - dir = "/tmp" +// localTmp returns a local temporary directory not on NFS. +func localTmp() string { + switch runtime.GOOS { + case "android", "windows": + return TempDir() + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + return TempDir() + } } - f, err := ioutil.TempFile(dir, "_Go_"+testName) + return "/tmp" +} + +func newFile(testName string, t *testing.T) (f *File) { + f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) if err != nil { t.Fatalf("TempFile %s: %s", testName, err) } @@ -128,14 +148,7 @@ func newFile(testName string, t *testing.T) (f *File) { } func newDir(testName string, t *testing.T) (name string) { - // Use a local file system, not NFS. - // On Unix, override $TMPDIR in case the user - // has it set to an NFS-mounted directory. - dir := "" - if runtime.GOOS != "android" && runtime.GOOS != "windows" { - dir = "/tmp" - } - name, err := ioutil.TempDir(dir, "_Go_"+testName) + name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) if err != nil { t.Fatalf("TempDir %s: %s", testName, err) } @@ -310,6 +323,15 @@ func TestReaddirnamesOneAtATime(t *testing.T) { switch runtime.GOOS { case "android": dir = "/system/bin" + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + wd, err := Getwd() + if err != nil { + t.Fatal(err) + } + dir = wd + } case "plan9": dir = "/bin" case "windows": @@ -489,11 +511,35 @@ func TestReaddirStatFailures(t *testing.T) { } } +// Readdir on a regular file should fail. +func TestReaddirOfFile(t *testing.T) { + f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") + if err != nil { + t.Fatal(err) + } + defer Remove(f.Name()) + f.Write([]byte("foo")) + f.Close() + reg, err := Open(f.Name()) + if err != nil { + t.Fatal(err) + } + defer reg.Close() + + names, err := reg.Readdirnames(-1) + if err == nil { + t.Error("Readdirnames succeeded; want non-nil error") + } + if len(names) > 0 { + t.Errorf("unexpected dir names in regular file: %q", names) + } +} + func TestHardLink(t *testing.T) { - // Hardlinks are not supported under windows or Plan 9. if runtime.GOOS == "plan9" { - return + t.Skip("skipping on plan9, hardlinks not supported") } + defer chtmpdir(t)() from, to := "hardlinktestfrom", "hardlinktestto" Remove(from) // Just in case. file, err := Create(to) @@ -508,6 +554,14 @@ func TestHardLink(t *testing.T) { if err != nil { t.Fatalf("link %q, %q failed: %v", to, from, err) } + + none := "hardlinktestnone" + err = Link(none, none) + // Check the returned error is well-formed. + if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { + t.Errorf("link %q, %q failed to return a valid error", none, none) + } + defer Remove(from) tostat, err := Stat(to) if err != nil { @@ -522,6 +576,31 @@ func TestHardLink(t *testing.T) { } } +// chtmpdir changes the working directory to a new temporary directory and +// provides a cleanup function. Used when PWD is read-only. +func chtmpdir(t *testing.T) func() { + if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { + return func() {} // only needed on darwin/arm{,64} + } + oldwd, err := Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + RemoveAll(d) + } +} + func TestSymlink(t *testing.T) { switch runtime.GOOS { case "android", "nacl", "plan9": @@ -531,6 +610,7 @@ func TestSymlink(t *testing.T) { t.Skipf("skipping on %s", runtime.GOOS) } } + defer chtmpdir(t)() from, to := "symlinktestfrom", "symlinktestto" Remove(from) // Just in case. file, err := Create(to) @@ -597,6 +677,7 @@ func TestLongSymlink(t *testing.T) { t.Skipf("skipping on %s", runtime.GOOS) } } + defer chtmpdir(t)() s := "0123456789abcdef" // Long, but not too long: a common limit is 255. s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s @@ -617,14 +698,18 @@ func TestLongSymlink(t *testing.T) { } func TestRename(t *testing.T) { + defer chtmpdir(t)() from, to := "renamefrom", "renameto" - Remove(to) // Just in case. + // Ensure we are not testing the overwrite case here. + Remove(from) + Remove(to) + file, err := Create(from) if err != nil { - t.Fatalf("open %q failed: %v", to, err) + t.Fatalf("open %q failed: %v", from, err) } if err = file.Close(); err != nil { - t.Errorf("close %q failed: %v", to, err) + t.Errorf("close %q failed: %v", from, err) } err = Rename(from, to) if err != nil { @@ -637,6 +722,79 @@ func TestRename(t *testing.T) { } } +func TestRenameOverwriteDest(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9") + } + defer chtmpdir(t)() + from, to := "renamefrom", "renameto" + // Just in case. + Remove(from) + Remove(to) + + toData := []byte("to") + fromData := []byte("from") + + err := ioutil.WriteFile(to, toData, 0777) + if err != nil { + t.Fatalf("write file %q failed: %v", to, err) + } + + err = ioutil.WriteFile(from, fromData, 0777) + if err != nil { + t.Fatalf("write file %q failed: %v", from, err) + } + err = Rename(from, to) + if err != nil { + t.Fatalf("rename %q, %q failed: %v", to, from, err) + } + defer Remove(to) + + _, err = Stat(from) + if err == nil { + t.Errorf("from file %q still exists", from) + } + if err != nil && !IsNotExist(err) { + t.Fatalf("stat from: %v", err) + } + toFi, err := Stat(to) + if err != nil { + t.Fatalf("stat %q failed: %v", to, err) + } + if toFi.Size() != int64(len(fromData)) { + t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) + } +} + +func TestRenameFailed(t *testing.T) { + defer chtmpdir(t)() + from, to := "renamefrom", "renameto" + // Ensure we are not testing the overwrite case here. + Remove(from) + Remove(to) + + err := Rename(from, to) + switch err := err.(type) { + case *LinkError: + if err.Op != "rename" { + t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) + } + if err.Old != from { + t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) + } + if err.New != to { + t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) + } + case nil: + t.Errorf("rename %q, %q: expected error, got nil", from, to) + + // cleanup whatever was placed in "renameto" + Remove(to) + default: + t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) + } +} + func exec(t *testing.T, dir, cmd string, args []string, expect string) { r, w, err := Pipe() if err != nil { @@ -664,18 +822,18 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) { } func TestStartProcess(t *testing.T) { - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } + testenv.MustHaveExec(t) var dir, cmd string var args []string - if runtime.GOOS == "windows" { + switch runtime.GOOS { + case "android": + t.Skip("android doesn't have /bin/pwd") + case "windows": cmd = Getenv("COMSPEC") dir = Getenv("SystemRoot") args = []string{"/c", "cd"} - } else { + default: cmd = "/bin/pwd" dir = "/" args = []string{} @@ -847,6 +1005,19 @@ func TestChdirAndGetwd(t *testing.T) { dirs = []string{"/", "/system/bin"} case "plan9": dirs = []string{"/", "/usr"} + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + d1, err := ioutil.TempDir("", "d1") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + d2, err := ioutil.TempDir("", "d2") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + dirs = []string{d1, d2} + } } oldwd := Getenv("PWD") for mode := 0; mode < 2; mode++ { @@ -892,6 +1063,64 @@ func TestChdirAndGetwd(t *testing.T) { fd.Close() } +// Test that Chdir+Getwd is program-wide. +func TestProgWideChdir(t *testing.T) { + const N = 10 + c := make(chan bool) + cpwd := make(chan string) + for i := 0; i < N; i++ { + go func(i int) { + // Lock half the goroutines in their own operating system + // thread to exercise more scheduler possibilities. + if i%2 == 1 { + // On Plan 9, after calling LockOSThread, the goroutines + // run on different processes which don't share the working + // directory. This used to be an issue because Go expects + // the working directory to be program-wide. + // See issue 9428. + runtime.LockOSThread() + } + <-c + pwd, err := Getwd() + if err != nil { + t.Errorf("Getwd on goroutine %d: %v", i, err) + return + } + cpwd <- pwd + }(i) + } + oldwd, err := Getwd() + if err != nil { + t.Fatalf("Getwd: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + defer func() { + if err := Chdir(oldwd); err != nil { + t.Fatalf("Chdir: %v", err) + } + RemoveAll(d) + }() + if err := Chdir(d); err != nil { + t.Fatalf("Chdir: %v", err) + } + // OS X sets TMPDIR to a symbolic link. + // So we resolve our working directory again before the test. + d, err = Getwd() + if err != nil { + t.Fatalf("Getwd: %v", err) + } + close(c) + for i := 0; i < N; i++ { + pwd := <-cpwd + if pwd != d { + t.Errorf("Getwd returned %q; want %q", pwd, d) + } + } +} + func TestSeek(t *testing.T) { f := newFile("TestSeek", t) defer Remove(f.Name()) @@ -920,7 +1149,7 @@ func TestSeek(t *testing.T) { if off != tt.out || err != nil { if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { // Reiserfs rejects the big seeks. - // http://code.google.com/p/go/issues/detail?id=91 + // https://golang.org/issue/91 break } t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) @@ -1033,14 +1262,35 @@ func run(t *testing.T, cmd []string) string { return output } +func testWindowsHostname(t *testing.T) { + hostname, err := Hostname() + if err != nil { + t.Fatal(err) + } + cmd := osexec.Command("hostname") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Failed to execute hostname command: %v %s", err, out) + } + want := strings.Trim(string(out), "\r\n") + if hostname != want { + t.Fatalf("Hostname() = %q, want %q", hostname, want) + } +} + func TestHostname(t *testing.T) { // There is no other way to fetch hostname on windows, but via winapi. // On Plan 9 it can be taken from #c/sysname as Hostname() does. switch runtime.GOOS { - case "android", "nacl", "plan9", "windows": - t.Skipf("skipping on %s", runtime.GOOS) + case "android", "plan9": + t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) + case "windows": + testWindowsHostname(t) + return } + testenv.MustHaveExec(t) + // Check internal Hostname() against the output of /bin/hostname. // Allow that the internal Hostname returns a Fully Qualified Domain Name // and the /bin/hostname only returns the first component @@ -1115,6 +1365,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string { } func TestAppend(t *testing.T) { + defer chtmpdir(t)() const f = "append.txt" defer Remove(f) s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") @@ -1178,6 +1429,7 @@ func TestNilProcessStateString(t *testing.T) { } func TestSameFile(t *testing.T) { + defer chtmpdir(t)() fa, err := Create("a") if err != nil { t.Fatalf("Create(a): %v", err) @@ -1297,45 +1549,11 @@ func TestReadAtEOF(t *testing.T) { } func testKillProcess(t *testing.T, processKiller func(p *Process)) { - t.Skip("gccgo does not have a go command") - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } - - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatalf("Failed to create temp directory: %v", err) - } - defer RemoveAll(dir) - - src := filepath.Join(dir, "main.go") - f, err := Create(src) - if err != nil { - t.Fatalf("Failed to create %v: %v", src, err) - } - st := template.Must(template.New("source").Parse(` -package main -import "time" -func main() { - time.Sleep(time.Second) -} -`)) - err = st.Execute(f, nil) - if err != nil { - f.Close() - t.Fatalf("Failed to execute template: %v", err) - } - f.Close() - - exe := filepath.Join(dir, "main.exe") - output, err := osexec.Command("go", "build", "-o", exe, src).CombinedOutput() - if err != nil { - t.Fatalf("Failed to build exe %v: %v %v", exe, err, string(output)) - } + testenv.MustHaveExec(t) - cmd := osexec.Command(exe) - err = cmd.Start() + // Re-exec the test binary itself to emulate "sleep 1". + cmd := osexec.Command(Args[0], "-test.run", "TestSleep") + err := cmd.Start() if err != nil { t.Fatalf("Failed to start test process: %v", err) } @@ -1349,6 +1567,15 @@ func main() { } } +// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we +// don't have to rely on an external "sleep" command being available. +func TestSleep(t *testing.T) { + if testing.Short() { + t.Skip("Skipping in short mode") + } + time.Sleep(time.Second) +} + func TestKillStartProcess(t *testing.T) { testKillProcess(t, func(p *Process) { err := p.Kill() @@ -1359,14 +1586,13 @@ func TestKillStartProcess(t *testing.T) { } func TestGetppid(t *testing.T) { - switch runtime.GOOS { - case "nacl": - t.Skip("skipping on nacl") - case "plan9": + if runtime.GOOS == "plan9" { // TODO: golang.org/issue/8206 t.Skipf("skipping test on plan9; see issue 8206") } + testenv.MustHaveExec(t) + if Getenv("GO_WANT_HELPER_PROCESS") == "1" { fmt.Print(Getppid()) Exit(0) |

