Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.

Commit 6d954f5

Browse files
Sherlock-Holoaperezg
authored andcommitted
feat: support std errors functions (#213)
* 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 <[email protected]> * style: delete useless comments Signed-off-by: Sherlock Holo <[email protected]> * build: update makefile update makefile to download dependencies before test anything Signed-off-by: Sherlock Holo <[email protected]> * build: fix makefile Signed-off-by: Sherlock Holo <[email protected]> * chore: delete useless comments Signed-off-by: Sherlock Holo <[email protected]> * Restore Makefile * 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 <[email protected]> * test: add more check for As unit test Signed-off-by: Sherlock Holo <[email protected]> * revert: only support Is As Unwrap for >=go1.13 Signed-off-by: Sherlock Holo <[email protected]> * feat(Unwrap): allow <go1.13 can use Unwrap `Unwrap` just use type assert, it doesn't need go1.13 actually Signed-off-by: Sherlock Holo <[email protected]> * test: add go1.13 errors compatibility check Signed-off-by: Sherlock Holo <[email protected]> * refactor(Unwrap): don't allow <go1.13 use Unwrap If we implement Unwrap ourselves, may create a risk of incompatibility if Go 1.14 subtly changes its `Unwrap` implementation. <go1.13 users doesn't have `Is` or `As`, if they want, they will use xerrors and it also provides `Unwrap` Signed-off-by: Sherlock Holo <[email protected]>
1 parent 7f95ac1 commit 6d954f5

File tree

2 files changed

+203
-3
lines changed

2 files changed

+203
-3
lines changed

go113.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// +build go1.13
2+
3+
package errors
4+
5+
import (
6+
stderrors "errors"
7+
)
8+
9+
// Is reports whether any error in err's chain matches target.
10+
//
11+
// The chain consists of err itself followed by the sequence of errors obtained by
12+
// repeatedly calling Unwrap.
13+
//
14+
// An error is considered to match a target if it is equal to that target or if
15+
// it implements a method Is(error) bool such that Is(target) returns true.
16+
func Is(err, target error) bool { return stderrors.Is(err, target) }
17+
18+
// As finds the first error in err's chain that matches target, and if so, sets
19+
// target to that error value and returns true.
20+
//
21+
// The chain consists of err itself followed by the sequence of errors obtained by
22+
// repeatedly calling Unwrap.
23+
//
24+
// An error matches target if the error's concrete value is assignable to the value
25+
// pointed to by target, or if the error has a method As(interface{}) bool such that
26+
// As(target) returns true. In the latter case, the As method is responsible for
27+
// setting target.
28+
//
29+
// As will panic if target is not a non-nil pointer to either a type that implements
30+
// error, or to any interface type. As returns false if err is nil.
31+
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
32+
33+
// Unwrap returns the result of calling the Unwrap method on err, if err's
34+
// type contains an Unwrap method returning error.
35+
// Otherwise, Unwrap returns nil.
36+
func Unwrap(err error) error {
37+
return stderrors.Unwrap(err)
38+
}

go113_test.go

Lines changed: 165 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,176 @@
33
package errors
44

55
import (
6-
stdlib_errors "errors"
6+
stderrors "errors"
7+
"fmt"
8+
"reflect"
79
"testing"
810
)
911

1012
func TestErrorChainCompat(t *testing.T) {
11-
err := stdlib_errors.New("error that gets wrapped")
13+
err := stderrors.New("error that gets wrapped")
1214
wrapped := Wrap(err, "wrapped up")
13-
if !stdlib_errors.Is(wrapped, err) {
15+
if !stderrors.Is(wrapped, err) {
1416
t.Errorf("Wrap does not support Go 1.13 error chains")
1517
}
1618
}
19+
20+
func TestIs(t *testing.T) {
21+
err := New("test")
22+
23+
type args struct {
24+
err error
25+
target error
26+
}
27+
tests := []struct {
28+
name string
29+
args args
30+
want bool
31+
}{
32+
{
33+
name: "with stack",
34+
args: args{
35+
err: WithStack(err),
36+
target: err,
37+
},
38+
want: true,
39+
},
40+
{
41+
name: "with message",
42+
args: args{
43+
err: WithMessage(err, "test"),
44+
target: err,
45+
},
46+
want: true,
47+
},
48+
{
49+
name: "with message format",
50+
args: args{
51+
err: WithMessagef(err, "%s", "test"),
52+
target: err,
53+
},
54+
want: true,
55+
},
56+
{
57+
name: "std errors compatibility",
58+
args: args{
59+
err: fmt.Errorf("wrap it: %w", err),
60+
target: err,
61+
},
62+
want: true,
63+
},
64+
}
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
if got := Is(tt.args.err, tt.args.target); got != tt.want {
68+
t.Errorf("Is() = %v, want %v", got, tt.want)
69+
}
70+
})
71+
}
72+
}
73+
74+
type customErr struct {
75+
msg string
76+
}
77+
78+
func (c customErr) Error() string { return c.msg }
79+
80+
func TestAs(t *testing.T) {
81+
var err = customErr{msg: "test message"}
82+
83+
type args struct {
84+
err error
85+
target interface{}
86+
}
87+
tests := []struct {
88+
name string
89+
args args
90+
want bool
91+
}{
92+
{
93+
name: "with stack",
94+
args: args{
95+
err: WithStack(err),
96+
target: new(customErr),
97+
},
98+
want: true,
99+
},
100+
{
101+
name: "with message",
102+
args: args{
103+
err: WithMessage(err, "test"),
104+
target: new(customErr),
105+
},
106+
want: true,
107+
},
108+
{
109+
name: "with message format",
110+
args: args{
111+
err: WithMessagef(err, "%s", "test"),
112+
target: new(customErr),
113+
},
114+
want: true,
115+
},
116+
{
117+
name: "std errors compatibility",
118+
args: args{
119+
err: fmt.Errorf("wrap it: %w", err),
120+
target: new(customErr),
121+
},
122+
want: true,
123+
},
124+
}
125+
for _, tt := range tests {
126+
t.Run(tt.name, func(t *testing.T) {
127+
if got := As(tt.args.err, tt.args.target); got != tt.want {
128+
t.Errorf("As() = %v, want %v", got, tt.want)
129+
}
130+
131+
ce := tt.args.target.(*customErr)
132+
if !reflect.DeepEqual(err, *ce) {
133+
t.Errorf("set target error failed, target error is %v", *ce)
134+
}
135+
})
136+
}
137+
}
138+
139+
func TestUnwrap(t *testing.T) {
140+
err := New("test")
141+
142+
type args struct {
143+
err error
144+
}
145+
tests := []struct {
146+
name string
147+
args args
148+
want error
149+
}{
150+
{
151+
name: "with stack",
152+
args: args{err: WithStack(err)},
153+
want: err,
154+
},
155+
{
156+
name: "with message",
157+
args: args{err: WithMessage(err, "test")},
158+
want: err,
159+
},
160+
{
161+
name: "with message format",
162+
args: args{err: WithMessagef(err, "%s", "test")},
163+
want: err,
164+
},
165+
{
166+
name: "std errors compatibility",
167+
args: args{err: fmt.Errorf("wrap: %w", err)},
168+
want: err,
169+
},
170+
}
171+
for _, tt := range tests {
172+
t.Run(tt.name, func(t *testing.T) {
173+
if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) {
174+
t.Errorf("Unwrap() error = %v, want %v", err, tt.want)
175+
}
176+
})
177+
}
178+
}

0 commit comments

Comments
 (0)