Skip to content

Commit 93d005d

Browse files
committed
Update tests locations.
* Move tests out of stackinternal_test.go in favor of testing externally from stack_test package. * Restrict TestCallerInlinedPanic to Go 1.9 and newer since older versions of Go did not return stack frames for inlined functions.
1 parent d644040 commit 93d005d

File tree

3 files changed

+247
-236
lines changed

3 files changed

+247
-236
lines changed

Diff for: stack-go19_test.go

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// +build go1.9
2+
3+
package stack_test
4+
5+
import (
6+
"runtime"
7+
"testing"
8+
9+
"github.com/go-stack/stack"
10+
)
11+
12+
func TestCallerInlinedPanic(t *testing.T) {
13+
t.Parallel()
14+
15+
var line int
16+
17+
defer func() {
18+
if recover() != nil {
19+
var pcs [32]uintptr
20+
n := runtime.Callers(1, pcs[:])
21+
frames := runtime.CallersFrames(pcs[:n])
22+
// count frames to runtime.sigpanic
23+
panicIdx := 0
24+
for {
25+
f, more := frames.Next()
26+
if f.Function == "runtime.sigpanic" {
27+
break
28+
}
29+
panicIdx++
30+
if !more {
31+
t.Fatal("no runtime.sigpanic entry on the stack")
32+
}
33+
}
34+
35+
c := stack.Caller(panicIdx)
36+
if got, want := c.Frame().Function, "runtime.sigpanic"; got != want {
37+
t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want)
38+
}
39+
40+
c1 := stack.Caller(panicIdx + 1)
41+
if got, want := c1.Frame().Function, "github.com/go-stack/stack_test.inlinablePanic"; got != want {
42+
t.Errorf("TestCallerInlinedPanic frame: got name == %v, want name == %v", got, want)
43+
}
44+
if got, want := c1.Frame().Line, line; got != want {
45+
t.Errorf("TestCallerInlinedPanic frame: got line == %v, want line == %v", got, want)
46+
}
47+
}
48+
}()
49+
50+
doPanic(t, &line)
51+
t.Fatal("failed to panic")
52+
}
53+
54+
func doPanic(t *testing.T, panicLine *int) {
55+
_, _, line, ok := runtime.Caller(0)
56+
*panicLine = line + 11 // adjust to match line of panic below
57+
if !ok {
58+
t.Fatal("runtime.Caller(0) failed")
59+
}
60+
inlinablePanic()
61+
}
62+
63+
func inlinablePanic() {
64+
// Initiate a sigpanic.
65+
var x *uintptr
66+
_ = *x
67+
}

Diff for: stack_test.go

+180
Original file line numberDiff line numberDiff line change
@@ -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+
16195
const importPath = "github.com/go-stack/stack"
17196

18197
type testType struct{}
@@ -178,6 +357,7 @@ func TestCallStackMarshalText(t *testing.T) {
178357
t.Errorf("\n got %v\nwant %v", got, want)
179358
}
180359
}
360+
181361
func getTrace(t *testing.T) (stack.CallStack, int) {
182362
cs := stack.Trace().TrimRuntime()
183363
_, _, line, ok := runtime.Caller(0)

0 commit comments

Comments
 (0)