github.com/haraldrudell/parl@v0.4.176/perrors/accessors_test.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package perrors 7 8 import ( 9 "errors" 10 "fmt" 11 "os" 12 "syscall" 13 "testing" 14 15 "github.com/haraldrudell/parl/perrors/errorglue" 16 "golang.org/x/sys/unix" 17 ) 18 19 func TestDumpChain(t *testing.T) { 20 errorMessage := "an error" 21 err := errors.New(errorMessage) 22 err2 := Stack(err) 23 expected := fmt.Sprintf("%T %T", err2, err) 24 actual := errorglue.DumpChain(err2) 25 if actual != expected { 26 t.Errorf("DumpChain: %q expected: %q", actual, expected) 27 } 28 } 29 30 func TestIsWarning(t *testing.T) { 31 err := errors.New("err") 32 w := Warning(err) // mark as warning 33 34 // outermost error is now the stack trace 35 // *errorglue.errorStack *errorglue.WarningType *errors.errorString 36 //t.Error(errorglue.DumpChain(w)) 37 38 actual := IsWarning(w) 39 if !actual { 40 t.Error("IsWarning broken") 41 } 42 } 43 44 func TestIsType(t *testing.T) { 45 var test string 46 expected := "expected" 47 wrongValue := "wrongValue" 48 49 test = "1 err nil" 50 { 51 var e2 error 52 t.Logf("%s", test) 53 if IsType(nil, &e2) { 54 t.Errorf("%s: IsType returned true FAIL", test) 55 } 56 } 57 58 { // value receiver error value 59 err := valueError{s: expected} 60 61 test = "2 value non-match" 62 { 63 err2 := pointerError{s: wrongValue} 64 t.Logf("%s", test) 65 if IsType(err, &err2) { 66 t.Errorf("%s: IsType returned true FAIL", test) 67 } 68 } 69 70 test = "3 value match" 71 { 72 err2 := valueError{s: wrongValue} 73 t.Logf("%s", test) 74 if !IsType(err, &err2) { 75 t.Errorf("%s: IsType returned false FAIL", test) 76 } 77 if err2.Error() != expected { 78 t.Errorf("%s: value not updated FAIL %#v exp: %q", test, err2, expected) 79 } 80 } 81 } 82 83 { // value receiver error pointer 84 err := &valueError{s: expected} 85 86 test = "4 value pointer non-match" 87 { 88 err2 := pointerError{s: wrongValue} 89 t.Logf("%s", test) 90 if IsType(err, &err2) { 91 t.Errorf("%s: IsType returned true FAIL", test) 92 } 93 } 94 95 test = "5 value pointer match" 96 { 97 err2 := valueError{s: wrongValue} 98 t.Logf("%s", test) 99 if !IsType(err, &err2) { 100 t.Errorf("%s: IsType returned false FAIL", test) 101 } 102 if err2.Error() != expected { 103 t.Errorf("%s: value not updated FAIL %q exp: %q", test, err2.Error(), expected) 104 } 105 } 106 } 107 108 { // pointer receiver 109 err := &pointerError{s: expected} 110 111 test = "6 pointer non-match" 112 { // non-match 113 err2 := valueError{s: wrongValue} 114 t.Logf("%s", test) 115 if IsType(err, &err2) { 116 t.Errorf("%s: IsType returned true FAIL", test) 117 } 118 } 119 120 test = "7 pointer match" 121 { 122 err2 := pointerError{s: wrongValue} 123 t.Logf("%s", test) 124 if !IsType(err, &err2) { 125 t.Errorf("%s: IsType returned false FAIL", test) 126 } 127 if err2.Error() != expected { 128 t.Errorf("%s: value not updated FAIL %q exp: %q", test, err2.Error(), expected) 129 } 130 } 131 } 132 } 133 134 func TestIsTypeErrno(t *testing.T) { 135 136 // an error implementation with value receiver 137 var err0 error = syscall.ENOENT 138 var err error = fmt.Errorf("error: %w", err0) 139 var actual bool 140 var err2 syscall.Errno 141 142 actual = IsType(err, &err2) 143 if !actual { 144 t.Errorf("errno: IsType returned false FAIL") 145 } 146 if err2 != err0 { 147 t.Errorf("errno: IsType returned wrong value FAIL") 148 } 149 } 150 func TestIsTypeSyscall(t *testing.T) { 151 expected := "expected" 152 153 // an error implementation with pointer receiver 154 err0 := os.NewSyscallError(expected, errors.New(expected)) 155 err := fmt.Errorf("error: %w", err0) 156 // pointer error implementation requires the star 157 var err3 *os.SyscallError 158 actual := IsType(err, &err3) 159 if !actual { 160 t.Errorf("syscall: IsType returned false FAIL") 161 } 162 if err3 == nil { 163 t.Errorf("syscall: IsType returned err3 nil FAIL") 164 } 165 if err3 != err0 { 166 t.Errorf("syscall: IsType returned wrong value %#v exp: %q#v FAIL", err3, err0) 167 } 168 } 169 170 type valueError struct{ s string } 171 172 func (er valueError) Error() string { return er.s } 173 174 type pointerError struct{ s string } 175 176 func (er *pointerError) Error() string { return er.s } 177 178 func TestIsError(t *testing.T) { 179 180 // err nil 181 var err error 182 if IsError(err) { 183 t.Error("error(nil): true") 184 } 185 186 // err non-nil 187 if !IsError(errors.New("x")) { 188 t.Error("errors.New: false") 189 } 190 191 // Errno 0 192 if IsError(unix.Errno(0)) { 193 t.Error("unix.Errno(0): true") 194 } 195 196 // Errno non-0 197 if !IsError(unix.EPERM) { 198 t.Error("unix.EPERM: false") 199 } 200 201 //t.Fail() 202 } 203 204 func TestErrorDataMap(t *testing.T) { 205 k1 := "k1" 206 v1 := "s1" 207 k2 := "k2" 208 v2 := "s2" 209 e1error := "e1" 210 211 var expectedInt int 212 213 e1 := errors.New(e1error) 214 e2 := errorglue.NewErrorData(e1, k1, v1) 215 e3 := errorglue.NewErrorData(e2, k2, v2) 216 strs, values := eErrorData(e3) 217 expectedInt = len(strs) 218 if expectedInt > 0 { 219 t.Errorf("slice has unexpected values: %d", expectedInt) 220 } 221 if len(values) != 2 || values[k1] != v1 || values[k2] != v2 { 222 t.Errorf("bad map: %#v expected: %#v", values, map[string]string{k1: v1, k2: v2}) 223 } 224 } 225 226 func TestErrorDataSlice(t *testing.T) { 227 s1 := "s1" 228 s2 := "s2" 229 e1error := "e1" 230 231 var expectedInt int 232 233 e1 := errors.New(e1error) 234 e2 := errorglue.NewErrorData(e1, "", s1) 235 e3 := errorglue.NewErrorData(e2, "", s2) 236 strs, values := eErrorData(e3) 237 expectedInt = len(values) 238 if expectedInt > 0 { 239 t.Errorf("map has unexpected values: %d", expectedInt) 240 } 241 if len(strs) != 2 || strs[0] != s1 || strs[1] != s2 { 242 t.Errorf("bad slice: %#v expected: %#v", strs, []string{s1, s2}) 243 } 244 } 245 246 func eErrorData(err error) (list []string, keyValues map[string]string) { 247 for err != nil { 248 if e, ok := err.(errorglue.ErrorHasData); ok { 249 key, value := e.KeyValue() 250 if key == "" { // for the slice 251 list = append([]string{value}, list...) 252 } else { // for the map 253 if keyValues == nil { 254 keyValues = map[string]string{key: value} 255 } else if _, ok := keyValues[key]; !ok { 256 keyValues[key] = value 257 } 258 } 259 } 260 err = errors.Unwrap(err) 261 } 262 return 263 }