blob: 00221e47a1971f9f3218cf616296e310f478e518 [file] [log] [blame]
package errors
import (
"fmt"
"runtime"
"testing"
)
var initpc, _, _, _ = runtime.Caller(0)
func TestFrameLine(t *testing.T) {
var tests = []struct {
Frame
want int
}{{
Frame(initpc),
9,
}, {
func() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}(),
20,
}, {
func() Frame {
var pc, _, _, _ = runtime.Caller(1)
return Frame(pc)
}(),
28,
}, {
Frame(0), // invalid PC
0,
}}
for _, tt := range tests {
got := tt.Frame.line()
want := tt.want
if want != got {
t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
}
}
}
type X struct{}
func (x X) val() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}
func (x *X) ptr() Frame {
var pc, _, _, _ = runtime.Caller(0)
return Frame(pc)
}
func TestFrameFormat(t *testing.T) {
var tests = []struct {
Frame
format string
want string
}{{
Frame(initpc),
"%s",
"stack_test.go",
}, {
Frame(initpc),
"%+s",
"github.com/pkg/errors/stack_test.go",
}, {
Frame(0),
"%s",
"unknown",
}, {
Frame(0),
"%+s",
"unknown",
}, {
Frame(initpc),
"%d",
"9",
}, {
Frame(0),
"%d",
"0",
}, {
Frame(initpc),
"%n",
"init",
}, {
func() Frame {
var x X
return x.ptr()
}(),
"%n",
"(*X).ptr",
}, {
func() Frame {
var x X
return x.val()
}(),
"%n",
"X.val",
}, {
Frame(0),
"%n",
"",
}, {
Frame(initpc),
"%v",
"stack_test.go:9",
}, {
Frame(initpc),
"%+v",
"github.com/pkg/errors/stack_test.go:9",
}, {
Frame(0),
"%v",
"unknown:0",
}}
for _, tt := range tests {
got := fmt.Sprintf(tt.format, tt.Frame)
want := tt.want
if want != got {
t.Errorf("%v %q: want: %q, got: %q", tt.Frame, tt.format, want, got)
}
}
}
func TestFuncname(t *testing.T) {
tests := []struct {
name, want string
}{
{"", ""},
{"runtime.main", "main"},
{"github.com/pkg/errors.funcname", "funcname"},
{"funcname", "funcname"},
{"io.copyBuffer", "copyBuffer"},
{"main.(*R).Write", "(*R).Write"},
}
for _, tt := range tests {
got := funcname(tt.name)
want := tt.want
if got != want {
t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got)
}
}
}
func TestTrimGOPATH(t *testing.T) {
var tests = []struct {
Frame
want string
}{{
Frame(initpc),
"github.com/pkg/errors/stack_test.go",
}}
for _, tt := range tests {
pc := tt.Frame.pc()
fn := runtime.FuncForPC(pc)
file, _ := fn.FileLine(pc)
got := trimGOPATH(fn.Name(), file)
want := tt.want
if want != got {
t.Errorf("%v: want %q, got %q", tt.Frame, want, got)
}
}
}
func TestStacktrace(t *testing.T) {
tests := []struct {
err error
want []string
}{{
New("ooh"), []string{
"github.com/pkg/errors/stack_test.go:177",
},
}, {
Wrap(New("ooh"), "ahh"), []string{
"github.com/pkg/errors/stack_test.go:181", // this is the stack of Wrap, not New
},
}, {
Cause(Wrap(New("ooh"), "ahh")), []string{
"github.com/pkg/errors/stack_test.go:185", // this is the stack of New
},
}, {
func() error { return New("ooh") }(), []string{
"github.com/pkg/errors/stack_test.go:189", // this is the stack of New
"github.com/pkg/errors/stack_test.go:189", // this is the stack of New's caller
},
}, {
Cause(func() error {
return func() error {
return Errorf("hello %s", fmt.Sprintf("world"))
}()
}()), []string{
"github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf
"github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller
"github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
},
}}
for i, tt := range tests {
x, ok := tt.err.(interface {
Stacktrace() Stacktrace
})
if !ok {
t.Errorf("expected %#v to implement Stacktrace() Stacktrace", tt.err)
continue
}
st := x.Stacktrace()
for j, want := range tt.want {
frame := st[j]
got := fmt.Sprintf("%+v", frame)
if got != want {
t.Errorf("test %d: frame %d: got %q, want %q", i, j, got, want)
}
}
}
}
func stacktrace() Stacktrace {
const depth = 8
var pcs [depth]uintptr
n := runtime.Callers(1, pcs[:])
var st stack = pcs[0:n]
return st.Stacktrace()
}
func TestStacktraceFormat(t *testing.T) {
tests := []struct {
Stacktrace
format string
want string
}{{
nil,
"%s",
"[]",
}, {
nil,
"%v",
"[]",
}, {
nil,
"%+v",
"[]",
}, {
nil,
"%#v",
"[]errors.Frame(nil)",
}, {
make(Stacktrace, 0),
"%s",
"[]",
}, {
make(Stacktrace, 0),
"%v",
"[]",
}, {
make(Stacktrace, 0),
"%+v",
"[]",
}, {
make(Stacktrace, 0),
"%#v",
"[]errors.Frame{}",
}, {
stacktrace()[:2],
"%s",
"[stack_test.go stack_test.go]",
}, {
stacktrace()[:2],
"%v",
"[stack_test.go:226 stack_test.go:273]",
}, {
stacktrace()[:2],
"%+v",
"[github.com/pkg/errors/stack_test.go:226 github.com/pkg/errors/stack_test.go:277]",
}, {
stacktrace()[:2],
"%#v",
"[]errors.Frame{stack_test.go:226, stack_test.go:281}",
}}
for i, tt := range tests {
got := fmt.Sprintf(tt.format, tt.Stacktrace)
if got != tt.want {
t.Errorf("test %d: got: %q, want: %q", i+1, got, tt.want)
}
}
}