mirror of https://github.com/pkg/errors.git
251 lines
4.7 KiB
Go
251 lines
4.7 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
var initpc = caller()
|
|
|
|
type X struct{}
|
|
|
|
// val returns a Frame pointing to itself.
|
|
func (x X) val() Frame {
|
|
return caller()
|
|
}
|
|
|
|
// ptr returns a Frame pointing to itself.
|
|
func (x *X) ptr() Frame {
|
|
return caller()
|
|
}
|
|
|
|
func TestFrameFormat(t *testing.T) {
|
|
var tests = []struct {
|
|
Frame
|
|
format string
|
|
want string
|
|
}{{
|
|
initpc,
|
|
"%s",
|
|
"stack_test.go",
|
|
}, {
|
|
initpc,
|
|
"%+s",
|
|
"github.com/pkg/errors.init\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go",
|
|
}, {
|
|
0,
|
|
"%s",
|
|
"unknown",
|
|
}, {
|
|
0,
|
|
"%+s",
|
|
"unknown",
|
|
}, {
|
|
initpc,
|
|
"%d",
|
|
"9",
|
|
}, {
|
|
0,
|
|
"%d",
|
|
"0",
|
|
}, {
|
|
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",
|
|
}, {
|
|
0,
|
|
"%n",
|
|
"",
|
|
}, {
|
|
initpc,
|
|
"%v",
|
|
"stack_test.go:9",
|
|
}, {
|
|
initpc,
|
|
"%+v",
|
|
"github.com/pkg/errors.init\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:9",
|
|
}, {
|
|
0,
|
|
"%v",
|
|
"unknown:0",
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.Frame, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
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 TestStackTrace(t *testing.T) {
|
|
tests := []struct {
|
|
err error
|
|
want []string
|
|
}{{
|
|
New("ooh"), []string{
|
|
"github.com/pkg/errors.TestStackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:121",
|
|
},
|
|
}, {
|
|
Wrap(New("ooh"), "ahh"), []string{
|
|
"github.com/pkg/errors.TestStackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:126", // this is the stack of Wrap, not New
|
|
},
|
|
}, {
|
|
Cause(Wrap(New("ooh"), "ahh")), []string{
|
|
"github.com/pkg/errors.TestStackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:131", // this is the stack of New
|
|
},
|
|
}, {
|
|
func() error { return New("ooh") }(), []string{
|
|
`github.com/pkg/errors.TestStackTrace.func1` +
|
|
"\n\t.+/github.com/pkg/errors/stack_test.go:136", // this is the stack of New
|
|
"github.com/pkg/errors.TestStackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:136", // this is the stack of New's caller
|
|
},
|
|
}, {
|
|
Cause(func() error {
|
|
return func() error {
|
|
return Errorf("hello %s", fmt.Sprintf("world: %s", "ooh"))
|
|
}()
|
|
}()), []string{
|
|
`github.com/pkg/errors.TestStackTrace.func2.1` +
|
|
"\n\t.+/github.com/pkg/errors/stack_test.go:145", // this is the stack of Errorf
|
|
`github.com/pkg/errors.TestStackTrace.func2` +
|
|
"\n\t.+/github.com/pkg/errors/stack_test.go:146", // this is the stack of Errorf's caller
|
|
"github.com/pkg/errors.TestStackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:147", // 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 {
|
|
testFormatRegexp(t, i, st[j], "%+v", 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:174 stack_test.go:221\]`,
|
|
}, {
|
|
stackTrace()[:2],
|
|
"%+v",
|
|
"\n" +
|
|
"github.com/pkg/errors.stackTrace\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:174\n" +
|
|
"github.com/pkg/errors.TestStackTraceFormat\n" +
|
|
"\t.+/github.com/pkg/errors/stack_test.go:225",
|
|
}, {
|
|
stackTrace()[:2],
|
|
"%#v",
|
|
`\[\]errors.Frame{stack_test.go:174, stack_test.go:233}`,
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
// a version of runtime.Caller that returns a Frame, not a uintptr.
|
|
func caller() Frame {
|
|
var pcs [3]uintptr
|
|
n := runtime.Callers(2, pcs[:])
|
|
frames := runtime.CallersFrames(pcs[:n])
|
|
frame, _ := frames.Next()
|
|
return Frame(frame.PC)
|
|
}
|