github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/errors/wrap_test.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package errors_test 6 7 import ( 8 "errors" 9 "fmt" 10 "io/fs" 11 "os" 12 "reflect" 13 "testing" 14 ) 15 16 func TestIs(t *testing.T) { 17 err1 := errors.New("1") 18 erra := wrapped{"wrap 2", err1} 19 errb := wrapped{"wrap 3", erra} 20 21 err3 := errors.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 {err1, nil, false}, 34 {err1, err1, true}, 35 {erra, err1, true}, 36 {errb, err1, true}, 37 {err1, err3, false}, 38 {erra, err3, false}, 39 {errb, err3, false}, 40 {poser, err1, true}, 41 {poser, err3, true}, 42 {poser, erra, false}, 43 {poser, errb, false}, 44 {errorUncomparable{}, errorUncomparable{}, true}, 45 {errorUncomparable{}, &errorUncomparable{}, false}, 46 {&errorUncomparable{}, errorUncomparable{}, true}, 47 {&errorUncomparable{}, &errorUncomparable{}, false}, 48 {errorUncomparable{}, err1, false}, 49 {&errorUncomparable{}, err1, false}, 50 } 51 for _, tc := range testCases { 52 t.Run("", func(t *testing.T) { 53 if got := errors.Is(tc.err, tc.target); got != tc.match { 54 t.Errorf("Is(%v, %v) = %v, want %v", tc.err, tc.target, got, tc.match) 55 } 56 }) 57 } 58 } 59 60 type poser struct { 61 msg string 62 f func(error) bool 63 } 64 65 var poserPathErr = &fs.PathError{Op: "poser"} 66 67 func (p *poser) Error() string { return p.msg } 68 func (p *poser) Is(err error) bool { return p.f(err) } 69 func (p *poser) As(err interface{}) bool { 70 switch x := err.(type) { 71 case **poser: 72 *x = p 73 case *errorT: 74 *x = errorT{"poser"} 75 case **fs.PathError: 76 *x = poserPathErr 77 default: 78 return false 79 } 80 return true 81 } 82 83 func TestAs(t *testing.T) { 84 var errT errorT 85 var errP *fs.PathError 86 var timeout interface{ Timeout() bool } 87 var p *poser 88 _, errF := os.Open("non-existing") 89 poserErr := &poser{"oh no", nil} 90 91 testCases := []struct { 92 err error 93 target interface{} 94 match bool 95 want interface{} // value of target on match 96 }{{ 97 nil, 98 &errP, 99 false, 100 nil, 101 }, { 102 wrapped{"pitied the fool", errorT{"T"}}, 103 &errT, 104 true, 105 errorT{"T"}, 106 }, { 107 errF, 108 &errP, 109 true, 110 errF, 111 }, { 112 errorT{}, 113 &errP, 114 false, 115 nil, 116 }, { 117 wrapped{"wrapped", nil}, 118 &errT, 119 false, 120 nil, 121 }, { 122 &poser{"error", nil}, 123 &errT, 124 true, 125 errorT{"poser"}, 126 }, { 127 &poser{"path", nil}, 128 &errP, 129 true, 130 poserPathErr, 131 }, { 132 poserErr, 133 &p, 134 true, 135 poserErr, 136 }, { 137 errors.New("err"), 138 &timeout, 139 false, 140 nil, 141 }, { 142 errF, 143 &timeout, 144 true, 145 errF, 146 }, { 147 wrapped{"path error", errF}, 148 &timeout, 149 true, 150 errF, 151 }} 152 for i, tc := range testCases { 153 name := fmt.Sprintf("%d:As(Errorf(..., %v), %v)", i, tc.err, tc.target) 154 // Clear the target pointer, in case it was set in a previous test. 155 rtarget := reflect.ValueOf(tc.target) 156 rtarget.Elem().Set(reflect.Zero(reflect.TypeOf(tc.target).Elem())) 157 t.Run(name, func(t *testing.T) { 158 match := errors.As(tc.err, tc.target) 159 if match != tc.match { 160 t.Fatalf("match: got %v; want %v", match, tc.match) 161 } 162 if !match { 163 return 164 } 165 if got := rtarget.Elem().Interface(); got != tc.want { 166 t.Fatalf("got %#v, want %#v", got, tc.want) 167 } 168 }) 169 } 170 } 171 172 func TestAsValidation(t *testing.T) { 173 var s string 174 testCases := []interface{}{ 175 nil, 176 (*int)(nil), 177 "error", 178 &s, 179 } 180 err := errors.New("error") 181 for _, tc := range testCases { 182 t.Run(fmt.Sprintf("%T(%v)", tc, tc), func(t *testing.T) { 183 defer func() { 184 recover() 185 }() 186 if errors.As(err, tc) { 187 t.Errorf("As(err, %T(%v)) = true, want false", tc, tc) 188 return 189 } 190 t.Errorf("As(err, %T(%v)) did not panic", tc, tc) 191 }) 192 } 193 } 194 195 func TestUnwrap(t *testing.T) { 196 err1 := errors.New("1") 197 erra := wrapped{"wrap 2", err1} 198 199 testCases := []struct { 200 err error 201 want error 202 }{ 203 {nil, nil}, 204 {wrapped{"wrapped", nil}, nil}, 205 {err1, nil}, 206 {erra, err1}, 207 {wrapped{"wrap 3", erra}, erra}, 208 } 209 for _, tc := range testCases { 210 if got := errors.Unwrap(tc.err); got != tc.want { 211 t.Errorf("Unwrap(%v) = %v, want %v", tc.err, got, tc.want) 212 } 213 } 214 } 215 216 type errorT struct{ s string } 217 218 func (e errorT) Error() string { return fmt.Sprintf("errorT(%s)", e.s) } 219 220 type wrapped struct { 221 msg string 222 err error 223 } 224 225 func (e wrapped) Error() string { return e.msg } 226 227 func (e wrapped) Unwrap() error { return e.err } 228 229 type errorUncomparable struct { 230 f []string 231 } 232 233 func (errorUncomparable) Error() string { 234 return "uncomparable error" 235 } 236 237 func (errorUncomparable) Is(target error) bool { 238 _, ok := target.(errorUncomparable) 239 return ok 240 } 241 242 func ExampleIs() { 243 if _, err := os.Open("non-existing"); err != nil { 244 if errors.Is(err, fs.ErrNotExist) { 245 fmt.Println("file does not exist") 246 } else { 247 fmt.Println(err) 248 } 249 } 250 251 // Output: 252 // file does not exist 253 } 254 255 func ExampleAs() { 256 if _, err := os.Open("non-existing"); err != nil { 257 var pathError *fs.PathError 258 if errors.As(err, &pathError) { 259 fmt.Println("Failed at path:", pathError.Path) 260 } else { 261 fmt.Println(err) 262 } 263 } 264 265 // Output: 266 // Failed at path: non-existing 267 }