1
2
3
4
5 package xerrors_test
6
7 import (
8 "fmt"
9 "os"
10 "testing"
11
12 "golang.org/x/xerrors"
13 )
14
15 func TestIs(t *testing.T) {
16 err1 := xerrors.New("1")
17 erra := xerrors.Errorf("wrap 2: %w", err1)
18 errb := xerrors.Errorf("wrap 3: %w", erra)
19 erro := xerrors.Opaque(err1)
20 errco := xerrors.Errorf("opaque: %w", erro)
21 err3 := xerrors.New("3")
22
23 poser := &poser{"either 1 or 3", func(err error) bool {
24 return err == err1 || err == err3
25 }}
26
27 testCases := []struct {
28 err error
29 target error
30 match bool
31 }{
32 {nil, nil, true},
33 {nil, err1, false},
34 {err1, nil, false},
35 {err1, err1, true},
36 {erra, err1, true},
37 {errb, err1, true},
38 {errco, erro, true},
39 {errco, err1, false},
40 {erro, erro, true},
41 {err1, err3, false},
42 {erra, err3, false},
43 {errb, err3, false},
44 {poser, err1, true},
45 {poser, err3, true},
46 {poser, erra, false},
47 {poser, errb, false},
48 {poser, erro, false},
49 {poser, errco, false},
50 {errorUncomparable{}, errorUncomparable{}, true},
51 {errorUncomparable{}, &errorUncomparable{}, false},
52 {&errorUncomparable{}, errorUncomparable{}, true},
53 {&errorUncomparable{}, &errorUncomparable{}, false},
54 {errorUncomparable{}, err1, false},
55 {&errorUncomparable{}, err1, false},
56 }
57 for _, tc := range testCases {
58 t.Run("", func(t *testing.T) {
59 if got := xerrors.Is(tc.err, tc.target); got != tc.match {
60 t.Errorf("Is(%v, %v) = %v, want %v", tc.err, tc.target, got, tc.match)
61 }
62 })
63 }
64 }
65
66 type poser struct {
67 msg string
68 f func(error) bool
69 }
70
71 func (p *poser) Error() string { return p.msg }
72 func (p *poser) Is(err error) bool { return p.f(err) }
73 func (p *poser) As(err interface{}) bool {
74 switch x := err.(type) {
75 case **poser:
76 *x = p
77 case *errorT:
78 *x = errorT{}
79 case **os.PathError:
80 *x = &os.PathError{}
81 default:
82 return false
83 }
84 return true
85 }
86
87 func TestAs(t *testing.T) {
88 var errT errorT
89 var errP *os.PathError
90 var timeout interface{ Timeout() bool }
91 var p *poser
92 _, errF := os.Open("non-existing")
93
94 testCases := []struct {
95 err error
96 target interface{}
97 match bool
98 }{{
99 nil,
100 &errP,
101 false,
102 }, {
103 xerrors.Errorf("pittied the fool: %w", errorT{}),
104 &errT,
105 true,
106 }, {
107 errF,
108 &errP,
109 true,
110 }, {
111 xerrors.Opaque(errT),
112 &errT,
113 false,
114 }, {
115 errorT{},
116 &errP,
117 false,
118 }, {
119 errWrap{nil},
120 &errT,
121 false,
122 }, {
123 &poser{"error", nil},
124 &errT,
125 true,
126 }, {
127 &poser{"path", nil},
128 &errP,
129 true,
130 }, {
131 &poser{"oh no", nil},
132 &p,
133 true,
134 }, {
135 xerrors.New("err"),
136 &timeout,
137 false,
138 }, {
139 errF,
140 &timeout,
141 true,
142 }, {
143 xerrors.Errorf("path error: %w", errF),
144 &timeout,
145 true,
146 }}
147 for i, tc := range testCases {
148 name := fmt.Sprintf("%d:As(Errorf(..., %v), %v)", i, tc.err, tc.target)
149 t.Run(name, func(t *testing.T) {
150 match := xerrors.As(tc.err, tc.target)
151 if match != tc.match {
152 t.Fatalf("xerrors.As(%T, %T): got %v; want %v", tc.err, tc.target, match, tc.match)
153 }
154 if !match {
155 return
156 }
157 if tc.target == nil {
158 t.Fatalf("non-nil result after match")
159 }
160 })
161 }
162 }
163
164 func TestAsValidation(t *testing.T) {
165 var s string
166 testCases := []interface{}{
167 nil,
168 (*int)(nil),
169 "error",
170 &s,
171 }
172 err := xerrors.New("error")
173 for _, tc := range testCases {
174 t.Run(fmt.Sprintf("%T(%v)", tc, tc), func(t *testing.T) {
175 defer func() {
176 recover()
177 }()
178 if xerrors.As(err, tc) {
179 t.Errorf("As(err, %T(%v)) = true, want false", tc, tc)
180 return
181 }
182 t.Errorf("As(err, %T(%v)) did not panic", tc, tc)
183 })
184 }
185 }
186
187 func TestUnwrap(t *testing.T) {
188 err1 := xerrors.New("1")
189 erra := xerrors.Errorf("wrap 2: %w", err1)
190 erro := xerrors.Opaque(err1)
191
192 testCases := []struct {
193 err error
194 want error
195 }{
196 {nil, nil},
197 {errWrap{nil}, nil},
198 {err1, nil},
199 {erra, err1},
200 {xerrors.Errorf("wrap 3: %w", erra), erra},
201
202 {erro, nil},
203 {xerrors.Errorf("opaque: %w", erro), erro},
204 }
205 for _, tc := range testCases {
206 if got := xerrors.Unwrap(tc.err); got != tc.want {
207 t.Errorf("Unwrap(%v) = %v, want %v", tc.err, got, tc.want)
208 }
209 }
210 }
211
212 func TestOpaque(t *testing.T) {
213 got := fmt.Sprintf("%v", xerrors.Errorf("foo: %v", xerrors.Opaque(errorT{})))
214 want := "foo: errorT"
215 if got != want {
216 t.Errorf("error without Format: got %v; want %v", got, want)
217 }
218
219 got = fmt.Sprintf("%v", xerrors.Errorf("foo: %v", xerrors.Opaque(errorD{})))
220 want = "foo: errorD"
221 if got != want {
222 t.Errorf("error with Format: got %v; want %v", got, want)
223 }
224 }
225
226 type errorT struct{}
227
228 func (errorT) Error() string { return "errorT" }
229
230 type errorD struct{}
231
232 func (errorD) Error() string { return "errorD" }
233
234 func (errorD) FormatError(p xerrors.Printer) error {
235 p.Print("errorD")
236 p.Detail()
237 p.Print("detail")
238 return nil
239 }
240
241 type errWrap struct{ error }
242
243 func (errWrap) Error() string { return "wrapped" }
244
245 func (errWrap) Unwrap() error { return nil }
246
247 type errorUncomparable struct {
248 f []string
249 }
250
251 func (errorUncomparable) Error() string {
252 return "uncomparable error"
253 }
254
255 func (errorUncomparable) Is(target error) bool {
256 _, ok := target.(errorUncomparable)
257 return ok
258 }
259
View as plain text