1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-23 22:14:53 +02:00
Files
fp-go/v2/either/either_coverage_test.go

703 lines
18 KiB
Go
Raw Normal View History

Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
// 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
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
// 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
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
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
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
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
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
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(validate)(input)
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
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(zero)
Implement v2 using type aliases (#141) * fix: initial checkin of v2 Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: slowly migrate IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate MonadTraverseArray and TraverseArray Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate traversal Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: complete migration of IO Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: migrate ioeither Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: refactorY Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: next step in migration Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust IO generation code Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO methods Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: get rid of more IO * fix: convert iooption Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: convert a bit of reader Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: new build script Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: reformat Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: simplify Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some cleanup Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: adjust Pair to Haskell semantic Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: documentation and testcases Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: some performance optimizations Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: remove coverage Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: better doc Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
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")
}