package stack_test import ( "fmt" "io/ioutil" "os" "path" "path/filepath" "runtime" "testing" "gopkg.in/inconshreveable/log15.v2/stack" ) type testType struct{} func (tt testType) testMethod() (pc uintptr, file string, line int, ok bool) { return runtime.Caller(0) } func TestCallFormat(t *testing.T) { t.Parallel() pc, file, line, ok := runtime.Caller(0) if !ok { t.Fatal("runtime.Caller(0) failed") } gopathSrc := filepath.Join(os.Getenv("GOPATH"), "src") relFile, err := filepath.Rel(gopathSrc, file) if err != nil { t.Fatalf("failed to determine path relative to GOPATH: %v", err) } relFile = filepath.ToSlash(relFile) pc2, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } relFile2, err := filepath.Rel(gopathSrc, file) if err != nil { t.Fatalf("failed to determine path relative to GOPATH: %v", err) } relFile2 = filepath.ToSlash(relFile2) data := []struct { pc uintptr desc string fmt string out string }{ {0, "error", "%s", "%!s(NOFUNC)"}, {pc, "func", "%s", path.Base(file)}, {pc, "func", "%+s", relFile}, {pc, "func", "%#s", file}, {pc, "func", "%d", fmt.Sprint(line)}, {pc, "func", "%n", "TestCallFormat"}, {pc, "func", "%+n", runtime.FuncForPC(pc).Name()}, {pc, "func", "%v", fmt.Sprint(path.Base(file), ":", line)}, {pc, "func", "%+v", fmt.Sprint(relFile, ":", line)}, {pc, "func", "%#v", fmt.Sprint(file, ":", line)}, {pc, "func", "%v|%[1]n()", fmt.Sprint(path.Base(file), ":", line, "|", "TestCallFormat()")}, {pc2, "meth", "%s", path.Base(file2)}, {pc2, "meth", "%+s", relFile2}, {pc2, "meth", "%#s", file2}, {pc2, "meth", "%d", fmt.Sprint(line2)}, {pc2, "meth", "%n", "testType.testMethod"}, {pc2, "meth", "%+n", runtime.FuncForPC(pc2).Name()}, {pc2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)}, {pc2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)}, {pc2, "meth", "%#v", fmt.Sprint(file2, ":", line2)}, {pc2, "meth", "%v|%[1]n()", fmt.Sprint(path.Base(file2), ":", line2, "|", "testType.testMethod()")}, } for _, d := range data { got := fmt.Sprintf(d.fmt, stack.Call(d.pc)) if got != d.out { t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out) } } } func BenchmarkCallVFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprint(ioutil.Discard, stack.Call(pc)) } } func BenchmarkCallPlusVFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%+v", stack.Call(pc)) } } func BenchmarkCallSharpVFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%#v", stack.Call(pc)) } } func BenchmarkCallSFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%s", stack.Call(pc)) } } func BenchmarkCallPlusSFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%+s", stack.Call(pc)) } } func BenchmarkCallSharpSFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%#s", stack.Call(pc)) } } func BenchmarkCallDFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%d", stack.Call(pc)) } } func BenchmarkCallNFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%n", stack.Call(pc)) } } func BenchmarkCallPlusNFmt(b *testing.B) { pc, _, _, ok := runtime.Caller(0) if !ok { b.Fatal("runtime.Caller(0) failed") } b.ResetTimer() for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, "%+n", stack.Call(pc)) } } func BenchmarkCallers(b *testing.B) { for i := 0; i < b.N; i++ { stack.Callers() } } func deepStack(depth int, b *testing.B) stack.Trace { if depth > 0 { return deepStack(depth-1, b) } b.StartTimer() s := stack.Callers() b.StopTimer() return s } func BenchmarkCallers10(b *testing.B) { b.StopTimer() for i := 0; i < b.N; i++ { deepStack(10, b) } } func BenchmarkCallers50(b *testing.B) { b.StopTimer() for i := 0; i < b.N; i++ { deepStack(50, b) } } func BenchmarkCallers100(b *testing.B) { b.StopTimer() for i := 0; i < b.N; i++ { deepStack(100, b) } }