@@ -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