mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
703 lines
18 KiB
Go
703 lines
18 KiB
Go
// Copyright (c) 2023 - 2025 IBM Corp.
|
|
// All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package either
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
|
|
F "github.com/IBM/fp-go/v2/function"
|
|
M "github.com/IBM/fp-go/v2/monoid"
|
|
O "github.com/IBM/fp-go/v2/option"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// Test BiMap
|
|
func TestBiMap(t *testing.T) {
|
|
errToStr := error.Error
|
|
intToStr := strconv.Itoa
|
|
|
|
// Test Right case
|
|
result := BiMap(errToStr, intToStr)(Right[error](42))
|
|
assert.Equal(t, Right[string]("42"), result)
|
|
|
|
// Test Left case
|
|
result = BiMap(errToStr, intToStr)(Left[int](errors.New("error")))
|
|
assert.Equal(t, Left[string]("error"), result)
|
|
}
|
|
|
|
// Test MonadBiMap
|
|
func TestMonadBiMap(t *testing.T) {
|
|
errToStr := error.Error
|
|
intToStr := strconv.Itoa
|
|
|
|
result := MonadBiMap(Right[error](42), errToStr, intToStr)
|
|
assert.Equal(t, Right[string]("42"), result)
|
|
|
|
result = MonadBiMap(Left[int](errors.New("error")), errToStr, intToStr)
|
|
assert.Equal(t, Left[string]("error"), result)
|
|
}
|
|
|
|
// Test MapLeft
|
|
func TestMapLeft(t *testing.T) {
|
|
errToStr := error.Error
|
|
|
|
result := MapLeft[int](errToStr)(Left[int](errors.New("error")))
|
|
assert.Equal(t, Left[int]("error"), result)
|
|
|
|
result = MapLeft[int](errToStr)(Right[error](42))
|
|
assert.Equal(t, Right[string](42), result)
|
|
}
|
|
|
|
// Test MonadMapLeft
|
|
func TestMonadMapLeft(t *testing.T) {
|
|
errToStr := error.Error
|
|
|
|
result := MonadMapLeft(Left[int](errors.New("error")), errToStr)
|
|
assert.Equal(t, Left[int]("error"), result)
|
|
|
|
result = MonadMapLeft(Right[error](42), errToStr)
|
|
assert.Equal(t, Right[string](42), result)
|
|
}
|
|
|
|
// Test MonadMapTo
|
|
func TestMonadMapTo(t *testing.T) {
|
|
result := MonadMapTo(Right[error](42), "success")
|
|
assert.Equal(t, Right[error]("success"), result)
|
|
|
|
result = MonadMapTo(Left[int](errors.New("error")), "success")
|
|
assert.Equal(t, Left[string](errors.New("error")), result)
|
|
}
|
|
|
|
// Test MonadChainFirst
|
|
func TestMonadChainFirst(t *testing.T) {
|
|
f := func(x int) Either[error, string] {
|
|
return Right[error](strconv.Itoa(x))
|
|
}
|
|
|
|
result := MonadChainFirst(Right[error](42), f)
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
result = MonadChainFirst(Left[int](errors.New("error")), f)
|
|
assert.Equal(t, Left[int](errors.New("error")), result)
|
|
}
|
|
|
|
// Test MonadChainTo
|
|
func TestMonadChainTo(t *testing.T) {
|
|
result := MonadChainTo(Right[error](42), Right[error]("hello"))
|
|
assert.Equal(t, Right[error]("hello"), result)
|
|
|
|
result = MonadChainTo(Left[int](errors.New("error")), Right[error]("hello"))
|
|
assert.Equal(t, Right[error]("hello"), result)
|
|
}
|
|
|
|
// Test Flatten
|
|
func TestFlatten(t *testing.T) {
|
|
nested := Right[error](Right[error](42))
|
|
result := Flatten(nested)
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
nestedLeft := Right[error](Left[int](errors.New("error")))
|
|
result = Flatten(nestedLeft)
|
|
assert.Equal(t, Left[int](errors.New("error")), result)
|
|
|
|
outerLeft := Left[Either[error, int]](errors.New("outer error"))
|
|
result = Flatten(outerLeft)
|
|
assert.Equal(t, Left[int](errors.New("outer error")), result)
|
|
}
|
|
|
|
// Test ToOption
|
|
func TestToOption(t *testing.T) {
|
|
result := ToOption(Right[error](42))
|
|
assert.Equal(t, O.Some(42), result)
|
|
|
|
result = ToOption(Left[int](errors.New("error")))
|
|
assert.Equal(t, O.None[int](), result)
|
|
}
|
|
|
|
// Test FromError
|
|
func TestFromError(t *testing.T) {
|
|
validate := func(x int) error {
|
|
if x < 0 {
|
|
return errors.New("negative")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
toEither := FromError(validate)
|
|
result := toEither(42)
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
result = toEither(-1)
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
// Test ToError
|
|
func TestToError(t *testing.T) {
|
|
err := ToError(Left[int](errors.New("error")))
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "error", err.Error())
|
|
|
|
err = ToError(Right[error](42))
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// Test OrElse
|
|
func TestOrElse(t *testing.T) {
|
|
recover := OrElse(func(e error) Either[error, int] {
|
|
return Right[error](0)
|
|
})
|
|
|
|
result := recover(Left[int](errors.New("error")))
|
|
assert.Equal(t, Right[error](0), result)
|
|
|
|
result = recover(Right[error](42))
|
|
assert.Equal(t, Right[error](42), result)
|
|
}
|
|
|
|
// Test ToType
|
|
func TestToType(t *testing.T) {
|
|
convert := ToType[int](func(v any) error {
|
|
return fmt.Errorf("cannot convert %v to int", v)
|
|
})
|
|
|
|
result := convert(42)
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
result = convert("string")
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
// Test Memoize
|
|
func TestMemoize(t *testing.T) {
|
|
val := Right[error](42)
|
|
result := Memoize(val)
|
|
assert.Equal(t, val, result)
|
|
}
|
|
|
|
// Test Swap
|
|
func TestSwap(t *testing.T) {
|
|
result := Swap(Right[error](42))
|
|
assert.Equal(t, Left[error](42), result)
|
|
|
|
result = Swap(Left[int](errors.New("error")))
|
|
assert.Equal(t, Right[int](errors.New("error")), result)
|
|
}
|
|
|
|
// Test MonadFlap and Flap
|
|
func TestFlap(t *testing.T) {
|
|
fab := Right[error](func(x int) string { return strconv.Itoa(x) })
|
|
result := MonadFlap(fab, 42)
|
|
assert.Equal(t, Right[error]("42"), result)
|
|
|
|
result = Flap[error, string](42)(fab)
|
|
assert.Equal(t, Right[error]("42"), result)
|
|
|
|
fabLeft := Left[func(int) string](errors.New("error"))
|
|
result = MonadFlap(fabLeft, 42)
|
|
assert.Equal(t, Left[string](errors.New("error")), result)
|
|
}
|
|
|
|
// Test Sequence2 and MonadSequence2
|
|
func TestSequence2(t *testing.T) {
|
|
f := func(a int, b int) Either[error, int] {
|
|
return Right[error](a + b)
|
|
}
|
|
|
|
result := Sequence2(f)(Right[error](1), Right[error](2))
|
|
assert.Equal(t, Right[error](3), result)
|
|
|
|
result = Sequence2(f)(Left[int](errors.New("error")), Right[error](2))
|
|
assert.Equal(t, Left[int](errors.New("error")), result)
|
|
|
|
result = MonadSequence2(Right[error](1), Right[error](2), f)
|
|
assert.Equal(t, Right[error](3), result)
|
|
}
|
|
|
|
// Test Sequence3 and MonadSequence3
|
|
func TestSequence3(t *testing.T) {
|
|
f := func(a, b, c int) Either[error, int] {
|
|
return Right[error](a + b + c)
|
|
}
|
|
|
|
result := Sequence3(f)(Right[error](1), Right[error](2), Right[error](3))
|
|
assert.Equal(t, Right[error](6), result)
|
|
|
|
result = Sequence3(f)(Left[int](errors.New("error")), Right[error](2), Right[error](3))
|
|
assert.Equal(t, Left[int](errors.New("error")), result)
|
|
|
|
result = MonadSequence3(Right[error](1), Right[error](2), Right[error](3), f)
|
|
assert.Equal(t, Right[error](6), result)
|
|
}
|
|
|
|
// Test Let
|
|
func TestLet(t *testing.T) {
|
|
type State struct{ value int }
|
|
result := F.Pipe2(
|
|
Right[error](State{value: 10}),
|
|
Let[error](
|
|
func(v int) func(State) State {
|
|
return func(s State) State { return State{value: s.value + v} }
|
|
},
|
|
func(s State) int { return 32 },
|
|
),
|
|
Map[error](F.Identity[State]),
|
|
)
|
|
assert.Equal(t, Right[error](State{value: 42}), result)
|
|
}
|
|
|
|
// Test LetTo
|
|
func TestLetTo(t *testing.T) {
|
|
type State struct{ name string }
|
|
result := F.Pipe2(
|
|
Right[error](State{}),
|
|
LetTo[error](
|
|
func(n string) func(State) State {
|
|
return func(s State) State { return State{name: n} }
|
|
},
|
|
"Alice",
|
|
),
|
|
Map[error](F.Identity[State]),
|
|
)
|
|
assert.Equal(t, Right[error](State{name: "Alice"}), result)
|
|
}
|
|
|
|
// Test BindTo
|
|
func TestBindTo(t *testing.T) {
|
|
type State struct{ value int }
|
|
result := F.Pipe2(
|
|
Right[error](42),
|
|
BindTo[error](func(v int) State { return State{value: v} }),
|
|
Map[error](F.Identity[State]),
|
|
)
|
|
assert.Equal(t, Right[error](State{value: 42}), result)
|
|
}
|
|
|
|
// Test TraverseArray
|
|
func TestTraverseArray(t *testing.T) {
|
|
parse := func(s string) Either[error, int] {
|
|
v, err := strconv.Atoi(s)
|
|
return TryCatchError(v, err)
|
|
}
|
|
|
|
result := TraverseArray(parse)([]string{"1", "2", "3"})
|
|
assert.Equal(t, Right[error]([]int{1, 2, 3}), result)
|
|
|
|
result = TraverseArray(parse)([]string{"1", "bad", "3"})
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
// Test TraverseArrayWithIndex
|
|
func TestTraverseArrayWithIndex(t *testing.T) {
|
|
validate := func(i int, s string) Either[error, string] {
|
|
if len(s) > 0 {
|
|
return Right[error](fmt.Sprintf("%d:%s", i, s))
|
|
}
|
|
return Left[string](fmt.Errorf("empty at index %d", i))
|
|
}
|
|
|
|
result := TraverseArrayWithIndex(validate)([]string{"a", "b"})
|
|
assert.Equal(t, Right[error]([]string{"0:a", "1:b"}), result)
|
|
|
|
result = TraverseArrayWithIndex(validate)([]string{"a", ""})
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
// Test TraverseRecord
|
|
func TestTraverseRecord(t *testing.T) {
|
|
parse := func(s string) Either[error, int] {
|
|
v, err := strconv.Atoi(s)
|
|
return TryCatchError(v, err)
|
|
}
|
|
|
|
input := map[string]string{"a": "1", "b": "2"}
|
|
result := TraverseRecord[string](parse)(input)
|
|
expected := Right[error](map[string]int{"a": 1, "b": 2})
|
|
assert.Equal(t, expected, result)
|
|
}
|
|
|
|
// Test TraverseRecordWithIndex
|
|
func TestTraverseRecordWithIndex(t *testing.T) {
|
|
validate := func(k string, v string) Either[error, string] {
|
|
if len(v) > 0 {
|
|
return Right[error](k + ":" + v)
|
|
}
|
|
return Left[string](fmt.Errorf("empty value for key %s", k))
|
|
}
|
|
|
|
input := map[string]string{"a": "1"}
|
|
result := TraverseRecordWithIndex[string](validate)(input)
|
|
expected := Right[error](map[string]string{"a": "a:1"})
|
|
assert.Equal(t, expected, result)
|
|
}
|
|
|
|
// Test SequenceRecord
|
|
func TestSequenceRecord(t *testing.T) {
|
|
eithers := map[string]Either[error, int]{
|
|
"a": Right[error](1),
|
|
"b": Right[error](2),
|
|
}
|
|
result := SequenceRecord(eithers)
|
|
expected := Right[error](map[string]int{"a": 1, "b": 2})
|
|
assert.Equal(t, expected, result)
|
|
|
|
eithersWithError := map[string]Either[error, int]{
|
|
"a": Right[error](1),
|
|
"b": Left[int](errors.New("error")),
|
|
}
|
|
result = SequenceRecord(eithersWithError)
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
// Test Curry functions
|
|
func TestCurry0(t *testing.T) {
|
|
getConfig := func() (string, error) { return "config", nil }
|
|
curried := Curry0(getConfig)
|
|
result := curried()
|
|
assert.Equal(t, Right[error]("config"), result)
|
|
}
|
|
|
|
func TestCurry1(t *testing.T) {
|
|
parse := func(s string) (int, error) { return strconv.Atoi(s) }
|
|
curried := Curry1(parse)
|
|
result := curried("42")
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
result = curried("bad")
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
func TestCurry2(t *testing.T) {
|
|
divide := func(a, b int) (int, error) {
|
|
if b == 0 {
|
|
return 0, errors.New("div by zero")
|
|
}
|
|
return a / b, nil
|
|
}
|
|
curried := Curry2(divide)
|
|
result := curried(10)(2)
|
|
assert.Equal(t, Right[error](5), result)
|
|
|
|
result = curried(10)(0)
|
|
assert.True(t, IsLeft(result))
|
|
}
|
|
|
|
func TestCurry3(t *testing.T) {
|
|
sum3 := func(a, b, c int) (int, error) {
|
|
return a + b + c, nil
|
|
}
|
|
curried := Curry3(sum3)
|
|
result := curried(1)(2)(3)
|
|
assert.Equal(t, Right[error](6), result)
|
|
}
|
|
|
|
func TestCurry4(t *testing.T) {
|
|
sum4 := func(a, b, c, d int) (int, error) {
|
|
return a + b + c + d, nil
|
|
}
|
|
curried := Curry4(sum4)
|
|
result := curried(1)(2)(3)(4)
|
|
assert.Equal(t, Right[error](10), result)
|
|
}
|
|
|
|
// Test Uncurry functions
|
|
func TestUncurry0(t *testing.T) {
|
|
curried := func() Either[error, string] { return Right[error]("value") }
|
|
uncurried := Uncurry0(curried)
|
|
result, err := uncurried()
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "value", result)
|
|
}
|
|
|
|
func TestUncurry1(t *testing.T) {
|
|
curried := func(x int) Either[error, string] { return Right[error](strconv.Itoa(x)) }
|
|
uncurried := Uncurry1(curried)
|
|
result, err := uncurried(42)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "42", result)
|
|
}
|
|
|
|
func TestUncurry2(t *testing.T) {
|
|
curried := func(a int) func(int) Either[error, int] {
|
|
return func(b int) Either[error, int] {
|
|
return Right[error](a + b)
|
|
}
|
|
}
|
|
uncurried := Uncurry2(curried)
|
|
result, err := uncurried(1, 2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 3, result)
|
|
}
|
|
|
|
func TestUncurry3(t *testing.T) {
|
|
curried := func(a int) func(int) func(int) Either[error, int] {
|
|
return func(b int) func(int) Either[error, int] {
|
|
return func(c int) Either[error, int] {
|
|
return Right[error](a + b + c)
|
|
}
|
|
}
|
|
}
|
|
uncurried := Uncurry3(curried)
|
|
result, err := uncurried(1, 2, 3)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 6, result)
|
|
}
|
|
|
|
func TestUncurry4(t *testing.T) {
|
|
curried := func(a int) func(int) func(int) func(int) Either[error, int] {
|
|
return func(b int) func(int) func(int) Either[error, int] {
|
|
return func(c int) func(int) Either[error, int] {
|
|
return func(d int) Either[error, int] {
|
|
return Right[error](a + b + c + d)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
uncurried := Uncurry4(curried)
|
|
result, err := uncurried(1, 2, 3, 4)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 10, result)
|
|
}
|
|
|
|
// Test Variadic functions
|
|
func TestVariadic0(t *testing.T) {
|
|
sum := func(nums []int) (int, error) {
|
|
total := 0
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
variadicSum := Variadic0(sum)
|
|
result := variadicSum(1, 2, 3)
|
|
assert.Equal(t, Right[error](6), result)
|
|
}
|
|
|
|
func TestVariadic1(t *testing.T) {
|
|
multiply := func(factor int, nums []int) ([]int, error) {
|
|
result := make([]int, len(nums))
|
|
for i, n := range nums {
|
|
result[i] = n * factor
|
|
}
|
|
return result, nil
|
|
}
|
|
variadicMultiply := Variadic1(multiply)
|
|
result := variadicMultiply(2, 1, 2, 3)
|
|
assert.Equal(t, Right[error]([]int{2, 4, 6}), result)
|
|
}
|
|
|
|
func TestVariadic2(t *testing.T) {
|
|
combine := func(a, b int, nums []int) (int, error) {
|
|
total := a + b
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
variadicCombine := Variadic2(combine)
|
|
result := variadicCombine(1, 2, 3, 4)
|
|
assert.Equal(t, Right[error](10), result)
|
|
}
|
|
|
|
func TestVariadic3(t *testing.T) {
|
|
combine := func(a, b, c int, nums []int) (int, error) {
|
|
total := a + b + c
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
variadicCombine := Variadic3(combine)
|
|
result := variadicCombine(1, 2, 3, 4, 5)
|
|
assert.Equal(t, Right[error](15), result)
|
|
}
|
|
|
|
func TestVariadic4(t *testing.T) {
|
|
combine := func(a, b, c, d int, nums []int) (int, error) {
|
|
total := a + b + c + d
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
variadicCombine := Variadic4(combine)
|
|
result := variadicCombine(1, 2, 3, 4, 5, 6)
|
|
assert.Equal(t, Right[error](21), result)
|
|
}
|
|
|
|
// Test Unvariadic functions
|
|
func TestUnvariadic0(t *testing.T) {
|
|
variadic := func(nums ...int) (int, error) {
|
|
total := 0
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
unvariadic := Unvariadic0(variadic)
|
|
result := unvariadic([]int{1, 2, 3})
|
|
assert.Equal(t, Right[error](6), result)
|
|
}
|
|
|
|
func TestUnvariadic1(t *testing.T) {
|
|
variadic := func(factor int, nums ...int) ([]int, error) {
|
|
result := make([]int, len(nums))
|
|
for i, n := range nums {
|
|
result[i] = n * factor
|
|
}
|
|
return result, nil
|
|
}
|
|
unvariadic := Unvariadic1(variadic)
|
|
result := unvariadic(2, []int{1, 2, 3})
|
|
assert.Equal(t, Right[error]([]int{2, 4, 6}), result)
|
|
}
|
|
|
|
func TestUnvariadic2(t *testing.T) {
|
|
variadic := func(a, b int, nums ...int) (int, error) {
|
|
total := a + b
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
unvariadic := Unvariadic2(variadic)
|
|
result := unvariadic(1, 2, []int{3, 4})
|
|
assert.Equal(t, Right[error](10), result)
|
|
}
|
|
|
|
func TestUnvariadic3(t *testing.T) {
|
|
variadic := func(a, b, c int, nums ...int) (int, error) {
|
|
total := a + b + c
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
unvariadic := Unvariadic3(variadic)
|
|
result := unvariadic(1, 2, 3, []int{4, 5})
|
|
assert.Equal(t, Right[error](15), result)
|
|
}
|
|
|
|
func TestUnvariadic4(t *testing.T) {
|
|
variadic := func(a, b, c, d int, nums ...int) (int, error) {
|
|
total := a + b + c + d
|
|
for _, n := range nums {
|
|
total += n
|
|
}
|
|
return total, nil
|
|
}
|
|
unvariadic := Unvariadic4(variadic)
|
|
result := unvariadic(1, 2, 3, 4, []int{5, 6})
|
|
assert.Equal(t, Right[error](21), result)
|
|
}
|
|
|
|
// Test Monad
|
|
func TestMonad(t *testing.T) {
|
|
m := Monad[error, int, string]()
|
|
|
|
// Test Of
|
|
result := m.Of(42)
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
// Test Map
|
|
mapFn := m.Map(func(x int) string { return strconv.Itoa(x) })
|
|
result2 := mapFn(Right[error](42))
|
|
assert.Equal(t, Right[error]("42"), result2)
|
|
|
|
// Test Chain
|
|
chainFn := m.Chain(func(x int) Either[error, string] {
|
|
return Right[error](strconv.Itoa(x))
|
|
})
|
|
result3 := chainFn(Right[error](42))
|
|
assert.Equal(t, Right[error]("42"), result3)
|
|
|
|
// Test Ap
|
|
apFn := m.Ap(Right[error](42))
|
|
result4 := apFn(Right[error](func(x int) string { return strconv.Itoa(x) }))
|
|
assert.Equal(t, Right[error]("42"), result4)
|
|
}
|
|
|
|
// Test AltSemigroup
|
|
func TestAltSemigroup(t *testing.T) {
|
|
sg := AltSemigroup[error, int]()
|
|
|
|
result := sg.Concat(Left[int](errors.New("error")), Right[error](42))
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
result = sg.Concat(Right[error](1), Right[error](2))
|
|
assert.Equal(t, Right[error](1), result)
|
|
}
|
|
|
|
// Test AlternativeMonoid
|
|
func TestAlternativeMonoid(t *testing.T) {
|
|
intAdd := M.MakeMonoid(func(a, b int) int { return a + b }, 0)
|
|
m := AlternativeMonoid[error](intAdd)
|
|
|
|
result := m.Concat(Right[error](1), Right[error](2))
|
|
assert.Equal(t, Right[error](3), result)
|
|
|
|
empty := m.Empty()
|
|
assert.Equal(t, Right[error](0), empty)
|
|
}
|
|
|
|
// Test AltMonoid
|
|
func TestAltMonoid(t *testing.T) {
|
|
zero := func() Either[error, int] { return Left[int](errors.New("empty")) }
|
|
m := AltMonoid[error, int](zero)
|
|
|
|
result := m.Concat(Left[int](errors.New("err1")), Right[error](42))
|
|
assert.Equal(t, Right[error](42), result)
|
|
|
|
empty := m.Empty()
|
|
assert.Equal(t, Left[int](errors.New("empty")), empty)
|
|
}
|
|
|
|
// Test core.go Format
|
|
func TestFormat(t *testing.T) {
|
|
e := Right[error](42)
|
|
formatted := fmt.Sprintf("%s", e)
|
|
assert.Contains(t, formatted, "Right")
|
|
assert.Contains(t, formatted, "42")
|
|
|
|
e2 := Left[int](errors.New("error"))
|
|
formatted2 := fmt.Sprintf("%v", e2)
|
|
assert.Contains(t, formatted2, "Left")
|
|
}
|
|
|
|
// Test TryCatch with error
|
|
func TestTryCatchWithError(t *testing.T) {
|
|
result := TryCatch(0, errors.New("error"), func(err error) string {
|
|
return err.Error()
|
|
})
|
|
assert.Equal(t, Left[int]("error"), result)
|
|
}
|
|
|
|
// Test Unwrap with else branch
|
|
func TestUnwrapElseBranch(t *testing.T) {
|
|
val, err := Unwrap(Right[error](42))
|
|
assert.Equal(t, 42, val)
|
|
assert.Equal(t, error(nil), err)
|
|
}
|
|
|
|
// Test eitherFormat with different rune
|
|
func TestEitherFormatDifferentRune(t *testing.T) {
|
|
e := Right[error](42)
|
|
formatted := fmt.Sprintf("%v", e)
|
|
assert.Contains(t, formatted, "Right")
|
|
}
|