From 69e8329b20325ed86d55e2ac402c63a36e9164d6 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 00:50:25 +0800 Subject: [PATCH 01/12] feat: support std errors functions add function `Is`, `As` and `Unwrap`, like std errors, so that we can continue to use pkg/errors with go1.13 compatibility Signed-off-by: Sherlock Holo --- .gitignore | 2 + .travis.yml | 1 + errors.go | 21 ++++---- go.mod | 5 ++ go.sum | 2 + go113.go | 25 +++++++++ go113_test.go | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ goold.go | 25 +++++++++ goold_test.go | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ stack.go | 26 +++++----- 10 files changed, 365 insertions(+), 22 deletions(-) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 go113.go create mode 100644 go113_test.go create mode 100644 goold.go create mode 100644 goold_test.go diff --git a/.gitignore b/.gitignore index daf913b..11b90db 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ _testmain.go *.exe *.test *.prof + +.idea diff --git a/.travis.yml b/.travis.yml index d2dfad4..1212a09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ go: - 1.10.x - 1.11.x - 1.12.x + - 1.13.x - tip script: diff --git a/errors.go b/errors.go index 8617bee..1668a37 100644 --- a/errors.go +++ b/errors.go @@ -128,15 +128,15 @@ func (f *fundamental) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { - io.WriteString(s, f.msg) + _, _ = io.WriteString(s, f.msg) f.stack.Format(s, verb) return } fallthrough case 's': - io.WriteString(s, f.msg) + _, _ = io.WriteString(s, f.msg) case 'q': - fmt.Fprintf(s, "%q", f.msg) + _, _ = fmt.Fprintf(s, "%q", f.msg) } } @@ -159,19 +159,21 @@ type withStack struct { func (w *withStack) Cause() error { return w.error } +func (w *withStack) Unwrap() error { return w.error } + func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { - fmt.Fprintf(s, "%+v", w.Cause()) + _, _ = fmt.Fprintf(s, "%+v", w.Cause()) w.stack.Format(s, verb) return } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': - fmt.Fprintf(s, "%q", w.Error()) + _, _ = fmt.Fprintf(s, "%q", w.Error()) } } @@ -240,18 +242,19 @@ type withMessage struct { func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } +func (w *withMessage) Unwrap() 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) + _, _ = fmt.Fprintf(s, "%+v\n", w.Cause()) + _, _ = io.WriteString(s, w.msg) return } fallthrough case 's', 'q': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) } } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f157643 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/pkg/errors + +go 1.13 + +require golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..78d447d --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go113.go b/go113.go new file mode 100644 index 0000000..b2c2829 --- /dev/null +++ b/go113.go @@ -0,0 +1,25 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +func Is(err, target error) bool { + // std errors use internal reflect to optimize performance, + // we can we use it. + return stderrors.Is(err, target) +} + +func As(err error, target interface{}) bool { + // std errors use internal reflect to optimize performance, + // we can we use it. + return stderrors.As(err, target) +} + +func Unwrap(err error) error { + // std errors use internal reflect to optimize performance, + // we can we use it. + return stderrors.Unwrap(err) +} diff --git a/go113_test.go b/go113_test.go new file mode 100644 index 0000000..862be44 --- /dev/null +++ b/go113_test.go @@ -0,0 +1,140 @@ +// +build go1.13 + +package errors + +import ( + "reflect" + "testing" +) + +func TestIs(t *testing.T) { + err := New("test") + + type args struct { + err error + target error + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: err, + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: err, + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: err, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Is(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("Is() = %v, want %v", got, tt.want) + } + }) + } +} + +type customErr struct{} + +func (customErr) Error() string { return "" } + +func TestAs(t *testing.T) { + var err customErr + + type args struct { + err error + target interface{} + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: new(customErr), + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: new(customErr), + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: new(customErr), + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := As(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("As() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUnwrap(t *testing.T) { + err := New("test") + + type args struct { + err error + } + tests := []struct { + name string + args args + want error + }{ + { + name: "with stack", + args: args{err: WithStack(err)}, + want: err, + }, + { + name: "with message", + args: args{err: WithMessage(err, "test")}, + want: err, + }, + { + name: "with message format", + args: args{err: WithMessagef(err, "%s", "test")}, + want: err, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { + t.Errorf("Unwrap() error = %v, want %v", err, tt.want) + } + }) + } +} diff --git a/goold.go b/goold.go new file mode 100644 index 0000000..0c43ade --- /dev/null +++ b/goold.go @@ -0,0 +1,25 @@ +// +build !go1.13 + +package errors + +import ( + "golang.org/x/xerrors" +) + +func Is(err, target error) bool { + // std errors use internal reflect to optimize performance, + // we can we use it. + return xerrors.Is(er, target) +} + +func As(err error, target interface{}) bool { + // std errors use internal reflect to optimize performance, + // we can we use it. + return xerrors.As(err, target) +} + +func Unwrap(err error) error { + // std errors use internal reflect to optimize performance, + // we can we use it. + return xerrors.Unwrap(err) +} diff --git a/goold_test.go b/goold_test.go new file mode 100644 index 0000000..e248fef --- /dev/null +++ b/goold_test.go @@ -0,0 +1,140 @@ +// +build !go1.13 + +package errors + +import ( + "reflect" + "testing" +) + +func TestIs(t *testing.T) { + err := New("test") + + type args struct { + err error + target error + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: err, + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: err, + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: err, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Is(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("Is() = %v, want %v", got, tt.want) + } + }) + } +} + +type customErr struct{} + +func (customErr) Error() string { return "" } + +func TestAs(t *testing.T) { + var err customErr + + type args struct { + err error + target interface{} + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: new(customErr), + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: new(customErr), + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: new(customErr), + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := As(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("As() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUnwrap(t *testing.T) { + err := New("test") + + type args struct { + err error + } + tests := []struct { + name string + args args + want error + }{ + { + name: "with stack", + args: args{err: WithStack(err)}, + want: err, + }, + { + name: "with message", + args: args{err: WithMessage(err, "test")}, + want: err, + }, + { + name: "with message format", + args: args{err: WithMessagef(err, "%s", "test")}, + want: err, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { + t.Errorf("Unwrap() error = %v, want %v", err, tt.want) + } + }) + } +} diff --git a/stack.go b/stack.go index 779a834..a4050d6 100644 --- a/stack.go +++ b/stack.go @@ -66,19 +66,19 @@ func (f Frame) Format(s fmt.State, verb rune) { case 's': switch { case s.Flag('+'): - io.WriteString(s, f.name()) - io.WriteString(s, "\n\t") - io.WriteString(s, f.file()) + _, _ = io.WriteString(s, f.name()) + _, _ = io.WriteString(s, "\n\t") + _, _ = io.WriteString(s, f.file()) default: - io.WriteString(s, path.Base(f.file())) + _, _ = io.WriteString(s, path.Base(f.file())) } case 'd': - io.WriteString(s, strconv.Itoa(f.line())) + _, _ = io.WriteString(s, strconv.Itoa(f.line())) case 'n': - io.WriteString(s, funcname(f.name())) + _, _ = io.WriteString(s, funcname(f.name())) case 'v': f.Format(s, 's') - io.WriteString(s, ":") + _, _ = io.WriteString(s, ":") f.Format(s, 'd') } } @@ -110,11 +110,11 @@ func (st StackTrace) Format(s fmt.State, verb rune) { switch { case s.Flag('+'): for _, f := range st { - io.WriteString(s, "\n") + _, _ = io.WriteString(s, "\n") f.Format(s, verb) } case s.Flag('#'): - fmt.Fprintf(s, "%#v", []Frame(st)) + _, _ = fmt.Fprintf(s, "%#v", []Frame(st)) default: st.formatSlice(s, verb) } @@ -126,14 +126,14 @@ func (st StackTrace) Format(s fmt.State, verb rune) { // formatSlice will format this StackTrace into the given buffer as a slice of // Frame, only valid when called with '%s' or '%v'. func (st StackTrace) formatSlice(s fmt.State, verb rune) { - io.WriteString(s, "[") + _, _ = io.WriteString(s, "[") for i, f := range st { if i > 0 { - io.WriteString(s, " ") + _, _ = io.WriteString(s, " ") } f.Format(s, verb) } - io.WriteString(s, "]") + _, _ = io.WriteString(s, "]") } // stack represents a stack of program counters. @@ -146,7 +146,7 @@ func (s *stack) Format(st fmt.State, verb rune) { case st.Flag('+'): for _, pc := range *s { f := Frame(pc) - fmt.Fprintf(st, "\n%+v", f) + _, _ = fmt.Fprintf(st, "\n%+v", f) } } } From 55262813e432b8f9cbd2058fb7fd3b93af46e0a8 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 00:56:32 +0800 Subject: [PATCH 02/12] style: delete useless comments Signed-off-by: Sherlock Holo --- goold.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/goold.go b/goold.go index 0c43ade..9d8f256 100644 --- a/goold.go +++ b/goold.go @@ -7,19 +7,13 @@ import ( ) func Is(err, target error) bool { - // std errors use internal reflect to optimize performance, - // we can we use it. return xerrors.Is(er, target) } func As(err error, target interface{}) bool { - // std errors use internal reflect to optimize performance, - // we can we use it. return xerrors.As(err, target) } func Unwrap(err error) error { - // std errors use internal reflect to optimize performance, - // we can we use it. return xerrors.Unwrap(err) } From 227a7b40069074087d293a588edc87b218edd7ac Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 00:59:21 +0800 Subject: [PATCH 03/12] build: update makefile update makefile to download dependencies before test anything Signed-off-by: Sherlock Holo --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ce9d7cd..26362ed 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ PKGS := github.com/pkg/errors SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS)) GO := go -check: test vet gofmt misspell unconvert staticcheck ineffassign unparam +check: mod test vet gofmt misspell unconvert staticcheck ineffassign unparam + +mod: + $(GO) mod download test: $(GO) test $(PKGS) From 9c503b9331a38ae60ef377447f75f044b5c74317 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 01:10:23 +0800 Subject: [PATCH 04/12] build: fix makefile Signed-off-by: Sherlock Holo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 26362ed..d1caf87 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ GO := go check: mod test vet gofmt misspell unconvert staticcheck ineffassign unparam mod: - $(GO) mod download + $(GO) mod download test: $(GO) test $(PKGS) From 34b42fb1806aa98c1edb34b5f2feb322182f4afd Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 23:51:54 +0800 Subject: [PATCH 05/12] chore: delete useless comments Signed-off-by: Sherlock Holo --- go113.go | 18 +++--------------- goold.go | 12 +++--------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/go113.go b/go113.go index b2c2829..109a618 100644 --- a/go113.go +++ b/go113.go @@ -6,20 +6,8 @@ import ( stderrors "errors" ) -func Is(err, target error) bool { - // std errors use internal reflect to optimize performance, - // we can we use it. - return stderrors.Is(err, target) -} +func Is(err, target error) bool { return stderrors.Is(err, target) } -func As(err error, target interface{}) bool { - // std errors use internal reflect to optimize performance, - // we can we use it. - return stderrors.As(err, target) -} +func As(err error, target interface{}) bool { return stderrors.As(err, target) } -func Unwrap(err error) error { - // std errors use internal reflect to optimize performance, - // we can we use it. - return stderrors.Unwrap(err) -} +func Unwrap(err error) error { return stderrors.Unwrap(err) } diff --git a/goold.go b/goold.go index 9d8f256..7120e49 100644 --- a/goold.go +++ b/goold.go @@ -6,14 +6,8 @@ import ( "golang.org/x/xerrors" ) -func Is(err, target error) bool { - return xerrors.Is(er, target) -} +func Is(err, target error) bool { return xerrors.Is(er, target) } -func As(err error, target interface{}) bool { - return xerrors.As(err, target) -} +func As(err error, target interface{}) bool { return xerrors.As(err, target) } -func Unwrap(err error) error { - return xerrors.Unwrap(err) -} +func Unwrap(err error) error { return xerrors.Unwrap(err) } From 057b7e23c1177014ca6d7f249af9971e81fc6f88 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Mon, 4 Nov 2019 23:55:54 +0800 Subject: [PATCH 06/12] Restore Makefile --- Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile b/Makefile index d1caf87..ce9d7cd 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,7 @@ PKGS := github.com/pkg/errors SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS)) GO := go -check: mod test vet gofmt misspell unconvert staticcheck ineffassign unparam - -mod: - $(GO) mod download +check: test vet gofmt misspell unconvert staticcheck ineffassign unparam test: $(GO) test $(PKGS) From d9389f6bbd4cc2d8faba039a30e3071031876441 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Fri, 8 Nov 2019 00:21:26 +0800 Subject: [PATCH 07/12] revert: revert some change some change are doing by PR #206 and #212 , so I don't need to do it Signed-off-by: Sherlock Holo --- .gitignore | 2 -- .travis.yml | 1 - errors.go | 21 +++++++++------------ go.mod | 5 ----- go.sum | 2 -- stack.go | 26 +++++++++++++------------- 6 files changed, 22 insertions(+), 35 deletions(-) delete mode 100644 go.mod delete mode 100644 go.sum diff --git a/.gitignore b/.gitignore index 11b90db..daf913b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,3 @@ _testmain.go *.exe *.test *.prof - -.idea diff --git a/.travis.yml b/.travis.yml index 1212a09..d2dfad4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ go: - 1.10.x - 1.11.x - 1.12.x - - 1.13.x - tip script: diff --git a/errors.go b/errors.go index 1668a37..8617bee 100644 --- a/errors.go +++ b/errors.go @@ -128,15 +128,15 @@ func (f *fundamental) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { - _, _ = io.WriteString(s, f.msg) + io.WriteString(s, f.msg) f.stack.Format(s, verb) return } fallthrough case 's': - _, _ = io.WriteString(s, f.msg) + io.WriteString(s, f.msg) case 'q': - _, _ = fmt.Fprintf(s, "%q", f.msg) + fmt.Fprintf(s, "%q", f.msg) } } @@ -159,21 +159,19 @@ type withStack struct { func (w *withStack) Cause() error { return w.error } -func (w *withStack) Unwrap() error { return w.error } - func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': if s.Flag('+') { - _, _ = fmt.Fprintf(s, "%+v", w.Cause()) + fmt.Fprintf(s, "%+v", w.Cause()) w.stack.Format(s, verb) return } fallthrough case 's': - _, _ = io.WriteString(s, w.Error()) + io.WriteString(s, w.Error()) case 'q': - _, _ = fmt.Fprintf(s, "%q", w.Error()) + fmt.Fprintf(s, "%q", w.Error()) } } @@ -242,19 +240,18 @@ type withMessage struct { func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } -func (w *withMessage) Unwrap() 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) + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) return } fallthrough case 's', 'q': - _, _ = io.WriteString(s, w.Error()) + io.WriteString(s, w.Error()) } } diff --git a/go.mod b/go.mod deleted file mode 100644 index f157643..0000000 --- a/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/pkg/errors - -go 1.13 - -require golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 diff --git a/go.sum b/go.sum deleted file mode 100644 index 78d447d..0000000 --- a/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/stack.go b/stack.go index a4050d6..779a834 100644 --- a/stack.go +++ b/stack.go @@ -66,19 +66,19 @@ func (f Frame) Format(s fmt.State, verb rune) { case 's': switch { case s.Flag('+'): - _, _ = io.WriteString(s, f.name()) - _, _ = io.WriteString(s, "\n\t") - _, _ = io.WriteString(s, f.file()) + io.WriteString(s, f.name()) + io.WriteString(s, "\n\t") + io.WriteString(s, f.file()) default: - _, _ = io.WriteString(s, path.Base(f.file())) + io.WriteString(s, path.Base(f.file())) } case 'd': - _, _ = io.WriteString(s, strconv.Itoa(f.line())) + io.WriteString(s, strconv.Itoa(f.line())) case 'n': - _, _ = io.WriteString(s, funcname(f.name())) + io.WriteString(s, funcname(f.name())) case 'v': f.Format(s, 's') - _, _ = io.WriteString(s, ":") + io.WriteString(s, ":") f.Format(s, 'd') } } @@ -110,11 +110,11 @@ func (st StackTrace) Format(s fmt.State, verb rune) { switch { case s.Flag('+'): for _, f := range st { - _, _ = io.WriteString(s, "\n") + io.WriteString(s, "\n") f.Format(s, verb) } case s.Flag('#'): - _, _ = fmt.Fprintf(s, "%#v", []Frame(st)) + fmt.Fprintf(s, "%#v", []Frame(st)) default: st.formatSlice(s, verb) } @@ -126,14 +126,14 @@ func (st StackTrace) Format(s fmt.State, verb rune) { // formatSlice will format this StackTrace into the given buffer as a slice of // Frame, only valid when called with '%s' or '%v'. func (st StackTrace) formatSlice(s fmt.State, verb rune) { - _, _ = io.WriteString(s, "[") + io.WriteString(s, "[") for i, f := range st { if i > 0 { - _, _ = io.WriteString(s, " ") + io.WriteString(s, " ") } f.Format(s, verb) } - _, _ = io.WriteString(s, "]") + io.WriteString(s, "]") } // stack represents a stack of program counters. @@ -146,7 +146,7 @@ func (s *stack) Format(st fmt.State, verb rune) { case st.Flag('+'): for _, pc := range *s { f := Frame(pc) - _, _ = fmt.Fprintf(st, "\n%+v", f) + fmt.Fprintf(st, "\n%+v", f) } } } From d0d34df53f460d3580a71d3654434326c9bc08a8 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Sat, 9 Nov 2019 20:28:16 +0800 Subject: [PATCH 08/12] test: add more check for As unit test Signed-off-by: Sherlock Holo --- go113_test.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/go113_test.go b/go113_test.go index 827461a..b6659af 100644 --- a/go113_test.go +++ b/go113_test.go @@ -60,12 +60,14 @@ func TestIs(t *testing.T) { } } -type customErr struct{} +type customErr struct { + msg string +} -func (customErr) Error() string { return "" } +func (c customErr) Error() string { return c.msg } func TestAs(t *testing.T) { - var err customErr + var err = customErr{msg: "test message"} type args struct { err error @@ -106,6 +108,11 @@ func TestAs(t *testing.T) { if got := As(tt.args.err, tt.args.target); got != tt.want { t.Errorf("As() = %v, want %v", got, tt.want) } + + ce := tt.args.target.(*customErr) + if !reflect.DeepEqual(err, *ce) { + t.Errorf("set target error failed, target error is %v", *ce) + } }) } } From 487ff7b92a2ddd1292a4fd431d3095b48cafeda3 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Sat, 9 Nov 2019 21:27:27 +0800 Subject: [PATCH 09/12] revert: only support Is As Unwrap for >=go1.13 Signed-off-by: Sherlock Holo --- go113_test.go | 8 +++++--- goold.go | 13 ------------- 2 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 goold.go diff --git a/go113_test.go b/go113_test.go index b6659af..acff816 100644 --- a/go113_test.go +++ b/go113_test.go @@ -1,15 +1,17 @@ +// +build go1.13 + package errors import ( - stdlib_errors "errors" + stderrors "errors" "reflect" "testing" ) func TestErrorChainCompat(t *testing.T) { - err := stdlib_errors.New("error that gets wrapped") + err := stderrors.New("error that gets wrapped") wrapped := Wrap(err, "wrapped up") - if !stdlib_errors.Is(wrapped, err) { + if !stderrors.Is(wrapped, err) { t.Errorf("Wrap does not support Go 1.13 error chains") } } diff --git a/goold.go b/goold.go deleted file mode 100644 index 7120e49..0000000 --- a/goold.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !go1.13 - -package errors - -import ( - "golang.org/x/xerrors" -) - -func Is(err, target error) bool { return xerrors.Is(er, target) } - -func As(err error, target interface{}) bool { return xerrors.As(err, target) } - -func Unwrap(err error) error { return xerrors.Unwrap(err) } From e473c5d60bb7bde1ca714c1535f496acb65da698 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Wed, 13 Nov 2019 00:09:53 +0800 Subject: [PATCH 10/12] feat(Unwrap): allow --- errors.go | 10 ++++++++++ errors_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ go113.go | 22 ++++++++++++++++++++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/errors.go b/errors.go index 161aea2..dac454b 100644 --- a/errors.go +++ b/errors.go @@ -286,3 +286,13 @@ func Cause(err error) error { } return err } + +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/errors_test.go b/errors_test.go index 2089b2f..0fe7f76 100644 --- a/errors_test.go +++ b/errors_test.go @@ -249,3 +249,44 @@ func TestErrorEquality(t *testing.T) { } } } + +func TestUnwrap(t *testing.T) { + err := New("test") + + type args struct { + err error + } + tests := []struct { + name string + args args + want error + }{ + { + name: "with stack", + args: args{err: WithStack(err)}, + want: err, + }, + { + name: "with message", + args: args{err: WithMessage(err, "test")}, + want: err, + }, + { + name: "with message format", + args: args{err: WithMessagef(err, "%s", "test")}, + want: err, + }, + { + name: "std errors compatibility", + args: args{err: fmt.Errorf("wrap: %w", err)}, + want: err, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { + t.Errorf("Unwrap() error = %v, want %v", err, tt.want) + } + }) + } +} diff --git a/go113.go b/go113.go index 109a618..6577d79 100644 --- a/go113.go +++ b/go113.go @@ -6,8 +6,26 @@ import ( stderrors "errors" ) +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. func Is(err, target error) bool { return stderrors.Is(err, target) } +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. func As(err error, target interface{}) bool { return stderrors.As(err, target) } - -func Unwrap(err error) error { return stderrors.Unwrap(err) } From bd678d4951e8a65d92d2d95ecb5477306f9aabba Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Wed, 13 Nov 2019 00:10:53 +0800 Subject: [PATCH 11/12] test: add go1.13 errors compatibility check Signed-off-by: Sherlock Holo --- go113_test.go | 53 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/go113_test.go b/go113_test.go index acff816..e062b0a 100644 --- a/go113_test.go +++ b/go113_test.go @@ -4,6 +4,7 @@ package errors import ( stderrors "errors" + "fmt" "reflect" "testing" ) @@ -52,6 +53,14 @@ func TestIs(t *testing.T) { }, want: true, }, + { + name: "std errors compatibility", + args: args{ + err: fmt.Errorf("wrap it: %w", err), + target: err, + }, + want: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -104,6 +113,14 @@ func TestAs(t *testing.T) { }, want: true, }, + { + name: "std errors compatibility", + args: args{ + err: fmt.Errorf("wrap it: %w", err), + target: new(customErr), + }, + want: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -118,39 +135,3 @@ func TestAs(t *testing.T) { }) } } - -func TestUnwrap(t *testing.T) { - err := New("test") - - type args struct { - err error - } - tests := []struct { - name string - args args - want error - }{ - { - name: "with stack", - args: args{err: WithStack(err)}, - want: err, - }, - { - name: "with message", - args: args{err: WithMessage(err, "test")}, - want: err, - }, - { - name: "with message format", - args: args{err: WithMessagef(err, "%s", "test")}, - want: err, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { - t.Errorf("Unwrap() error = %v, want %v", err, tt.want) - } - }) - } -} From 613b81c88de6a510b8390722583460dde50c308c Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Wed, 13 Nov 2019 01:01:57 +0800 Subject: [PATCH 12/12] refactor(Unwrap): don't allow --- errors.go | 10 ---------- errors_test.go | 41 ----------------------------------------- go113.go | 7 +++++++ go113_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/errors.go b/errors.go index dac454b..161aea2 100644 --- a/errors.go +++ b/errors.go @@ -286,13 +286,3 @@ func Cause(err error) error { } return err } - -func Unwrap(err error) error { - u, ok := err.(interface { - Unwrap() error - }) - if !ok { - return nil - } - return u.Unwrap() -} diff --git a/errors_test.go b/errors_test.go index 0fe7f76..2089b2f 100644 --- a/errors_test.go +++ b/errors_test.go @@ -249,44 +249,3 @@ func TestErrorEquality(t *testing.T) { } } } - -func TestUnwrap(t *testing.T) { - err := New("test") - - type args struct { - err error - } - tests := []struct { - name string - args args - want error - }{ - { - name: "with stack", - args: args{err: WithStack(err)}, - want: err, - }, - { - name: "with message", - args: args{err: WithMessage(err, "test")}, - want: err, - }, - { - name: "with message format", - args: args{err: WithMessagef(err, "%s", "test")}, - want: err, - }, - { - name: "std errors compatibility", - args: args{err: fmt.Errorf("wrap: %w", err)}, - want: err, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { - t.Errorf("Unwrap() error = %v, want %v", err, tt.want) - } - }) - } -} diff --git a/go113.go b/go113.go index 6577d79..be0d10d 100644 --- a/go113.go +++ b/go113.go @@ -29,3 +29,10 @@ func Is(err, target error) bool { return stderrors.Is(err, target) } // As will panic if target is not a non-nil pointer to either a type that implements // error, or to any interface type. As returns false if err is nil. func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/go113_test.go b/go113_test.go index e062b0a..4ea37e6 100644 --- a/go113_test.go +++ b/go113_test.go @@ -135,3 +135,44 @@ func TestAs(t *testing.T) { }) } } + +func TestUnwrap(t *testing.T) { + err := New("test") + + type args struct { + err error + } + tests := []struct { + name string + args args + want error + }{ + { + name: "with stack", + args: args{err: WithStack(err)}, + want: err, + }, + { + name: "with message", + args: args{err: WithMessage(err, "test")}, + want: err, + }, + { + name: "with message format", + args: args{err: WithMessagef(err, "%s", "test")}, + want: err, + }, + { + name: "std errors compatibility", + args: args{err: fmt.Errorf("wrap: %w", err)}, + want: err, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { + t.Errorf("Unwrap() error = %v, want %v", err, tt.want) + } + }) + } +}