Source file
src/runtime/callers_test.go
Documentation: runtime
1
2
3
4
5 package runtime_test
6
7 import (
8 "reflect"
9 "runtime"
10 "strings"
11 "testing"
12 )
13
14 func f1(pan bool) []uintptr {
15 return f2(pan)
16 }
17
18 func f2(pan bool) []uintptr {
19 return f3(pan)
20 }
21
22 func f3(pan bool) []uintptr {
23 if pan {
24 panic("f3")
25 }
26 ret := make([]uintptr, 20)
27 return ret[:runtime.Callers(0, ret)]
28 }
29
30 func testCallers(t *testing.T, pcs []uintptr, pan bool) {
31 m := make(map[string]int, len(pcs))
32 frames := runtime.CallersFrames(pcs)
33 for {
34 frame, more := frames.Next()
35 if frame.Function != "" {
36 m[frame.Function] = frame.Line
37 }
38 if !more {
39 break
40 }
41 }
42
43 var seen []string
44 for k := range m {
45 seen = append(seen, k)
46 }
47 t.Logf("functions seen: %s", strings.Join(seen, " "))
48
49 var f3Line int
50 if pan {
51 f3Line = 24
52 } else {
53 f3Line = 27
54 }
55 want := []struct {
56 name string
57 line int
58 }{
59 {"f1", 15},
60 {"f2", 19},
61 {"f3", f3Line},
62 }
63 for _, w := range want {
64 if got := m["runtime_test."+w.name]; got != w.line {
65 t.Errorf("%s is line %d, want %d", w.name, got, w.line)
66 }
67 }
68 }
69
70 func testCallersEqual(t *testing.T, pcs []uintptr, want []string) {
71 t.Helper()
72
73 got := make([]string, 0, len(want))
74
75 frames := runtime.CallersFrames(pcs)
76 for {
77 frame, more := frames.Next()
78 if !more || len(got) >= len(want) {
79 break
80 }
81 got = append(got, frame.Function)
82 }
83 if !reflect.DeepEqual(want, got) {
84 t.Fatalf("wanted %v, got %v", want, got)
85 }
86 }
87
88 func TestCallers(t *testing.T) {
89 testCallers(t, f1(false), false)
90 }
91
92 func TestCallersPanic(t *testing.T) {
93
94
95 want := []string{"runtime.Callers", "runtime_test.TestCallersPanic.func1",
96 "runtime.gopanic", "runtime_test.f3", "runtime_test.f2", "runtime_test.f1",
97 "runtime_test.TestCallersPanic"}
98
99 defer func() {
100 if r := recover(); r == nil {
101 t.Fatal("did not panic")
102 }
103 pcs := make([]uintptr, 20)
104 pcs = pcs[:runtime.Callers(0, pcs)]
105 testCallers(t, pcs, true)
106 testCallersEqual(t, pcs, want)
107 }()
108 f1(true)
109 }
110
111 func TestCallersDoublePanic(t *testing.T) {
112
113
114 want := []string{"runtime.Callers", "runtime_test.TestCallersDoublePanic.func1.1",
115 "runtime.gopanic", "runtime_test.TestCallersDoublePanic.func1", "runtime.gopanic", "runtime_test.TestCallersDoublePanic"}
116
117 defer func() {
118 defer func() {
119 pcs := make([]uintptr, 20)
120 pcs = pcs[:runtime.Callers(0, pcs)]
121 if recover() == nil {
122 t.Fatal("did not panic")
123 }
124 testCallersEqual(t, pcs, want)
125 }()
126 if recover() == nil {
127 t.Fatal("did not panic")
128 }
129 panic(2)
130 }()
131 panic(1)
132 }
133
134
135
136 func TestCallersAfterRecovery(t *testing.T) {
137 want := []string{"runtime.Callers", "runtime_test.TestCallersAfterRecovery.func1", "runtime_test.TestCallersAfterRecovery"}
138
139 defer func() {
140 pcs := make([]uintptr, 20)
141 pcs = pcs[:runtime.Callers(0, pcs)]
142 testCallersEqual(t, pcs, want)
143 }()
144 defer func() {
145 if recover() == nil {
146 t.Fatal("did not recover from panic")
147 }
148 }()
149 panic(1)
150 }
151
152 func TestCallersAbortedPanic(t *testing.T) {
153 want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic.func2", "runtime_test.TestCallersAbortedPanic"}
154
155 defer func() {
156 r := recover()
157 if r != nil {
158 t.Fatalf("should be no panic remaining to recover")
159 }
160 }()
161
162 defer func() {
163
164
165 pcs := make([]uintptr, 20)
166 pcs = pcs[:runtime.Callers(0, pcs)]
167 testCallersEqual(t, pcs, want)
168 }()
169 defer func() {
170 r := recover()
171 if r != "panic2" {
172 t.Fatalf("got %v, wanted %v", r, "panic2")
173 }
174 }()
175 defer func() {
176
177
178
179 panic("panic2")
180 }()
181 panic("panic1")
182 }
183
184 func TestCallersAbortedPanic2(t *testing.T) {
185 want := []string{"runtime.Callers", "runtime_test.TestCallersAbortedPanic2.func2", "runtime_test.TestCallersAbortedPanic2"}
186 defer func() {
187 r := recover()
188 if r != nil {
189 t.Fatalf("should be no panic remaining to recover")
190 }
191 }()
192 defer func() {
193 pcs := make([]uintptr, 20)
194 pcs = pcs[:runtime.Callers(0, pcs)]
195 testCallersEqual(t, pcs, want)
196 }()
197 func() {
198 defer func() {
199 r := recover()
200 if r != "panic2" {
201 t.Fatalf("got %v, wanted %v", r, "panic2")
202 }
203 }()
204 func() {
205 defer func() {
206
207 panic("panic2")
208 }()
209 panic("panic1")
210 }()
211 }()
212 }
213
214 func TestCallersNilPointerPanic(t *testing.T) {
215
216
217 want := []string{"runtime.Callers", "runtime_test.TestCallersNilPointerPanic.func1",
218 "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic",
219 "runtime_test.TestCallersNilPointerPanic"}
220
221 defer func() {
222 if r := recover(); r == nil {
223 t.Fatal("did not panic")
224 }
225 pcs := make([]uintptr, 20)
226 pcs = pcs[:runtime.Callers(0, pcs)]
227 testCallersEqual(t, pcs, want)
228 }()
229 var p *int
230 if *p == 3 {
231 t.Fatal("did not see nil pointer panic")
232 }
233 }
234
235 func TestCallersDivZeroPanic(t *testing.T) {
236
237
238 want := []string{"runtime.Callers", "runtime_test.TestCallersDivZeroPanic.func1",
239 "runtime.gopanic", "runtime.panicdivide",
240 "runtime_test.TestCallersDivZeroPanic"}
241
242 defer func() {
243 if r := recover(); r == nil {
244 t.Fatal("did not panic")
245 }
246 pcs := make([]uintptr, 20)
247 pcs = pcs[:runtime.Callers(0, pcs)]
248 testCallersEqual(t, pcs, want)
249 }()
250 var n int
251 if 5/n == 1 {
252 t.Fatal("did not see divide-by-sizer panic")
253 }
254 }
255
256 func TestCallersDeferNilFuncPanic(t *testing.T) {
257
258
259
260
261 state := 1
262 want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanic.func1",
263 "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic"}
264
265 defer func() {
266 if r := recover(); r == nil {
267 t.Fatal("did not panic")
268 }
269 pcs := make([]uintptr, 20)
270 pcs = pcs[:runtime.Callers(0, pcs)]
271 testCallersEqual(t, pcs, want)
272 if state == 1 {
273 t.Fatal("nil defer func panicked at defer time rather than function exit time")
274 }
275
276 }()
277 var f func()
278 defer f()
279
280
281 state = 2
282 }
283
284
285
286 func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) {
287 state := 1
288 want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanicWithLoop.func1",
289 "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", "runtime.deferreturn", "runtime_test.TestCallersDeferNilFuncPanicWithLoop"}
290
291 defer func() {
292 if r := recover(); r == nil {
293 t.Fatal("did not panic")
294 }
295 pcs := make([]uintptr, 20)
296 pcs = pcs[:runtime.Callers(0, pcs)]
297 testCallersEqual(t, pcs, want)
298 if state == 1 {
299 t.Fatal("nil defer func panicked at defer time rather than function exit time")
300 }
301
302 }()
303
304 for i := 0; i < 1; i++ {
305 var f func()
306 defer f()
307 }
308
309
310 state = 2
311 }
312
View as plain text