mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
* 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>
324 lines
8.0 KiB
Go
324 lines
8.0 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 array
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
N "github.com/IBM/fp-go/v2/number"
|
|
O "github.com/IBM/fp-go/v2/option"
|
|
S "github.com/IBM/fp-go/v2/string"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestReplicate(t *testing.T) {
|
|
result := Replicate(3, "a")
|
|
assert.Equal(t, []string{"a", "a", "a"}, result)
|
|
|
|
empty := Replicate(0, 42)
|
|
assert.Equal(t, []int{}, empty)
|
|
}
|
|
|
|
func TestMonadMap(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
result := MonadMap(src, func(x int) int { return x * 2 })
|
|
assert.Equal(t, []int{2, 4, 6}, result)
|
|
}
|
|
|
|
func TestMonadMapRef(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
result := MonadMapRef(src, func(x *int) int { return *x * 2 })
|
|
assert.Equal(t, []int{2, 4, 6}, result)
|
|
}
|
|
|
|
func TestMapWithIndex(t *testing.T) {
|
|
src := []string{"a", "b", "c"}
|
|
mapper := MapWithIndex(func(i int, s string) string {
|
|
return fmt.Sprintf("%d:%s", i, s)
|
|
})
|
|
result := mapper(src)
|
|
assert.Equal(t, []string{"0:a", "1:b", "2:c"}, result)
|
|
}
|
|
|
|
func TestMapRef(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
mapper := MapRef(func(x *int) int { return *x * 2 })
|
|
result := mapper(src)
|
|
assert.Equal(t, []int{2, 4, 6}, result)
|
|
}
|
|
|
|
func TestFilterWithIndex(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
filter := FilterWithIndex(func(i, x int) bool {
|
|
return i%2 == 0 && x > 2
|
|
})
|
|
result := filter(src)
|
|
assert.Equal(t, []int{3, 5}, result)
|
|
}
|
|
|
|
func TestFilterRef(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
filter := FilterRef(func(x *int) bool { return *x > 2 })
|
|
result := filter(src)
|
|
assert.Equal(t, []int{3, 4, 5}, result)
|
|
}
|
|
|
|
func TestMonadFilterMap(t *testing.T) {
|
|
src := []int{1, 2, 3, 4}
|
|
result := MonadFilterMap(src, func(x int) O.Option[string] {
|
|
if x%2 == 0 {
|
|
return O.Some(fmt.Sprintf("even:%d", x))
|
|
}
|
|
return O.None[string]()
|
|
})
|
|
assert.Equal(t, []string{"even:2", "even:4"}, result)
|
|
}
|
|
|
|
func TestMonadFilterMapWithIndex(t *testing.T) {
|
|
src := []int{1, 2, 3, 4}
|
|
result := MonadFilterMapWithIndex(src, func(i, x int) O.Option[string] {
|
|
if i%2 == 0 {
|
|
return O.Some(fmt.Sprintf("%d:%d", i, x))
|
|
}
|
|
return O.None[string]()
|
|
})
|
|
assert.Equal(t, []string{"0:1", "2:3"}, result)
|
|
}
|
|
|
|
func TestFilterMapWithIndex(t *testing.T) {
|
|
src := []int{1, 2, 3, 4}
|
|
filter := FilterMapWithIndex(func(i, x int) O.Option[string] {
|
|
if i%2 == 0 {
|
|
return O.Some(fmt.Sprintf("%d:%d", i, x))
|
|
}
|
|
return O.None[string]()
|
|
})
|
|
result := filter(src)
|
|
assert.Equal(t, []string{"0:1", "2:3"}, result)
|
|
}
|
|
|
|
func TestFilterMapRef(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
filter := FilterMapRef(
|
|
func(x *int) bool { return *x > 2 },
|
|
func(x *int) string { return fmt.Sprintf("val:%d", *x) },
|
|
)
|
|
result := filter(src)
|
|
assert.Equal(t, []string{"val:3", "val:4", "val:5"}, result)
|
|
}
|
|
|
|
func TestReduceWithIndex(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
reducer := ReduceWithIndex(func(i, acc, x int) int {
|
|
return acc + i + x
|
|
}, 0)
|
|
result := reducer(src)
|
|
assert.Equal(t, 9, result) // 0 + (0+1) + (1+2) + (2+3) = 9
|
|
}
|
|
|
|
func TestReduceRightWithIndex(t *testing.T) {
|
|
src := []string{"a", "b", "c"}
|
|
reducer := ReduceRightWithIndex(func(i int, x, acc string) string {
|
|
return fmt.Sprintf("%s%d:%s", acc, i, x)
|
|
}, "")
|
|
result := reducer(src)
|
|
assert.Equal(t, "2:c1:b0:a", result)
|
|
}
|
|
|
|
func TestReduceRef(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
reducer := ReduceRef(func(acc int, x *int) int {
|
|
return acc + *x
|
|
}, 0)
|
|
result := reducer(src)
|
|
assert.Equal(t, 6, result)
|
|
}
|
|
|
|
func TestZero(t *testing.T) {
|
|
result := Zero[int]()
|
|
assert.Equal(t, []int{}, result)
|
|
assert.True(t, IsEmpty(result))
|
|
}
|
|
|
|
func TestMonadChain(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
result := MonadChain(src, func(x int) []int {
|
|
return []int{x, x * 10}
|
|
})
|
|
assert.Equal(t, []int{1, 10, 2, 20, 3, 30}, result)
|
|
}
|
|
|
|
func TestChain(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
chain := Chain(func(x int) []int {
|
|
return []int{x, x * 10}
|
|
})
|
|
result := chain(src)
|
|
assert.Equal(t, []int{1, 10, 2, 20, 3, 30}, result)
|
|
}
|
|
|
|
func TestMonadAp(t *testing.T) {
|
|
fns := []func(int) int{
|
|
func(x int) int { return x * 2 },
|
|
func(x int) int { return x + 10 },
|
|
}
|
|
values := []int{1, 2}
|
|
result := MonadAp(fns, values)
|
|
assert.Equal(t, []int{2, 4, 11, 12}, result)
|
|
}
|
|
|
|
func TestMatchLeft(t *testing.T) {
|
|
matcher := MatchLeft(
|
|
func() string { return "empty" },
|
|
func(head int, tail []int) string {
|
|
return fmt.Sprintf("head:%d,tail:%v", head, tail)
|
|
},
|
|
)
|
|
|
|
assert.Equal(t, "empty", matcher([]int{}))
|
|
assert.Equal(t, "head:1,tail:[2 3]", matcher([]int{1, 2, 3}))
|
|
}
|
|
|
|
func TestTail(t *testing.T) {
|
|
assert.Equal(t, O.None[[]int](), Tail([]int{}))
|
|
assert.Equal(t, O.Some([]int{2, 3}), Tail([]int{1, 2, 3}))
|
|
assert.Equal(t, O.Some([]int{}), Tail([]int{1}))
|
|
}
|
|
|
|
func TestFirst(t *testing.T) {
|
|
assert.Equal(t, O.None[int](), First([]int{}))
|
|
assert.Equal(t, O.Some(1), First([]int{1, 2, 3}))
|
|
}
|
|
|
|
func TestLast(t *testing.T) {
|
|
assert.Equal(t, O.None[int](), Last([]int{}))
|
|
assert.Equal(t, O.Some(3), Last([]int{1, 2, 3}))
|
|
assert.Equal(t, O.Some(1), Last([]int{1}))
|
|
}
|
|
|
|
func TestUpsertAt(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
upsert := UpsertAt(99)
|
|
|
|
result1 := upsert(src)
|
|
assert.Equal(t, []int{1, 2, 3, 99}, result1)
|
|
}
|
|
|
|
func TestSize(t *testing.T) {
|
|
assert.Equal(t, 0, Size([]int{}))
|
|
assert.Equal(t, 3, Size([]int{1, 2, 3}))
|
|
}
|
|
|
|
func TestMonadPartition(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
result := MonadPartition(src, func(x int) bool { return x > 2 })
|
|
assert.Equal(t, []int{1, 2}, result.F1)
|
|
assert.Equal(t, []int{3, 4, 5}, result.F2)
|
|
}
|
|
|
|
func TestIsNil(t *testing.T) {
|
|
var nilSlice []int
|
|
assert.True(t, IsNil(nilSlice))
|
|
assert.False(t, IsNil([]int{}))
|
|
assert.False(t, IsNil([]int{1}))
|
|
}
|
|
|
|
func TestIsNonNil(t *testing.T) {
|
|
var nilSlice []int
|
|
assert.False(t, IsNonNil(nilSlice))
|
|
assert.True(t, IsNonNil([]int{}))
|
|
assert.True(t, IsNonNil([]int{1}))
|
|
}
|
|
|
|
func TestConstNil(t *testing.T) {
|
|
result := ConstNil[int]()
|
|
assert.True(t, IsNil(result))
|
|
}
|
|
|
|
func TestSliceRight(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
slicer := SliceRight[int](2)
|
|
result := slicer(src)
|
|
assert.Equal(t, []int{3, 4, 5}, result)
|
|
}
|
|
|
|
func TestCopy(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
copied := Copy(src)
|
|
assert.Equal(t, src, copied)
|
|
// Verify it's a different slice
|
|
copied[0] = 99
|
|
assert.Equal(t, 1, src[0])
|
|
assert.Equal(t, 99, copied[0])
|
|
}
|
|
|
|
func TestClone(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
cloner := Clone(func(x int) int { return x * 2 })
|
|
result := cloner(src)
|
|
assert.Equal(t, []int{2, 4, 6}, result)
|
|
}
|
|
|
|
func TestFoldMapWithIndex(t *testing.T) {
|
|
src := []string{"a", "b", "c"}
|
|
folder := FoldMapWithIndex[string](S.Monoid)(func(i int, s string) string {
|
|
return fmt.Sprintf("%d:%s", i, s)
|
|
})
|
|
result := folder(src)
|
|
assert.Equal(t, "0:a1:b2:c", result)
|
|
}
|
|
|
|
func TestFold(t *testing.T) {
|
|
src := []int{1, 2, 3, 4, 5}
|
|
folder := Fold(N.MonoidSum[int]())
|
|
result := folder(src)
|
|
assert.Equal(t, 15, result)
|
|
}
|
|
|
|
func TestPush(t *testing.T) {
|
|
src := []int{1, 2, 3}
|
|
pusher := Push(4)
|
|
result := pusher(src)
|
|
assert.Equal(t, []int{1, 2, 3, 4}, result)
|
|
}
|
|
|
|
func TestMonadFlap(t *testing.T) {
|
|
fns := []func(int) string{
|
|
func(x int) string { return fmt.Sprintf("a%d", x) },
|
|
func(x int) string { return fmt.Sprintf("b%d", x) },
|
|
}
|
|
result := MonadFlap(fns, 5)
|
|
assert.Equal(t, []string{"a5", "b5"}, result)
|
|
}
|
|
|
|
func TestFlap(t *testing.T) {
|
|
fns := []func(int) string{
|
|
func(x int) string { return fmt.Sprintf("a%d", x) },
|
|
func(x int) string { return fmt.Sprintf("b%d", x) },
|
|
}
|
|
flapper := Flap[string](5)
|
|
result := flapper(fns)
|
|
assert.Equal(t, []string{"a5", "b5"}, result)
|
|
}
|
|
|
|
func TestPrepend(t *testing.T) {
|
|
src := []int{2, 3, 4}
|
|
prepender := Prepend(1)
|
|
result := prepender(src)
|
|
assert.Equal(t, []int{1, 2, 3, 4}, result)
|
|
}
|