373 lines
7.5 KiB
Go
373 lines
7.5 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 := []types.Elem{3, 2, 1}
|
|
l := NewList(intl...)
|
|
nl := Reverse(l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{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 n.(int) + 1
|
|
}
|
|
|
|
// Normal case
|
|
intl := []types.Elem{1, 2, 3}
|
|
l := NewList(intl...)
|
|
nl := mapFn(fn, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{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) {
|
|
return acc.(int) + el.(int), false
|
|
}
|
|
|
|
// Normal case
|
|
intl := []types.Elem{1, 2, 3, 4}
|
|
l := NewList(intl...)
|
|
r := Reduce(fn, 0, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertValue(r, 10, t)
|
|
|
|
// Short-circuit case
|
|
fns := func(acc, el types.Elem) (types.Elem, bool) {
|
|
return acc.(int) + el.(int), el.(int) > 2
|
|
}
|
|
r = Reduce(fns, 0, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertValue(r, 6, t)
|
|
|
|
// Degenerate case
|
|
l = NewList()
|
|
r = Reduce(fn, 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.(int) > 3
|
|
}
|
|
|
|
// Value found case
|
|
intl := []types.Elem{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 = []types.Elem{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.(int) > 3
|
|
}
|
|
|
|
// All match case
|
|
intl := []types.Elem{4, 5, 6}
|
|
l := NewList(intl...)
|
|
ok := All(fn, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertValue(ok, true, t)
|
|
|
|
// Not all match case
|
|
intl = []types.Elem{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.(int)%2 != 0
|
|
}
|
|
|
|
// Normal case
|
|
intl := []types.Elem{1, 2, 3, 4, 5}
|
|
l := NewList(intl...)
|
|
r := filterFn(fn, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(r, []types.Elem{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 := []types.Elem{0, 1, 2}
|
|
intl2 := []types.Elem{3, 4, 5}
|
|
l1 := NewList(intl1...)
|
|
l2 := NewList(intl2...)
|
|
blank := NewList()
|
|
intl := []types.Elem{-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, []types.Elem{-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 := []types.Elem{0, 1, 2, 3, 4}
|
|
l := NewList(intl...)
|
|
nl := takeFn(3, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{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.(int) < 3
|
|
}
|
|
|
|
// Normal case
|
|
intl := []types.Elem{0, 1, 2, 3, 4, 5}
|
|
l := NewList(intl...)
|
|
nl := takeWhileFn(pred, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{0, 1, 2}, t)
|
|
|
|
// Edge cases
|
|
intl = []types.Elem{5, 5, 5}
|
|
l = NewList(intl...)
|
|
nl = takeWhileFn(pred, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertEmpty(nl, t)
|
|
|
|
intl = []types.Elem{0, 1, 2}
|
|
l = NewList(intl...)
|
|
nl = takeWhileFn(pred, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{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 := []types.Elem{0, 1, 2, 3, 4}
|
|
l := NewList(intl...)
|
|
nl := Drop(3, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{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.(int) < 3
|
|
}
|
|
|
|
// Normal case
|
|
intl := []types.Elem{0, 1, 2, 3, 4, 5}
|
|
l := NewList(intl...)
|
|
nl := DropWhile(pred, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, []types.Elem{3, 4, 5}, t)
|
|
|
|
// Edge cases
|
|
intl = []types.Elem{5, 5, 5}
|
|
l = NewList(intl...)
|
|
nl = DropWhile(pred, l)
|
|
assertSeqContents(l, intl, t)
|
|
assertSeqContents(nl, intl, t)
|
|
|
|
intl = []types.Elem{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)
|
|
}
|