@@ -13,6 +13,185 @@ import (
13
13
"github.com/go-stack/stack"
14
14
)
15
15
16
+ func TestCaller (t * testing.T ) {
17
+ t .Parallel ()
18
+
19
+ c := stack .Caller (0 )
20
+ _ , file , line , ok := runtime .Caller (0 )
21
+ line --
22
+ if ! ok {
23
+ t .Fatal ("runtime.Caller(0) failed" )
24
+ }
25
+
26
+ if got , want := c .Frame ().File , file ; got != want {
27
+ t .Errorf ("got file == %v, want file == %v" , got , want )
28
+ }
29
+
30
+ if got , want := c .Frame ().Line , line ; got != want {
31
+ t .Errorf ("got line == %v, want line == %v" , got , want )
32
+ }
33
+ }
34
+
35
+ func f3 (f1 func () stack.Call ) stack.Call {
36
+ return f2 (f1 )
37
+ }
38
+
39
+ func f2 (f1 func () stack.Call ) stack.Call {
40
+ return f1 ()
41
+ }
42
+
43
+ func TestCallerMidstackInlined (t * testing.T ) {
44
+ t .Parallel ()
45
+
46
+ _ , _ , line , ok := runtime .Caller (0 )
47
+ line -= 10 // adjust to return f1() line inside f2()
48
+ if ! ok {
49
+ t .Fatal ("runtime.Caller(0) failed" )
50
+ }
51
+
52
+ c := f3 (func () stack.Call {
53
+ return stack .Caller (2 )
54
+ })
55
+
56
+ if got , want := c .Frame ().Line , line ; got != want {
57
+ t .Errorf ("got line == %v, want line == %v" , got , want )
58
+ }
59
+ if got , want := c .Frame ().Function , "github.com/go-stack/stack_test.f3" ; got != want {
60
+ t .Errorf ("got func name == %v, want func name == %v" , got , want )
61
+ }
62
+ }
63
+
64
+ func TestCallerPanic (t * testing.T ) {
65
+ t .Parallel ()
66
+
67
+ var (
68
+ line int
69
+ ok bool
70
+ )
71
+
72
+ defer func () {
73
+ if recover () != nil {
74
+ var pcs [32 ]uintptr
75
+ n := runtime .Callers (1 , pcs [:])
76
+ frames := runtime .CallersFrames (pcs [:n ])
77
+ // count frames to runtime.sigpanic
78
+ panicIdx := 0
79
+ for {
80
+ f , more := frames .Next ()
81
+ if f .Function == "runtime.sigpanic" {
82
+ break
83
+ }
84
+ panicIdx ++
85
+ if ! more {
86
+ t .Fatal ("no runtime.sigpanic entry on the stack" )
87
+ }
88
+ }
89
+ c := stack .Caller (panicIdx )
90
+ if got , want := c .Frame ().Function , "runtime.sigpanic" ; got != want {
91
+ t .Errorf ("sigpanic frame: got name == %v, want name == %v" , got , want )
92
+ }
93
+ c1 := stack .Caller (panicIdx + 1 )
94
+ if got , want := c1 .Frame ().Function , "github.com/go-stack/stack_test.TestCallerPanic" ; got != want {
95
+ t .Errorf ("TestCallerPanic frame: got name == %v, want name == %v" , got , want )
96
+ }
97
+ if got , want := c1 .Frame ().Line , line ; got != want {
98
+ t .Errorf ("TestCallerPanic frame: got line == %v, want line == %v" , got , want )
99
+ }
100
+ }
101
+ }()
102
+
103
+ _ , _ , line , ok = runtime .Caller (0 )
104
+ line += 7 // adjust to match line of panic below
105
+ if ! ok {
106
+ t .Fatal ("runtime.Caller(0) failed" )
107
+ }
108
+ // Initiate a sigpanic.
109
+ var x * uintptr
110
+ _ = * x
111
+ }
112
+
113
+ type tholder struct {
114
+ trace func () stack.CallStack
115
+ }
116
+
117
+ func (th * tholder ) traceLabyrinth () stack.CallStack {
118
+ for {
119
+ return th .trace ()
120
+ }
121
+ }
122
+
123
+ func TestTrace (t * testing.T ) {
124
+ t .Parallel ()
125
+
126
+ _ , _ , line , ok := runtime .Caller (0 )
127
+ if ! ok {
128
+ t .Fatal ("runtime.Caller(0) failed" )
129
+ }
130
+
131
+ fh := tholder {
132
+ trace : func () stack.CallStack {
133
+ cs := stack .Trace ()
134
+ return cs
135
+ },
136
+ }
137
+
138
+ cs := fh .traceLabyrinth ()
139
+
140
+ lines := []int {line + 7 , line - 7 , line + 12 }
141
+
142
+ for i , line := range lines {
143
+ if got , want := cs [i ].Frame ().Line , line ; got != want {
144
+ t .Errorf ("got line[%d] == %v, want line[%d] == %v" , i , got , i , want )
145
+ }
146
+ }
147
+ }
148
+
149
+ // Test stack handling originating from a sigpanic.
150
+ func TestTracePanic (t * testing.T ) {
151
+ t .Parallel ()
152
+
153
+ var (
154
+ line int
155
+ ok bool
156
+ )
157
+
158
+ defer func () {
159
+ if recover () != nil {
160
+ trace := stack .Trace ()
161
+
162
+ // find runtime.sigpanic
163
+ panicIdx := - 1
164
+ for i , c := range trace {
165
+ if c .Frame ().Function == "runtime.sigpanic" {
166
+ panicIdx = i
167
+ break
168
+ }
169
+ }
170
+ if panicIdx == - 1 {
171
+ t .Fatal ("no runtime.sigpanic entry on the stack" )
172
+ }
173
+ if got , want := trace [panicIdx ].Frame ().Function , "runtime.sigpanic" ; got != want {
174
+ t .Errorf ("sigpanic frame: got name == %v, want name == %v" , got , want )
175
+ }
176
+ if got , want := trace [panicIdx + 1 ].Frame ().Function , "github.com/go-stack/stack_test.TestTracePanic" ; got != want {
177
+ t .Errorf ("TestTracePanic frame: got name == %v, want name == %v" , got , want )
178
+ }
179
+ if got , want := trace [panicIdx + 1 ].Frame ().Line , line ; got != want {
180
+ t .Errorf ("TestTracePanic frame: got line == %v, want line == %v" , got , want )
181
+ }
182
+ }
183
+ }()
184
+
185
+ _ , _ , line , ok = runtime .Caller (0 )
186
+ line += 7 // adjust to match line of panic below
187
+ if ! ok {
188
+ t .Fatal ("runtime.Caller(0) failed" )
189
+ }
190
+ // Initiate a sigpanic.
191
+ var x * uintptr
192
+ _ = * x
193
+ }
194
+
16
195
const importPath = "github.com/go-stack/stack"
17
196
18
197
type testType struct {}
@@ -178,6 +357,7 @@ func TestCallStackMarshalText(t *testing.T) {
178
357
t .Errorf ("\n got %v\n want %v" , got , want )
179
358
}
180
359
}
360
+
181
361
func getTrace (t * testing.T ) (stack.CallStack , int ) {
182
362
cs := stack .Trace ().TrimRuntime ()
183
363
_ , _ , line , ok := runtime .Caller (0 )
0 commit comments