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.
16 var equalIntTests = []struct {
42 var equalFloatTests = []struct {
54 []float64{1, 2, math.NaN()},
55 []float64{1, 2, math.NaN()},
61 func TestEqual(t *testing.T) {
62 for _, test := range equalIntTests {
63 if got := Equal(test.s1, test.s2); got != test.want {
64 t.Errorf("Equal(%v, %v) = %t, want %t", test.s1, test.s2, got, test.want)
67 for _, test := range equalFloatTests {
68 if got := Equal(test.s1, test.s2); got != test.wantEqual {
69 t.Errorf("Equal(%v, %v) = %t, want %t", test.s1, test.s2, got, test.wantEqual)
74 // equal is simply ==.
75 func equal[T comparable](v1, v2 T) bool {
79 // equalNaN is like == except that all NaNs are equal.
80 func equalNaN[T comparable](v1, v2 T) bool {
81 isNaN := func(f T) bool { return f != f }
82 return v1 == v2 || (isNaN(v1) && isNaN(v2))
85 // offByOne returns true if integers v1 and v2 differ by 1.
86 func offByOne(v1, v2 int) bool {
87 return v1 == v2+1 || v1 == v2-1
90 func TestEqualFunc(t *testing.T) {
91 for _, test := range equalIntTests {
92 if got := EqualFunc(test.s1, test.s2, equal[int]); got != test.want {
93 t.Errorf("EqualFunc(%v, %v, equal[int]) = %t, want %t", test.s1, test.s2, got, test.want)
96 for _, test := range equalFloatTests {
97 if got := EqualFunc(test.s1, test.s2, equal[float64]); got != test.wantEqual {
98 t.Errorf("Equal(%v, %v, equal[float64]) = %t, want %t", test.s1, test.s2, got, test.wantEqual)
100 if got := EqualFunc(test.s1, test.s2, equalNaN[float64]); got != test.wantEqualNaN {
101 t.Errorf("Equal(%v, %v, equalNaN[float64]) = %t, want %t", test.s1, test.s2, got, test.wantEqualNaN)
107 if EqualFunc(s1, s1, offByOne) {
108 t.Errorf("EqualFunc(%v, %v, offByOne) = true, want false", s1, s1)
110 if !EqualFunc(s1, s2, offByOne) {
111 t.Errorf("EqualFunc(%v, %v, offByOne) = false, want true", s1, s2)
114 s3 := []string{"a", "b", "c"}
115 s4 := []string{"A", "B", "C"}
116 if !EqualFunc(s3, s4, strings.EqualFold) {
117 t.Errorf("EqualFunc(%v, %v, strings.EqualFold) = false, want true", s3, s4)
120 cmpIntString := func(v1 int, v2 string) bool {
121 return string(rune(v1)-1+'a') == v2
123 if !EqualFunc(s1, s3, cmpIntString) {
124 t.Errorf("EqualFunc(%v, %v, cmpIntString) = false, want true", s1, s3)
128 func BenchmarkEqualFunc_Large(b *testing.B) {
129 type Large [4 * 1024]byte
131 xs := make([]Large, 1024)
132 ys := make([]Large, 1024)
133 for i := 0; i < b.N; i++ {
134 _ = EqualFunc(xs, ys, func(x, y Large) bool { return x == y })
138 var compareIntTests = []struct {
189 []int{1, 2, 3, 8, 9},
194 var compareFloatTests = []struct {
209 []float64{math.NaN()},
210 []float64{math.NaN()},
214 []float64{1, 2, math.NaN()},
215 []float64{1, 2, math.NaN()},
219 []float64{1, math.NaN(), 3},
220 []float64{1, math.NaN(), 4},
224 []float64{1, math.NaN(), 3},
229 []float64{1, math.NaN(), 3},
230 []float64{1, 2, math.NaN()},
235 []float64{1, 2, math.NaN()},
240 []float64{1, math.NaN(), 3},
244 []float64{1, math.NaN(), 3, 4},
245 []float64{1, 2, math.NaN()},
250 func TestCompare(t *testing.T) {
251 intWant := func(want bool) string {
257 for _, test := range equalIntTests {
258 if got := Compare(test.s1, test.s2); (got == 0) != test.want {
259 t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
262 for _, test := range equalFloatTests {
263 if got := Compare(test.s1, test.s2); (got == 0) != test.wantEqualNaN {
264 t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqualNaN))
268 for _, test := range compareIntTests {
269 if got := Compare(test.s1, test.s2); got != test.want {
270 t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
273 for _, test := range compareFloatTests {
274 if got := Compare(test.s1, test.s2); got != test.want {
275 t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
280 func equalToCmp[T comparable](eq func(T, T) bool) func(T, T) int {
281 return func(v1, v2 T) int {
289 func TestCompareFunc(t *testing.T) {
290 intWant := func(want bool) string {
296 for _, test := range equalIntTests {
297 if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[int])); (got == 0) != test.want {
298 t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[int])) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
301 for _, test := range equalFloatTests {
302 if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[float64])); (got == 0) != test.wantEqual {
303 t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[float64])) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqual))
307 for _, test := range compareIntTests {
308 if got := CompareFunc(test.s1, test.s2, cmp.Compare[int]); got != test.want {
309 t.Errorf("CompareFunc(%v, %v, cmp[int]) = %d, want %d", test.s1, test.s2, got, test.want)
312 for _, test := range compareFloatTests {
313 if got := CompareFunc(test.s1, test.s2, cmp.Compare[float64]); got != test.want {
314 t.Errorf("CompareFunc(%v, %v, cmp[float64]) = %d, want %d", test.s1, test.s2, got, test.want)
320 if got := CompareFunc(s1, s2, equalToCmp(offByOne)); got != 0 {
321 t.Errorf("CompareFunc(%v, %v, offByOne) = %d, want 0", s1, s2, got)
324 s3 := []string{"a", "b", "c"}
325 s4 := []string{"A", "B", "C"}
326 if got := CompareFunc(s3, s4, strings.Compare); got != 1 {
327 t.Errorf("CompareFunc(%v, %v, strings.Compare) = %d, want 1", s3, s4, got)
330 compareLower := func(v1, v2 string) int {
331 return strings.Compare(strings.ToLower(v1), strings.ToLower(v2))
333 if got := CompareFunc(s3, s4, compareLower); got != 0 {
334 t.Errorf("CompareFunc(%v, %v, compareLower) = %d, want 0", s3, s4, got)
337 cmpIntString := func(v1 int, v2 string) int {
338 return strings.Compare(string(rune(v1)-1+'a'), v2)
340 if got := CompareFunc(s1, s3, cmpIntString); got != 0 {
341 t.Errorf("CompareFunc(%v, %v, cmpIntString) = %d, want 0", s1, s3, got)
345 var indexTests = []struct {
377 func TestIndex(t *testing.T) {
378 for _, test := range indexTests {
379 if got := Index(test.s, test.v); got != test.want {
380 t.Errorf("Index(%v, %v) = %d, want %d", test.s, test.v, got, test.want)
385 func equalToIndex[T any](f func(T, T) bool, v1 T) func(T) bool {
386 return func(v2 T) bool {
391 func BenchmarkIndex_Large(b *testing.B) {
392 type Large [4 * 1024]byte
394 ss := make([]Large, 1024)
395 for i := 0; i < b.N; i++ {
396 _ = Index(ss, Large{1})
400 func TestIndexFunc(t *testing.T) {
401 for _, test := range indexTests {
402 if got := IndexFunc(test.s, equalToIndex(equal[int], test.v)); got != test.want {
403 t.Errorf("IndexFunc(%v, equalToIndex(equal[int], %v)) = %d, want %d", test.s, test.v, got, test.want)
407 s1 := []string{"hi", "HI"}
408 if got := IndexFunc(s1, equalToIndex(equal[string], "HI")); got != 1 {
409 t.Errorf("IndexFunc(%v, equalToIndex(equal[string], %q)) = %d, want %d", s1, "HI", got, 1)
411 if got := IndexFunc(s1, equalToIndex(strings.EqualFold, "HI")); got != 0 {
412 t.Errorf("IndexFunc(%v, equalToIndex(strings.EqualFold, %q)) = %d, want %d", s1, "HI", got, 0)
416 func BenchmarkIndexFunc_Large(b *testing.B) {
417 type Large [4 * 1024]byte
419 ss := make([]Large, 1024)
420 for i := 0; i < b.N; i++ {
421 _ = IndexFunc(ss, func(e Large) bool {
427 func TestContains(t *testing.T) {
428 for _, test := range indexTests {
429 if got := Contains(test.s, test.v); got != (test.want != -1) {
430 t.Errorf("Contains(%v, %v) = %t, want %t", test.s, test.v, got, test.want != -1)
435 func TestContainsFunc(t *testing.T) {
436 for _, test := range indexTests {
437 if got := ContainsFunc(test.s, equalToIndex(equal[int], test.v)); got != (test.want != -1) {
438 t.Errorf("ContainsFunc(%v, equalToIndex(equal[int], %v)) = %t, want %t", test.s, test.v, got, test.want != -1)
442 s1 := []string{"hi", "HI"}
443 if got := ContainsFunc(s1, equalToIndex(equal[string], "HI")); got != true {
444 t.Errorf("ContainsFunc(%v, equalToContains(equal[string], %q)) = %t, want %t", s1, "HI", got, true)
446 if got := ContainsFunc(s1, equalToIndex(equal[string], "hI")); got != false {
447 t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, false)
449 if got := ContainsFunc(s1, equalToIndex(strings.EqualFold, "hI")); got != true {
450 t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, true)
454 var insertTests = []struct {
482 []int{1, 2, 4, 5, 3},
486 func TestInsert(t *testing.T) {
488 if got := Insert(s, 0); !Equal(got, s) {
489 t.Errorf("Insert(%v, 0) = %v, want %v", s, got, s)
491 for _, test := range insertTests {
492 copy := Clone(test.s)
493 if got := Insert(copy, test.i, test.add...); !Equal(got, test.want) {
494 t.Errorf("Insert(%v, %d, %v...) = %v, want %v", test.s, test.i, test.add, got, test.want)
498 if !testenv.OptimizationOff() && !race.Enabled {
499 // Allocations should be amortized.
501 n := testing.AllocsPerRun(10, func() {
503 for i := 0; i < count; i++ {
508 t.Errorf("too many allocations inserting %d elements: got %v, want less than %d", count, n, count/2)
513 func TestInsertOverlap(t *testing.T) {
516 want := make([]int, 2*N)
517 for n := 0; n <= N; n++ { // length
518 for i := 0; i <= n; i++ { // insertion point
519 for x := 0; x <= N; x++ { // start of inserted data
520 for y := x; y <= N; y++ { // end of inserted data
521 for k := 0; k < N; k++ {
525 want = append(want, a[:i]...)
526 want = append(want, a[x:y]...)
527 want = append(want, a[i:n]...)
528 got := Insert(a[:n], i, a[x:y]...)
529 if !Equal(got, want) {
530 t.Errorf("Insert with overlap failed n=%d i=%d x=%d y=%d, got %v want %v", n, i, x, y, got, want)
538 var deleteTests = []struct {
575 func TestDelete(t *testing.T) {
576 for _, test := range deleteTests {
577 copy := Clone(test.s)
578 if got := Delete(copy, test.i, test.j); !Equal(got, test.want) {
579 t.Errorf("Delete(%v, %d, %d) = %v, want %v", test.s, test.i, test.j, got, test.want)
584 var deleteFuncTests = []struct {
591 func(int) bool { return true },
596 func(int) bool { return true },
601 func(int) bool { return false },
606 func(i int) bool { return i > 2 },
611 func(i int) bool { return i < 2 },
616 func(i int) bool { return i >= 10 },
621 func TestDeleteFunc(t *testing.T) {
622 for i, test := range deleteFuncTests {
623 copy := Clone(test.s)
624 if got := DeleteFunc(copy, test.fn); !Equal(got, test.want) {
625 t.Errorf("DeleteFunc case %d: got %v, want %v", i, got, test.want)
630 func panics(f func()) (b bool) {
632 if x := recover(); x != nil {
640 func TestDeletePanics(t *testing.T) {
641 for _, test := range []struct {
646 {"with negative first index", []int{42}, -2, 1},
647 {"with negative second index", []int{42}, 1, -1},
648 {"with out-of-bounds first index", []int{42}, 2, 3},
649 {"with out-of-bounds second index", []int{42}, 0, 2},
650 {"with invalid i>j", []int{42}, 1, 0},
652 if !panics(func() { Delete(test.s, test.i, test.j) }) {
653 t.Errorf("Delete %s: got no panic, want panic", test.name)
658 func TestClone(t *testing.T) {
662 t.Errorf("Clone(%v) = %v, want %v", s1, s2, s1)
665 want := []int{1, 2, 3}
666 if !Equal(s2, want) {
667 t.Errorf("Clone(%v) changed unexpectedly to %v", want, s2)
669 if got := Clone([]int(nil)); got != nil {
670 t.Errorf("Clone(nil) = %#v, want nil", got)
672 if got := Clone(s1[:0]); got == nil || len(got) != 0 {
673 t.Errorf("Clone(%v) = %#v, want %#v", s1[:0], got, s1[:0])
677 var compactTests = []struct {
709 []int{1, 2, 2, 3, 3, 4},
714 func TestCompact(t *testing.T) {
715 for _, test := range compactTests {
716 copy := Clone(test.s)
717 if got := Compact(copy); !Equal(got, test.want) {
718 t.Errorf("Compact(%v) = %v, want %v", test.s, got, test.want)
723 func BenchmarkCompact(b *testing.B) {
724 for _, c := range compactTests {
725 b.Run(c.name, func(b *testing.B) {
726 ss := make([]int, 0, 64)
727 for k := 0; k < b.N; k++ {
729 ss = append(ss, c.s...)
736 func BenchmarkCompact_Large(b *testing.B) {
737 type Large [4 * 1024]byte
739 ss := make([]Large, 1024)
740 for i := 0; i < b.N; i++ {
745 func TestCompactFunc(t *testing.T) {
746 for _, test := range compactTests {
747 copy := Clone(test.s)
748 if got := CompactFunc(copy, equal[int]); !Equal(got, test.want) {
749 t.Errorf("CompactFunc(%v, equal[int]) = %v, want %v", test.s, got, test.want)
753 s1 := []string{"a", "a", "A", "B", "b"}
755 want := []string{"a", "B"}
756 if got := CompactFunc(copy, strings.EqualFold); !Equal(got, want) {
757 t.Errorf("CompactFunc(%v, strings.EqualFold) = %v, want %v", s1, got, want)
761 func BenchmarkCompactFunc_Large(b *testing.B) {
762 type Large [4 * 1024]byte
764 ss := make([]Large, 1024)
765 for i := 0; i < b.N; i++ {
766 _ = CompactFunc(ss, func(a, b Large) bool { return a == b })
770 func TestGrow(t *testing.T) {
774 s2 := Grow(copy, 1000)
776 t.Errorf("Grow(%v) = %v, want %v", s1, s2, s1)
778 if cap(s2) < 1000+len(s1) {
779 t.Errorf("after Grow(%v) cap = %d, want >= %d", s1, cap(s2), 1000+len(s1))
782 // Test mutation of elements between length and capacity.
784 s3 := Grow(copy[:1], 2)[:3]
786 t.Errorf("Grow should not mutate elements between length and capacity")
788 s3 = Grow(copy[:1], 1000)[:3]
790 t.Errorf("Grow should not mutate elements between length and capacity")
793 // Test number of allocations.
794 if n := testing.AllocsPerRun(100, func() { Grow(s2, cap(s2)-len(s2)) }); n != 0 {
795 t.Errorf("Grow should not allocate when given sufficient capacity; allocated %v times", n)
797 if n := testing.AllocsPerRun(100, func() { Grow(s2, cap(s2)-len(s2)+1) }); n != 1 {
799 if race.Enabled || testenv.OptimizationOff() {
800 errorf = t.Logf // this allocates multiple times in race detector mode
802 errorf("Grow should allocate once when given insufficient capacity; allocated %v times", n)
805 // Test for negative growth sizes.
808 defer func() { gotPanic = recover() != nil }()
812 t.Errorf("Grow(-1) did not panic; expected a panic")
816 func TestClip(t *testing.T) {
817 s1 := []int{1, 2, 3, 4, 5, 6}[:3]
820 t.Errorf("len(%v) = %d, want 3", s1, len(s1))
823 t.Errorf("cap(%v[:3]) = %d, want >= 6", orig, cap(s1))
827 t.Errorf("Clip(%v) = %v, want %v", s1, s2, s1)
830 t.Errorf("cap(Clip(%v)) = %d, want 3", orig, cap(s2))
834 func TestReverse(t *testing.T) {
835 even := []int{3, 1, 4, 1, 5, 9} // len = 6
837 if want := []int{9, 5, 1, 4, 1, 3}; !Equal(even, want) {
838 t.Errorf("Reverse(even) = %v, want %v", even, want)
841 odd := []int{3, 1, 4, 1, 5, 9, 2} // len = 7
843 if want := []int{2, 9, 5, 1, 4, 1, 3}; !Equal(odd, want) {
844 t.Errorf("Reverse(odd) = %v, want %v", odd, want)
847 words := strings.Fields("one two three")
849 if want := strings.Fields("three two one"); !Equal(words, want) {
850 t.Errorf("Reverse(words) = %v, want %v", words, want)
853 singleton := []string{"one"}
855 if want := []string{"one"}; !Equal(singleton, want) {
856 t.Errorf("Reverse(singeleton) = %v, want %v", singleton, want)
862 // naiveReplace is a baseline implementation to the Replace function.
863 func naiveReplace[S ~[]E, E any](s S, i, j int, v ...E) S {
865 s = Insert(s, i, v...)
869 func TestReplace(t *testing.T) {
870 for _, test := range []struct {
874 {}, // all zero value
876 s: []int{1, 2, 3, 4},
882 s: []int{1, 2, 3, 4},
883 v: []int{5, 6, 7, 8},
889 s := make([]int, 3, 20)
895 v: []int{3, 4, 5, 6, 7},
900 ss, vv := Clone(test.s), Clone(test.v)
901 want := naiveReplace(ss, test.i, test.j, vv...)
902 got := Replace(test.s, test.i, test.j, test.v...)
903 if !Equal(got, want) {
904 t.Errorf("Replace(%v, %v, %v, %v) = %v, want %v", test.s, test.i, test.j, test.v, got, want)
909 func TestReplacePanics(t *testing.T) {
910 for _, test := range []struct {
915 {"indexes out of order", []int{1, 2}, []int{3}, 2, 1},
916 {"large index", []int{1, 2}, []int{3}, 1, 10},
917 {"negative index", []int{1, 2}, []int{3}, -1, 2},
919 ss, vv := Clone(test.s), Clone(test.v)
920 if !panics(func() { Replace(ss, test.i, test.j, vv...) }) {
921 t.Errorf("Replace %s: should have panicked", test.name)
926 func TestReplaceOverlap(t *testing.T) {
929 want := make([]int, 2*N)
930 for n := 0; n <= N; n++ { // length
931 for i := 0; i <= n; i++ { // insertion point 1
932 for j := i; j <= n; j++ { // insertion point 2
933 for x := 0; x <= N; x++ { // start of inserted data
934 for y := x; y <= N; y++ { // end of inserted data
935 for k := 0; k < N; k++ {
939 want = append(want, a[:i]...)
940 want = append(want, a[x:y]...)
941 want = append(want, a[j:n]...)
942 got := Replace(a[:n], i, j, a[x:y]...)
943 if !Equal(got, want) {
944 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)
953 func BenchmarkReplace(b *testing.B) {
962 return make([]int, 100)
965 return make([]int, 20)
973 return make([]int, 100)
976 return make([]int, 20)
983 for _, c := range cases {
984 b.Run("naive-"+c.name, func(b *testing.B) {
985 for k := 0; k < b.N; k++ {
988 _ = naiveReplace(s, c.i, c.j, v...)
991 b.Run("optimized-"+c.name, func(b *testing.B) {
992 for k := 0; k < b.N; k++ {
995 _ = Replace(s, c.i, c.j, v...)
1002 func TestRotate(t *testing.T) {
1004 s := make([]int, 0, N)
1005 for n := 0; n < N; n++ {
1006 for r := 0; r < n; r++ {
1008 for i := 0; i < n; i++ {
1012 for i := 0; i < n; i++ {
1013 if s[i] != (i+r)%n {
1014 t.Errorf("expected n=%d r=%d i:%d want:%d got:%d", n, r, i, (i+r)%n, s[i])
1021 func TestInsertGrowthRate(t *testing.T) {
1022 b := make([]byte, 1)
1026 for i := 0; i < N; i++ {
1027 b = Insert(b, len(b)-1, 0)
1028 if cap(b) > maxCap {
1033 want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices
1035 t.Errorf("too many grows. got:%d want:%d", nGrow, want)
1039 func TestReplaceGrowthRate(t *testing.T) {
1040 b := make([]byte, 2)
1044 for i := 0; i < N; i++ {
1045 b = Replace(b, len(b)-2, len(b)-1, 0, 0)
1046 if cap(b) > maxCap {
1051 want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices
1053 t.Errorf("too many grows. got:%d want:%d", nGrow, want)