From 90ce1bc984979e06d0fe8055bc391de1cda4970f Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 17 Jun 2022 13:14:06 +0800 Subject: [PATCH] x/errors: Summary --- errors/errors.go | 66 ++++++++++++++++++++++++++++++++++++++++-------- errors_test.go | 19 ++++++++++++++ 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/errors/errors.go b/errors/errors.go index 025bc24..5a93db8 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -43,8 +43,20 @@ func Err(err error) error { return err } +// Summary returns summary of specified error. +func Summary(err error) string { + e, ok := err.(interface { + Summary() string + }) + if !ok { + return err.Error() + } + return e.Summary() +} + // -------------------------------------------------------------------- +// NotFound is a generic NotFound error. type NotFound struct { Category string } @@ -74,27 +86,57 @@ func (p *List) Add(err error) { } func (p List) Error() string { - switch len(p) { - case 1: - return p[0].Error() - case 0: - return "" - default: - s := make([]string, len(p)) + n := len(p) + if n >= 2 { + s := make([]string, n) for i, v := range p { s[i] = v.Error() } return strings.Join(s, "\n") } + if n == 1 { + return p[0].Error() + } + return "" +} + +func (p List) Summary() string { + n := len(p) + if n >= 2 { + s := make([]string, n) + for i, v := range p { + s[i] = Summary(v) + } + return strings.Join(s, "\n") + } + if n == 1 { + return Summary(p[0]) + } + return "" } func (p List) ToError() error { - if len(p) == 0 { + switch len(p) { + case 1: + return p[0] + case 0: return nil } return p } +// Format is required by fmt.Formatter +func (p List) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + io.WriteString(s, p.Error()) + case 's': + io.WriteString(s, p.Summary()) + case 'q': + fmt.Fprintf(s, "%q", p.Error()) + } +} + // -------------------------------------------------------------------- // Frame represents an error frame. @@ -127,6 +169,10 @@ func (p *Frame) Error() string { return string(errorDetail(make([]byte, 0, 32), p)) } +func (p *Frame) Summary() string { + return Summary(p.Err) +} + func errorDetail(b []byte, p *Frame) []byte { if f, ok := p.Err.(*Frame); ok { b = errorDetail(b, f) @@ -196,9 +242,9 @@ func (p *Frame) Format(s fmt.State, verb rune) { case 'v': io.WriteString(s, p.Error()) case 's': - io.WriteString(s, Err(p.Err).Error()) + io.WriteString(s, p.Summary()) case 'q': - fmt.Fprintf(s, "%q", Err(p.Err).Error()) + fmt.Fprintf(s, "%q", p.Error()) } } diff --git a/errors_test.go b/errors_test.go index 458b130..96b15ef 100644 --- a/errors_test.go +++ b/errors_test.go @@ -17,6 +17,7 @@ package x_test import ( + "fmt" "strings" "syscall" "testing" @@ -40,4 +41,22 @@ func TestNewWith(t *testing.T) { } } +func TestErrList(t *testing.T) { + err1 := errors.New("error 1") + err2 := errors.New("error 2") + e1 := errors.NewWith(err1, ``, -2, "errors.New", "error 1") + e2 := errors.NewWith(err2, ``, -2, "errors.New", "error 2") + e := errors.List{e1, e2} + if v := fmt.Sprintf("%q", e); v != fmt.Sprintf("%q", e.Error()) { + t.Fatal(v) + } + if v := fmt.Sprintf("%v", e); v != fmt.Sprintf("%v", e.Error()) { + t.Fatal(v) + } + if v := fmt.Sprintf("%s", e); v != `error 1 +error 2` { + t.Fatal(v) + } +} + // --------------------------------------------------------------------