// 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]) }