diff options
author | Kali Kaneko (leap communications) <kali@leap.se> | 2019-01-12 18:39:45 +0100 |
---|---|---|
committer | Ruben Pollan <meskio@sindominio.net> | 2019-01-17 12:30:32 +0100 |
commit | b1247d2d0d51108c910a73891ff3116e5f032ab1 (patch) | |
tree | e9948964f0bfb1ad2df3bc7bad02aa1f41ccfbd8 /vendor/github.com/go-stack/stack/stack_test.go | |
parent | efcb8312e31b5c2261b1a1e95ace55b322cfcc27 (diff) |
[pkg] all your deps are vendored to us
Diffstat (limited to 'vendor/github.com/go-stack/stack/stack_test.go')
-rw-r--r-- | vendor/github.com/go-stack/stack/stack_test.go | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/vendor/github.com/go-stack/stack/stack_test.go b/vendor/github.com/go-stack/stack/stack_test.go new file mode 100644 index 0000000..44f3a7d --- /dev/null +++ b/vendor/github.com/go-stack/stack/stack_test.go @@ -0,0 +1,582 @@ +package stack_test + +import ( + "fmt" + "io/ioutil" + "path" + "path/filepath" + "reflect" + "runtime" + "strings" + "testing" + + "github.com/go-stack/stack" +) + +func TestCaller(t *testing.T) { + t.Parallel() + + c := stack.Caller(0) + _, file, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + if got, want := c.Frame().File, file; got != want { + t.Errorf("got file == %v, want file == %v", got, want) + } + + if got, want := c.Frame().Line, line; got != want { + t.Errorf("got line == %v, want line == %v", got, want) + } +} + +func f3(f1 func() stack.Call) stack.Call { + return f2(f1) +} + +func f2(f1 func() stack.Call) stack.Call { + return f1() +} + +func TestCallerMidstackInlined(t *testing.T) { + t.Parallel() + + _, _, line, ok := runtime.Caller(0) + line -= 10 // adjust to return f1() line inside f2() + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + c := f3(func() stack.Call { + return stack.Caller(2) + }) + + if got, want := c.Frame().Line, line; got != want { + t.Errorf("got line == %v, want line == %v", got, want) + } + if got, want := c.Frame().Function, "github.com/go-stack/stack_test.f3"; got != want { + t.Errorf("got func name == %v, want func name == %v", got, want) + } +} + +func TestCallerPanic(t *testing.T) { + t.Parallel() + + var ( + line int + ok bool + ) + + defer func() { + if recover() != nil { + var pcs [32]uintptr + n := runtime.Callers(1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + // count frames to runtime.sigpanic + panicIdx := 0 + for { + f, more := frames.Next() + if f.Function == "runtime.sigpanic" { + break + } + panicIdx++ + if !more { + t.Fatal("no runtime.sigpanic entry on the stack") + } + } + c := stack.Caller(panicIdx) + if got, want := c.Frame().Function, "runtime.sigpanic"; got != want { + t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want) + } + c1 := stack.Caller(panicIdx + 1) + if got, want := c1.Frame().Function, "github.com/go-stack/stack_test.TestCallerPanic"; got != want { + t.Errorf("TestCallerPanic frame: got name == %v, want name == %v", got, want) + } + if got, want := c1.Frame().Line, line; got != want { + t.Errorf("TestCallerPanic frame: got line == %v, want line == %v", got, want) + } + } + }() + + _, _, line, ok = runtime.Caller(0) + line += 7 // adjust to match line of panic below + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + // Initiate a sigpanic. + var x *uintptr + _ = *x +} + +type tholder struct { + trace func() stack.CallStack +} + +func (th *tholder) traceLabyrinth() stack.CallStack { + for { + return th.trace() + } +} + +func TestTrace(t *testing.T) { + t.Parallel() + + _, _, line, ok := runtime.Caller(0) + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + fh := tholder{ + trace: func() stack.CallStack { + cs := stack.Trace() + return cs + }, + } + + cs := fh.traceLabyrinth() + + lines := []int{line + 7, line - 7, line + 12} + + for i, line := range lines { + if got, want := cs[i].Frame().Line, line; got != want { + t.Errorf("got line[%d] == %v, want line[%d] == %v", i, got, i, want) + } + } +} + +// Test stack handling originating from a sigpanic. +func TestTracePanic(t *testing.T) { + t.Parallel() + + var ( + line int + ok bool + ) + + defer func() { + if recover() != nil { + trace := stack.Trace() + + // find runtime.sigpanic + panicIdx := -1 + for i, c := range trace { + if c.Frame().Function == "runtime.sigpanic" { + panicIdx = i + break + } + } + if panicIdx == -1 { + t.Fatal("no runtime.sigpanic entry on the stack") + } + if got, want := trace[panicIdx].Frame().Function, "runtime.sigpanic"; got != want { + t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want) + } + if got, want := trace[panicIdx+1].Frame().Function, "github.com/go-stack/stack_test.TestTracePanic"; got != want { + t.Errorf("TestTracePanic frame: got name == %v, want name == %v", got, want) + } + if got, want := trace[panicIdx+1].Frame().Line, line; got != want { + t.Errorf("TestTracePanic frame: got line == %v, want line == %v", got, want) + } + } + }() + + _, _, line, ok = runtime.Caller(0) + line += 7 // adjust to match line of panic below + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + // Initiate a sigpanic. + var x *uintptr + _ = *x +} + +const importPath = "github.com/go-stack/stack" + +type testType struct{} + +func (tt testType) testMethod() (c stack.Call, file string, line int, ok bool) { + c = stack.Caller(0) + _, file, line, ok = runtime.Caller(0) + line-- + return +} + +func TestCallFormat(t *testing.T) { + t.Parallel() + + c := stack.Caller(0) + _, file, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + relFile := path.Join(importPath, filepath.Base(file)) + + c2, file2, line2, ok2 := testType{}.testMethod() + if !ok2 { + t.Fatal("runtime.Caller(0) failed") + } + relFile2 := path.Join(importPath, filepath.Base(file2)) + + data := []struct { + c stack.Call + desc string + fmt string + out string + }{ + {stack.Call{}, "error", "%s", "%!s(NOFUNC)"}, + + {c, "func", "%s", path.Base(file)}, + {c, "func", "%+s", relFile}, + {c, "func", "%#s", file}, + {c, "func", "%d", fmt.Sprint(line)}, + {c, "func", "%n", "TestCallFormat"}, + {c, "func", "%+n", "github.com/go-stack/stack_test.TestCallFormat"}, + {c, "func", "%k", "stack_test"}, + {c, "func", "%+k", "github.com/go-stack/stack_test"}, + {c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)}, + {c, "func", "%+v", fmt.Sprint(relFile, ":", line)}, + {c, "func", "%#v", fmt.Sprint(file, ":", line)}, + + {c2, "meth", "%s", path.Base(file2)}, + {c2, "meth", "%+s", relFile2}, + {c2, "meth", "%#s", file2}, + {c2, "meth", "%d", fmt.Sprint(line2)}, + {c2, "meth", "%n", "testType.testMethod"}, + {c2, "meth", "%+n", "github.com/go-stack/stack_test.testType.testMethod"}, + {c2, "meth", "%k", "stack_test"}, + {c2, "meth", "%+k", "github.com/go-stack/stack_test"}, + {c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)}, + {c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)}, + {c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)}, + } + + for _, d := range data { + got := fmt.Sprintf(d.fmt, d.c) + if got != d.out { + t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out) + } + } +} + +func TestCallString(t *testing.T) { + t.Parallel() + + c := stack.Caller(0) + _, file, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + c2, file2, line2, ok2 := testType{}.testMethod() + if !ok2 { + t.Fatal("runtime.Caller(0) failed") + } + + data := []struct { + c stack.Call + desc string + out string + }{ + {stack.Call{}, "error", "%!v(NOFUNC)"}, + {c, "func", fmt.Sprint(path.Base(file), ":", line)}, + {c2, "meth", fmt.Sprint(path.Base(file2), ":", line2)}, + } + + for _, d := range data { + got := d.c.String() + if got != d.out { + t.Errorf("got %s, want %s", got, d.out) + } + } +} + +func TestCallMarshalText(t *testing.T) { + t.Parallel() + + c := stack.Caller(0) + _, file, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + c2, file2, line2, ok2 := testType{}.testMethod() + if !ok2 { + t.Fatal("runtime.Caller(0) failed") + } + + data := []struct { + c stack.Call + desc string + out []byte + err error + }{ + {stack.Call{}, "error", nil, stack.ErrNoFunc}, + {c, "func", []byte(fmt.Sprint(path.Base(file), ":", line)), nil}, + {c2, "meth", []byte(fmt.Sprint(path.Base(file2), ":", line2)), nil}, + } + + for _, d := range data { + text, err := d.c.MarshalText() + if got, want := err, d.err; got != want { + t.Errorf("%s: got err %v, want err %v", d.desc, got, want) + } + if got, want := text, d.out; !reflect.DeepEqual(got, want) { + t.Errorf("%s: got %s, want %s", d.desc, got, want) + } + } +} + +func TestCallStackString(t *testing.T) { + cs, line0 := getTrace(t) + _, file, line1, ok := runtime.Caller(0) + line1-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + file = path.Base(file) + if got, want := cs.String(), fmt.Sprintf("[%s:%d %s:%d]", file, line0, file, line1); got != want { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func TestCallStackMarshalText(t *testing.T) { + cs, line0 := getTrace(t) + _, file, line1, ok := runtime.Caller(0) + line1-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + file = path.Base(file) + text, _ := cs.MarshalText() + if got, want := text, []byte(fmt.Sprintf("[%s:%d %s:%d]", file, line0, file, line1)); !reflect.DeepEqual(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func getTrace(t *testing.T) (stack.CallStack, int) { + cs := stack.Trace().TrimRuntime() + _, _, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + return cs, line +} + +func TestTrimAbove(t *testing.T) { + trace := trimAbove() + if got, want := len(trace), 2; got != want { + t.Fatalf("got len(trace) == %v, want %v, trace: %n", got, want, trace) + } + if got, want := fmt.Sprintf("%n", trace[1]), "TestTrimAbove"; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func trimAbove() stack.CallStack { + call := stack.Caller(1) + trace := stack.Trace() + return trace.TrimAbove(call) +} + +func TestTrimBelow(t *testing.T) { + trace := trimBelow() + if got, want := fmt.Sprintf("%n", trace[0]), "TestTrimBelow"; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func trimBelow() stack.CallStack { + call := stack.Caller(1) + trace := stack.Trace() + return trace.TrimBelow(call) +} + +func TestTrimRuntime(t *testing.T) { + trace := stack.Trace().TrimRuntime() + if got, want := len(trace), 1; got != want { + t.Errorf("got len(trace) == %v, want %v, goroot: %q, trace: %#v", got, want, runtime.GOROOT(), trace) + } +} + +func BenchmarkCallVFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprint(ioutil.Discard, c) + } +} + +func BenchmarkCallPlusVFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%+v", c) + } +} + +func BenchmarkCallSharpVFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%#v", c) + } +} + +func BenchmarkCallSFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%s", c) + } +} + +func BenchmarkCallPlusSFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%+s", c) + } +} + +func BenchmarkCallSharpSFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%#s", c) + } +} + +func BenchmarkCallDFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%d", c) + } +} + +func BenchmarkCallNFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%n", c) + } +} + +func BenchmarkCallPlusNFmt(b *testing.B) { + c := stack.Caller(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, "%+n", c) + } +} + +func BenchmarkCaller(b *testing.B) { + for i := 0; i < b.N; i++ { + stack.Caller(0) + } +} + +func BenchmarkTrace(b *testing.B) { + for i := 0; i < b.N; i++ { + stack.Trace() + } +} + +func deepStack(depth int, b *testing.B) stack.CallStack { + if depth > 0 { + return deepStack(depth-1, b) + } + b.StartTimer() + s := stack.Trace() + return s +} + +func BenchmarkTrace10(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + deepStack(10, b) + } +} + +func BenchmarkTrace50(b *testing.B) { + b.StopTimer() + for i := 0; i < b.N; i++ { + deepStack(50, b) + } +} + +func BenchmarkTrace100(b *testing.B) { + b.StopTimer() + for i := 0; i < b.N; i++ { + deepStack(100, b) + } +} + +//////////////// +// Benchmark functions followed by formatting +//////////////// + +func BenchmarkCallerAndVFmt(b *testing.B) { + for i := 0; i < b.N; i++ { + fmt.Fprint(ioutil.Discard, stack.Caller(0)) + } +} + +func BenchmarkTraceAndVFmt(b *testing.B) { + for i := 0; i < b.N; i++ { + fmt.Fprint(ioutil.Discard, stack.Trace()) + } +} + +func BenchmarkTrace10AndVFmt(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + fmt.Fprint(ioutil.Discard, deepStack(10, b)) + } +} + +//////////////// +// Baseline against package runtime. +//////////////// + +func BenchmarkRuntimeCaller(b *testing.B) { + for i := 0; i < b.N; i++ { + runtime.Caller(0) + } +} + +func BenchmarkRuntimeCallerAndFmt(b *testing.B) { + for i := 0; i < b.N; i++ { + _, file, line, _ := runtime.Caller(0) + const sep = "/" + if i := strings.LastIndex(file, sep); i != -1 { + file = file[i+len(sep):] + } + fmt.Fprint(ioutil.Discard, file, ":", line) + } +} + +func BenchmarkFuncForPC(b *testing.B) { + pc, _, _, _ := runtime.Caller(0) + pc-- + b.ResetTimer() + for i := 0; i < b.N; i++ { + runtime.FuncForPC(pc) + } +} + +func BenchmarkFuncFileLine(b *testing.B) { + pc, _, _, _ := runtime.Caller(0) + pc-- + fn := runtime.FuncForPC(pc) + b.ResetTimer() + for i := 0; i < b.N; i++ { + fn.FileLine(pc) + } +} |