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