ginger/seq/seq_test.go

377 lines
7.8 KiB
Go

package seq
import (
. "testing"
"github.com/mediocregopher/ginger/types"
)
// Tests the FirstRest, Size, and ToSlice methods of a Seq
func testSeqGen(t *T, s Seq, ints []types.Elem) Seq {
intsl := uint64(len(ints))
for i := range ints {
assertSaneList(ToList(s), t)
assertValue(Size(s), intsl-uint64(i), t)
assertSeqContents(s, ints[i:], t)
first, rest, ok := s.FirstRest()
assertValue(ok, true, t)
assertValue(first, ints[i], t)
s = rest
}
return s
}
// Tests the FirstRest, Size, and ToSlice methods of an unordered Seq
func testSeqNoOrderGen(t *T, s Seq, ints []types.Elem) Seq {
intsl := uint64(len(ints))
m := map[types.Elem]bool{}
for i := range ints {
m[ints[i]] = true
}
for i := range ints {
assertSaneList(ToList(s), t)
assertValue(Size(s), intsl-uint64(i), t)
assertSeqContentsNoOrderMap(s, m, t)
first, rest, ok := s.FirstRest()
assertValue(ok, true, t)
assertInMap(first, m, t)
delete(m, first)
s = rest
}
return s
}
// Test reversing a Seq
func TestReverse(t *T) {
// Normal case
intl := elemSliceV(3, 2, 1)
l := NewList(intl...)
nl := Reverse(l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(1, 2, 3), t)
// Degenerate case
l = NewList()
nl = Reverse(l)
assertEmpty(l, t)
assertEmpty(nl, t)
}
func testMapGen(t *T, mapFn func(func(types.Elem) types.Elem, Seq) Seq) {
fn := func(n types.Elem) types.Elem {
return types.GoType{n.(types.GoType).V.(int) + 1}
}
// Normal case
intl := elemSliceV(1, 2, 3)
l := NewList(intl...)
nl := mapFn(fn, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(2, 3, 4), t)
// Degenerate case
l = NewList()
nl = mapFn(fn, l)
assertEmpty(l, t)
assertEmpty(nl, t)
}
// Test mapping over a Seq
func TestMap(t *T) {
testMapGen(t, Map)
}
// Test lazily mapping over a Seq
func TestLMap(t *T) {
testMapGen(t, LMap)
}
// Test reducing over a Seq
func TestReduce(t *T) {
fn := func(acc, el types.Elem) (types.Elem, bool) {
acci := acc.(types.GoType).V.(int)
eli := el.(types.GoType).V.(int)
return types.GoType{acci + eli}, false
}
// Normal case
intl := elemSliceV(1, 2, 3, 4)
l := NewList(intl...)
r := Reduce(fn, types.GoType{0}, l)
assertSeqContents(l, intl, t)
assertValue(r, 10, t)
// Short-circuit case
fns := func(acc, el types.Elem) (types.Elem, bool) {
acci := acc.(types.GoType).V.(int)
eli := el.(types.GoType).V.(int)
return types.GoType{acci + eli}, eli > 2
}
r = Reduce(fns, types.GoType{0}, l)
assertSeqContents(l, intl, t)
assertValue(r, 6, t)
// Degenerate case
l = NewList()
r = Reduce(fn, types.GoType{0}, l)
assertEmpty(l, t)
assertValue(r, 0, t)
}
// Test the Any function
func TestAny(t *T) {
fn := func(el types.Elem) bool {
return el.(types.GoType).V.(int) > 3
}
// Value found case
intl := elemSliceV(1, 2, 3, 4)
l := NewList(intl...)
r, ok := Any(fn, l)
assertSeqContents(l, intl, t)
assertValue(r, 4, t)
assertValue(ok, true, t)
// Value not found case
intl = elemSliceV(1, 2, 3)
l = NewList(intl...)
r, ok = Any(fn, l)
assertSeqContents(l, intl, t)
assertValue(r, nil, t)
assertValue(ok, false, t)
// Degenerate case
l = NewList()
r, ok = Any(fn, l)
assertEmpty(l, t)
assertValue(r, nil, t)
assertValue(ok, false, t)
}
// Test the All function
func TestAll(t *T) {
fn := func(el types.Elem) bool {
return el.(types.GoType).V.(int) > 3
}
// All match case
intl := elemSliceV(4, 5, 6)
l := NewList(intl...)
ok := All(fn, l)
assertSeqContents(l, intl, t)
assertValue(ok, true, t)
// Not all match case
intl = elemSliceV(3, 4, 2, 5)
l = NewList(intl...)
ok = All(fn, l)
assertSeqContents(l, intl, t)
assertValue(ok, false, t)
// Degenerate case
l = NewList()
ok = All(fn, l)
assertEmpty(l, t)
assertValue(ok, true, t)
}
func testFilterGen(t *T, filterFn func(func(types.Elem) bool, Seq) Seq) {
fn := func(el types.Elem) bool {
return el.(types.GoType).V.(int)%2 != 0
}
// Normal case
intl := elemSliceV(1, 2, 3, 4, 5)
l := NewList(intl...)
r := filterFn(fn, l)
assertSeqContents(l, intl, t)
assertSeqContents(r, elemSliceV(1, 3, 5), t)
// Degenerate cases
l = NewList()
r = filterFn(fn, l)
assertEmpty(l, t)
assertEmpty(r, t)
}
// Test the Filter function
func TestFilter(t *T) {
testFilterGen(t, Filter)
}
// Test the lazy Filter function
func TestLFilter(t *T) {
testFilterGen(t, LFilter)
}
// Test Flatten-ing of a Seq
func TestFlatten(t *T) {
// Normal case
intl1 := elemSliceV(0, 1, 2)
intl2 := elemSliceV(3, 4, 5)
l1 := NewList(intl1...)
l2 := NewList(intl2...)
blank := NewList()
intl := elemSliceV(-1, l1, l2, 6, blank, 7)
l := NewList(intl...)
nl := Flatten(l)
assertSeqContents(l1, intl1, t)
assertSeqContents(l2, intl2, t)
assertEmpty(blank, t)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(-1, 0, 1, 2, 3, 4, 5, 6, 7), t)
// Degenerate case
nl = Flatten(blank)
assertEmpty(blank, t)
assertEmpty(nl, t)
}
func testTakeGen(t *T, takeFn func(uint64, Seq) Seq) {
// Normal case
intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...)
nl := takeFn(3, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Edge cases
nl = takeFn(5, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, intl, t)
nl = takeFn(6, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, intl, t)
// Degenerate cases
empty := NewList()
nl = takeFn(1, empty)
assertEmpty(empty, t)
assertEmpty(nl, t)
nl = takeFn(0, l)
assertSeqContents(l, intl, t)
assertEmpty(nl, t)
}
// Test taking from a Seq
func TestTake(t *T) {
testTakeGen(t, Take)
}
// Test lazily taking from a Seq
func TestLTake(t *T) {
testTakeGen(t, LTake)
}
func testTakeWhileGen(t *T, takeWhileFn func(func(types.Elem) bool, Seq) Seq) {
pred := func(el types.Elem) bool {
return el.(types.GoType).V.(int) < 3
}
// Normal case
intl := elemSliceV(0, 1, 2, 3, 4, 5)
l := NewList(intl...)
nl := takeWhileFn(pred, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Edge cases
intl = elemSliceV(5, 5, 5)
l = NewList(intl...)
nl = takeWhileFn(pred, l)
assertSeqContents(l, intl, t)
assertEmpty(nl, t)
intl = elemSliceV(0, 1, 2)
l = NewList(intl...)
nl = takeWhileFn(pred, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Degenerate case
l = NewList()
nl = takeWhileFn(pred, l)
assertEmpty(l, t)
assertEmpty(nl, t)
}
// Test taking from a Seq until a given condition
func TestTakeWhile(t *T) {
testTakeWhileGen(t, TakeWhile)
}
// Test lazily taking from a Seq until a given condition
func TestLTakeWhile(t *T) {
testTakeWhileGen(t, LTakeWhile)
}
// Test dropping from a Seq
func TestDrop(t *T) {
// Normal case
intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...)
nl := Drop(3, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(3, 4), t)
// Edge cases
nl = Drop(5, l)
assertSeqContents(l, intl, t)
assertEmpty(nl, t)
nl = Drop(6, l)
assertSeqContents(l, intl, t)
assertEmpty(nl, t)
// Degenerate cases
empty := NewList()
nl = Drop(1, empty)
assertEmpty(empty, t)
assertEmpty(nl, t)
nl = Drop(0, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, intl, t)
}
// Test dropping from a Seq until a given condition
func TestDropWhile(t *T) {
pred := func(el types.Elem) bool {
return el.(types.GoType).V.(int) < 3
}
// Normal case
intl := elemSliceV(0, 1, 2, 3, 4, 5)
l := NewList(intl...)
nl := DropWhile(pred, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, elemSliceV(3, 4, 5), t)
// Edge cases
intl = elemSliceV(5, 5, 5)
l = NewList(intl...)
nl = DropWhile(pred, l)
assertSeqContents(l, intl, t)
assertSeqContents(nl, intl, t)
intl = elemSliceV(0, 1, 2)
l = NewList(intl...)
nl = DropWhile(pred, l)
assertSeqContents(l, intl, t)
assertEmpty(nl, t)
// Degenerate case
l = NewList()
nl = DropWhile(pred, l)
assertEmpty(l, t)
assertEmpty(nl, t)
}