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  }