mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
377 lines
7.4 KiB
Go
377 lines
7.4 KiB
Go
package fn
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"testing"
|
|
"testing/quick"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func even(a int) bool { return a%2 == 0 }
|
|
func odd(a int) bool { return a%2 != 0 }
|
|
|
|
func TestAll(t *testing.T) {
|
|
x := []int{0, 2, 4, 6, 8}
|
|
require.True(t, All(even, x))
|
|
require.False(t, All(odd, x))
|
|
|
|
y := []int{1, 3, 5, 7, 9}
|
|
require.False(t, All(even, y))
|
|
require.True(t, All(odd, y))
|
|
|
|
z := []int{0, 2, 4, 6, 9}
|
|
require.False(t, All(even, z))
|
|
require.False(t, All(odd, z))
|
|
}
|
|
|
|
func TestAny(t *testing.T) {
|
|
x := []int{1, 3, 5, 7, 9}
|
|
require.False(t, Any(even, x))
|
|
require.True(t, Any(odd, x))
|
|
|
|
y := []int{0, 3, 5, 7, 9}
|
|
require.True(t, Any(even, y))
|
|
require.True(t, Any(odd, y))
|
|
|
|
z := []int{0, 2, 4, 6, 8}
|
|
require.True(t, Any(even, z))
|
|
require.False(t, Any(odd, z))
|
|
}
|
|
|
|
func TestMap(t *testing.T) {
|
|
inc := func(i int) int { return i + 1 }
|
|
|
|
x := []int{0, 2, 4, 6, 8}
|
|
|
|
y := Map(inc, x)
|
|
|
|
z := []int{1, 3, 5, 7, 9}
|
|
|
|
require.True(t, slices.Equal(y, z))
|
|
}
|
|
|
|
func TestFilter(t *testing.T) {
|
|
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
|
|
y := Filter(even, x)
|
|
|
|
require.True(t, All(even, y))
|
|
|
|
z := Filter(odd, y)
|
|
|
|
require.Zero(t, len(z))
|
|
}
|
|
|
|
func TestFoldl(t *testing.T) {
|
|
seed := []int{}
|
|
stupid := func(s []int, a int) []int { return append(s, a) }
|
|
|
|
x := []int{0, 1, 2, 3, 4}
|
|
|
|
r := Foldl(stupid, seed, x)
|
|
|
|
require.True(t, slices.Equal(x, r))
|
|
}
|
|
|
|
func TestFoldr(t *testing.T) {
|
|
seed := []int{}
|
|
stupid := func(a int, s []int) []int { return append(s, a) }
|
|
|
|
x := []int{0, 1, 2, 3, 4}
|
|
|
|
z := Foldr(stupid, seed, x)
|
|
|
|
slices.Reverse[[]int](x)
|
|
|
|
require.True(t, slices.Equal(x, z))
|
|
}
|
|
|
|
func TestFind(t *testing.T) {
|
|
x := []int{10, 11, 12, 13, 14, 15}
|
|
|
|
div3 := func(a int) bool { return a%3 == 0 }
|
|
div8 := func(a int) bool { return a%8 == 0 }
|
|
|
|
require.Equal(t, Find(div3, x), Some(12))
|
|
|
|
require.Equal(t, Find(div8, x), None[int]())
|
|
}
|
|
|
|
func TestFlatten(t *testing.T) {
|
|
x := [][]int{{0}, {1}, {2}}
|
|
|
|
y := Flatten(x)
|
|
|
|
require.True(t, slices.Equal(y, []int{0, 1, 2}))
|
|
}
|
|
|
|
func TestReplicate(t *testing.T) {
|
|
require.True(t, slices.Equal([]int{1, 1, 1, 1, 1}, Replicate(5, 1)))
|
|
}
|
|
|
|
func TestSpan(t *testing.T) {
|
|
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
lt5 := func(a int) bool { return a < 5 }
|
|
|
|
low, high := Span(lt5, x)
|
|
|
|
require.True(t, slices.Equal(low, []int{0, 1, 2, 3, 4}))
|
|
require.True(t, slices.Equal(high, []int{5, 6, 7, 8, 9}))
|
|
}
|
|
|
|
func TestSplitAt(t *testing.T) {
|
|
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
fst, snd := SplitAt(5, x)
|
|
|
|
require.True(t, slices.Equal(fst, []int{0, 1, 2, 3, 4}))
|
|
require.True(t, slices.Equal(snd, []int{5, 6, 7, 8, 9}))
|
|
}
|
|
|
|
func TestZipWith(t *testing.T) {
|
|
eq := func(a, b int) bool { return a == b }
|
|
x := []int{0, 1, 2, 3, 4}
|
|
y := Replicate(5, 1)
|
|
z := ZipWith(eq, x, y)
|
|
require.True(t, slices.Equal(
|
|
z, []bool{false, true, false, false, false},
|
|
))
|
|
}
|
|
|
|
// TestSum checks if the Sum function correctly calculates the sum of the
|
|
// numbers in the slice.
|
|
func TestSum(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
items interface{}
|
|
result interface{}
|
|
}{
|
|
{
|
|
name: "Sum of positive integers",
|
|
items: []int{1, 2, 3},
|
|
result: 6,
|
|
},
|
|
{
|
|
name: "Sum of negative integers",
|
|
items: []int{-1, -2, -3},
|
|
result: -6,
|
|
},
|
|
{
|
|
name: "Sum of float numbers",
|
|
items: []float64{1.1, 2.2, 3.3},
|
|
result: 6.6,
|
|
},
|
|
{
|
|
name: "Sum of complex numbers",
|
|
items: []complex128{
|
|
complex(1, 1),
|
|
complex(2, 2),
|
|
complex(3, 3),
|
|
},
|
|
result: complex(6, 6),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
switch v := tt.items.(type) {
|
|
case []int:
|
|
require.Equal(t, tt.result, Sum(v))
|
|
case []float64:
|
|
require.Equal(t, tt.result, Sum(v))
|
|
case []complex128:
|
|
require.Equal(t, tt.result, Sum(v))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSliceToMap tests the SliceToMap function.
|
|
func TestSliceToMap(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
slice []int
|
|
keyFunc func(int) int
|
|
valueFunc func(int) string
|
|
expected map[int]string
|
|
}{
|
|
{
|
|
name: "Integers to string map",
|
|
slice: []int{1, 2, 3},
|
|
keyFunc: func(a int) int { return a },
|
|
valueFunc: func(a int) string {
|
|
return fmt.Sprintf("Value%d", a)
|
|
},
|
|
expected: map[int]string{
|
|
1: "Value1",
|
|
2: "Value2",
|
|
3: "Value3",
|
|
},
|
|
},
|
|
{
|
|
name: "Duplicates in slice",
|
|
slice: []int{1, 2, 2, 3},
|
|
keyFunc: func(a int) int { return a },
|
|
valueFunc: func(a int) string {
|
|
return fmt.Sprintf("Value%d", a)
|
|
},
|
|
expected: map[int]string{
|
|
1: "Value1",
|
|
2: "Value2",
|
|
3: "Value3",
|
|
},
|
|
},
|
|
{
|
|
name: "Empty slice",
|
|
slice: []int{},
|
|
keyFunc: func(a int) int { return a },
|
|
valueFunc: func(a int) string {
|
|
return fmt.Sprintf("Value%d", a)
|
|
},
|
|
expected: map[int]string{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
require.Equal(
|
|
t, tt.expected,
|
|
SliceToMap(tt.slice, tt.keyFunc, tt.valueFunc),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestHasDuplicates tests the HasDuplicates function.
|
|
func TestHasDuplicates(t *testing.T) {
|
|
// Define test cases.
|
|
testCases := []struct {
|
|
name string
|
|
items []int
|
|
want bool
|
|
}{
|
|
{
|
|
name: "All unique",
|
|
items: []int{1, 2, 3, 4, 5},
|
|
want: false,
|
|
},
|
|
{
|
|
name: "Some duplicates",
|
|
items: []int{1, 2, 2, 3, 4},
|
|
want: true,
|
|
},
|
|
{
|
|
name: "No items",
|
|
items: []int{},
|
|
want: false,
|
|
},
|
|
{
|
|
name: "All duplicates",
|
|
items: []int{1, 1, 1, 1},
|
|
want: true,
|
|
},
|
|
}
|
|
|
|
// Execute each test case.
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := HasDuplicates(tc.items)
|
|
|
|
require.Equal(t, tc.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestPropForEachConcMapIsomorphism ensures the property that ForEachConc and
|
|
// Map always yield the same results.
|
|
func TestPropForEachConcMapIsomorphism(t *testing.T) {
|
|
f := func(incSize int, s []int) bool {
|
|
inc := func(i int) int { return i + incSize }
|
|
mapped := Map(inc, s)
|
|
conc := ForEachConc(inc, s)
|
|
|
|
return slices.Equal(mapped, conc)
|
|
}
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// TestPropForEachConcOutperformsMapWhenExpensive ensures the property that
|
|
// ForEachConc will beat Map in a race in circumstances where the computation in
|
|
// the argument closure is expensive.
|
|
func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) {
|
|
f := func(incSize int, s []int) bool {
|
|
if len(s) < 2 {
|
|
// Intuitively we don't expect the extra overhead of
|
|
// ForEachConc to justify itself for list sizes of 1 or
|
|
// 0.
|
|
return true
|
|
}
|
|
|
|
inc := func(i int) int {
|
|
time.Sleep(time.Millisecond)
|
|
return i + incSize
|
|
}
|
|
c := make(chan bool, 1)
|
|
|
|
go func() {
|
|
Map(inc, s)
|
|
select {
|
|
case c <- false:
|
|
default:
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
ForEachConc(inc, s)
|
|
select {
|
|
case c <- true:
|
|
default:
|
|
}
|
|
}()
|
|
|
|
return <-c
|
|
}
|
|
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestPropFindIdxFindIdentity(t *testing.T) {
|
|
f := func(div, mod uint8, s []uint8) bool {
|
|
if div == 0 || div == 1 {
|
|
return true
|
|
}
|
|
|
|
pred := func(i uint8) bool {
|
|
return i%div == mod
|
|
}
|
|
|
|
foundIdx := FindIdx(pred, s)
|
|
|
|
// onlyVal :: Option[T2[A, B]] -> Option[B]
|
|
onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 {
|
|
return t2.Second()
|
|
})
|
|
|
|
valuesEqual := Find(pred, s) == onlyVal(foundIdx)
|
|
|
|
idxGetsVal := ElimOption(
|
|
foundIdx,
|
|
func() bool { return true },
|
|
func(t2 T2[int, uint8]) bool {
|
|
return s[t2.First()] == t2.Second()
|
|
})
|
|
|
|
return valuesEqual && idxGetsVal
|
|
}
|
|
|
|
if err := quick.Check(f, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|