github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/debug/stack_test.go (about) 1 // Copyright 2011 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 debug_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "internal/testenv" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "runtime" 15 . "runtime/debug" 16 "strings" 17 "testing" 18 ) 19 20 func TestMain(m *testing.M) { 21 if os.Getenv("GO_RUNTIME_DEBUG_TEST_DUMP_GOROOT") != "" { 22 fmt.Println(runtime.GOROOT()) 23 os.Exit(0) 24 } 25 os.Exit(m.Run()) 26 } 27 28 type T int 29 30 func (t *T) ptrmethod() []byte { 31 return Stack() 32 } 33 func (t T) method() []byte { 34 return t.ptrmethod() 35 } 36 37 /* 38 The traceback should look something like this, modulo line numbers and hex constants. 39 Don't worry much about the base levels, but check the ones in our own package. 40 41 goroutine 10 [running]: 42 runtime/debug.Stack(0x0, 0x0, 0x0) 43 /Users/r/go/src/runtime/debug/stack.go:28 +0x80 44 runtime/debug.(*T).ptrmethod(0xc82005ee70, 0x0, 0x0, 0x0) 45 /Users/r/go/src/runtime/debug/stack_test.go:15 +0x29 46 runtime/debug.T.method(0x0, 0x0, 0x0, 0x0) 47 /Users/r/go/src/runtime/debug/stack_test.go:18 +0x32 48 runtime/debug.TestStack(0xc8201ce000) 49 /Users/r/go/src/runtime/debug/stack_test.go:37 +0x38 50 testing.tRunner(0xc8201ce000, 0x664b58) 51 /Users/r/go/src/testing/testing.go:456 +0x98 52 created by testing.RunTests 53 /Users/r/go/src/testing/testing.go:561 +0x86d 54 */ 55 func TestStack(t *testing.T) { 56 b := T(0).method() 57 lines := strings.Split(string(b), "\n") 58 if len(lines) < 6 { 59 t.Fatal("too few lines") 60 } 61 62 // If built with -trimpath, file locations should start with package paths. 63 // Otherwise, file locations should start with a GOROOT/src prefix 64 // (for whatever value of GOROOT is baked into the binary, not the one 65 // that may be set in the environment). 66 fileGoroot := "" 67 if envGoroot := os.Getenv("GOROOT"); envGoroot != "" { 68 // Since GOROOT is set explicitly in the environment, we can't be certain 69 // that it is the same GOROOT value baked into the binary, and we can't 70 // change the value in-process because runtime.GOROOT uses the value from 71 // initial (not current) environment. Spawn a subprocess to determine the 72 // real baked-in GOROOT. 73 t.Logf("found GOROOT %q from environment; checking embedded GOROOT value", envGoroot) 74 testenv.MustHaveExec(t) 75 exe, err := os.Executable() 76 if err != nil { 77 t.Fatal(err) 78 } 79 cmd := exec.Command(exe) 80 cmd.Env = append(os.Environ(), "GOROOT=", "GO_RUNTIME_DEBUG_TEST_DUMP_GOROOT=1") 81 out, err := cmd.Output() 82 if err != nil { 83 t.Fatal(err) 84 } 85 fileGoroot = string(bytes.TrimSpace(out)) 86 } else { 87 // Since GOROOT is not set in the environment, its value (if any) must come 88 // from the path embedded in the binary. 89 fileGoroot = runtime.GOROOT() 90 } 91 filePrefix := "" 92 if fileGoroot != "" { 93 filePrefix = filepath.ToSlash(fileGoroot) + "/src/" 94 } 95 96 n := 0 97 frame := func(file, code string) { 98 t.Helper() 99 100 line := lines[n] 101 if !strings.Contains(line, code) { 102 t.Errorf("expected %q in %q", code, line) 103 } 104 n++ 105 106 line = lines[n] 107 108 wantPrefix := "\t" + filePrefix + file 109 if !strings.HasPrefix(line, wantPrefix) { 110 t.Errorf("in line %q, expected prefix %q", line, wantPrefix) 111 } 112 n++ 113 } 114 n++ 115 116 frame("runtime/debug/stack.go", "runtime/debug.Stack") 117 frame("runtime/debug/stack_test.go", "runtime/debug_test.(*T).ptrmethod") 118 frame("runtime/debug/stack_test.go", "runtime/debug_test.T.method") 119 frame("runtime/debug/stack_test.go", "runtime/debug_test.TestStack") 120 frame("testing/testing.go", "") 121 }