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