// Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package os_test import ( "fmt" "internal/testenv" "os" osexec "os/exec" "path/filepath" "runtime" "testing" ) const executable_EnvVar = "OSTEST_OUTPUT_EXECPATH" func TestExecutable(t *testing.T) { testenv.MustHaveExec(t) ep, err := os.Executable() if err != nil { t.Fatalf("Executable failed: %v", err) } // we want fn to be of the form "dir/prog" dir := filepath.Dir(filepath.Dir(ep)) fn, err := filepath.Rel(dir, ep) if err != nil { t.Fatalf("filepath.Rel: %v", err) } cmd := &osexec.Cmd{} // make child start with a relative program path cmd.Dir = dir cmd.Path = fn // forge argv[0] for child, so that we can verify we could correctly // get real path of the executable without influenced by argv[0]. cmd.Args = []string{"-", "-test.run=XXXX"} if runtime.GOOS == "openbsd" || runtime.GOOS == "aix" { // OpenBSD and AIX rely on argv[0] cmd.Args[0] = fn } cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar)) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("exec(self) failed: %v", err) } outs := string(out) if !filepath.IsAbs(outs) { t.Fatalf("Child returned %q, want an absolute path", out) } if !sameFile(outs, ep) { t.Fatalf("Child returned %q, not the same file as %q", out, ep) } } func sameFile(fn1, fn2 string) bool { fi1, err := os.Stat(fn1) if err != nil { return false } fi2, err := os.Stat(fn2) if err != nil { return false } return os.SameFile(fi1, fi2) } func init() { if e := os.Getenv(executable_EnvVar); e != "" { // first chdir to another path dir := "/" if runtime.GOOS == "windows" { cwd, err := os.Getwd() if err != nil { panic(err) } dir = filepath.VolumeName(cwd) } os.Chdir(dir) if ep, err := os.Executable(); err != nil { fmt.Fprint(os.Stderr, "ERROR: ", err) } else { fmt.Fprint(os.Stderr, ep) } os.Exit(0) } }