@@ -13,49 +13,70 @@ func Info(traceFilterFunc ...func(filepath string) bool) []string {
1313 var pc uintptr
1414 var file string
1515 var line int
16- var ok bool
17-
1816 var funcName string
1917 var lastCaller string
2018
21- callers := []string {}
22- for i := 0 ; ; i ++ {
23- pc , file , line , ok = runtime .Caller (i )
24- if ! ok {
25- break
26- }
27-
28- // Avoid panic. https://github.com/stretchr/testify/issues/180
29- if file == "<autogenerated>" {
30- break
31- }
19+ const stackFrameBufferSize = 10
20+ pcs := make ([]uintptr , stackFrameBufferSize )
3221
33- f := runtime .FuncForPC (pc )
34- if f == nil {
35- break
36- }
22+ callers := []string {}
23+ offset := 1
3724
38- funcName = f .Name ()
25+ for {
26+ n := runtime .Callers (offset , pcs )
3927
40- // testing.tRunner is the standard library function that calls
41- // tests. Subtests are called directly by tRunner, without going through
42- // the Test/Benchmark/Example function that contains the t.Run calls.
43- if funcName == "testing.tRunner" {
28+ if n == 0 {
4429 break
4530 }
4631
47- lastCaller = fmt .Sprintf ("%s:%d" , file , line )
48-
49- if len (strings .Split (file , "/" )) > 1 && // https://github.com/stretchr/testify/pull/402
50- ! skipLibs (file , traceFilterFunc ... ) {
51- callers = append (callers , lastCaller )
32+ frames := runtime .CallersFrames (pcs [:n ])
33+
34+ for {
35+ frame , more := frames .Next ()
36+ pc = frame .PC
37+ file = frame .File
38+ line = frame .Line
39+
40+ // This is a huge edge case, but it will panic if this is the case, see #180
41+ if file == "<autogenerated>" {
42+ break
43+ }
44+
45+ f := runtime .FuncForPC (pc )
46+ if f == nil {
47+ break
48+ }
49+ funcName = f .Name ()
50+
51+ // testing.tRunner is the standard library function that calls
52+ // tests. Subtests are called directly by tRunner, without going through
53+ // the Test/Benchmark/Example function that contains the t.Run calls, so
54+ // with subtests we should break when we hit tRunner, without adding it
55+ // to the list of callers.
56+ if funcName == "testing.tRunner" {
57+ break
58+ }
59+
60+ lastCaller = fmt .Sprintf ("%s:%d" , file , line )
61+
62+ if len (strings .Split (file , "/" )) > 1 && // https://github.com/stretchr/testify/pull/402
63+ ! skipLibs (file , traceFilterFunc ... ) {
64+ callers = append (callers , lastCaller )
65+ }
66+
67+ funcName = funcName [strings .LastIndexByte (funcName , '.' )+ 1 :]
68+ if isGolangTestFunc (funcName ) {
69+ break
70+ }
71+
72+
73+ if ! more {
74+ break
75+ }
5276 }
5377
54- funcName = funcName [strings .LastIndexByte (funcName , '.' )+ 1 :]
55-
56- if isGolangTestFunc (funcName ) {
57- break
58- }
78+ // Next batch
79+ offset += cap (pcs )
5980 }
6081
6182 if len (callers ) == 0 {
@@ -75,15 +96,15 @@ func skipLibs(filepath string, traceFilterFunc ...func(filepath string) bool) bo
7596 return false
7697}
7798
78- func isGolangTestFunc (name string ) bool {
99+ func isGolangTestFunc (funcName string ) bool {
79100 for _ , prefix := range [3 ]string {"Test" , "Benchmark" , "Example" } {
80- if ! strings .HasPrefix (name , prefix ) {
101+ if ! strings .HasPrefix (funcName , prefix ) {
81102 continue
82103 }
83- if len (name ) == len (prefix ) {
104+ if len (funcName ) == len (prefix ) {
84105 return true
85106 }
86- r , _ := utf8 .DecodeRuneInString (name [len (prefix ):])
107+ r , _ := utf8 .DecodeRuneInString (funcName [len (prefix ):])
87108 if ! unicode .IsLower (r ) {
88109 return true
89110 }
0 commit comments