lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/xerr/xerr_test.go (about) 1 // Copyright (C) 2016-2018 Nexedi SA and Contributors. 2 // Kirill Smelkov <kirr@nexedi.com> 3 // 4 // This program is free software: you can Use, Study, Modify and Redistribute 5 // it under the terms of the GNU General Public License version 3, or (at your 6 // option) any later version, as published by the Free Software Foundation. 7 // 8 // You can also Link and Combine this program with other software covered by 9 // the terms of any of the Free Software licenses or any of the Open Source 10 // Initiative approved licenses and Convey the resulting work. Corresponding 11 // source of such a combination shall include the source code for all other 12 // software used. 13 // 14 // This program is distributed WITHOUT ANY WARRANTY; without even the implied 15 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 // 17 // See COPYING file for full licensing terms. 18 // See https://www.nexedi.com/licensing for rationale and options. 19 20 package xerr 21 22 import ( 23 "errors" 24 "io" 25 "reflect" 26 "testing" 27 28 pkgerrors "github.com/pkg/errors" 29 ) 30 31 func TestErrorv(t *testing.T) { 32 var errv Errorv 33 34 // check verifies that: 35 // 1. errv.Err() == aserr 36 // 2. errv.Error() == errmsg 37 check := func(aserr error, errmsg string) { 38 err := errv.Err() 39 // cannot use err != aserr as Errorv is not generally comparable (it is a slice) 40 if !reflect.DeepEqual(err, aserr) { 41 t.Fatalf("%#v: Err() -> %#v ; want %#v", errv, err, aserr) 42 } 43 msg := errv.Error() 44 if msg != errmsg { 45 t.Fatalf("%#v: Error() -> %q ; want %q", errv, msg, errmsg) 46 } 47 } 48 49 check(nil, "") 50 51 err1 := errors.New("err1") 52 err2 := errors.New("err2") 53 54 errv.Append(err1) 55 check(err1, "err1") 56 57 errv.Appendif(nil) 58 check(err1, "err1") 59 60 errv.Appendif(err2) 61 check(errv, 62 `2 errors: 63 - err1 64 - err2 65 `) 66 67 errv.Appendf("err3 %q", "hello world") 68 check(errv, 69 `3 errors: 70 - err1 71 - err2 72 - err3 "hello world" 73 `) 74 75 // since Errorv is a slice it cannot be generally compared - for 76 // example comparing 2 error interfaces that both have dynamic type 77 // Errorv will panic. However it is possible to compare Errorv to other 78 // types, because interfaces with different dynamic types are always 79 // not equal. 80 eqcheck := func(a, b error, expect bool) { 81 t.Helper() 82 eq := (a == b) 83 ne := (a != b) 84 if eq != expect { 85 t.Fatalf("%#v == %#v -> %v; want %v", a, b, eq, expect) 86 } 87 if ne != !expect { 88 t.Fatalf("%#v != %#v -> %v; want %v", a, b, ne, !expect) 89 } 90 } 91 92 eqcheck(err1, nil, false) 93 eqcheck(err1, err1, true) 94 eqcheck(errv, nil, false) 95 eqcheck(errv, err1, false) 96 eqcheck(errv, io.EOF, false) 97 98 // check Errorv == Errorv panics. 99 func() { 100 defer func() { 101 if r := recover(); r == nil { 102 t.Fatal("Errorv == Errorv -> not paniced") 103 } 104 }() 105 106 eqcheck(errv, errv, true) 107 }() 108 } 109 110 func TestMerge(t *testing.T) { 111 e := errors.New("e") 112 e2 := errors.New("e2") 113 114 testv := []struct { 115 in []error 116 out error 117 }{ 118 {nil, nil}, 119 {[]error{}, nil}, 120 {[]error{nil}, nil}, 121 {[]error{nil, nil}, nil}, 122 {[]error{e}, e}, 123 {[]error{e, nil}, e}, 124 {[]error{nil, e}, e}, 125 {[]error{nil, e, nil}, e}, 126 {[]error{nil, e, e2}, Errorv{e, e2}}, 127 {[]error{nil, e2, e}, Errorv{e2, e}}, 128 {[]error{nil, e2, nil, e}, Errorv{e2, e}}, 129 {[]error{nil, e2, nil, e, nil}, Errorv{e2, e}}, 130 } 131 132 for _, tt := range testv { 133 err := Merge(tt.in...) 134 //if err != tt.out { 135 // XXX Errorv is uncomparable because it is [] 136 if !reflect.DeepEqual(err, tt.out) { 137 t.Errorf("Merge(%v) -> %v ; want %v", tt.in, err, tt.out) 138 } 139 } 140 } 141 142 func TestFirst(t *testing.T) { 143 e := errors.New("e") 144 e2 := errors.New("e2") 145 146 testv := []struct { 147 in []error 148 out error 149 }{ 150 {nil, nil}, 151 {[]error{}, nil}, 152 {[]error{nil}, nil}, 153 {[]error{nil, nil}, nil}, 154 {[]error{e}, e}, 155 {[]error{e, nil}, e}, 156 {[]error{nil, e}, e}, 157 {[]error{nil, e, nil}, e}, 158 {[]error{nil, e, e2}, e}, 159 {[]error{nil, e2, e}, e2}, 160 } 161 162 for _, tt := range testv { 163 err := First(tt.in...) 164 if err != tt.out { 165 t.Errorf("First(%v) -> %v ; want %v", tt.in, err, tt.out) 166 } 167 } 168 } 169 170 func TestContext(t *testing.T) { 171 test := func(e error) (err error) { 172 defer Context(&err, "test ctx") 173 return e 174 } 175 176 testf := func(e error) (err error) { 177 defer Contextf(&err, "testf ctx %d %q", 123, "hello") 178 return e 179 } 180 181 if test(nil) != nil { 182 t.Error("Context(nil) -> !nil") 183 } 184 if testf(nil) != nil { 185 t.Error("Contextf(nil) -> !nil") 186 } 187 188 err := errors.New("an error") 189 190 e := test(err) 191 want := "test ctx: an error" 192 if !(e != nil && e.Error() == want) { 193 t.Errorf("Context(%v) -> %v ; want %v", err, e, want) 194 } 195 if ec := pkgerrors.Cause(e); ec != err { 196 t.Errorf("Context(%v) -> %v -> cause %v ; want %v", err, e, ec, err) 197 } 198 199 e = testf(err) 200 want = `testf ctx 123 "hello": an error` 201 if !(e != nil && e.Error() == want) { 202 t.Errorf("Contextf(%v) -> %v ; want %v", err, e, want) 203 } 204 if ec := pkgerrors.Cause(e); ec != err { 205 t.Errorf("Contextf(%v) -> %v -> cause %v ; want %v", err, e, ec, err) 206 } 207 }