stack_test.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. package errors
  2. import (
  3. "fmt"
  4. "runtime"
  5. "testing"
  6. )
  7. var initpc, _, _, _ = runtime.Caller(0)
  8. func TestFrameLine(t *testing.T) {
  9. var tests = []struct {
  10. Frame
  11. want int
  12. }{{
  13. Frame(initpc),
  14. 9,
  15. }, {
  16. func() Frame {
  17. var pc, _, _, _ = runtime.Caller(0)
  18. return Frame(pc)
  19. }(),
  20. 20,
  21. }, {
  22. func() Frame {
  23. var pc, _, _, _ = runtime.Caller(1)
  24. return Frame(pc)
  25. }(),
  26. 28,
  27. }, {
  28. Frame(0), // invalid PC
  29. 0,
  30. }}
  31. for _, tt := range tests {
  32. got := tt.Frame.line()
  33. want := tt.want
  34. if want != got {
  35. t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
  36. }
  37. }
  38. }
  39. type X struct{}
  40. func (x X) val() Frame {
  41. var pc, _, _, _ = runtime.Caller(0)
  42. return Frame(pc)
  43. }
  44. func (x *X) ptr() Frame {
  45. var pc, _, _, _ = runtime.Caller(0)
  46. return Frame(pc)
  47. }
  48. func TestFrameFormat(t *testing.T) {
  49. var tests = []struct {
  50. Frame
  51. format string
  52. want string
  53. }{{
  54. Frame(initpc),
  55. "%s",
  56. "stack_test.go",
  57. }, {
  58. Frame(initpc),
  59. "%+s",
  60. "github.com/pkg/errors/stack_test.go",
  61. }, {
  62. Frame(0),
  63. "%s",
  64. "unknown",
  65. }, {
  66. Frame(0),
  67. "%+s",
  68. "unknown",
  69. }, {
  70. Frame(initpc),
  71. "%d",
  72. "9",
  73. }, {
  74. Frame(0),
  75. "%d",
  76. "0",
  77. }, {
  78. Frame(initpc),
  79. "%n",
  80. "init",
  81. }, {
  82. func() Frame {
  83. var x X
  84. return x.ptr()
  85. }(),
  86. "%n",
  87. "(*X).ptr",
  88. }, {
  89. func() Frame {
  90. var x X
  91. return x.val()
  92. }(),
  93. "%n",
  94. "X.val",
  95. }, {
  96. Frame(0),
  97. "%n",
  98. "",
  99. }, {
  100. Frame(initpc),
  101. "%v",
  102. "stack_test.go:9",
  103. }, {
  104. Frame(initpc),
  105. "%+v",
  106. "github.com/pkg/errors/stack_test.go:9",
  107. }, {
  108. Frame(0),
  109. "%v",
  110. "unknown:0",
  111. }}
  112. for _, tt := range tests {
  113. got := fmt.Sprintf(tt.format, tt.Frame)
  114. want := tt.want
  115. if want != got {
  116. t.Errorf("%v %q: want: %q, got: %q", tt.Frame, tt.format, want, got)
  117. }
  118. }
  119. }
  120. func TestFuncname(t *testing.T) {
  121. tests := []struct {
  122. name, want string
  123. }{
  124. {"", ""},
  125. {"runtime.main", "main"},
  126. {"github.com/pkg/errors.funcname", "funcname"},
  127. {"funcname", "funcname"},
  128. {"io.copyBuffer", "copyBuffer"},
  129. {"main.(*R).Write", "(*R).Write"},
  130. }
  131. for _, tt := range tests {
  132. got := funcname(tt.name)
  133. want := tt.want
  134. if got != want {
  135. t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got)
  136. }
  137. }
  138. }
  139. func TestTrimGOPATH(t *testing.T) {
  140. var tests = []struct {
  141. Frame
  142. want string
  143. }{{
  144. Frame(initpc),
  145. "github.com/pkg/errors/stack_test.go",
  146. }}
  147. for _, tt := range tests {
  148. pc := tt.Frame.pc()
  149. fn := runtime.FuncForPC(pc)
  150. file, _ := fn.FileLine(pc)
  151. got := trimGOPATH(fn.Name(), file)
  152. want := tt.want
  153. if want != got {
  154. t.Errorf("%v: want %q, got %q", tt.Frame, want, got)
  155. }
  156. }
  157. }
  158. func TestStacktrace(t *testing.T) {
  159. type fileline struct {
  160. file string
  161. line int
  162. }
  163. tests := []struct {
  164. err error
  165. want []fileline
  166. }{{
  167. New("ooh"), []fileline{
  168. {"github.com/pkg/errors/stack_test.go", 181},
  169. },
  170. }, {
  171. Wrap(New("ooh"), "ahh"), []fileline{
  172. {"github.com/pkg/errors/stack_test.go", 185}, // this is the stack of Wrap, not New
  173. },
  174. }, {
  175. Cause(Wrap(New("ooh"), "ahh")), []fileline{
  176. {"github.com/pkg/errors/stack_test.go", 189}, // this is the stack of New
  177. },
  178. }, {
  179. func() error { return New("ooh") }(), []fileline{
  180. {"github.com/pkg/errors/stack_test.go", 193}, // this is the stack of New
  181. {"github.com/pkg/errors/stack_test.go", 193}, // this is the stack of New's caller
  182. },
  183. }, {
  184. Cause(func() error {
  185. return func() error {
  186. return Errorf("hello %s", fmt.Sprintf("world"))
  187. }()
  188. }()), []fileline{
  189. {"github.com/pkg/errors/stack_test.go", 200}, // this is the stack of Errorf
  190. {"github.com/pkg/errors/stack_test.go", 201}, // this is the stack of Errorf's caller
  191. {"github.com/pkg/errors/stack_test.go", 202}, // this is the stack of Errorf's caller's caller
  192. },
  193. }}
  194. for _, tt := range tests {
  195. x, ok := tt.err.(interface {
  196. Stacktrace() []Frame
  197. })
  198. if !ok {
  199. t.Errorf("expected %#v to implement Stacktrace() []Frame", tt.err)
  200. continue
  201. }
  202. st := x.Stacktrace()
  203. for i, want := range tt.want {
  204. frame := st[i]
  205. file, line := fmt.Sprintf("%+s", frame), frame.line()
  206. if file != want.file || line != want.line {
  207. t.Errorf("frame %d: expected %s:%d, got %s:%d", i, want.file, want.line, file, line)
  208. }
  209. }
  210. }
  211. }