blob: 07d73e90e2bc561287f5181a88d4d71618a1d31c [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package slices_test
import (
"iter"
"math/rand/v2"
. "slices"
"testing"
)
func TestAll(t *testing.T) {
for size := 0; size < 10; size++ {
var s []int
for i := range size {
s = append(s, i)
}
ei, ev := 0, 0
cnt := 0
for i, v := range All(s) {
if i != ei || v != ev {
t.Errorf("at iteration %d got %d, %d want %d, %d", cnt, i, v, ei, ev)
}
ei++
ev++
cnt++
}
if cnt != size {
t.Errorf("read %d values expected %d", cnt, size)
}
}
}
func TestBackward(t *testing.T) {
for size := 0; size < 10; size++ {
var s []int
for i := range size {
s = append(s, i)
}
ei, ev := size-1, size-1
cnt := 0
for i, v := range Backward(s) {
if i != ei || v != ev {
t.Errorf("at iteration %d got %d, %d want %d, %d", cnt, i, v, ei, ev)
}
ei--
ev--
cnt++
}
if cnt != size {
t.Errorf("read %d values expected %d", cnt, size)
}
}
}
func TestValues(t *testing.T) {
for size := 0; size < 10; size++ {
var s []int
for i := range size {
s = append(s, i)
}
ev := 0
cnt := 0
for v := range Values(s) {
if v != ev {
t.Errorf("at iteration %d got %d want %d", cnt, v, ev)
}
ev++
cnt++
}
if cnt != size {
t.Errorf("read %d values expected %d", cnt, size)
}
}
}
func testSeq(yield func(int) bool) {
for i := 0; i < 10; i += 2 {
if !yield(i) {
return
}
}
}
var testSeqResult = []int{0, 2, 4, 6, 8}
func TestAppendSeq(t *testing.T) {
s := AppendSeq([]int{1, 2}, testSeq)
want := append([]int{1, 2}, testSeqResult...)
if !Equal(s, want) {
t.Errorf("got %v, want %v", s, want)
}
}
func TestCollect(t *testing.T) {
s := Collect(testSeq)
want := testSeqResult
if !Equal(s, want) {
t.Errorf("got %v, want %v", s, want)
}
}
var iterTests = [][]string{
nil,
{"a"},
{"a", "b"},
{"b", "a"},
strs[:],
}
func TestValuesAppendSeq(t *testing.T) {
for _, prefix := range iterTests {
for _, s := range iterTests {
got := AppendSeq(prefix, Values(s))
want := append(prefix, s...)
if !Equal(got, want) {
t.Errorf("AppendSeq(%v, Values(%v)) == %v, want %v", prefix, s, got, want)
}
}
}
}
func TestValuesCollect(t *testing.T) {
for _, s := range iterTests {
got := Collect(Values(s))
if !Equal(got, s) {
t.Errorf("Collect(Values(%v)) == %v, want %v", s, got, s)
}
}
}
func TestSorted(t *testing.T) {
s := Sorted(Values(ints[:]))
if !IsSorted(s) {
t.Errorf("sorted %v", ints)
t.Errorf(" got %v", s)
}
}
func TestSortedFunc(t *testing.T) {
s := SortedFunc(Values(ints[:]), func(a, b int) int { return a - b })
if !IsSorted(s) {
t.Errorf("sorted %v", ints)
t.Errorf(" got %v", s)
}
}
func TestSortedStableFunc(t *testing.T) {
n, m := 1000, 100
data := make(intPairs, n)
for i := range data {
data[i].a = rand.IntN(m)
}
data.initB()
s := intPairs(SortedStableFunc(Values(data), intPairCmp))
if !IsSortedFunc(s, intPairCmp) {
t.Errorf("SortedStableFunc didn't sort %d ints", n)
}
if !s.inOrder(false) {
t.Errorf("SortedStableFunc wasn't stable on %d ints", n)
}
// iterVal converts a Seq2 to a Seq.
iterVal := func(seq iter.Seq2[int, intPair]) iter.Seq[intPair] {
return func(yield func(intPair) bool) {
for _, v := range seq {
if !yield(v) {
return
}
}
}
}
s = intPairs(SortedStableFunc(iterVal(Backward(data)), intPairCmp))
if !IsSortedFunc(s, intPairCmp) {
t.Errorf("SortedStableFunc didn't sort %d reverse ints", n)
}
if !s.inOrder(true) {
t.Errorf("SortedStableFunc wasn't stable on %d reverse ints", n)
}
}
func TestChunk(t *testing.T) {
cases := []struct {
name string
s []int
n int
chunks [][]int
}{
{
name: "nil",
s: nil,
n: 1,
chunks: nil,
},
{
name: "empty",
s: []int{},
n: 1,
chunks: nil,
},
{
name: "short",
s: []int{1, 2},
n: 3,
chunks: [][]int{{1, 2}},
},
{
name: "one",
s: []int{1, 2},
n: 2,
chunks: [][]int{{1, 2}},
},
{
name: "even",
s: []int{1, 2, 3, 4},
n: 2,
chunks: [][]int{{1, 2}, {3, 4}},
},
{
name: "odd",
s: []int{1, 2, 3, 4, 5},
n: 2,
chunks: [][]int{{1, 2}, {3, 4}, {5}},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
var chunks [][]int
for c := range Chunk(tc.s, tc.n) {
chunks = append(chunks, c)
}
if !chunkEqual(chunks, tc.chunks) {
t.Errorf("Chunk(%v, %d) = %v, want %v", tc.s, tc.n, chunks, tc.chunks)
}
if len(chunks) == 0 {
return
}
// Verify that appending to the end of the first chunk does not
// clobber the beginning of the next chunk.
s := Clone(tc.s)
chunks[0] = append(chunks[0], -1)
if !Equal(s, tc.s) {
t.Errorf("slice was clobbered: %v, want %v", s, tc.s)
}
})
}
}
func TestChunkPanics(t *testing.T) {
for _, test := range []struct {
name string
x []struct{}
n int
}{
{
name: "cannot be less than 1",
x: make([]struct{}, 0),
n: 0,
},
} {
if !panics(func() { _ = Chunk(test.x, test.n) }) {
t.Errorf("Chunk %s: got no panic, want panic", test.name)
}
}
}
func TestChunkRange(t *testing.T) {
// Verify Chunk iteration can be stopped.
var got [][]int
for c := range Chunk([]int{1, 2, 3, 4, -100}, 2) {
if len(got) == 2 {
// Found enough values, break early.
break
}
got = append(got, c)
}
if want := [][]int{{1, 2}, {3, 4}}; !chunkEqual(got, want) {
t.Errorf("Chunk iteration did not stop, got %v, want %v", got, want)
}
}
func chunkEqual[Slice ~[]E, E comparable](s1, s2 []Slice) bool {
return EqualFunc(s1, s2, Equal[Slice])
}