@@ -13,6 +13,185 @@ import (
1313 "github.com/go-stack/stack"
1414)
1515
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+
16195const importPath = "github.com/go-stack/stack"
17196
18197type testType struct {}
@@ -178,6 +357,7 @@ func TestCallStackMarshalText(t *testing.T) {
178357 t .Errorf ("\n got %v\n want %v" , got , want )
179358 }
180359}
360+
181361func getTrace (t * testing.T ) (stack.CallStack , int ) {
182362 cs := stack .Trace ().TrimRuntime ()
183363 _ , _ , line , ok := runtime .Caller (0 )
0 commit comments