1// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package slices_test
6
7import (
8	"cmp"
9	"internal/race"
10	"internal/testenv"
11	"math"
12	. "slices"
13	"strings"
14	"testing"
15)
16
17var equalIntTests = []struct {
18	s1, s2 []int
19	want   bool
20}{
21	{
22		[]int{1},
23		nil,
24		false,
25	},
26	{
27		[]int{},
28		nil,
29		true,
30	},
31	{
32		[]int{1, 2, 3},
33		[]int{1, 2, 3},
34		true,
35	},
36	{
37		[]int{1, 2, 3},
38		[]int{1, 2, 3, 4},
39		false,
40	},
41}
42
43var equalFloatTests = []struct {
44	s1, s2       []float64
45	wantEqual    bool
46	wantEqualNaN bool
47}{
48	{
49		[]float64{1, 2},
50		[]float64{1, 2},
51		true,
52		true,
53	},
54	{
55		[]float64{1, 2, math.NaN()},
56		[]float64{1, 2, math.NaN()},
57		false,
58		true,
59	},
60}
61
62func TestEqual(t *testing.T) {
63	for _, test := range equalIntTests {
64		if got := Equal(test.s1, test.s2); got != test.want {
65			t.Errorf("Equal(%v, %v) = %t, want %t", test.s1, test.s2, got, test.want)
66		}
67	}
68	for _, test := range equalFloatTests {
69		if got := Equal(test.s1, test.s2); got != test.wantEqual {
70			t.Errorf("Equal(%v, %v) = %t, want %t", test.s1, test.s2, got, test.wantEqual)
71		}
72	}
73}
74
75// equal is simply ==.
76func equal[T comparable](v1, v2 T) bool {
77	return v1 == v2
78}
79
80// equalNaN is like == except that all NaNs are equal.
81func equalNaN[T comparable](v1, v2 T) bool {
82	isNaN := func(f T) bool { return f != f }
83	return v1 == v2 || (isNaN(v1) && isNaN(v2))
84}
85
86// offByOne returns true if integers v1 and v2 differ by 1.
87func offByOne(v1, v2 int) bool {
88	return v1 == v2+1 || v1 == v2-1
89}
90
91func TestEqualFunc(t *testing.T) {
92	for _, test := range equalIntTests {
93		if got := EqualFunc(test.s1, test.s2, equal[int]); got != test.want {
94			t.Errorf("EqualFunc(%v, %v, equal[int]) = %t, want %t", test.s1, test.s2, got, test.want)
95		}
96	}
97	for _, test := range equalFloatTests {
98		if got := EqualFunc(test.s1, test.s2, equal[float64]); got != test.wantEqual {
99			t.Errorf("Equal(%v, %v, equal[float64]) = %t, want %t", test.s1, test.s2, got, test.wantEqual)
100		}
101		if got := EqualFunc(test.s1, test.s2, equalNaN[float64]); got != test.wantEqualNaN {
102			t.Errorf("Equal(%v, %v, equalNaN[float64]) = %t, want %t", test.s1, test.s2, got, test.wantEqualNaN)
103		}
104	}
105
106	s1 := []int{1, 2, 3}
107	s2 := []int{2, 3, 4}
108	if EqualFunc(s1, s1, offByOne) {
109		t.Errorf("EqualFunc(%v, %v, offByOne) = true, want false", s1, s1)
110	}
111	if !EqualFunc(s1, s2, offByOne) {
112		t.Errorf("EqualFunc(%v, %v, offByOne) = false, want true", s1, s2)
113	}
114
115	s3 := []string{"a", "b", "c"}
116	s4 := []string{"A", "B", "C"}
117	if !EqualFunc(s3, s4, strings.EqualFold) {
118		t.Errorf("EqualFunc(%v, %v, strings.EqualFold) = false, want true", s3, s4)
119	}
120
121	cmpIntString := func(v1 int, v2 string) bool {
122		return string(rune(v1)-1+'a') == v2
123	}
124	if !EqualFunc(s1, s3, cmpIntString) {
125		t.Errorf("EqualFunc(%v, %v, cmpIntString) = false, want true", s1, s3)
126	}
127}
128
129func BenchmarkEqualFunc_Large(b *testing.B) {
130	type Large [4 * 1024]byte
131
132	xs := make([]Large, 1024)
133	ys := make([]Large, 1024)
134	for i := 0; i < b.N; i++ {
135		_ = EqualFunc(xs, ys, func(x, y Large) bool { return x == y })
136	}
137}
138
139var compareIntTests = []struct {
140	s1, s2 []int
141	want   int
142}{
143	{
144		[]int{1},
145		[]int{1},
146		0,
147	},
148	{
149		[]int{1},
150		[]int{},
151		1,
152	},
153	{
154		[]int{},
155		[]int{1},
156		-1,
157	},
158	{
159		[]int{},
160		[]int{},
161		0,
162	},
163	{
164		[]int{1, 2, 3},
165		[]int{1, 2, 3},
166		0,
167	},
168	{
169		[]int{1, 2, 3},
170		[]int{1, 2, 3, 4},
171		-1,
172	},
173	{
174		[]int{1, 2, 3, 4},
175		[]int{1, 2, 3},
176		+1,
177	},
178	{
179		[]int{1, 2, 3},
180		[]int{1, 4, 3},
181		-1,
182	},
183	{
184		[]int{1, 4, 3},
185		[]int{1, 2, 3},
186		+1,
187	},
188	{
189		[]int{1, 4, 3},
190		[]int{1, 2, 3, 8, 9},
191		+1,
192	},
193}
194
195var compareFloatTests = []struct {
196	s1, s2 []float64
197	want   int
198}{
199	{
200		[]float64{},
201		[]float64{},
202		0,
203	},
204	{
205		[]float64{1},
206		[]float64{1},
207		0,
208	},
209	{
210		[]float64{math.NaN()},
211		[]float64{math.NaN()},
212		0,
213	},
214	{
215		[]float64{1, 2, math.NaN()},
216		[]float64{1, 2, math.NaN()},
217		0,
218	},
219	{
220		[]float64{1, math.NaN(), 3},
221		[]float64{1, math.NaN(), 4},
222		-1,
223	},
224	{
225		[]float64{1, math.NaN(), 3},
226		[]float64{1, 2, 4},
227		-1,
228	},
229	{
230		[]float64{1, math.NaN(), 3},
231		[]float64{1, 2, math.NaN()},
232		-1,
233	},
234	{
235		[]float64{1, 2, 3},
236		[]float64{1, 2, math.NaN()},
237		+1,
238	},
239	{
240		[]float64{1, 2, 3},
241		[]float64{1, math.NaN(), 3},
242		+1,
243	},
244	{
245		[]float64{1, math.NaN(), 3, 4},
246		[]float64{1, 2, math.NaN()},
247		-1,
248	},
249}
250
251func TestCompare(t *testing.T) {
252	intWant := func(want bool) string {
253		if want {
254			return "0"
255		}
256		return "!= 0"
257	}
258	for _, test := range equalIntTests {
259		if got := Compare(test.s1, test.s2); (got == 0) != test.want {
260			t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
261		}
262	}
263	for _, test := range equalFloatTests {
264		if got := Compare(test.s1, test.s2); (got == 0) != test.wantEqualNaN {
265			t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqualNaN))
266		}
267	}
268
269	for _, test := range compareIntTests {
270		if got := Compare(test.s1, test.s2); got != test.want {
271			t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
272		}
273	}
274	for _, test := range compareFloatTests {
275		if got := Compare(test.s1, test.s2); got != test.want {
276			t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
277		}
278	}
279}
280
281func equalToCmp[T comparable](eq func(T, T) bool) func(T, T) int {
282	return func(v1, v2 T) int {
283		if eq(v1, v2) {
284			return 0
285		}
286		return 1
287	}
288}
289
290func TestCompareFunc(t *testing.T) {
291	intWant := func(want bool) string {
292		if want {
293			return "0"
294		}
295		return "!= 0"
296	}
297	for _, test := range equalIntTests {
298		if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[int])); (got == 0) != test.want {
299			t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[int])) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
300		}
301	}
302	for _, test := range equalFloatTests {
303		if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[float64])); (got == 0) != test.wantEqual {
304			t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[float64])) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqual))
305		}
306	}
307
308	for _, test := range compareIntTests {
309		if got := CompareFunc(test.s1, test.s2, cmp.Compare[int]); got != test.want {
310			t.Errorf("CompareFunc(%v, %v, cmp[int]) = %d, want %d", test.s1, test.s2, got, test.want)
311		}
312	}
313	for _, test := range compareFloatTests {
314		if got := CompareFunc(test.s1, test.s2, cmp.Compare[float64]); got != test.want {
315			t.Errorf("CompareFunc(%v, %v, cmp[float64]) = %d, want %d", test.s1, test.s2, got, test.want)
316		}
317	}
318
319	s1 := []int{1, 2, 3}
320	s2 := []int{2, 3, 4}
321	if got := CompareFunc(s1, s2, equalToCmp(offByOne)); got != 0 {
322		t.Errorf("CompareFunc(%v, %v, offByOne) = %d, want 0", s1, s2, got)
323	}
324
325	s3 := []string{"a", "b", "c"}
326	s4 := []string{"A", "B", "C"}
327	if got := CompareFunc(s3, s4, strings.Compare); got != 1 {
328		t.Errorf("CompareFunc(%v, %v, strings.Compare) = %d, want 1", s3, s4, got)
329	}
330
331	compareLower := func(v1, v2 string) int {
332		return strings.Compare(strings.ToLower(v1), strings.ToLower(v2))
333	}
334	if got := CompareFunc(s3, s4, compareLower); got != 0 {
335		t.Errorf("CompareFunc(%v, %v, compareLower) = %d, want 0", s3, s4, got)
336	}
337
338	cmpIntString := func(v1 int, v2 string) int {
339		return strings.Compare(string(rune(v1)-1+'a'), v2)
340	}
341	if got := CompareFunc(s1, s3, cmpIntString); got != 0 {
342		t.Errorf("CompareFunc(%v, %v, cmpIntString) = %d, want 0", s1, s3, got)
343	}
344}
345
346var indexTests = []struct {
347	s    []int
348	v    int
349	want int
350}{
351	{
352		nil,
353		0,
354		-1,
355	},
356	{
357		[]int{},
358		0,
359		-1,
360	},
361	{
362		[]int{1, 2, 3},
363		2,
364		1,
365	},
366	{
367		[]int{1, 2, 2, 3},
368		2,
369		1,
370	},
371	{
372		[]int{1, 2, 3, 2},
373		2,
374		1,
375	},
376}
377
378func TestIndex(t *testing.T) {
379	for _, test := range indexTests {
380		if got := Index(test.s, test.v); got != test.want {
381			t.Errorf("Index(%v, %v) = %d, want %d", test.s, test.v, got, test.want)
382		}
383	}
384}
385
386func equalToIndex[T any](f func(T, T) bool, v1 T) func(T) bool {
387	return func(v2 T) bool {
388		return f(v1, v2)
389	}
390}
391
392func BenchmarkIndex_Large(b *testing.B) {
393	type Large [4 * 1024]byte
394
395	ss := make([]Large, 1024)
396	for i := 0; i < b.N; i++ {
397		_ = Index(ss, Large{1})
398	}
399}
400
401func TestIndexFunc(t *testing.T) {
402	for _, test := range indexTests {
403		if got := IndexFunc(test.s, equalToIndex(equal[int], test.v)); got != test.want {
404			t.Errorf("IndexFunc(%v, equalToIndex(equal[int], %v)) = %d, want %d", test.s, test.v, got, test.want)
405		}
406	}
407
408	s1 := []string{"hi", "HI"}
409	if got := IndexFunc(s1, equalToIndex(equal[string], "HI")); got != 1 {
410		t.Errorf("IndexFunc(%v, equalToIndex(equal[string], %q)) = %d, want %d", s1, "HI", got, 1)
411	}
412	if got := IndexFunc(s1, equalToIndex(strings.EqualFold, "HI")); got != 0 {
413		t.Errorf("IndexFunc(%v, equalToIndex(strings.EqualFold, %q)) = %d, want %d", s1, "HI", got, 0)
414	}
415}
416
417func BenchmarkIndexFunc_Large(b *testing.B) {
418	type Large [4 * 1024]byte
419
420	ss := make([]Large, 1024)
421	for i := 0; i < b.N; i++ {
422		_ = IndexFunc(ss, func(e Large) bool {
423			return e == Large{1}
424		})
425	}
426}
427
428func TestContains(t *testing.T) {
429	for _, test := range indexTests {
430		if got := Contains(test.s, test.v); got != (test.want != -1) {
431			t.Errorf("Contains(%v, %v) = %t, want %t", test.s, test.v, got, test.want != -1)
432		}
433	}
434}
435
436func TestContainsFunc(t *testing.T) {
437	for _, test := range indexTests {
438		if got := ContainsFunc(test.s, equalToIndex(equal[int], test.v)); got != (test.want != -1) {
439			t.Errorf("ContainsFunc(%v, equalToIndex(equal[int], %v)) = %t, want %t", test.s, test.v, got, test.want != -1)
440		}
441	}
442
443	s1 := []string{"hi", "HI"}
444	if got := ContainsFunc(s1, equalToIndex(equal[string], "HI")); got != true {
445		t.Errorf("ContainsFunc(%v, equalToContains(equal[string], %q)) = %t, want %t", s1, "HI", got, true)
446	}
447	if got := ContainsFunc(s1, equalToIndex(equal[string], "hI")); got != false {
448		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, false)
449	}
450	if got := ContainsFunc(s1, equalToIndex(strings.EqualFold, "hI")); got != true {
451		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, true)
452	}
453}
454
455var insertTests = []struct {
456	s    []int
457	i    int
458	add  []int
459	want []int
460}{
461	{
462		[]int{1, 2, 3},
463		0,
464		[]int{4},
465		[]int{4, 1, 2, 3},
466	},
467	{
468		[]int{1, 2, 3},
469		1,
470		[]int{4},
471		[]int{1, 4, 2, 3},
472	},
473	{
474		[]int{1, 2, 3},
475		3,
476		[]int{4},
477		[]int{1, 2, 3, 4},
478	},
479	{
480		[]int{1, 2, 3},
481		2,
482		[]int{4, 5},
483		[]int{1, 2, 4, 5, 3},
484	},
485}
486
487func TestInsert(t *testing.T) {
488	s := []int{1, 2, 3}
489	if got := Insert(s, 0); !Equal(got, s) {
490		t.Errorf("Insert(%v, 0) = %v, want %v", s, got, s)
491	}
492	for _, test := range insertTests {
493		copy := Clone(test.s)
494		if got := Insert(copy, test.i, test.add...); !Equal(got, test.want) {
495			t.Errorf("Insert(%v, %d, %v...) = %v, want %v", test.s, test.i, test.add, got, test.want)
496		}
497	}
498
499	if !testenv.OptimizationOff() && !race.Enabled {
500		// Allocations should be amortized.
501		const count = 50
502		n := testing.AllocsPerRun(10, func() {
503			s := []int{1, 2, 3}
504			for i := 0; i < count; i++ {
505				s = Insert(s, 0, 1)
506			}
507		})
508		if n > count/2 {
509			t.Errorf("too many allocations inserting %d elements: got %v, want less than %d", count, n, count/2)
510		}
511	}
512}
513
514func TestInsertOverlap(t *testing.T) {
515	const N = 10
516	a := make([]int, N)
517	want := make([]int, 2*N)
518	for n := 0; n <= N; n++ { // length
519		for i := 0; i <= n; i++ { // insertion point
520			for x := 0; x <= N; x++ { // start of inserted data
521				for y := x; y <= N; y++ { // end of inserted data
522					for k := 0; k < N; k++ {
523						a[k] = k
524					}
525					want = want[:0]
526					want = append(want, a[:i]...)
527					want = append(want, a[x:y]...)
528					want = append(want, a[i:n]...)
529					got := Insert(a[:n], i, a[x:y]...)
530					if !Equal(got, want) {
531						t.Errorf("Insert with overlap failed n=%d i=%d x=%d y=%d, got %v want %v", n, i, x, y, got, want)
532					}
533				}
534			}
535		}
536	}
537}
538
539func TestInsertPanics(t *testing.T) {
540	a := [3]int{}
541	b := [1]int{}
542	for _, test := range []struct {
543		name string
544		s    []int
545		i    int
546		v    []int
547	}{
548		// There are no values.
549		{"with negative index", a[:1:1], -1, nil},
550		{"with out-of-bounds index and > cap", a[:1:1], 2, nil},
551		{"with out-of-bounds index and = cap", a[:1:2], 2, nil},
552		{"with out-of-bounds index and < cap", a[:1:3], 2, nil},
553
554		// There are values.
555		{"with negative index", a[:1:1], -1, b[:]},
556		{"with out-of-bounds index and > cap", a[:1:1], 2, b[:]},
557		{"with out-of-bounds index and = cap", a[:1:2], 2, b[:]},
558		{"with out-of-bounds index and < cap", a[:1:3], 2, b[:]},
559	} {
560		if !panics(func() { _ = Insert(test.s, test.i, test.v...) }) {
561			t.Errorf("Insert %s: got no panic, want panic", test.name)
562		}
563	}
564}
565
566var deleteTests = []struct {
567	s    []int
568	i, j int
569	want []int
570}{
571	{
572		[]int{1, 2, 3},
573		0,
574		0,
575		[]int{1, 2, 3},
576	},
577	{
578		[]int{1, 2, 3},
579		0,
580		1,
581		[]int{2, 3},
582	},
583	{
584		[]int{1, 2, 3},
585		3,
586		3,
587		[]int{1, 2, 3},
588	},
589	{
590		[]int{1, 2, 3},
591		0,
592		2,
593		[]int{3},
594	},
595	{
596		[]int{1, 2, 3},
597		0,
598		3,
599		[]int{},
600	},
601}
602
603func TestDelete(t *testing.T) {
604	for _, test := range deleteTests {
605		copy := Clone(test.s)
606		if got := Delete(copy, test.i, test.j); !Equal(got, test.want) {
607			t.Errorf("Delete(%v, %d, %d) = %v, want %v", test.s, test.i, test.j, got, test.want)
608		}
609	}
610}
611
612var deleteFuncTests = []struct {
613	s    []int
614	fn   func(int) bool
615	want []int
616}{
617	{
618		nil,
619		func(int) bool { return true },
620		nil,
621	},
622	{
623		[]int{1, 2, 3},
624		func(int) bool { return true },
625		nil,
626	},
627	{
628		[]int{1, 2, 3},
629		func(int) bool { return false },
630		[]int{1, 2, 3},
631	},
632	{
633		[]int{1, 2, 3},
634		func(i int) bool { return i > 2 },
635		[]int{1, 2},
636	},
637	{
638		[]int{1, 2, 3},
639		func(i int) bool { return i < 2 },
640		[]int{2, 3},
641	},
642	{
643		[]int{10, 2, 30},
644		func(i int) bool { return i >= 10 },
645		[]int{2},
646	},
647}
648
649func TestDeleteFunc(t *testing.T) {
650	for i, test := range deleteFuncTests {
651		copy := Clone(test.s)
652		if got := DeleteFunc(copy, test.fn); !Equal(got, test.want) {
653			t.Errorf("DeleteFunc case %d: got %v, want %v", i, got, test.want)
654		}
655	}
656}
657
658func panics(f func()) (b bool) {
659	defer func() {
660		if x := recover(); x != nil {
661			b = true
662		}
663	}()
664	f()
665	return false
666}
667
668func TestDeletePanics(t *testing.T) {
669	s := []int{0, 1, 2, 3, 4}
670	s = s[0:2]
671	_ = s[0:4] // this is a valid slice of s
672
673	for _, test := range []struct {
674		name string
675		s    []int
676		i, j int
677	}{
678		{"with negative first index", []int{42}, -2, 1},
679		{"with negative second index", []int{42}, 1, -1},
680		{"with out-of-bounds first index", []int{42}, 2, 3},
681		{"with out-of-bounds second index", []int{42}, 0, 2},
682		{"with out-of-bounds both indexes", []int{42}, 2, 2},
683		{"with invalid i>j", []int{42}, 1, 0},
684		{"s[i:j] is valid and j > len(s)", s, 0, 4},
685		{"s[i:j] is valid and i == j > len(s)", s, 3, 3},
686	} {
687		if !panics(func() { _ = Delete(test.s, test.i, test.j) }) {
688			t.Errorf("Delete %s: got no panic, want panic", test.name)
689		}
690	}
691}
692
693func TestDeleteClearTail(t *testing.T) {
694	mem := []*int{new(int), new(int), new(int), new(int), new(int), new(int)}
695	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
696
697	s = Delete(s, 2, 4)
698
699	if mem[3] != nil || mem[4] != nil {
700		// Check that potential memory leak is avoided
701		t.Errorf("Delete: want nil discarded elements, got %v, %v", mem[3], mem[4])
702	}
703	if mem[5] == nil {
704		t.Errorf("Delete: want unchanged elements beyond original len, got nil")
705	}
706}
707
708func TestDeleteFuncClearTail(t *testing.T) {
709	mem := []*int{new(int), new(int), new(int), new(int), new(int), new(int)}
710	*mem[2], *mem[3] = 42, 42
711	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
712
713	s = DeleteFunc(s, func(i *int) bool {
714		return i != nil && *i == 42
715	})
716
717	if mem[3] != nil || mem[4] != nil {
718		// Check that potential memory leak is avoided
719		t.Errorf("DeleteFunc: want nil discarded elements, got %v, %v", mem[3], mem[4])
720	}
721	if mem[5] == nil {
722		t.Errorf("DeleteFunc: want unchanged elements beyond original len, got nil")
723	}
724}
725
726func TestClone(t *testing.T) {
727	s1 := []int{1, 2, 3}
728	s2 := Clone(s1)
729	if !Equal(s1, s2) {
730		t.Errorf("Clone(%v) = %v, want %v", s1, s2, s1)
731	}
732	s1[0] = 4
733	want := []int{1, 2, 3}
734	if !Equal(s2, want) {
735		t.Errorf("Clone(%v) changed unexpectedly to %v", want, s2)
736	}
737	if got := Clone([]int(nil)); got != nil {
738		t.Errorf("Clone(nil) = %#v, want nil", got)
739	}
740	if got := Clone(s1[:0]); got == nil || len(got) != 0 {
741		t.Errorf("Clone(%v) = %#v, want %#v", s1[:0], got, s1[:0])
742	}
743}
744
745var compactTests = []struct {
746	name string
747	s    []int
748	want []int
749}{
750	{
751		"nil",
752		nil,
753		nil,
754	},
755	{
756		"one",
757		[]int{1},
758		[]int{1},
759	},
760	{
761		"sorted",
762		[]int{1, 2, 3},
763		[]int{1, 2, 3},
764	},
765	{
766		"2 items",
767		[]int{1, 1, 2},
768		[]int{1, 2},
769	},
770	{
771		"unsorted",
772		[]int{1, 2, 1},
773		[]int{1, 2, 1},
774	},
775	{
776		"many",
777		[]int{1, 2, 2, 3, 3, 4},
778		[]int{1, 2, 3, 4},
779	},
780}
781
782func TestCompact(t *testing.T) {
783	for _, test := range compactTests {
784		copy := Clone(test.s)
785		if got := Compact(copy); !Equal(got, test.want) {
786			t.Errorf("Compact(%v) = %v, want %v", test.s, got, test.want)
787		}
788	}
789}
790
791func BenchmarkCompact(b *testing.B) {
792	for _, c := range compactTests {
793		b.Run(c.name, func(b *testing.B) {
794			ss := make([]int, 0, 64)
795			for k := 0; k < b.N; k++ {
796				ss = ss[:0]
797				ss = append(ss, c.s...)
798				_ = Compact(ss)
799			}
800		})
801	}
802}
803
804func BenchmarkCompact_Large(b *testing.B) {
805	type Large [16]int
806	const N = 1024
807
808	b.Run("all_dup", func(b *testing.B) {
809		ss := make([]Large, N)
810		b.ResetTimer()
811		for i := 0; i < b.N; i++ {
812			_ = Compact(ss)
813		}
814	})
815	b.Run("no_dup", func(b *testing.B) {
816		ss := make([]Large, N)
817		for i := range ss {
818			ss[i][0] = i
819		}
820		b.ResetTimer()
821		for i := 0; i < b.N; i++ {
822			_ = Compact(ss)
823		}
824	})
825}
826
827func TestCompactFunc(t *testing.T) {
828	for _, test := range compactTests {
829		copy := Clone(test.s)
830		if got := CompactFunc(copy, equal[int]); !Equal(got, test.want) {
831			t.Errorf("CompactFunc(%v, equal[int]) = %v, want %v", test.s, got, test.want)
832		}
833	}
834
835	s1 := []string{"a", "a", "A", "B", "b"}
836	copy := Clone(s1)
837	want := []string{"a", "B"}
838	if got := CompactFunc(copy, strings.EqualFold); !Equal(got, want) {
839		t.Errorf("CompactFunc(%v, strings.EqualFold) = %v, want %v", s1, got, want)
840	}
841}
842
843func TestCompactClearTail(t *testing.T) {
844	one, two, three, four := 1, 2, 3, 4
845	mem := []*int{&one, &one, &two, &two, &three, &four}
846	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
847	copy := Clone(s)
848
849	s = Compact(s)
850
851	if want := []*int{&one, &two, &three}; !Equal(s, want) {
852		t.Errorf("Compact(%v) = %v, want %v", copy, s, want)
853	}
854
855	if mem[3] != nil || mem[4] != nil {
856		// Check that potential memory leak is avoided
857		t.Errorf("Compact: want nil discarded elements, got %v, %v", mem[3], mem[4])
858	}
859	if mem[5] != &four {
860		t.Errorf("Compact: want unchanged element beyond original len, got %v", mem[5])
861	}
862}
863
864func TestCompactFuncClearTail(t *testing.T) {
865	a, b, c, d, e, f := 1, 1, 2, 2, 3, 4
866	mem := []*int{&a, &b, &c, &d, &e, &f}
867	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
868	copy := Clone(s)
869
870	s = CompactFunc(s, func(x, y *int) bool {
871		if x == nil || y == nil {
872			return x == y
873		}
874		return *x == *y
875	})
876
877	if want := []*int{&a, &c, &e}; !Equal(s, want) {
878		t.Errorf("CompactFunc(%v) = %v, want %v", copy, s, want)
879	}
880
881	if mem[3] != nil || mem[4] != nil {
882		// Check that potential memory leak is avoided
883		t.Errorf("CompactFunc: want nil discarded elements, got %v, %v", mem[3], mem[4])
884	}
885	if mem[5] != &f {
886		t.Errorf("CompactFunc: want unchanged elements beyond original len, got %v", mem[5])
887	}
888}
889
890func BenchmarkCompactFunc(b *testing.B) {
891	for _, c := range compactTests {
892		b.Run(c.name, func(b *testing.B) {
893			ss := make([]int, 0, 64)
894			for k := 0; k < b.N; k++ {
895				ss = ss[:0]
896				ss = append(ss, c.s...)
897				_ = CompactFunc(ss, func(a, b int) bool { return a == b })
898			}
899		})
900	}
901}
902
903func BenchmarkCompactFunc_Large(b *testing.B) {
904	type Element = int
905	const N = 1024 * 1024
906
907	b.Run("all_dup", func(b *testing.B) {
908		ss := make([]Element, N)
909		b.ResetTimer()
910		for i := 0; i < b.N; i++ {
911			_ = CompactFunc(ss, func(a, b Element) bool { return a == b })
912		}
913	})
914	b.Run("no_dup", func(b *testing.B) {
915		ss := make([]Element, N)
916		for i := range ss {
917			ss[i] = i
918		}
919		b.ResetTimer()
920		for i := 0; i < b.N; i++ {
921			_ = CompactFunc(ss, func(a, b Element) bool { return a == b })
922		}
923	})
924}
925
926func TestGrow(t *testing.T) {
927	s1 := []int{1, 2, 3}
928
929	copy := Clone(s1)
930	s2 := Grow(copy, 1000)
931	if !Equal(s1, s2) {
932		t.Errorf("Grow(%v) = %v, want %v", s1, s2, s1)
933	}
934	if cap(s2) < 1000+len(s1) {
935		t.Errorf("after Grow(%v) cap = %d, want >= %d", s1, cap(s2), 1000+len(s1))
936	}
937
938	// Test mutation of elements between length and capacity.
939	copy = Clone(s1)
940	s3 := Grow(copy[:1], 2)[:3]
941	if !Equal(s1, s3) {
942		t.Errorf("Grow should not mutate elements between length and capacity")
943	}
944	s3 = Grow(copy[:1], 1000)[:3]
945	if !Equal(s1, s3) {
946		t.Errorf("Grow should not mutate elements between length and capacity")
947	}
948
949	// Test number of allocations.
950	if n := testing.AllocsPerRun(100, func() { _ = Grow(s2, cap(s2)-len(s2)) }); n != 0 {
951		t.Errorf("Grow should not allocate when given sufficient capacity; allocated %v times", n)
952	}
953	if n := testing.AllocsPerRun(100, func() { _ = Grow(s2, cap(s2)-len(s2)+1) }); n != 1 {
954		errorf := t.Errorf
955		if race.Enabled || testenv.OptimizationOff() {
956			errorf = t.Logf // this allocates multiple times in race detector mode
957		}
958		errorf("Grow should allocate once when given insufficient capacity; allocated %v times", n)
959	}
960
961	// Test for negative growth sizes.
962	var gotPanic bool
963	func() {
964		defer func() { gotPanic = recover() != nil }()
965		_ = Grow(s1, -1)
966	}()
967	if !gotPanic {
968		t.Errorf("Grow(-1) did not panic; expected a panic")
969	}
970}
971
972func TestClip(t *testing.T) {
973	s1 := []int{1, 2, 3, 4, 5, 6}[:3]
974	orig := Clone(s1)
975	if len(s1) != 3 {
976		t.Errorf("len(%v) = %d, want 3", s1, len(s1))
977	}
978	if cap(s1) < 6 {
979		t.Errorf("cap(%v[:3]) = %d, want >= 6", orig, cap(s1))
980	}
981	s2 := Clip(s1)
982	if !Equal(s1, s2) {
983		t.Errorf("Clip(%v) = %v, want %v", s1, s2, s1)
984	}
985	if cap(s2) != 3 {
986		t.Errorf("cap(Clip(%v)) = %d, want 3", orig, cap(s2))
987	}
988}
989
990func TestReverse(t *testing.T) {
991	even := []int{3, 1, 4, 1, 5, 9} // len = 6
992	Reverse(even)
993	if want := []int{9, 5, 1, 4, 1, 3}; !Equal(even, want) {
994		t.Errorf("Reverse(even) = %v, want %v", even, want)
995	}
996
997	odd := []int{3, 1, 4, 1, 5, 9, 2} // len = 7
998	Reverse(odd)
999	if want := []int{2, 9, 5, 1, 4, 1, 3}; !Equal(odd, want) {
1000		t.Errorf("Reverse(odd) = %v, want %v", odd, want)
1001	}
1002
1003	words := strings.Fields("one two three")
1004	Reverse(words)
1005	if want := strings.Fields("three two one"); !Equal(words, want) {
1006		t.Errorf("Reverse(words) = %v, want %v", words, want)
1007	}
1008
1009	singleton := []string{"one"}
1010	Reverse(singleton)
1011	if want := []string{"one"}; !Equal(singleton, want) {
1012		t.Errorf("Reverse(singeleton) = %v, want %v", singleton, want)
1013	}
1014
1015	Reverse[[]string](nil)
1016}
1017
1018// naiveReplace is a baseline implementation to the Replace function.
1019func naiveReplace[S ~[]E, E any](s S, i, j int, v ...E) S {
1020	s = Delete(s, i, j)
1021	s = Insert(s, i, v...)
1022	return s
1023}
1024
1025func TestReplace(t *testing.T) {
1026	for _, test := range []struct {
1027		s, v []int
1028		i, j int
1029	}{
1030		{}, // all zero value
1031		{
1032			s: []int{1, 2, 3, 4},
1033			v: []int{5},
1034			i: 1,
1035			j: 2,
1036		},
1037		{
1038			s: []int{1, 2, 3, 4},
1039			v: []int{5, 6, 7, 8},
1040			i: 1,
1041			j: 2,
1042		},
1043		{
1044			s: func() []int {
1045				s := make([]int, 3, 20)
1046				s[0] = 0
1047				s[1] = 1
1048				s[2] = 2
1049				return s
1050			}(),
1051			v: []int{3, 4, 5, 6, 7},
1052			i: 0,
1053			j: 1,
1054		},
1055	} {
1056		ss, vv := Clone(test.s), Clone(test.v)
1057		want := naiveReplace(ss, test.i, test.j, vv...)
1058		got := Replace(test.s, test.i, test.j, test.v...)
1059		if !Equal(got, want) {
1060			t.Errorf("Replace(%v, %v, %v, %v) = %v, want %v", test.s, test.i, test.j, test.v, got, want)
1061		}
1062	}
1063}
1064
1065func TestReplacePanics(t *testing.T) {
1066	s := []int{0, 1, 2, 3, 4}
1067	s = s[0:2]
1068	_ = s[0:4] // this is a valid slice of s
1069
1070	for _, test := range []struct {
1071		name string
1072		s, v []int
1073		i, j int
1074	}{
1075		{"indexes out of order", []int{1, 2}, []int{3}, 2, 1},
1076		{"large index", []int{1, 2}, []int{3}, 1, 10},
1077		{"negative index", []int{1, 2}, []int{3}, -1, 2},
1078		{"s[i:j] is valid and j > len(s)", s, nil, 0, 4},
1079	} {
1080		ss, vv := Clone(test.s), Clone(test.v)
1081		if !panics(func() { _ = Replace(ss, test.i, test.j, vv...) }) {
1082			t.Errorf("Replace %s: should have panicked", test.name)
1083		}
1084	}
1085}
1086
1087func TestReplaceGrow(t *testing.T) {
1088	// When Replace needs to allocate a new slice, we want the original slice
1089	// to not be changed.
1090	a, b, c, d, e, f := 1, 2, 3, 4, 5, 6
1091	mem := []*int{&a, &b, &c, &d, &e, &f}
1092	memcopy := Clone(mem)
1093	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
1094	copy := Clone(s)
1095	original := s
1096
1097	// The new elements don't fit within cap(s), so Replace will allocate.
1098	z := 99
1099	s = Replace(s, 1, 3, &z, &z, &z, &z)
1100
1101	if want := []*int{&a, &z, &z, &z, &z, &d, &e}; !Equal(s, want) {
1102		t.Errorf("Replace(%v, 1, 3, %v, %v, %v, %v) = %v, want %v", copy, &z, &z, &z, &z, s, want)
1103	}
1104
1105	if !Equal(original, copy) {
1106		t.Errorf("original slice has changed, got %v, want %v", original, copy)
1107	}
1108
1109	if !Equal(mem, memcopy) {
1110		// Changing the original tail s[len(s):cap(s)] is unwanted
1111		t.Errorf("original backing memory has changed, got %v, want %v", mem, memcopy)
1112	}
1113}
1114
1115func TestReplaceClearTail(t *testing.T) {
1116	a, b, c, d, e, f := 1, 2, 3, 4, 5, 6
1117	mem := []*int{&a, &b, &c, &d, &e, &f}
1118	s := mem[0:5] // there is 1 element beyond len(s), within cap(s)
1119	copy := Clone(s)
1120
1121	y, z := 8, 9
1122	s = Replace(s, 1, 4, &y, &z)
1123
1124	if want := []*int{&a, &y, &z, &e}; !Equal(s, want) {
1125		t.Errorf("Replace(%v) = %v, want %v", copy, s, want)
1126	}
1127
1128	if mem[4] != nil {
1129		// Check that potential memory leak is avoided
1130		t.Errorf("Replace: want nil discarded element, got %v", mem[4])
1131	}
1132	if mem[5] != &f {
1133		t.Errorf("Replace: want unchanged elements beyond original len, got %v", mem[5])
1134	}
1135}
1136
1137func TestReplaceOverlap(t *testing.T) {
1138	const N = 10
1139	a := make([]int, N)
1140	want := make([]int, 2*N)
1141	for n := 0; n <= N; n++ { // length
1142		for i := 0; i <= n; i++ { // insertion point 1
1143			for j := i; j <= n; j++ { // insertion point 2
1144				for x := 0; x <= N; x++ { // start of inserted data
1145					for y := x; y <= N; y++ { // end of inserted data
1146						for k := 0; k < N; k++ {
1147							a[k] = k
1148						}
1149						want = want[:0]
1150						want = append(want, a[:i]...)
1151						want = append(want, a[x:y]...)
1152						want = append(want, a[j:n]...)
1153						got := Replace(a[:n], i, j, a[x:y]...)
1154						if !Equal(got, want) {
1155							t.Errorf("Insert with overlap failed n=%d i=%d j=%d x=%d y=%d, got %v want %v", n, i, j, x, y, got, want)
1156						}
1157					}
1158				}
1159			}
1160		}
1161	}
1162}
1163
1164func TestReplaceEndClearTail(t *testing.T) {
1165	s := []int{11, 22, 33}
1166	v := []int{99}
1167	// case when j == len(s)
1168	i, j := 1, 3
1169	s = Replace(s, i, j, v...)
1170
1171	x := s[:3][2]
1172	if want := 0; x != want {
1173		t.Errorf("TestReplaceEndClearTail: obsolete element is %d, want %d", x, want)
1174	}
1175}
1176
1177func BenchmarkReplace(b *testing.B) {
1178	cases := []struct {
1179		name string
1180		s, v func() []int
1181		i, j int
1182	}{
1183		{
1184			name: "fast",
1185			s: func() []int {
1186				return make([]int, 100)
1187			},
1188			v: func() []int {
1189				return make([]int, 20)
1190			},
1191			i: 10,
1192			j: 40,
1193		},
1194		{
1195			name: "slow",
1196			s: func() []int {
1197				return make([]int, 100)
1198			},
1199			v: func() []int {
1200				return make([]int, 20)
1201			},
1202			i: 0,
1203			j: 2,
1204		},
1205	}
1206
1207	for _, c := range cases {
1208		b.Run("naive-"+c.name, func(b *testing.B) {
1209			for k := 0; k < b.N; k++ {
1210				s := c.s()
1211				v := c.v()
1212				_ = naiveReplace(s, c.i, c.j, v...)
1213			}
1214		})
1215		b.Run("optimized-"+c.name, func(b *testing.B) {
1216			for k := 0; k < b.N; k++ {
1217				s := c.s()
1218				v := c.v()
1219				_ = Replace(s, c.i, c.j, v...)
1220			}
1221		})
1222	}
1223
1224}
1225
1226func TestInsertGrowthRate(t *testing.T) {
1227	b := make([]byte, 1)
1228	maxCap := cap(b)
1229	nGrow := 0
1230	const N = 1e6
1231	for i := 0; i < N; i++ {
1232		b = Insert(b, len(b)-1, 0)
1233		if cap(b) > maxCap {
1234			maxCap = cap(b)
1235			nGrow++
1236		}
1237	}
1238	want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices
1239	if nGrow > want {
1240		t.Errorf("too many grows. got:%d want:%d", nGrow, want)
1241	}
1242}
1243
1244func TestReplaceGrowthRate(t *testing.T) {
1245	b := make([]byte, 2)
1246	maxCap := cap(b)
1247	nGrow := 0
1248	const N = 1e6
1249	for i := 0; i < N; i++ {
1250		b = Replace(b, len(b)-2, len(b)-1, 0, 0)
1251		if cap(b) > maxCap {
1252			maxCap = cap(b)
1253			nGrow++
1254		}
1255	}
1256	want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices
1257	if nGrow > want {
1258		t.Errorf("too many grows. got:%d want:%d", nGrow, want)
1259	}
1260}
1261
1262func apply[T any](v T, f func(T)) {
1263	f(v)
1264}
1265
1266// Test type inference with a named slice type.
1267func TestInference(t *testing.T) {
1268	s1 := []int{1, 2, 3}
1269	apply(s1, Reverse)
1270	if want := []int{3, 2, 1}; !Equal(s1, want) {
1271		t.Errorf("Reverse(%v) = %v, want %v", []int{1, 2, 3}, s1, want)
1272	}
1273
1274	type S []int
1275	s2 := S{4, 5, 6}
1276	apply(s2, Reverse)
1277	if want := (S{6, 5, 4}); !Equal(s2, want) {
1278		t.Errorf("Reverse(%v) = %v, want %v", S{4, 5, 6}, s2, want)
1279	}
1280}
1281
1282func TestConcat(t *testing.T) {
1283	cases := []struct {
1284		s    [][]int
1285		want []int
1286	}{
1287		{
1288			s:    [][]int{nil},
1289			want: nil,
1290		},
1291		{
1292			s:    [][]int{{1}},
1293			want: []int{1},
1294		},
1295		{
1296			s:    [][]int{{1}, {2}},
1297			want: []int{1, 2},
1298		},
1299		{
1300			s:    [][]int{{1}, nil, {2}},
1301			want: []int{1, 2},
1302		},
1303	}
1304	for _, tc := range cases {
1305		got := Concat(tc.s...)
1306		if !Equal(tc.want, got) {
1307			t.Errorf("Concat(%v) = %v, want %v", tc.s, got, tc.want)
1308		}
1309		var sink []int
1310		allocs := testing.AllocsPerRun(5, func() {
1311			sink = Concat(tc.s...)
1312		})
1313		_ = sink
1314		if allocs > 1 {
1315			errorf := t.Errorf
1316			if testenv.OptimizationOff() || race.Enabled {
1317				errorf = t.Logf
1318			}
1319			errorf("Concat(%v) allocated %v times; want 1", tc.s, allocs)
1320		}
1321	}
1322}
1323
1324func TestConcat_too_large(t *testing.T) {
1325	// Use zero length element to minimize memory in testing
1326	type void struct{}
1327	cases := []struct {
1328		lengths     []int
1329		shouldPanic bool
1330	}{
1331		{
1332			lengths:     []int{0, 0},
1333			shouldPanic: false,
1334		},
1335		{
1336			lengths:     []int{math.MaxInt, 0},
1337			shouldPanic: false,
1338		},
1339		{
1340			lengths:     []int{0, math.MaxInt},
1341			shouldPanic: false,
1342		},
1343		{
1344			lengths:     []int{math.MaxInt - 1, 1},
1345			shouldPanic: false,
1346		},
1347		{
1348			lengths:     []int{math.MaxInt - 1, 1, 1},
1349			shouldPanic: true,
1350		},
1351		{
1352			lengths:     []int{math.MaxInt, 1},
1353			shouldPanic: true,
1354		},
1355		{
1356			lengths:     []int{math.MaxInt, math.MaxInt},
1357			shouldPanic: true,
1358		},
1359	}
1360	for _, tc := range cases {
1361		var r any
1362		ss := make([][]void, 0, len(tc.lengths))
1363		for _, l := range tc.lengths {
1364			s := make([]void, l)
1365			ss = append(ss, s)
1366		}
1367		func() {
1368			defer func() {
1369				r = recover()
1370			}()
1371			_ = Concat(ss...)
1372		}()
1373		if didPanic := r != nil; didPanic != tc.shouldPanic {
1374			t.Errorf("slices.Concat(lens(%v)) got panic == %v",
1375				tc.lengths, didPanic)
1376		}
1377	}
1378}
1379
1380func TestRepeat(t *testing.T) {
1381	// normal cases
1382	for _, tc := range []struct {
1383		x     []int
1384		count int
1385		want  []int
1386	}{
1387		{x: []int(nil), count: 0, want: []int{}},
1388		{x: []int(nil), count: 1, want: []int{}},
1389		{x: []int(nil), count: math.MaxInt, want: []int{}},
1390		{x: []int{}, count: 0, want: []int{}},
1391		{x: []int{}, count: 1, want: []int{}},
1392		{x: []int{}, count: math.MaxInt, want: []int{}},
1393		{x: []int{0}, count: 0, want: []int{}},
1394		{x: []int{0}, count: 1, want: []int{0}},
1395		{x: []int{0}, count: 2, want: []int{0, 0}},
1396		{x: []int{0}, count: 3, want: []int{0, 0, 0}},
1397		{x: []int{0}, count: 4, want: []int{0, 0, 0, 0}},
1398		{x: []int{0, 1}, count: 0, want: []int{}},
1399		{x: []int{0, 1}, count: 1, want: []int{0, 1}},
1400		{x: []int{0, 1}, count: 2, want: []int{0, 1, 0, 1}},
1401		{x: []int{0, 1}, count: 3, want: []int{0, 1, 0, 1, 0, 1}},
1402		{x: []int{0, 1}, count: 4, want: []int{0, 1, 0, 1, 0, 1, 0, 1}},
1403		{x: []int{0, 1, 2}, count: 0, want: []int{}},
1404		{x: []int{0, 1, 2}, count: 1, want: []int{0, 1, 2}},
1405		{x: []int{0, 1, 2}, count: 2, want: []int{0, 1, 2, 0, 1, 2}},
1406		{x: []int{0, 1, 2}, count: 3, want: []int{0, 1, 2, 0, 1, 2, 0, 1, 2}},
1407		{x: []int{0, 1, 2}, count: 4, want: []int{0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2}},
1408	} {
1409		if got := Repeat(tc.x, tc.count); got == nil || cap(got) != cap(tc.want) || !Equal(got, tc.want) {
1410			t.Errorf("Repeat(%v, %v): got: %v, want: %v, (got == nil): %v, cap(got): %v, cap(want): %v",
1411				tc.x, tc.count, got, tc.want, got == nil, cap(got), cap(tc.want))
1412		}
1413	}
1414
1415	// big slices
1416	for _, tc := range []struct {
1417		x     []struct{}
1418		count int
1419		want  []struct{}
1420	}{
1421		{x: make([]struct{}, math.MaxInt/1-0), count: 1, want: make([]struct{}, 1*(math.MaxInt/1-0))},
1422		{x: make([]struct{}, math.MaxInt/2-1), count: 2, want: make([]struct{}, 2*(math.MaxInt/2-1))},
1423		{x: make([]struct{}, math.MaxInt/3-2), count: 3, want: make([]struct{}, 3*(math.MaxInt/3-2))},
1424		{x: make([]struct{}, math.MaxInt/4-3), count: 4, want: make([]struct{}, 4*(math.MaxInt/4-3))},
1425		{x: make([]struct{}, math.MaxInt/5-4), count: 5, want: make([]struct{}, 5*(math.MaxInt/5-4))},
1426		{x: make([]struct{}, math.MaxInt/6-5), count: 6, want: make([]struct{}, 6*(math.MaxInt/6-5))},
1427		{x: make([]struct{}, math.MaxInt/7-6), count: 7, want: make([]struct{}, 7*(math.MaxInt/7-6))},
1428		{x: make([]struct{}, math.MaxInt/8-7), count: 8, want: make([]struct{}, 8*(math.MaxInt/8-7))},
1429		{x: make([]struct{}, math.MaxInt/9-8), count: 9, want: make([]struct{}, 9*(math.MaxInt/9-8))},
1430	} {
1431		if got := Repeat(tc.x, tc.count); got == nil || len(got) != len(tc.want) || cap(got) != cap(tc.want) {
1432			t.Errorf("Repeat(make([]struct{}, %v), %v): (got == nil): %v, len(got): %v, len(want): %v, cap(got): %v, cap(want): %v",
1433				len(tc.x), tc.count, got == nil, len(got), len(tc.want), cap(got), cap(tc.want))
1434		}
1435	}
1436}
1437
1438func TestRepeatPanics(t *testing.T) {
1439	for _, test := range []struct {
1440		name  string
1441		x     []struct{}
1442		count int
1443	}{
1444		{name: "cannot be negative", x: make([]struct{}, 0), count: -1},
1445		{name: "the result of (len(x) * count) overflows, hi > 0", x: make([]struct{}, 3), count: math.MaxInt},
1446		{name: "the result of (len(x) * count) overflows, lo > maxInt", x: make([]struct{}, 2), count: 1 + math.MaxInt/2},
1447	} {
1448		if !panics(func() { _ = Repeat(test.x, test.count) }) {
1449			t.Errorf("Repeat %s: got no panic, want panic", test.name)
1450		}
1451	}
1452}
1453