github.com/storacha/go-ucanto@v0.7.2/core/result/result_test.go (about) 1 package result_test 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 "github.com/storacha/go-ucanto/core/result" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestMatchResult(t *testing.T) { 13 t.Run("MatchResultR0", func(t *testing.T) { 14 testMatchResultR0(t, "ok (int)", result.Ok[int, any](5), true, false) 15 testMatchResultR0(t, "ok (string)", result.Ok[string, any]("apple"), true, false) 16 testMatchResultR0(t, "err (error)", result.Error[int](errors.New("bad")), false, true) 17 }) 18 t.Run("MatchResultR1", func(t *testing.T) { 19 testMatchResultR1(t, "ok (int)", 20 result.Ok[int, any](5), 21 func(o int) int { return o * 2 }, 22 func(x any) int { return 0 }, 23 10) 24 testMatchResultR1(t, "ok (string)", 25 result.Ok[string, any]("apple"), 26 func(o string) string { return o + " tree" }, 27 func(x any) string { return "nothing" }, 28 "apple tree") 29 testMatchResultR1(t, "err (error)", 30 result.Error[int](errors.New("bad")), 31 func(o int) string { return "" }, 32 func(x error) string { return x.Error() }, 33 "bad") 34 }) 35 t.Run("MatchResultR2", func(t *testing.T) { 36 testMatchResultR2(t, "ok (int)", 37 result.Ok[int, any](5), 38 func(o int) (int, int) { return o * 2, o * 3 }, 39 func(x any) (int, int) { return 0, 0 }, 40 10, 15) 41 testMatchResultR2(t, "ok (string)", 42 result.Ok[string, any]("apple"), 43 func(o string) (string, int) { return o + " tree", len(o) }, 44 func(x any) (string, int) { return "nothing", 0 }, 45 "apple tree", 5) 46 testMatchResultR2(t, "err (error)", 47 result.Error[int](errors.New("bad")), 48 func(o int) (string, error) { return "", nil }, 49 func(x error) (string, error) { return x.Error(), fmt.Errorf("something: %w", x) }, 50 "bad", fmt.Errorf("something: %w", errors.New("bad"))) 51 }) 52 53 t.Run("MatchResultR2", func(t *testing.T) { 54 testMatchResultR3(t, "ok (int)", 55 result.Ok[int, any](5), 56 func(o int) (int, int, int) { return o * 2, o * 3, o * 4 }, 57 func(x any) (int, int, int) { return 0, 0, 0 }, 58 10, 15, 20) 59 testMatchResultR3(t, "ok (string)", 60 result.Ok[string, any]("apple"), 61 func(o string) (string, int, string) { return o + " tree", len(o), o + " cart" }, 62 func(x any) (string, int, string) { return "nothing", 0, "nothing" }, 63 "apple tree", 5, "apple cart") 64 testMatchResultR3(t, "err (error)", 65 result.Error[int](errors.New("bad")), 66 func(o int) (string, error, int) { return "", nil, 0 }, 67 func(x error) (string, error, int) { return x.Error(), fmt.Errorf("something: %w", x), len(x.Error()) }, 68 "bad", fmt.Errorf("something: %w", errors.New("bad")), 3) 69 }) 70 } 71 72 func TestMap(t *testing.T) { 73 t.Run("MapOk", func(t *testing.T) { 74 testMapOk(t, "ok (int)", result.Ok[int, error](5), func(o int) int { return o * 2 }, result.Ok[int, error](10)) 75 testMapOk(t, "ok (string)", 76 result.Ok[string, error]("apple"), 77 func(o string) int { return len(o) }, 78 result.Ok[int, error](5)) 79 testMapOk(t, "err (int)", 80 result.Error[int](errors.New("bad")), 81 func(o int) int { return o * 2 }, 82 result.Error[int](errors.New("bad"))) 83 testMapOk(t, "err (string)", 84 result.Error[string](errors.New("bad")), 85 func(o string) int { return len(o) }, 86 result.Error[int](errors.New("bad"))) 87 }) 88 t.Run("MapError", func(t *testing.T) { 89 testMapErr(t, "ok (int)", 90 result.Ok[int, error](5), 91 func(e error) error { return fmt.Errorf("something: %w", e) }, 92 result.Ok[int, error](5)) 93 testMapErr(t, "ok (string)", 94 result.Ok[string, error]("apple"), 95 func(e error) string { return e.Error() }, 96 result.Ok[string, string]("apple")) 97 testMapErr(t, "err (int)", 98 result.Error[int](errors.New("bad")), 99 func(e error) error { return fmt.Errorf("something: %w", e) }, 100 result.Error[int](fmt.Errorf("something: %w", errors.New("bad")))) 101 testMapErr(t, "err (string)", 102 result.Error[string](errors.New("bad")), 103 func(e error) string { return e.Error() }, 104 result.Error[string]("bad")) 105 }) 106 t.Run("MapResult", func(t *testing.T) { 107 testMapResult(t, "ok (int)", 108 result.Ok[int, error](5), 109 func(o int) int { return o * 2 }, 110 func(e error) error { return fmt.Errorf("something: %w", e) }, 111 result.Ok[int, error](10)) 112 testMapResult(t, "ok (string)", 113 result.Ok[string, error]("apple"), 114 func(o string) int { return len(o) }, 115 func(e error) string { return e.Error() }, 116 result.Ok[int, string](5)) 117 testMapResult(t, "err (int)", 118 result.Error[int](errors.New("bad")), 119 func(o int) int { return o * 2 }, 120 func(e error) error { return fmt.Errorf("something: %w", e) }, 121 result.Error[int](fmt.Errorf("something: %w", errors.New("bad")))) 122 testMapResult(t, "err (string)", 123 result.Error[string](errors.New("bad")), 124 func(o string) int { return len(o) }, 125 func(e error) string { return e.Error() }, 126 result.Error[int]("bad")) 127 }) 128 129 t.Run("MapResult", func(t *testing.T) { 130 testMapResultR1(t, "ok (int)", 131 result.Ok[int, error](5), 132 func(o int) (int, error) { return o * 2, nil }, 133 func(e error) (error, error) { return fmt.Errorf("something: %w", e), errors.New("very") }, 134 result.Ok[int, error](10), nil) 135 testMapResultR1(t, "ok (string)", 136 result.Ok[string, error]("apple"), 137 func(o string) (int, string) { return len(o), o + " tree" }, 138 func(e error) (string, string) { return e.Error(), fmt.Errorf("something: %w", e).Error() }, 139 result.Ok[int, string](5), "apple tree") 140 testMapResultR1(t, "err (int)", 141 result.Error[int](errors.New("bad")), 142 func(o int) (int, error) { return o * 2, nil }, 143 func(e error) (error, error) { return fmt.Errorf("something: %w", e), errors.New("very") }, 144 result.Error[int](fmt.Errorf("something: %w", errors.New("bad"))), errors.New("very")) 145 testMapResultR1(t, "err (string)", 146 result.Error[string](errors.New("bad")), 147 func(o string) (int, string) { return len(o), o + " tree" }, 148 func(e error) (string, string) { return e.Error(), fmt.Errorf("something: %w", e).Error() }, 149 result.Error[int]("bad"), "something: bad") 150 }) 151 } 152 153 func TestWrap(t *testing.T) { 154 require.Equal(t, 155 result.Ok[int, error](5), 156 result.Wrap(func() (int, error) { return 5, nil }), 157 "int (no error)") 158 require.Equal(t, 159 result.Error[int](errors.New("bad")), 160 result.Wrap(func() (int, error) { return 0, errors.New("bad") }), 161 "int (error)") 162 require.Equal(t, 163 result.Ok[string, error]("apple"), 164 result.Wrap(func() (string, error) { return "apple", nil }), 165 "string (no error)") 166 require.Equal(t, 167 result.Error[string](errors.New("bad")), 168 result.Wrap(func() (string, error) { return "", errors.New("bad") }), 169 "string (error present)") 170 } 171 172 func TestWrapUnwrap(t *testing.T) { 173 val, err := result.Unwrap(result.Wrap(func() (int, error) { return 5, nil })) 174 require.Equal(t, 5, val, "int (no error)") 175 require.NoError(t, err, "int (no error)") 176 val, err = result.Unwrap(result.Wrap(func() (int, error) { return 0, errors.New("bad") })) 177 require.EqualError(t, err, "bad", "int (error)") 178 require.Equal(t, 0, val, "int (error)") 179 str, err := result.Unwrap(result.Wrap(func() (string, error) { return "apple", nil })) 180 require.Equal(t, "apple", str, "string (no error)") 181 require.NoError(t, err, "string (no error)") 182 str, err = result.Unwrap(result.Wrap(func() (string, error) { return "", errors.New("bad") })) 183 require.EqualError(t, err, "bad", "string (error)") 184 require.Equal(t, "", str, "string (error)") 185 } 186 187 func TestAndOr(t *testing.T) { 188 t.Run("And", func(t *testing.T) { 189 testAnd(t, "O - int, O2 - string, X - error (no error)", 190 result.Ok[int, error](10), 191 result.Ok[string, error]("apple"), 192 result.Ok[string, error]("apple")) 193 testAnd(t, "O - int, O2 - string, X - error (first error)", 194 result.Error[int](errors.New("bad")), 195 result.Ok[string, error]("apple"), 196 result.Error[string](errors.New("bad"))) 197 testAnd(t, "O - int, O2 - string, X - error (second error)", 198 result.Ok[int, error](10), 199 result.Error[string](errors.New("very bad")), 200 result.Error[string](errors.New("very bad"))) 201 testAnd(t, "O - int, O2 - string, X - error (both error)", 202 result.Error[int](errors.New("bad")), 203 result.Error[string](errors.New("very bad")), 204 result.Error[string](errors.New("bad"))) 205 }) 206 207 t.Run("Or", func(t *testing.T) { 208 testOr(t, "O - int, X - error, X2 - string (no error)", 209 result.Ok[int, error](10), 210 result.Ok[int, string](5), 211 result.Ok[int, string](10)) 212 testOr(t, "O - int, X - error, X2 - string (first error)", 213 result.Error[int](errors.New("bad")), 214 result.Ok[int, string](5), 215 result.Ok[int, string](5)) 216 testOr(t, "O - int, X - error, X2 - string (second error)", 217 result.Ok[int, error](10), 218 result.Error[int]("very bad"), 219 result.Ok[int, string](10)) 220 testOr(t, "O - int, X - error, X2 - string (both error)", 221 result.Error[int](errors.New("bad")), 222 result.Error[int]("very bad"), 223 result.Error[int]("very bad")) 224 }) 225 226 t.Run("AndThen", func(t *testing.T) { 227 testAndThen(t, "O - int, O2 - string, X - error (ok, () -> ok)", 228 result.Ok[int, error](10), 229 func(x int) result.Result[string, error] { 230 return result.Ok[string, error](fmt.Sprintf("%d", x)) 231 }, 232 result.Ok[string, error]("10")) 233 testAndThen(t, "O - int, O2 - string, X - error (err, () -> ok)", 234 result.Error[int](errors.New("bad")), 235 func(x int) result.Result[string, error] { 236 return result.Ok[string, error](fmt.Sprintf("%d", x)) 237 }, 238 result.Error[string](errors.New("bad"))) 239 testAndThen(t, "O - int, O2 - string, X - error (ok, () -> err)", 240 result.Ok[int, error](10), 241 func(x int) result.Result[string, error] { 242 return result.Error[string](fmt.Errorf("%d", x)) 243 }, 244 result.Error[string](fmt.Errorf("10"))) 245 testAndThen(t, "O - int, O2 - string, X - error (err, () -> err)", 246 result.Error[int](errors.New("bad")), 247 func(x int) result.Result[string, error] { 248 return result.Error[string](fmt.Errorf("%d", x)) 249 }, 250 result.Error[string](errors.New("bad"))) 251 }) 252 t.Run("OrElse", func(t *testing.T) { 253 testOrElse(t, "O - int, X - error, X2 - string (ok, () -> ok)", 254 result.Ok[int, error](10), 255 func(e error) result.Result[int, string] { 256 return result.Ok[int, string](len(e.Error())) 257 }, 258 result.Ok[int, string](10)) 259 testOrElse(t, "O - int, X - error, X2 - string (err, () -> ok)", 260 result.Error[int](errors.New("bad")), 261 func(e error) result.Result[int, string] { 262 return result.Ok[int, string](len(e.Error())) 263 }, 264 result.Ok[int, string](3)) 265 testOrElse(t, "O - int, X - error, X2 - string (ok, () -> err)", 266 result.Ok[int, error](10), 267 func(e error) result.Result[int, string] { 268 return result.Error[int](e.Error()) 269 }, 270 result.Ok[int, string](10)) 271 testOrElse(t, "O - int, X - error, X2 - string (err, () -> err)", 272 result.Error[int](errors.New("bad")), 273 func(e error) result.Result[int, string] { 274 return result.Error[int](e.Error()) 275 }, 276 result.Error[int]("bad")) 277 }) 278 } 279 func testMatchResultR0[X, O any](t *testing.T, testCase string, testResult result.Result[O, X], expOk bool, expErr bool) { 280 t.Run(testCase, func(t *testing.T) { 281 var okCalled, errCalled bool 282 result.MatchResultR0(testResult, func(_ O) { 283 okCalled = true 284 }, func(_ X) { 285 errCalled = true 286 }) 287 require.Equal(t, expOk, okCalled) 288 require.Equal(t, expErr, errCalled) 289 }) 290 } 291 292 func testMatchResultR1[X, O, R1 any](t *testing.T, testCase string, testResult result.Result[O, X], onOk func(O) R1, onErr func(X) R1, expR1 R1) { 293 t.Run(testCase, func(t *testing.T) { 294 r1 := result.MatchResultR1(testResult, onOk, onErr) 295 require.Equal(t, expR1, r1) 296 }) 297 } 298 299 func testMatchResultR2[X, O, R1, R2 any](t *testing.T, testCase string, testResult result.Result[O, X], onOk func(O) (R1, R2), onErr func(X) (R1, R2), expR1 R1, expR2 R2) { 300 t.Run(testCase, func(t *testing.T) { 301 r1, r2 := result.MatchResultR2(testResult, onOk, onErr) 302 require.Equal(t, expR1, r1) 303 require.Equal(t, expR2, r2) 304 }) 305 } 306 307 func testMatchResultR3[X, O, R1, R2, R3 any]( 308 t *testing.T, 309 testCase string, 310 testResult result.Result[O, X], 311 onOk func(O) (R1, R2, R3), 312 onErr func(X) (R1, R2, R3), 313 expR1 R1, 314 expR2 R2, 315 expR3 R3, 316 ) { 317 t.Run(testCase, func(t *testing.T) { 318 r1, r2, r3 := result.MatchResultR3(testResult, onOk, onErr) 319 require.Equal(t, expR1, r1) 320 require.Equal(t, expR2, r2) 321 require.Equal(t, expR3, r3) 322 }) 323 } 324 325 func testMapOk[O, O2, X any](t *testing.T, 326 testCase string, 327 testResult result.Result[O, X], 328 mapFn func(O) O2, 329 expResult result.Result[O2, X]) { 330 t.Run(testCase, func(t *testing.T) { 331 result := result.MapOk(testResult, mapFn) 332 require.Equal(t, expResult, result) 333 }) 334 } 335 336 func testMapErr[O, X, X2 any](t *testing.T, 337 testCase string, 338 testResult result.Result[O, X], 339 mapFn func(X) X2, 340 expResult result.Result[O, X2]) { 341 t.Run(testCase, func(t *testing.T) { 342 result := result.MapError(testResult, mapFn) 343 require.Equal(t, expResult, result) 344 }) 345 } 346 347 func testMapResult[O, O2, X, X2 any](t *testing.T, 348 testCase string, 349 testResult result.Result[O, X], 350 mapOk func(O) O2, 351 mapErr func(X) X2, 352 expResult result.Result[O2, X2]) { 353 t.Run(testCase, func(t *testing.T) { 354 result := result.MapResultR0(testResult, mapOk, mapErr) 355 require.Equal(t, expResult, result) 356 }) 357 } 358 359 func testMapResultR1[O, O2, X, X2, R1 any](t *testing.T, 360 testCase string, 361 testResult result.Result[O, X], 362 mapOk func(O) (O2, R1), 363 mapErr func(X) (X2, R1), 364 expResult result.Result[O2, X2], 365 expR1 R1) { 366 t.Run(testCase, func(t *testing.T) { 367 result, r1 := result.MapResultR1(testResult, mapOk, mapErr) 368 require.Equal(t, expResult, result) 369 require.Equal(t, expR1, r1) 370 }) 371 } 372 373 func testAnd[O, O2, X any]( 374 t *testing.T, 375 testCase string, 376 r1 result.Result[O, X], 377 r2 result.Result[O2, X], 378 expResult result.Result[O2, X]) { 379 t.Run(testCase, func(t *testing.T) { 380 require.Equal(t, expResult, result.And(r1, r2)) 381 }) 382 } 383 384 func testOr[O, X, X2 any]( 385 t *testing.T, 386 testCase string, 387 r1 result.Result[O, X], 388 r2 result.Result[O, X2], 389 expResult result.Result[O, X2]) { 390 t.Run(testCase, func(t *testing.T) { 391 require.Equal(t, expResult, result.Or(r1, r2)) 392 }) 393 } 394 395 func testAndThen[O, O2, X any]( 396 t *testing.T, 397 testCase string, 398 r1 result.Result[O, X], 399 after func(O) result.Result[O2, X], 400 expResult result.Result[O2, X]) { 401 t.Run(testCase, func(t *testing.T) { 402 require.Equal(t, expResult, result.AndThen(r1, after)) 403 }) 404 } 405 406 func testOrElse[O, X, X2 any]( 407 t *testing.T, 408 testCase string, 409 r1 result.Result[O, X], 410 after func(X) result.Result[O, X2], 411 expResult result.Result[O, X2]) { 412 t.Run(testCase, func(t *testing.T) { 413 require.Equal(t, expResult, result.OrElse(r1, after)) 414 }) 415 }