diff --git a/errors.go b/errors.go index 449658b..cf009f3 100644 --- a/errors.go +++ b/errors.go @@ -92,6 +92,37 @@ func (p *Error) Error() string { return output.String() } +func (p *Error) Format(f fmt.State, verb rune) { + var s string + + switch verb { + case 's', 'v': + if f.Flag('+') { + s = p.VerboseString() + } else if f.Flag('#') { + s = p.GoString() + } else { + s = p.Error() + } + } + + if s == "" { + fmt.Fprint(f, p) + } else { + _, _ = f.Write([]byte(s)) + } +} + +func (p *Error) GoString() string { + isRetryable := "nil" + if p.IsRetryable != nil { + isRetryable = fmt.Sprintf("%#v", *p.IsRetryable) + } + return fmt.Sprintf("&terrors.Error{Code: %q, Message: %q, Params: %#v, StackFrames: %#v, IsRetryable: %s, cause: %#v}", + p.Code, p.Message, p.Params, p.StackFrames, isRetryable, p.cause, + ) +} + func (p *Error) legacyErrString() string { if p == nil { return "" diff --git a/errors_test.go b/errors_test.go index 9d5d534..d3a0dfb 100644 --- a/errors_test.go +++ b/errors_test.go @@ -481,3 +481,22 @@ func TestRetryable(t *testing.T) { }) } } + +func TestFormat(t *testing.T) { + err := New("test", "Test", map[string]string{"flavour": "banana"}) + + assert.Equal(t, err.Error(), + fmt.Sprintf("%v", err)) + assert.Equal(t, err.VerboseString(), + fmt.Sprintf("%+v", err)) + + goStringErr := fmt.Sprintf("%#v", err) + goStringErrPrefix := `&terrors.Error{Code: "test", Message: "Test", Params: map[string]string{"flavour":"banana"}, StackFrames: []*stack.Frame{` + assert.Equal(t, goStringErrPrefix, goStringErr[0:len(goStringErrPrefix)]) + + goStringErrSuffix := `}, IsRetryable: false, cause: }` + assert.Equal(t, goStringErrSuffix, goStringErr[len(goStringErr)-len(goStringErrSuffix):]) + + assert.Equal(t, err.Error(), + fmt.Sprintf("%d", err)) +} diff --git a/stack/stack.go b/stack/stack.go index 0d9a9e8..6535199 100644 --- a/stack/stack.go +++ b/stack/stack.go @@ -27,6 +27,19 @@ type Frame struct { type Stack []*Frame +func (s Stack) GoString() string { + b := strings.Builder{} + + if len(s) > 0 { + b.WriteString(fmt.Sprintf("&%#v", *s[0])) + for _, f := range s[1:] { + b.WriteString(fmt.Sprintf(", &%#v", *f)) + } + } + + return fmt.Sprintf("[]*stack.Frame{%s}", b.String()) +} + func BuildStack(skip int) Stack { stack := make(Stack, 0)