From ddbdc319c27294f02e174c58d808cabf6143973e Mon Sep 17 00:00:00 2001 From: Stephen Gelman Date: Mon, 17 Jul 2017 20:27:58 +0000 Subject: [PATCH] Bump github.com/pkg/errors to the current git HEAD --- glide.lock | 6 +- glide.yaml | 2 +- vendor/github.com/pkg/errors/.travis.yml | 8 +- vendor/github.com/pkg/errors/LICENSE | 1 - vendor/github.com/pkg/errors/README.md | 2 + vendor/github.com/pkg/errors/bench_test.go | 63 +++ vendor/github.com/pkg/errors/errors.go | 186 +++++--- vendor/github.com/pkg/errors/errors_test.go | 90 +++- vendor/github.com/pkg/errors/example_test.go | 63 ++- vendor/github.com/pkg/errors/format_test.go | 448 +++++++++++++++++-- vendor/github.com/pkg/errors/stack.go | 21 + vendor/github.com/pkg/errors/stack_test.go | 61 ++- 12 files changed, 803 insertions(+), 148 deletions(-) create mode 100644 vendor/github.com/pkg/errors/bench_test.go diff --git a/glide.lock b/glide.lock index dd20a3df..bfcbaa7c 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 53d7484e21e3a93702191bef6c0d8a0f01082c9ab9c9c81fb9884ba31f31002e -updated: 2017-07-05T09:11:19.970140093-06:00 +hash: c96d9438238597d9a70aa231b5a1a00ac2a961154bd76c01f5dec018d60145e1 +updated: 2017-07-17T20:26:21.026348832Z imports: - name: github.com/bgentry/go-netrc version: 9fd32a8b3d3d3f9d43c341bfe098430e07609480 @@ -16,7 +16,7 @@ imports: - name: github.com/olekukonko/ts version: ecf753e7c962639ab5a1fb46f7da627d4c0a04b8 - name: github.com/pkg/errors - version: 01fa4104b9c248c8945d14d9f128454d5b28d595 + version: c605e284fe17294bda444b34710735b29d1a9d90 - name: github.com/rubyist/tracerx version: d7bcc0bc315bed2a841841bee5dbecc8d7d7582f - name: github.com/spf13/cobra diff --git a/glide.yaml b/glide.yaml index d52fe9cc..fc98e1c4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -33,4 +33,4 @@ import: - package: github.com/xeipuuv/gojsonschema version: 6b67b3fab74d992bd07f72550006ab2c6907c416 - package: github.com/pkg/errors - version: 01fa4104b9c248c8945d14d9f128454d5b28d595 + version: c605e284fe17294bda444b34710735b29d1a9d90 diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml index 024e2846..bf3eed6f 100644 --- a/vendor/github.com/pkg/errors/.travis.yml +++ b/vendor/github.com/pkg/errors/.travis.yml @@ -1,9 +1,11 @@ language: go go_import_path: github.com/pkg/errors go: - - 1.4.3 - - 1.5.4 - - 1.6.2 + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x - tip script: diff --git a/vendor/github.com/pkg/errors/LICENSE b/vendor/github.com/pkg/errors/LICENSE index fafcaafd..835ba3e7 100644 --- a/vendor/github.com/pkg/errors/LICENSE +++ b/vendor/github.com/pkg/errors/LICENSE @@ -21,4 +21,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md index 6ea6422e..273db3c9 100644 --- a/vendor/github.com/pkg/errors/README.md +++ b/vendor/github.com/pkg/errors/README.md @@ -2,6 +2,8 @@ Package errors provides simple error handling primitives. +`go get github.com/pkg/errors` + The traditional error handling idiom in Go is roughly akin to ```go if err != nil { diff --git a/vendor/github.com/pkg/errors/bench_test.go b/vendor/github.com/pkg/errors/bench_test.go new file mode 100644 index 00000000..903b5f2d --- /dev/null +++ b/vendor/github.com/pkg/errors/bench_test.go @@ -0,0 +1,63 @@ +// +build go1.7 + +package errors + +import ( + "fmt" + "testing" + + stderrors "errors" +) + +func noErrors(at, depth int) error { + if at >= depth { + return stderrors.New("no error") + } + return noErrors(at+1, depth) +} + +func yesErrors(at, depth int) error { + if at >= depth { + return New("ye error") + } + return yesErrors(at+1, depth) +} + +// GlobalE is an exported global to store the result of benchmark results, +// preventing the compiler from optimising the benchmark functions away. +var GlobalE error + +func BenchmarkErrors(b *testing.B) { + type run struct { + stack int + std bool + } + runs := []run{ + {10, false}, + {10, true}, + {100, false}, + {100, true}, + {1000, false}, + {1000, true}, + } + for _, r := range runs { + part := "pkg/errors" + if r.std { + part = "errors" + } + name := fmt.Sprintf("%s-stack-%d", part, r.stack) + b.Run(name, func(b *testing.B) { + var err error + f := yesErrors + if r.std { + f = noErrors + } + b.ReportAllocs() + for i := 0; i < b.N; i++ { + err = f(0, r.stack) + } + b.StopTimer() + GlobalE = err + }) + } +} diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 65bf7a0f..842ee804 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -14,13 +14,18 @@ // Adding context to an error // // The errors.Wrap function returns a new error that adds context to the -// original error. For example +// original error by recording a stack trace at the point Wrap is called, +// and the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { // return errors.Wrap(err, "read failed") // } // +// If additional control is required the errors.WithStack and errors.WithMessage +// functions destructure errors.Wrap into its component operations of annotating +// an error with a stack trace and an a message, respectively. +// // Retrieving the cause of an error // // Using errors.Wrap constructs a stack of errors, adding context to the @@ -28,7 +33,7 @@ // to reverse the operation of errors.Wrap to retrieve the original error // for inspection. Any error value which implements this interface // -// type Causer interface { +// type causer interface { // Cause() error // } // @@ -43,6 +48,9 @@ // // unknown error // } // +// causer interface is not exported by this package, but is considered a part +// of stable public API. +// // Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can @@ -59,7 +67,7 @@ // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are // invoked. This information can be retrieved with the following interface. // -// type StackTrace interface { +// type stackTracer interface { // StackTrace() errors.StackTrace // } // @@ -67,16 +75,19 @@ // // type StackTrace []Frame // -// The Frame type represents a call site in the stacktrace. Frame supports +// The Frame type represents a call site in the stack trace. Frame supports // the fmt.Formatter interface that can be used for printing information about -// the stacktrace of this error. For example: +// the stack trace of this error. For example: // -// if err, ok := err.(StackTrace); ok { +// if err, ok := err.(stackTracer); ok { // for _, f := range err.StackTrace() { // fmt.Printf("%+s:%d", f) // } // } // +// stackTracer interface is not exported by this package, but is considered a part +// of stable public API. +// // See the documentation for Frame.Format for more details. package errors @@ -85,102 +96,149 @@ import ( "io" ) -// _error is an error implementation returned by New and Errorf -// that implements its own fmt.Formatter. -type _error struct { - msg string - *stack -} - -func (e _error) Error() string { return e.msg } - -func (e _error) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - if s.Flag('+') { - io.WriteString(s, e.msg) - fmt.Fprintf(s, "%+v", e.StackTrace()) - return - } - fallthrough - case 's': - io.WriteString(s, e.msg) - } -} - // New returns an error with the supplied message. +// New also records the stack trace at the point it was called. func New(message string) error { - return _error{ - message, - callers(), + return &fundamental{ + msg: message, + stack: callers(), } } // Errorf formats according to a format specifier and returns the string // as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. func Errorf(format string, args ...interface{}) error { - return _error{ - fmt.Sprintf(format, args...), + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, callers(), } } -type cause struct { - cause error - msg string -} - -func (c cause) Error() string { return fmt.Sprintf("%s: %v", c.msg, c.Cause()) } -func (c cause) Cause() error { return c.cause } - -// wrapper is an error implementation returned by Wrap and Wrapf -// that implements its own fmt.Formatter. -type wrapper struct { - cause +type withStack struct { + error *stack } -func (w wrapper) Format(s fmt.State, verb rune) { +func (w *withStack) Cause() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { - fmt.Fprintf(s, "%+v\n", w.Cause()) - fmt.Fprintf(s, "%+v: %s", w.StackTrace()[0], w.msg) + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) return } fallthrough case 's': io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) } } -// Wrap returns an error annotating err with message. +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. // If err is nil, Wrap returns nil. func Wrap(err error, message string) error { if err == nil { return nil } - return wrapper{ - cause: cause{ - cause: err, - msg: message, - }, - stack: callers(), + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), } } -// Wrapf returns an error annotating err with the format specifier. +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is call, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { return nil } - return wrapper{ - cause: cause{ - cause: err, - msg: fmt.Sprintf(format, args...), - }, - stack: callers(), + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) } } @@ -188,7 +246,7 @@ func Wrapf(err error, format string, args ...interface{}) error { // An error value has a cause if it implements the following // interface: // -// type Causer interface { +// type causer interface { // Cause() error // } // diff --git a/vendor/github.com/pkg/errors/errors_test.go b/vendor/github.com/pkg/errors/errors_test.go index 11d45554..c4e6eef6 100644 --- a/vendor/github.com/pkg/errors/errors_test.go +++ b/vendor/github.com/pkg/errors/errors_test.go @@ -84,6 +84,18 @@ func TestCause(t *testing.T) { }, { err: x, // return from errors.New want: x, + }, { + WithMessage(nil, "whoops"), + nil, + }, { + WithMessage(io.EOF, "whoops"), + io.EOF, + }, { + WithStack(nil), + nil, + }, { + WithStack(io.EOF), + io.EOF, }} for i, tt := range tests { @@ -137,23 +149,77 @@ func TestErrorf(t *testing.T) { } } +func TestWithStackNil(t *testing.T) { + got := WithStack(nil) + if got != nil { + t.Errorf("WithStack(nil): got %#v, expected nil", got) + } +} + +func TestWithStack(t *testing.T) { + tests := []struct { + err error + want string + }{ + {io.EOF, "EOF"}, + {WithStack(io.EOF), "EOF"}, + } + + for _, tt := range tests { + got := WithStack(tt.err).Error() + if got != tt.want { + t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want) + } + } +} + +func TestWithMessageNil(t *testing.T) { + got := WithMessage(nil, "no error") + if got != nil { + t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got) + } +} + +func TestWithMessage(t *testing.T) { + tests := []struct { + err error + message string + want string + }{ + {io.EOF, "read error", "read error: EOF"}, + {WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"}, + } + + for _, tt := range tests { + got := WithMessage(tt.err, tt.message).Error() + if got != tt.want { + t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want) + } + } +} + // errors.New, etc values are not expected to be compared by value // but the change in errors#27 made them incomparable. Assert that // various kinds of errors have a functional equality operator, even // if the result of that equality is always false. func TestErrorEquality(t *testing.T) { - tests := []struct { - err1, err2 error - }{ - {io.EOF, io.EOF}, - {io.EOF, nil}, - {io.EOF, errors.New("EOF")}, - {io.EOF, New("EOF")}, - {New("EOF"), New("EOF")}, - {New("EOF"), Errorf("EOF")}, - {New("EOF"), Wrap(io.EOF, "EOF")}, + vals := []error{ + nil, + io.EOF, + errors.New("EOF"), + New("EOF"), + Errorf("EOF"), + Wrap(io.EOF, "EOF"), + Wrapf(io.EOF, "EOF%d", 2), + WithMessage(nil, "whoops"), + WithMessage(io.EOF, "whoops"), + WithStack(io.EOF), + WithStack(nil), } - for _, tt := range tests { - _ = tt.err1 == tt.err2 // mustn't panic + + for i := range vals { + for j := range vals { + _ = vals[i] == vals[j] // mustn't panic + } } } diff --git a/vendor/github.com/pkg/errors/example_test.go b/vendor/github.com/pkg/errors/example_test.go index f1df2340..c1fc13e3 100644 --- a/vendor/github.com/pkg/errors/example_test.go +++ b/vendor/github.com/pkg/errors/example_test.go @@ -35,6 +35,59 @@ func ExampleNew_printf() { // /home/dfc/go/src/runtime/asm_amd64.s:2059 } +func ExampleWithMessage() { + cause := errors.New("whoops") + err := errors.WithMessage(cause, "oh noes") + fmt.Println(err) + + // Output: oh noes: whoops +} + +func ExampleWithStack() { + cause := errors.New("whoops") + err := errors.WithStack(cause) + fmt.Println(err) + + // Output: whoops +} + +func ExampleWithStack_printf() { + cause := errors.New("whoops") + err := errors.WithStack(cause) + fmt.Printf("%+v", err) + + // Example Output: + // whoops + // github.com/pkg/errors_test.ExampleWithStack_printf + // /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55 + // testing.runExample + // /usr/lib/go/src/testing/example.go:114 + // testing.RunExamples + // /usr/lib/go/src/testing/example.go:38 + // testing.(*M).Run + // /usr/lib/go/src/testing/testing.go:744 + // main.main + // github.com/pkg/errors/_test/_testmain.go:106 + // runtime.main + // /usr/lib/go/src/runtime/proc.go:183 + // runtime.goexit + // /usr/lib/go/src/runtime/asm_amd64.s:2086 + // github.com/pkg/errors_test.ExampleWithStack_printf + // /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56 + // testing.runExample + // /usr/lib/go/src/testing/example.go:114 + // testing.RunExamples + // /usr/lib/go/src/testing/example.go:38 + // testing.(*M).Run + // /usr/lib/go/src/testing/testing.go:744 + // main.main + // github.com/pkg/errors/_test/_testmain.go:106 + // runtime.main + // /usr/lib/go/src/runtime/proc.go:183 + // runtime.goexit + // /usr/lib/go/src/runtime/asm_amd64.s:2086 +} + func ExampleWrap() { cause := errors.New("whoops") err := errors.Wrap(cause, "oh noes") @@ -119,14 +172,14 @@ func ExampleErrorf_extended() { // /home/dfc/go/src/runtime/asm_amd64.s:2059 } -func Example_stacktrace() { - type StackTrace interface { +func Example_stackTrace() { + type stackTracer interface { StackTrace() errors.StackTrace } - err, ok := errors.Cause(fn()).(StackTrace) + err, ok := errors.Cause(fn()).(stackTracer) if !ok { - panic("oops, err does not implement StackTrace") + panic("oops, err does not implement stackTracer") } st := err.StackTrace() @@ -135,7 +188,7 @@ func Example_stacktrace() { // Example output: // github.com/pkg/errors_test.fn // /home/dfc/src/github.com/pkg/errors/example_test.go:47 - // github.com/pkg/errors_test.Example_stacktrace + // github.com/pkg/errors_test.Example_stackTrace // /home/dfc/src/github.com/pkg/errors/example_test.go:127 } diff --git a/vendor/github.com/pkg/errors/format_test.go b/vendor/github.com/pkg/errors/format_test.go index 60806ae8..15fd7d89 100644 --- a/vendor/github.com/pkg/errors/format_test.go +++ b/vendor/github.com/pkg/errors/format_test.go @@ -1,6 +1,7 @@ package errors import ( + "errors" "fmt" "io" "regexp" @@ -26,11 +27,15 @@ func TestFormatNew(t *testing.T) { "%+v", "error\n" + "github.com/pkg/errors.TestFormatNew\n" + - "\t.+/github.com/pkg/errors/format_test.go:25", + "\t.+/github.com/pkg/errors/format_test.go:26", + }, { + New("error"), + "%q", + `"error"`, }} - for _, tt := range tests { - testFormatRegexp(t, tt.error, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.error, tt.format, tt.want) } } @@ -52,11 +57,11 @@ func TestFormatErrorf(t *testing.T) { "%+v", "error\n" + "github.com/pkg/errors.TestFormatErrorf\n" + - "\t.+/github.com/pkg/errors/format_test.go:51", + "\t.+/github.com/pkg/errors/format_test.go:56", }} - for _, tt := range tests { - testFormatRegexp(t, tt.error, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.error, tt.format, tt.want) } } @@ -78,15 +83,37 @@ func TestFormatWrap(t *testing.T) { "%+v", "error\n" + "github.com/pkg/errors.TestFormatWrap\n" + - "\t.+/github.com/pkg/errors/format_test.go:77", + "\t.+/github.com/pkg/errors/format_test.go:82", }, { Wrap(io.EOF, "error"), "%s", "error: EOF", + }, { + Wrap(io.EOF, "error"), + "%v", + "error: EOF", + }, { + Wrap(io.EOF, "error"), + "%+v", + "EOF\n" + + "error\n" + + "github.com/pkg/errors.TestFormatWrap\n" + + "\t.+/github.com/pkg/errors/format_test.go:96", + }, { + Wrap(Wrap(io.EOF, "error1"), "error2"), + "%+v", + "EOF\n" + + "error1\n" + + "github.com/pkg/errors.TestFormatWrap\n" + + "\t.+/github.com/pkg/errors/format_test.go:103\n", + }, { + Wrap(New("error with space"), "context"), + "%q", + `"context: error with space"`, }} - for _, tt := range tests { - testFormatRegexp(t, tt.error, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.error, tt.format, tt.want) } } @@ -96,19 +123,24 @@ func TestFormatWrapf(t *testing.T) { format string want string }{{ + Wrapf(io.EOF, "error%d", 2), + "%s", + "error2: EOF", + }, { + Wrapf(io.EOF, "error%d", 2), + "%v", + "error2: EOF", + }, { + Wrapf(io.EOF, "error%d", 2), + "%+v", + "EOF\n" + + "error2\n" + + "github.com/pkg/errors.TestFormatWrapf\n" + + "\t.+/github.com/pkg/errors/format_test.go:134", + }, { Wrapf(New("error"), "error%d", 2), "%s", "error2: error", - }, { - Wrap(io.EOF, "error"), - "%v", - "error: EOF", - }, { - Wrap(io.EOF, "error"), - "%+v", - "EOF\n" + - "github.com/pkg/errors.TestFormatWrapf\n" + - "\t.+/github.com/pkg/errors/format_test.go:107: error", }, { Wrapf(New("error"), "error%d", 2), "%v", @@ -118,24 +150,386 @@ func TestFormatWrapf(t *testing.T) { "%+v", "error\n" + "github.com/pkg/errors.TestFormatWrapf\n" + - "\t.+/github.com/pkg/errors/format_test.go:117", + "\t.+/github.com/pkg/errors/format_test.go:149", }} - for _, tt := range tests { - testFormatRegexp(t, tt.error, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.error, tt.format, tt.want) } } -func testFormatRegexp(t *testing.T, arg interface{}, format, want string) { +func TestFormatWithStack(t *testing.T) { + tests := []struct { + error + format string + want []string + }{{ + WithStack(io.EOF), + "%s", + []string{"EOF"}, + }, { + WithStack(io.EOF), + "%v", + []string{"EOF"}, + }, { + WithStack(io.EOF), + "%+v", + []string{"EOF", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:175"}, + }, { + WithStack(New("error")), + "%s", + []string{"error"}, + }, { + WithStack(New("error")), + "%v", + []string{"error"}, + }, { + WithStack(New("error")), + "%+v", + []string{"error", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:189", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:189"}, + }, { + WithStack(WithStack(io.EOF)), + "%+v", + []string{"EOF", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:197", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:197"}, + }, { + WithStack(WithStack(Wrapf(io.EOF, "message"))), + "%+v", + []string{"EOF", + "message", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:205", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:205", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:205"}, + }, { + WithStack(Errorf("error%d", 1)), + "%+v", + []string{"error1", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:216", + "github.com/pkg/errors.TestFormatWithStack\n" + + "\t.+/github.com/pkg/errors/format_test.go:216"}, + }} + + for i, tt := range tests { + testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true) + } +} + +func TestFormatWithMessage(t *testing.T) { + tests := []struct { + error + format string + want []string + }{{ + WithMessage(New("error"), "error2"), + "%s", + []string{"error2: error"}, + }, { + WithMessage(New("error"), "error2"), + "%v", + []string{"error2: error"}, + }, { + WithMessage(New("error"), "error2"), + "%+v", + []string{ + "error", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:244", + "error2"}, + }, { + WithMessage(io.EOF, "addition1"), + "%s", + []string{"addition1: EOF"}, + }, { + WithMessage(io.EOF, "addition1"), + "%v", + []string{"addition1: EOF"}, + }, { + WithMessage(io.EOF, "addition1"), + "%+v", + []string{"EOF", "addition1"}, + }, { + WithMessage(WithMessage(io.EOF, "addition1"), "addition2"), + "%v", + []string{"addition2: addition1: EOF"}, + }, { + WithMessage(WithMessage(io.EOF, "addition1"), "addition2"), + "%+v", + []string{"EOF", "addition1", "addition2"}, + }, { + Wrap(WithMessage(io.EOF, "error1"), "error2"), + "%+v", + []string{"EOF", "error1", "error2", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:272"}, + }, { + WithMessage(Errorf("error%d", 1), "error2"), + "%+v", + []string{"error1", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:278", + "error2"}, + }, { + WithMessage(WithStack(io.EOF), "error"), + "%+v", + []string{ + "EOF", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:285", + "error"}, + }, { + WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"), + "%+v", + []string{ + "EOF", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:293", + "inside-error", + "github.com/pkg/errors.TestFormatWithMessage\n" + + "\t.+/github.com/pkg/errors/format_test.go:293", + "outside-error"}, + }} + + for i, tt := range tests { + testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true) + } +} + +func TestFormatGeneric(t *testing.T) { + starts := []struct { + err error + want []string + }{ + {New("new-error"), []string{ + "new-error", + "github.com/pkg/errors.TestFormatGeneric\n" + + "\t.+/github.com/pkg/errors/format_test.go:315"}, + }, {Errorf("errorf-error"), []string{ + "errorf-error", + "github.com/pkg/errors.TestFormatGeneric\n" + + "\t.+/github.com/pkg/errors/format_test.go:319"}, + }, {errors.New("errors-new-error"), []string{ + "errors-new-error"}, + }, + } + + wrappers := []wrapper{ + { + func(err error) error { return WithMessage(err, "with-message") }, + []string{"with-message"}, + }, { + func(err error) error { return WithStack(err) }, + []string{ + "github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" + + ".+/github.com/pkg/errors/format_test.go:333", + }, + }, { + func(err error) error { return Wrap(err, "wrap-error") }, + []string{ + "wrap-error", + "github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" + + ".+/github.com/pkg/errors/format_test.go:339", + }, + }, { + func(err error) error { return Wrapf(err, "wrapf-error%d", 1) }, + []string{ + "wrapf-error1", + "github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" + + ".+/github.com/pkg/errors/format_test.go:346", + }, + }, + } + + for s := range starts { + err := starts[s].err + want := starts[s].want + testFormatCompleteCompare(t, s, err, "%+v", want, false) + testGenericRecursive(t, err, want, wrappers, 3) + } +} + +func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) { got := fmt.Sprintf(format, arg) - lines := strings.SplitN(got, "\n", -1) - for i, w := range strings.SplitN(want, "\n", -1) { - match, err := regexp.MatchString(w, lines[i]) + gotLines := strings.SplitN(got, "\n", -1) + wantLines := strings.SplitN(want, "\n", -1) + + if len(wantLines) > len(gotLines) { + t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want) + return + } + + for i, w := range wantLines { + match, err := regexp.MatchString(w, gotLines[i]) if err != nil { t.Fatal(err) } if !match { - t.Errorf("fmt.Sprintf(%q, err): got: %q, want: %q", format, got, want) + t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want) + } + } +} + +var stackLineR = regexp.MustCompile(`\.`) + +// parseBlocks parses input into a slice, where: +// - incase entry contains a newline, its a stacktrace +// - incase entry contains no newline, its a solo line. +// +// Detecting stack boundaries only works incase the WithStack-calls are +// to be found on the same line, thats why it is optionally here. +// +// Example use: +// +// for _, e := range blocks { +// if strings.ContainsAny(e, "\n") { +// // Match as stack +// } else { +// // Match as line +// } +// } +// +func parseBlocks(input string, detectStackboundaries bool) ([]string, error) { + var blocks []string + + stack := "" + wasStack := false + lines := map[string]bool{} // already found lines + + for _, l := range strings.Split(input, "\n") { + isStackLine := stackLineR.MatchString(l) + + switch { + case !isStackLine && wasStack: + blocks = append(blocks, stack, l) + stack = "" + lines = map[string]bool{} + case isStackLine: + if wasStack { + // Detecting two stacks after another, possible cause lines match in + // our tests due to WithStack(WithStack(io.EOF)) on same line. + if detectStackboundaries { + if lines[l] { + if len(stack) == 0 { + return nil, errors.New("len of block must not be zero here") + } + + blocks = append(blocks, stack) + stack = l + lines = map[string]bool{l: true} + continue + } + } + + stack = stack + "\n" + l + } else { + stack = l + } + lines[l] = true + case !isStackLine && !wasStack: + blocks = append(blocks, l) + default: + return nil, errors.New("must not happen") + } + + wasStack = isStackLine + } + + // Use up stack + if stack != "" { + blocks = append(blocks, stack) + } + return blocks, nil +} + +func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) { + gotStr := fmt.Sprintf(format, arg) + + got, err := parseBlocks(gotStr, detectStackBoundaries) + if err != nil { + t.Fatal(err) + } + + if len(got) != len(want) { + t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q", + n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr) + } + + for i := range got { + if strings.ContainsAny(want[i], "\n") { + // Match as stack + match, err := regexp.MatchString(want[i], got[i]) + if err != nil { + t.Fatal(err) + } + if !match { + t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n", + n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want)) + } + } else { + // Match as message + if got[i] != want[i] { + t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i]) + } + } + } +} + +type wrapper struct { + wrap func(err error) error + want []string +} + +func prettyBlocks(blocks []string, prefix ...string) string { + var out []string + + for _, b := range blocks { + out = append(out, fmt.Sprintf("%v", b)) + } + + return " " + strings.Join(out, "\n ") +} + +func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) { + if len(beforeWant) == 0 { + panic("beforeWant must not be empty") + } + for _, w := range list { + if len(w.want) == 0 { + panic("want must not be empty") + } + + err := w.wrap(beforeErr) + + // Copy required cause append(beforeWant, ..) modified beforeWant subtly. + beforeCopy := make([]string, len(beforeWant)) + copy(beforeCopy, beforeWant) + + beforeWant := beforeCopy + last := len(beforeWant) - 1 + var want []string + + // Merge two stacks behind each other. + if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") { + want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...) + } else { + want = append(beforeWant, w.want...) + } + + testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false) + if maxDepth > 0 { + testGenericRecursive(t, err, want, list, maxDepth-1) } } } diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 243a64a2..cbe3f3e3 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -79,6 +79,14 @@ func (f Frame) Format(s fmt.State, verb rune) { // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -100,6 +108,19 @@ func (st StackTrace) Format(s fmt.State, verb rune) { // stack represents a stack of program counters. type stack []uintptr +func (s *stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + func (s *stack) StackTrace() StackTrace { f := make([]Frame, len(*s)) for i := 0; i < len(f); i++ { diff --git a/vendor/github.com/pkg/errors/stack_test.go b/vendor/github.com/pkg/errors/stack_test.go index c0488d53..510c27a9 100644 --- a/vendor/github.com/pkg/errors/stack_test.go +++ b/vendor/github.com/pkg/errors/stack_test.go @@ -120,8 +120,8 @@ func TestFrameFormat(t *testing.T) { "unknown:0", }} - for _, tt := range tests { - testFormatRegexp(t, tt.Frame, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.Frame, tt.format, tt.want) } } @@ -155,15 +155,12 @@ func TestTrimGOPATH(t *testing.T) { "github.com/pkg/errors/stack_test.go", }} - for _, tt := range tests { + for i, 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) - } + testFormatRegexp(t, i, got, "%s", tt.want) } } @@ -174,24 +171,24 @@ func TestStackTrace(t *testing.T) { }{{ New("ooh"), []string{ "github.com/pkg/errors.TestStackTrace\n" + - "\t.+/github.com/pkg/errors/stack_test.go:175", + "\t.+/github.com/pkg/errors/stack_test.go:172", }, }, { Wrap(New("ooh"), "ahh"), []string{ "github.com/pkg/errors.TestStackTrace\n" + - "\t.+/github.com/pkg/errors/stack_test.go:180", // this is the stack of Wrap, not New + "\t.+/github.com/pkg/errors/stack_test.go:177", // 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:185", // this is the stack of New + "\t.+/github.com/pkg/errors/stack_test.go:182", // this is the stack of New }, }, { func() error { return New("ooh") }(), []string{ - `github.com/pkg/errors.(func·005|TestStackTrace.func1)` + - "\n\t.+/github.com/pkg/errors/stack_test.go:190", // this is the stack of New + `github.com/pkg/errors.(func·009|TestStackTrace.func1)` + + "\n\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New "github.com/pkg/errors.TestStackTrace\n" + - "\t.+/github.com/pkg/errors/stack_test.go:190", // this is the stack of New's caller + "\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New's caller }, }, { Cause(func() error { @@ -199,15 +196,15 @@ func TestStackTrace(t *testing.T) { return Errorf("hello %s", fmt.Sprintf("world")) }() }()), []string{ - `github.com/pkg/errors.(func·006|TestStackTrace.func2.1)` + - "\n\t.+/github.com/pkg/errors/stack_test.go:199", // this is the stack of Errorf - `github.com/pkg/errors.(func·007|TestStackTrace.func2)` + - "\n\t.+/github.com/pkg/errors/stack_test.go:200", // this is the stack of Errorf's caller + `github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` + + "\n\t.+/github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf + `github.com/pkg/errors.(func·011|TestStackTrace.func2)` + + "\n\t.+/github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller "github.com/pkg/errors.TestStackTrace\n" + - "\t.+/github.com/pkg/errors/stack_test.go:201", // this is the stack of Errorf's caller's caller + "\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller }, }} - for _, tt := range tests { + for i, tt := range tests { x, ok := tt.err.(interface { StackTrace() StackTrace }) @@ -217,12 +214,12 @@ func TestStackTrace(t *testing.T) { } st := x.StackTrace() for j, want := range tt.want { - testFormatRegexp(t, st[j], "%+v", want) + testFormatRegexp(t, i, st[j], "%+v", want) } } } -func stacktrace() StackTrace { +func stackTrace() StackTrace { const depth = 8 var pcs [depth]uintptr n := runtime.Callers(1, pcs[:]) @@ -268,28 +265,28 @@ func TestStackTraceFormat(t *testing.T) { "%#v", `\[\]errors.Frame{}`, }, { - stacktrace()[:2], + stackTrace()[:2], "%s", `\[stack_test.go stack_test.go\]`, }, { - stacktrace()[:2], + stackTrace()[:2], "%v", - `\[stack_test.go:228 stack_test.go:275\]`, + `\[stack_test.go:225 stack_test.go:272\]`, }, { - stacktrace()[:2], + stackTrace()[:2], "%+v", "\n" + - "github.com/pkg/errors.stacktrace\n" + - "\t.+/github.com/pkg/errors/stack_test.go:228\n" + + "github.com/pkg/errors.stackTrace\n" + + "\t.+/github.com/pkg/errors/stack_test.go:225\n" + "github.com/pkg/errors.TestStackTraceFormat\n" + - "\t.+/github.com/pkg/errors/stack_test.go:279", + "\t.+/github.com/pkg/errors/stack_test.go:276", }, { - stacktrace()[:2], + stackTrace()[:2], "%#v", - `\[\]errors.Frame{stack_test.go:228, stack_test.go:287}`, + `\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`, }} - for _, tt := range tests { - testFormatRegexp(t, tt.StackTrace, tt.format, tt.want) + for i, tt := range tests { + testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want) } }