13 "github.com/go-stack/stack"
16 const importPath = "github.com/go-stack/stack"
18 type testType struct{}
20 func (tt testType) testMethod() (c stack.Call, pc uintptr, file string, line int, ok bool) {
22 pc, file, line, ok = runtime.Caller(0)
27 func TestCallFormat(t *testing.T) {
31 pc, file, line, ok := runtime.Caller(0)
34 t.Fatal("runtime.Caller(0) failed")
36 relFile := path.Join(importPath, filepath.Base(file))
38 c2, pc2, file2, line2, ok2 := testType{}.testMethod()
40 t.Fatal("runtime.Caller(0) failed")
42 relFile2 := path.Join(importPath, filepath.Base(file2))
50 {stack.Call{}, "error", "%s", "%!s(NOFUNC)"},
52 {c, "func", "%s", path.Base(file)},
53 {c, "func", "%+s", relFile},
54 {c, "func", "%#s", file},
55 {c, "func", "%d", fmt.Sprint(line)},
56 {c, "func", "%n", "TestCallFormat"},
57 {c, "func", "%+n", runtime.FuncForPC(pc - 1).Name()},
58 {c, "func", "%k", "stack_test"},
59 {c, "func", "%+k", "github.com/go-stack/stack_test"},
60 {c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)},
61 {c, "func", "%+v", fmt.Sprint(relFile, ":", line)},
62 {c, "func", "%#v", fmt.Sprint(file, ":", line)},
64 {c2, "meth", "%s", path.Base(file2)},
65 {c2, "meth", "%+s", relFile2},
66 {c2, "meth", "%#s", file2},
67 {c2, "meth", "%d", fmt.Sprint(line2)},
68 {c2, "meth", "%n", "testType.testMethod"},
69 {c2, "meth", "%+n", runtime.FuncForPC(pc2).Name()},
70 {c2, "meth", "%k", "stack_test"},
71 {c2, "meth", "%+k", "github.com/go-stack/stack_test"},
72 {c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)},
73 {c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)},
74 {c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)},
77 for _, d := range data {
78 got := fmt.Sprintf(d.fmt, d.c)
80 t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out)
85 func TestCallString(t *testing.T) {
89 _, file, line, ok := runtime.Caller(0)
92 t.Fatal("runtime.Caller(0) failed")
95 c2, _, file2, line2, ok2 := testType{}.testMethod()
97 t.Fatal("runtime.Caller(0) failed")
105 {stack.Call{}, "error", "%!v(NOFUNC)"},
106 {c, "func", fmt.Sprint(path.Base(file), ":", line)},
107 {c2, "meth", fmt.Sprint(path.Base(file2), ":", line2)},
110 for _, d := range data {
113 t.Errorf("got %s, want %s", got, d.out)
118 func TestCallMarshalText(t *testing.T) {
122 _, file, line, ok := runtime.Caller(0)
125 t.Fatal("runtime.Caller(0) failed")
128 c2, _, file2, line2, ok2 := testType{}.testMethod()
130 t.Fatal("runtime.Caller(0) failed")
139 {stack.Call{}, "error", nil, stack.ErrNoFunc},
140 {c, "func", []byte(fmt.Sprint(path.Base(file), ":", line)), nil},
141 {c2, "meth", []byte(fmt.Sprint(path.Base(file2), ":", line2)), nil},
144 for _, d := range data {
145 text, err := d.c.MarshalText()
146 if got, want := err, d.err; got != want {
147 t.Errorf("%s: got err %v, want err %v", d.desc, got, want)
149 if got, want := text, d.out; !reflect.DeepEqual(got, want) {
150 t.Errorf("%s: got %s, want %s", d.desc, got, want)
155 func TestCallStackString(t *testing.T) {
156 cs, line0 := getTrace(t)
157 _, file, line1, ok := runtime.Caller(0)
160 t.Fatal("runtime.Caller(0) failed")
162 file = path.Base(file)
163 if got, want := cs.String(), fmt.Sprintf("[%s:%d %s:%d]", file, line0, file, line1); got != want {
164 t.Errorf("\n got %v\nwant %v", got, want)
168 func TestCallStackMarshalText(t *testing.T) {
169 cs, line0 := getTrace(t)
170 _, file, line1, ok := runtime.Caller(0)
173 t.Fatal("runtime.Caller(0) failed")
175 file = path.Base(file)
176 text, _ := cs.MarshalText()
177 if got, want := text, []byte(fmt.Sprintf("[%s:%d %s:%d]", file, line0, file, line1)); !reflect.DeepEqual(got, want) {
178 t.Errorf("\n got %v\nwant %v", got, want)
181 func getTrace(t *testing.T) (stack.CallStack, int) {
182 cs := stack.Trace().TrimRuntime()
183 _, _, line, ok := runtime.Caller(0)
186 t.Fatal("runtime.Caller(0) failed")
191 func TestTrimAbove(t *testing.T) {
193 if got, want := len(trace), 2; got != want {
194 t.Errorf("got len(trace) == %v, want %v, trace: %n", got, want, trace)
196 if got, want := fmt.Sprintf("%n", trace[1]), "TestTrimAbove"; got != want {
197 t.Errorf("got %q, want %q", got, want)
201 func trimAbove() stack.CallStack {
202 call := stack.Caller(1)
203 trace := stack.Trace()
204 return trace.TrimAbove(call)
207 func TestTrimBelow(t *testing.T) {
209 if got, want := fmt.Sprintf("%n", trace[0]), "TestTrimBelow"; got != want {
210 t.Errorf("got %q, want %q", got, want)
214 func trimBelow() stack.CallStack {
215 call := stack.Caller(1)
216 trace := stack.Trace()
217 return trace.TrimBelow(call)
220 func TestTrimRuntime(t *testing.T) {
221 trace := stack.Trace().TrimRuntime()
222 if got, want := len(trace), 1; got != want {
223 t.Errorf("got len(trace) == %v, want %v, goroot: %q, trace: %#v", got, want, runtime.GOROOT(), trace)
227 func BenchmarkCallVFmt(b *testing.B) {
230 for i := 0; i < b.N; i++ {
231 fmt.Fprint(ioutil.Discard, c)
235 func BenchmarkCallPlusVFmt(b *testing.B) {
238 for i := 0; i < b.N; i++ {
239 fmt.Fprintf(ioutil.Discard, "%+v", c)
243 func BenchmarkCallSharpVFmt(b *testing.B) {
246 for i := 0; i < b.N; i++ {
247 fmt.Fprintf(ioutil.Discard, "%#v", c)
251 func BenchmarkCallSFmt(b *testing.B) {
254 for i := 0; i < b.N; i++ {
255 fmt.Fprintf(ioutil.Discard, "%s", c)
259 func BenchmarkCallPlusSFmt(b *testing.B) {
262 for i := 0; i < b.N; i++ {
263 fmt.Fprintf(ioutil.Discard, "%+s", c)
267 func BenchmarkCallSharpSFmt(b *testing.B) {
270 for i := 0; i < b.N; i++ {
271 fmt.Fprintf(ioutil.Discard, "%#s", c)
275 func BenchmarkCallDFmt(b *testing.B) {
278 for i := 0; i < b.N; i++ {
279 fmt.Fprintf(ioutil.Discard, "%d", c)
283 func BenchmarkCallNFmt(b *testing.B) {
286 for i := 0; i < b.N; i++ {
287 fmt.Fprintf(ioutil.Discard, "%n", c)
291 func BenchmarkCallPlusNFmt(b *testing.B) {
294 for i := 0; i < b.N; i++ {
295 fmt.Fprintf(ioutil.Discard, "%+n", c)
299 func BenchmarkCaller(b *testing.B) {
300 for i := 0; i < b.N; i++ {
305 func BenchmarkTrace(b *testing.B) {
306 for i := 0; i < b.N; i++ {
311 func deepStack(depth int, b *testing.B) stack.CallStack {
313 return deepStack(depth-1, b)
320 func BenchmarkTrace10(b *testing.B) {
321 for i := 0; i < b.N; i++ {
327 func BenchmarkTrace50(b *testing.B) {
329 for i := 0; i < b.N; i++ {
334 func BenchmarkTrace100(b *testing.B) {
336 for i := 0; i < b.N; i++ {
342 // Benchmark functions followed by formatting
345 func BenchmarkCallerAndVFmt(b *testing.B) {
346 for i := 0; i < b.N; i++ {
347 fmt.Fprint(ioutil.Discard, stack.Caller(0))
351 func BenchmarkTraceAndVFmt(b *testing.B) {
352 for i := 0; i < b.N; i++ {
353 fmt.Fprint(ioutil.Discard, stack.Trace())
357 func BenchmarkTrace10AndVFmt(b *testing.B) {
358 for i := 0; i < b.N; i++ {
360 fmt.Fprint(ioutil.Discard, deepStack(10, b))
365 // Baseline against package runtime.
368 func BenchmarkRuntimeCaller(b *testing.B) {
369 for i := 0; i < b.N; i++ {
374 func BenchmarkRuntimeCallerAndFmt(b *testing.B) {
375 for i := 0; i < b.N; i++ {
376 _, file, line, _ := runtime.Caller(0)
378 if i := strings.LastIndex(file, sep); i != -1 {
379 file = file[i+len(sep):]
381 fmt.Fprint(ioutil.Discard, file, ":", line)
385 func BenchmarkFuncForPC(b *testing.B) {
386 pc, _, _, _ := runtime.Caller(0)
389 for i := 0; i < b.N; i++ {
390 runtime.FuncForPC(pc)
394 func BenchmarkFuncFileLine(b *testing.B) {
395 pc, _, _, _ := runtime.Caller(0)
397 fn := runtime.FuncForPC(pc)
399 for i := 0; i < b.N; i++ {