shad-go/genericsum/genericsum_test.go

208 lines
5.1 KiB
Go

package genericsum_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/slon/shad-go/genericsum"
"go.uber.org/goleak"
)
func TestMin(t *testing.T) {
assert.Equal(t, 10, genericsum.Min(10, 20))
assert.Equal(t, -10, genericsum.Min(20, -10))
assert.Equal(t, 1.0, genericsum.Min(1.0, 2.0))
assert.Equal(t, int64(10), genericsum.Min(int64(10), 20))
assert.Equal(t, "abc", genericsum.Min("def", "abc"))
type myString string
assert.Equal(t, myString("abc"), genericsum.Min(myString("def"), myString("abc")))
}
func TestSortSlice(t *testing.T) {
t.Run("ints", func(t *testing.T) {
inputs, expected := []int{3, 6, 2, 4, 5, 1}, []int{1, 2, 3, 4, 5, 6}
genericsum.SortSlice(inputs)
assert.Equal(t, expected, inputs)
})
t.Run("ints64", func(t *testing.T) {
inputs, expected := []int64{3, 6, 2, 4, 5, 1}, []int64{1, 2, 3, 4, 5, 6}
genericsum.SortSlice(inputs)
assert.Equal(t, expected, inputs)
})
t.Run("strings", func(t *testing.T) {
inputs, expected := []string{"d", "b", "ab", "a"}, []string{"a", "ab", "b", "d"}
genericsum.SortSlice(inputs)
assert.Equal(t, expected, inputs)
})
type myStringSlice []string
t.Run("strings custom type", func(t *testing.T) {
inputs, expected := myStringSlice([]string{"d", "b", "ab", "a"}), myStringSlice([]string{"a", "ab", "b", "d"})
genericsum.SortSlice(inputs)
assert.Equal(t, expected, inputs)
})
}
func TestMapsEqual(t *testing.T) {
assert.True(t, genericsum.MapsEqual(map[string]string{"1": "3", "2": "4"}, map[string]string{"2": "4", "1": "3"}))
var i int
assert.False(t, genericsum.MapsEqual(map[string]*int{"1": &i, "2": nil}, map[string]*int{"1": &i}))
assert.False(t, genericsum.MapsEqual(map[string]*int{"1": &i}, map[string]*int{"1": &i, "2": nil}))
assert.False(t, genericsum.MapsEqual(map[string]*int{"1": new(int)}, map[string]*int{"1": new(int)}),
"different pointers")
type k struct {
i int
s string
}
assert.True(t, genericsum.MapsEqual(map[k]k{{10, "abc"}: {20, "def"}}, map[k]k{{10, "abc"}: {20, "def"}}))
type myMap map[int]int
assert.True(t, genericsum.MapsEqual(myMap(nil), myMap(nil)), "type aliases must also be ok")
}
func TestSliceContains(t *testing.T) {
assert.True(t, genericsum.SliceContains([]int{5, 9, 12}, 5))
assert.False(t, genericsum.SliceContains([]int{5, 9, 12}, 7))
type k struct{ i, j int }
assert.True(t, genericsum.SliceContains([]k{{1, 2}, {5, 7}, {9, 12}}, k{5, 7}))
type mySlice []k
assert.True(t, genericsum.SliceContains(mySlice{{1, 2}, {5, 7}, {9, 12}}, k{5, 7}))
}
func TestMergeChansTypes(t *testing.T) {
t.Run("floats", func(t *testing.T) {
defer goleak.VerifyNone(t)
chans := make([]chan float64, 5)
chanArgs := make([]<-chan float64, 5)
for i := range chans {
chans[i] = make(chan float64, 1)
chanArgs[i] = chans[i]
}
ch := genericsum.MergeChans(chanArgs...)
for _, ch := range chans {
close(ch)
}
for range ch {
}
})
t.Run("structs", func(t *testing.T) {
defer goleak.VerifyNone(t)
type tp struct{}
chans := make([]chan tp, 5)
chanArgs := make([]<-chan tp, 5)
for i := range chans {
chans[i] = make(chan tp, 1)
chanArgs[i] = chans[i]
}
ch := genericsum.MergeChans(chanArgs...)
for _, ch := range chans {
close(ch)
}
for range ch {
}
})
}
func TestMergeChans(t *testing.T) {
defer goleak.VerifyNone(t)
const numChans = 10
chans := make([]chan int, numChans)
chanArgs := make([]<-chan int, numChans)
for i := range chans {
chans[i] = make(chan int, 1)
chanArgs[i] = chans[i]
}
ch := genericsum.MergeChans(chanArgs...)
chans[5] <- 10
assert.Equal(t, 10, <-ch)
chans[1] <- 5
assert.Equal(t, 5, <-ch)
const numIter = 1000
receivedNumbers := make([]bool, numIter)
go func() {
for i := 0; i < numIter; i++ {
chans[i%numChans] <- i
}
for _, ch := range chans {
close(ch)
}
}()
// don't ever deadlock
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var receivedNum int
Loop:
for {
select {
case v, ok := <-ch:
if !ok {
break Loop
}
require.True(t, v >= 0 && v < len(receivedNumbers), "invalid received number", v)
require.False(t, receivedNumbers[v], "shouldn't receive number twice", v)
receivedNumbers[v] = true
receivedNum++
case <-ctx.Done():
require.FailNow(t, "timeouted")
}
}
assert.Equal(t, numIter, receivedNum)
}
func TestIsHermitianMatrix(t *testing.T) {
assert.True(t, genericsum.IsHermitianMatrix([][]int{
{1, 7, 9},
{7, 2, 12},
{9, 12, 19},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]int{
{1, 12, 8},
{3, 4, 7},
{8, 7, 11},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]complex64{
{1, 3 + 2i},
{3 - 2i, 4},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]complex128{
{1, 3 + 2i, 9 - 1i},
{3 - 2i, 5, 7 - 3i},
{9 + 1i, 7 + 3i, 19},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]complex64{
{1 + 1i, 3 + 2i},
{3 - 2i, 4},
}))
first, second := [][]int{{1, 2}, {3, 4}}, [][]int{{1, 2}, {3, 4}}
assert.False(t, genericsum.IsHermitianMatrix(first))
assert.Equal(t, second, first, "shouldn't change matrix in the method")
}