github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/base/bslice/slices_test.go (about)

     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  
     5  package bslice
     6  
     7  import (
     8  	"github.com/songzhibin97/go-baseutils/base/btype"
     9  	"math"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  var raceEnabled bool
    15  
    16  var equalIntTests = []struct {
    17  	s1, s2 []int
    18  	want   bool
    19  }{
    20  	{
    21  		[]int{1},
    22  		nil,
    23  		false,
    24  	},
    25  	{
    26  		[]int{},
    27  		nil,
    28  		true,
    29  	},
    30  	{
    31  		[]int{1, 2, 3},
    32  		[]int{1, 2, 3},
    33  		true,
    34  	},
    35  	{
    36  		[]int{1, 2, 3},
    37  		[]int{1, 2, 3, 4},
    38  		false,
    39  	},
    40  }
    41  
    42  var equalFloatTests = []struct {
    43  	s1, s2       []float64
    44  	wantEqual    bool
    45  	wantEqualNaN bool
    46  }{
    47  	{
    48  		[]float64{1, 2},
    49  		[]float64{1, 2},
    50  		true,
    51  		true,
    52  	},
    53  	{
    54  		[]float64{1, 2, math.NaN()},
    55  		[]float64{1, 2, math.NaN()},
    56  		false,
    57  		true,
    58  	},
    59  }
    60  
    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)
    65  		}
    66  	}
    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)
    70  		}
    71  	}
    72  }
    73  
    74  // equal is simply ==.
    75  func equal[T comparable](v1, v2 T) bool {
    76  	return v1 == v2
    77  }
    78  
    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))
    83  }
    84  
    85  // offByOne returns true if integers v1 and v2 differ by 1.
    86  func offByOne[E btype.Integer](v1, v2 E) bool {
    87  	return v1 == v2+1 || v1 == v2-1
    88  }
    89  
    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)
    94  		}
    95  	}
    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)
    99  		}
   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)
   102  		}
   103  	}
   104  
   105  	s1 := []int{1, 2, 3}
   106  	s2 := []int{2, 3, 4}
   107  	if EqualFunc(s1, s1, offByOne[int]) {
   108  		t.Errorf("EqualFunc(%v, %v, offByOne) = true, want false", s1, s1)
   109  	}
   110  	if !EqualFunc(s1, s2, offByOne[int]) {
   111  		t.Errorf("EqualFunc(%v, %v, offByOne) = false, want true", s1, s2)
   112  	}
   113  
   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)
   118  	}
   119  
   120  	cmpIntString := func(v1 int, v2 string) bool {
   121  		return string(rune(v1)-1+'a') == v2
   122  	}
   123  	if !EqualFunc(s1, s3, cmpIntString) {
   124  		t.Errorf("EqualFunc(%v, %v, cmpIntString) = false, want true", s1, s3)
   125  	}
   126  }
   127  
   128  func BenchmarkEqualFunc_Large(b *testing.B) {
   129  	type Large [4 * 1024]byte
   130  
   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 })
   135  	}
   136  }
   137  
   138  var compareIntTests = []struct {
   139  	s1, s2 []int
   140  	want   int
   141  }{
   142  	{
   143  		[]int{1, 2, 3},
   144  		[]int{1, 2, 3, 4},
   145  		-1,
   146  	},
   147  	{
   148  		[]int{1, 2, 3, 4},
   149  		[]int{1, 2, 3},
   150  		+1,
   151  	},
   152  	{
   153  		[]int{1, 2, 3},
   154  		[]int{1, 4, 3},
   155  		-1,
   156  	},
   157  	{
   158  		[]int{1, 4, 3},
   159  		[]int{1, 2, 3},
   160  		+1,
   161  	},
   162  }
   163  
   164  var compareFloatTests = []struct {
   165  	s1, s2 []float64
   166  	want   int
   167  }{
   168  	{
   169  		[]float64{1, 2, math.NaN()},
   170  		[]float64{1, 2, math.NaN()},
   171  		0,
   172  	},
   173  	{
   174  		[]float64{1, math.NaN(), 3},
   175  		[]float64{1, math.NaN(), 4},
   176  		-1,
   177  	},
   178  	{
   179  		[]float64{1, math.NaN(), 3},
   180  		[]float64{1, 2, 4},
   181  		-1,
   182  	},
   183  	{
   184  		[]float64{1, math.NaN(), 3},
   185  		[]float64{1, 2, math.NaN()},
   186  		0,
   187  	},
   188  	{
   189  		[]float64{1, math.NaN(), 3, 4},
   190  		[]float64{1, 2, math.NaN()},
   191  		+1,
   192  	},
   193  }
   194  
   195  func TestCompare(t *testing.T) {
   196  	intWant := func(want bool) string {
   197  		if want {
   198  			return "0"
   199  		}
   200  		return "!= 0"
   201  	}
   202  	for _, test := range equalIntTests {
   203  		if got := Compare(test.s1, test.s2); (got == 0) != test.want {
   204  			t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
   205  		}
   206  	}
   207  	for _, test := range equalFloatTests {
   208  		if got := Compare(test.s1, test.s2); (got == 0) != test.wantEqualNaN {
   209  			t.Errorf("Compare(%v, %v) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqualNaN))
   210  		}
   211  	}
   212  
   213  	for _, test := range compareIntTests {
   214  		if got := Compare(test.s1, test.s2); got != test.want {
   215  			t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
   216  		}
   217  	}
   218  	for _, test := range compareFloatTests {
   219  		if got := Compare(test.s1, test.s2); got != test.want {
   220  			t.Errorf("Compare(%v, %v) = %d, want %d", test.s1, test.s2, got, test.want)
   221  		}
   222  	}
   223  }
   224  
   225  func equalToCmp[T comparable](eq func(T, T) bool) func(T, T) int {
   226  	return func(v1, v2 T) int {
   227  		if eq(v1, v2) {
   228  			return 0
   229  		}
   230  		return 1
   231  	}
   232  }
   233  
   234  func cmp[T btype.Ordered](v1, v2 T) int {
   235  	if v1 < v2 {
   236  		return -1
   237  	} else if v1 > v2 {
   238  		return 1
   239  	} else {
   240  		return 0
   241  	}
   242  }
   243  
   244  func TestCompareFunc(t *testing.T) {
   245  	intWant := func(want bool) string {
   246  		if want {
   247  			return "0"
   248  		}
   249  		return "!= 0"
   250  	}
   251  	for _, test := range equalIntTests {
   252  		if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[int])); (got == 0) != test.want {
   253  			t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[int])) = %d, want %s", test.s1, test.s2, got, intWant(test.want))
   254  		}
   255  	}
   256  	for _, test := range equalFloatTests {
   257  		if got := CompareFunc(test.s1, test.s2, equalToCmp(equal[float64])); (got == 0) != test.wantEqual {
   258  			t.Errorf("CompareFunc(%v, %v, equalToCmp(equal[float64])) = %d, want %s", test.s1, test.s2, got, intWant(test.wantEqual))
   259  		}
   260  	}
   261  
   262  	for _, test := range compareIntTests {
   263  		if got := CompareFunc(test.s1, test.s2, cmp[int]); got != test.want {
   264  			t.Errorf("CompareFunc(%v, %v, cmp[int]) = %d, want %d", test.s1, test.s2, got, test.want)
   265  		}
   266  	}
   267  	for _, test := range compareFloatTests {
   268  		if got := CompareFunc(test.s1, test.s2, cmp[float64]); got != test.want {
   269  			t.Errorf("CompareFunc(%v, %v, cmp[float64]) = %d, want %d", test.s1, test.s2, got, test.want)
   270  		}
   271  	}
   272  
   273  	s1 := []int{1, 2, 3}
   274  	s2 := []int{2, 3, 4}
   275  	if got := CompareFunc(s1, s2, equalToCmp(offByOne[int])); got != 0 {
   276  		t.Errorf("CompareFunc(%v, %v, offByOne) = %d, want 0", s1, s2, got)
   277  	}
   278  
   279  	s3 := []string{"a", "b", "c"}
   280  	s4 := []string{"A", "B", "C"}
   281  	if got := CompareFunc(s3, s4, strings.Compare); got != 1 {
   282  		t.Errorf("CompareFunc(%v, %v, strings.Compare) = %d, want 1", s3, s4, got)
   283  	}
   284  
   285  	compareLower := func(v1, v2 string) int {
   286  		return strings.Compare(strings.ToLower(v1), strings.ToLower(v2))
   287  	}
   288  	if got := CompareFunc(s3, s4, compareLower); got != 0 {
   289  		t.Errorf("CompareFunc(%v, %v, compareLower) = %d, want 0", s3, s4, got)
   290  	}
   291  
   292  	cmpIntString := func(v1 int, v2 string) int {
   293  		return strings.Compare(string(rune(v1)-1+'a'), v2)
   294  	}
   295  	if got := CompareFunc(s1, s3, cmpIntString); got != 0 {
   296  		t.Errorf("CompareFunc(%v, %v, cmpIntString) = %d, want 0", s1, s3, got)
   297  	}
   298  }
   299  
   300  var indexTests = []struct {
   301  	s    []int
   302  	v    int
   303  	want int
   304  }{
   305  	{
   306  		nil,
   307  		0,
   308  		-1,
   309  	},
   310  	{
   311  		[]int{},
   312  		0,
   313  		-1,
   314  	},
   315  	{
   316  		[]int{1, 2, 3},
   317  		2,
   318  		1,
   319  	},
   320  	{
   321  		[]int{1, 2, 2, 3},
   322  		2,
   323  		1,
   324  	},
   325  	{
   326  		[]int{1, 2, 3, 2},
   327  		2,
   328  		1,
   329  	},
   330  }
   331  
   332  func TestIndex(t *testing.T) {
   333  	for _, test := range indexTests {
   334  		if got := Index(test.s, test.v); got != test.want {
   335  			t.Errorf("Index(%v, %v) = %d, want %d", test.s, test.v, got, test.want)
   336  		}
   337  	}
   338  }
   339  
   340  func equalToIndex[T any](f func(T, T) bool, v1 T) func(T) bool {
   341  	return func(v2 T) bool {
   342  		return f(v1, v2)
   343  	}
   344  }
   345  
   346  func BenchmarkIndex_Large(b *testing.B) {
   347  	type Large [4 * 1024]byte
   348  
   349  	ss := make([]Large, 1024)
   350  	for i := 0; i < b.N; i++ {
   351  		_ = Index(ss, Large{1})
   352  	}
   353  }
   354  
   355  func TestIndexFunc(t *testing.T) {
   356  	for _, test := range indexTests {
   357  		if got := IndexFunc(test.s, equalToIndex(equal[int], test.v)); got != test.want {
   358  			t.Errorf("IndexFunc(%v, equalToIndex(equal[int], %v)) = %d, want %d", test.s, test.v, got, test.want)
   359  		}
   360  	}
   361  
   362  	s1 := []string{"hi", "HI"}
   363  	if got := IndexFunc(s1, equalToIndex(equal[string], "HI")); got != 1 {
   364  		t.Errorf("IndexFunc(%v, equalToIndex(equal[string], %q)) = %d, want %d", s1, "HI", got, 1)
   365  	}
   366  	if got := IndexFunc(s1, equalToIndex(strings.EqualFold, "HI")); got != 0 {
   367  		t.Errorf("IndexFunc(%v, equalToIndex(strings.EqualFold, %q)) = %d, want %d", s1, "HI", got, 0)
   368  	}
   369  }
   370  
   371  func BenchmarkIndexFunc_Large(b *testing.B) {
   372  	type Large [4 * 1024]byte
   373  
   374  	ss := make([]Large, 1024)
   375  	for i := 0; i < b.N; i++ {
   376  		_ = IndexFunc(ss, func(e Large) bool {
   377  			return e == Large{1}
   378  		})
   379  	}
   380  }
   381  
   382  func TestContains(t *testing.T) {
   383  	for _, test := range indexTests {
   384  		if got := Contains(test.s, test.v); got != (test.want != -1) {
   385  			t.Errorf("Contains(%v, %v) = %t, want %t", test.s, test.v, got, test.want != -1)
   386  		}
   387  	}
   388  }
   389  
   390  func TestContainsFunc(t *testing.T) {
   391  	for _, test := range indexTests {
   392  		if got := ContainsFunc(test.s, equalToIndex(equal[int], test.v)); got != (test.want != -1) {
   393  			t.Errorf("ContainsFunc(%v, equalToIndex(equal[int], %v)) = %t, want %t", test.s, test.v, got, test.want != -1)
   394  		}
   395  	}
   396  
   397  	s1 := []string{"hi", "HI"}
   398  	if got := ContainsFunc(s1, equalToIndex(equal[string], "HI")); got != true {
   399  		t.Errorf("ContainsFunc(%v, equalToContains(equal[string], %q)) = %t, want %t", s1, "HI", got, true)
   400  	}
   401  	if got := ContainsFunc(s1, equalToIndex(equal[string], "hI")); got != false {
   402  		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, false)
   403  	}
   404  	if got := ContainsFunc(s1, equalToIndex(strings.EqualFold, "hI")); got != true {
   405  		t.Errorf("ContainsFunc(%v, equalToContains(strings.EqualFold, %q)) = %t, want %t", s1, "hI", got, true)
   406  	}
   407  }
   408  
   409  var insertTests = []struct {
   410  	s    []int
   411  	i    int
   412  	add  []int
   413  	want []int
   414  }{
   415  	{
   416  		[]int{1, 2, 3},
   417  		0,
   418  		[]int{4},
   419  		[]int{4, 1, 2, 3},
   420  	},
   421  	{
   422  		[]int{1, 2, 3},
   423  		1,
   424  		[]int{4},
   425  		[]int{1, 4, 2, 3},
   426  	},
   427  	{
   428  		[]int{1, 2, 3},
   429  		3,
   430  		[]int{4},
   431  		[]int{1, 2, 3, 4},
   432  	},
   433  	{
   434  		[]int{1, 2, 3},
   435  		2,
   436  		[]int{4, 5},
   437  		[]int{1, 2, 4, 5, 3},
   438  	},
   439  }
   440  
   441  func TestInsert(t *testing.T) {
   442  	s := []int{1, 2, 3}
   443  	if got := Insert(s, 0); !Equal(got, s) {
   444  		t.Errorf("Insert(%v, 0) = %v, want %v", s, got, s)
   445  	}
   446  	for _, test := range insertTests {
   447  		copy := Clone(test.s)
   448  		if got := Insert(copy, test.i, test.add...); !Equal(got, test.want) {
   449  			t.Errorf("Insert(%v, %d, %v...) = %v, want %v", test.s, test.i, test.add, got, test.want)
   450  		}
   451  	}
   452  }
   453  
   454  var deleteTests = []struct {
   455  	s    []int
   456  	i, j int
   457  	want []int
   458  }{
   459  	{
   460  		[]int{1, 2, 3},
   461  		0,
   462  		0,
   463  		[]int{1, 2, 3},
   464  	},
   465  	{
   466  		[]int{1, 2, 3},
   467  		0,
   468  		1,
   469  		[]int{2, 3},
   470  	},
   471  	{
   472  		[]int{1, 2, 3},
   473  		3,
   474  		3,
   475  		[]int{1, 2, 3},
   476  	},
   477  	{
   478  		[]int{1, 2, 3},
   479  		0,
   480  		2,
   481  		[]int{3},
   482  	},
   483  	{
   484  		[]int{1, 2, 3},
   485  		0,
   486  		3,
   487  		[]int{},
   488  	},
   489  }
   490  
   491  func TestDelete(t *testing.T) {
   492  	for _, test := range deleteTests {
   493  		copy := Clone(test.s)
   494  		if got := Delete(copy, test.i, test.j); !Equal(got, test.want) {
   495  			t.Errorf("Delete(%v, %d, %d) = %v, want %v", test.s, test.i, test.j, got, test.want)
   496  		}
   497  	}
   498  }
   499  
   500  func panics(f func()) (b bool) {
   501  	defer func() {
   502  		if x := recover(); x != nil {
   503  			b = true
   504  		}
   505  	}()
   506  	f()
   507  	return false
   508  }
   509  
   510  func TestDeletePanics(t *testing.T) {
   511  	for _, test := range []struct {
   512  		name string
   513  		s    []int
   514  		i, j int
   515  	}{
   516  		{"with negative first index", []int{42}, -2, 1},
   517  		{"with negative second index", []int{42}, 1, -1},
   518  		{"with out-of-bounds first index", []int{42}, 2, 3},
   519  		{"with out-of-bounds second index", []int{42}, 0, 2},
   520  		{"with invalid i>j", []int{42}, 1, 0},
   521  	} {
   522  		if !panics(func() { Delete(test.s, test.i, test.j) }) {
   523  			t.Errorf("Delete %s: got no panic, want panic", test.name)
   524  		}
   525  	}
   526  }
   527  
   528  func TestClone(t *testing.T) {
   529  	s1 := []int{1, 2, 3}
   530  	s2 := Clone(s1)
   531  	if !Equal(s1, s2) {
   532  		t.Errorf("Clone(%v) = %v, want %v", s1, s2, s1)
   533  	}
   534  	s1[0] = 4
   535  	want := []int{1, 2, 3}
   536  	if !Equal(s2, want) {
   537  		t.Errorf("Clone(%v) changed unexpectedly to %v", want, s2)
   538  	}
   539  	if got := Clone([]int(nil)); got != nil {
   540  		t.Errorf("Clone(nil) = %#v, want nil", got)
   541  	}
   542  	if got := Clone(s1[:0]); got == nil || len(got) != 0 {
   543  		t.Errorf("Clone(%v) = %#v, want %#v", s1[:0], got, s1[:0])
   544  	}
   545  }
   546  
   547  var compactTests = []struct {
   548  	name string
   549  	s    []int
   550  	want []int
   551  }{
   552  	{
   553  		"nil",
   554  		nil,
   555  		nil,
   556  	},
   557  	{
   558  		"one",
   559  		[]int{1},
   560  		[]int{1},
   561  	},
   562  	{
   563  		"sorted",
   564  		[]int{1, 2, 3},
   565  		[]int{1, 2, 3},
   566  	},
   567  	{
   568  		"1 item",
   569  		[]int{1, 1, 2},
   570  		[]int{1, 2},
   571  	},
   572  	{
   573  		"unsorted",
   574  		[]int{1, 2, 1},
   575  		[]int{1, 2, 1},
   576  	},
   577  	{
   578  		"many",
   579  		[]int{1, 2, 2, 3, 3, 4},
   580  		[]int{1, 2, 3, 4},
   581  	},
   582  }
   583  
   584  func TestCompact(t *testing.T) {
   585  	for _, test := range compactTests {
   586  		copy := Clone(test.s)
   587  		if got := Compact(copy); !Equal(got, test.want) {
   588  			t.Errorf("Compact(%v) = %v, want %v", test.s, got, test.want)
   589  		}
   590  	}
   591  }
   592  
   593  func BenchmarkCompact(b *testing.B) {
   594  	for _, c := range compactTests {
   595  		b.Run(c.name, func(b *testing.B) {
   596  			ss := make([]int, 0, 64)
   597  			for k := 0; k < b.N; k++ {
   598  				ss = ss[:0]
   599  				ss = append(ss, c.s...)
   600  				_ = Compact(ss)
   601  			}
   602  		})
   603  	}
   604  }
   605  
   606  func BenchmarkCompact_Large(b *testing.B) {
   607  	type Large [4 * 1024]byte
   608  
   609  	ss := make([]Large, 1024)
   610  	for i := 0; i < b.N; i++ {
   611  		_ = Compact(ss)
   612  	}
   613  }
   614  
   615  func TestCompactFunc(t *testing.T) {
   616  	for _, test := range compactTests {
   617  		copy := Clone(test.s)
   618  		if got := CompactFunc(copy, equal[int]); !Equal(got, test.want) {
   619  			t.Errorf("CompactFunc(%v, equal[int]) = %v, want %v", test.s, got, test.want)
   620  		}
   621  	}
   622  
   623  	s1 := []string{"a", "a", "A", "B", "b"}
   624  	copy := Clone(s1)
   625  	want := []string{"a", "B"}
   626  	if got := CompactFunc(copy, strings.EqualFold); !Equal(got, want) {
   627  		t.Errorf("CompactFunc(%v, strings.EqualFold) = %v, want %v", s1, got, want)
   628  	}
   629  }
   630  
   631  func BenchmarkCompactFunc_Large(b *testing.B) {
   632  	type Large [4 * 1024]byte
   633  
   634  	ss := make([]Large, 1024)
   635  	for i := 0; i < b.N; i++ {
   636  		_ = CompactFunc(ss, func(a, b Large) bool { return a == b })
   637  	}
   638  }
   639  
   640  func TestGrow(t *testing.T) {
   641  	s1 := []int{1, 2, 3}
   642  
   643  	copy := Clone(s1)
   644  	s2 := Grow(copy, 1000)
   645  	if !Equal(s1, s2) {
   646  		t.Errorf("Grow(%v) = %v, want %v", s1, s2, s1)
   647  	}
   648  	if cap(s2) < 1000+len(s1) {
   649  		t.Errorf("after Grow(%v) cap = %d, want >= %d", s1, cap(s2), 1000+len(s1))
   650  	}
   651  
   652  	// Test mutation of elements between length and capacity.
   653  	copy = Clone(s1)
   654  	s3 := Grow(copy[:1], 2)[:3]
   655  	if !Equal(s1, s3) {
   656  		t.Errorf("Grow should not mutate elements between length and capacity")
   657  	}
   658  	s3 = Grow(copy[:1], 1000)[:3]
   659  	if !Equal(s1, s3) {
   660  		t.Errorf("Grow should not mutate elements between length and capacity")
   661  	}
   662  
   663  	// Test number of allocations.
   664  	if n := testing.AllocsPerRun(100, func() { Grow(s2, cap(s2)-len(s2)) }); n != 0 {
   665  		t.Errorf("Grow should not allocate when given sufficient capacity; allocated %v times", n)
   666  	}
   667  	if n := testing.AllocsPerRun(100, func() { Grow(s2, cap(s2)-len(s2)+1) }); n != 1 {
   668  		errorf := t.Errorf
   669  		if raceEnabled {
   670  			errorf = t.Logf // this allocates multiple times in race detector mode
   671  		}
   672  		errorf("Grow should allocate once when given insufficient capacity; allocated %v times", n)
   673  	}
   674  
   675  	// Test for negative growth sizes.
   676  	var gotPanic bool
   677  	func() {
   678  		defer func() { gotPanic = recover() != nil }()
   679  		Grow(s1, -1)
   680  	}()
   681  	if !gotPanic {
   682  		t.Errorf("Grow(-1) did not panic; expected a panic")
   683  	}
   684  }
   685  
   686  func TestClip(t *testing.T) {
   687  	s1 := []int{1, 2, 3, 4, 5, 6}[:3]
   688  	orig := Clone(s1)
   689  	if len(s1) != 3 {
   690  		t.Errorf("len(%v) = %d, want 3", s1, len(s1))
   691  	}
   692  	if cap(s1) < 6 {
   693  		t.Errorf("cap(%v[:3]) = %d, want >= 6", orig, cap(s1))
   694  	}
   695  	s2 := Clip(s1)
   696  	if !Equal(s1, s2) {
   697  		t.Errorf("Clip(%v) = %v, want %v", s1, s2, s1)
   698  	}
   699  	if cap(s2) != 3 {
   700  		t.Errorf("cap(Clip(%v)) = %d, want 3", orig, cap(s2))
   701  	}
   702  }
   703  
   704  // naiveReplace is a baseline implementation to the Replace function.
   705  func naiveReplace[S ~[]E, E any](s S, i, j int, v ...E) S {
   706  	s = Delete(s, i, j)
   707  	s = Insert(s, i, v...)
   708  	return s
   709  }
   710  
   711  func TestReplace(t *testing.T) {
   712  	for _, test := range []struct {
   713  		s, v []int
   714  		i, j int
   715  	}{
   716  		{}, // all zero value
   717  		{
   718  			s: []int{1, 2, 3, 4},
   719  			v: []int{5},
   720  			i: 1,
   721  			j: 2,
   722  		},
   723  		{
   724  			s: []int{1, 2, 3, 4},
   725  			v: []int{5, 6, 7, 8},
   726  			i: 1,
   727  			j: 2,
   728  		},
   729  		{
   730  			s: func() []int {
   731  				s := make([]int, 3, 20)
   732  				s[0] = 0
   733  				s[1] = 1
   734  				s[2] = 2
   735  				return s
   736  			}(),
   737  			v: []int{3, 4, 5, 6, 7},
   738  			i: 0,
   739  			j: 1,
   740  		},
   741  	} {
   742  		ss, vv := Clone(test.s), Clone(test.v)
   743  		want := naiveReplace(ss, test.i, test.j, vv...)
   744  		got := Replace(test.s, test.i, test.j, test.v...)
   745  		if !Equal(got, want) {
   746  			t.Errorf("Replace(%v, %v, %v, %v) = %v, want %v", test.s, test.i, test.j, test.v, got, want)
   747  		}
   748  	}
   749  }
   750  
   751  func TestReplacePanics(t *testing.T) {
   752  	for _, test := range []struct {
   753  		name string
   754  		s, v []int
   755  		i, j int
   756  	}{
   757  		{"indexes out of order", []int{1, 2}, []int{3}, 2, 1},
   758  		{"large index", []int{1, 2}, []int{3}, 1, 10},
   759  		{"negative index", []int{1, 2}, []int{3}, -1, 2},
   760  	} {
   761  		ss, vv := Clone(test.s), Clone(test.v)
   762  		if !panics(func() { Replace(ss, test.i, test.j, vv...) }) {
   763  			t.Errorf("Replace %s: should have panicked", test.name)
   764  		}
   765  	}
   766  }
   767  
   768  func BenchmarkReplace(b *testing.B) {
   769  	cases := []struct {
   770  		name string
   771  		s, v func() []int
   772  		i, j int
   773  	}{
   774  		{
   775  			name: "fast",
   776  			s: func() []int {
   777  				return make([]int, 100)
   778  			},
   779  			v: func() []int {
   780  				return make([]int, 20)
   781  			},
   782  			i: 10,
   783  			j: 40,
   784  		},
   785  		{
   786  			name: "slow",
   787  			s: func() []int {
   788  				return make([]int, 100)
   789  			},
   790  			v: func() []int {
   791  				return make([]int, 20)
   792  			},
   793  			i: 0,
   794  			j: 2,
   795  		},
   796  	}
   797  
   798  	for _, c := range cases {
   799  		b.Run("naive-"+c.name, func(b *testing.B) {
   800  			for k := 0; k < b.N; k++ {
   801  				s := c.s()
   802  				v := c.v()
   803  				_ = naiveReplace(s, c.i, c.j, v...)
   804  			}
   805  		})
   806  		b.Run("optimized-"+c.name, func(b *testing.B) {
   807  			for k := 0; k < b.N; k++ {
   808  				s := c.s()
   809  				v := c.v()
   810  				_ = Replace(s, c.i, c.j, v...)
   811  			}
   812  		})
   813  	}
   814  
   815  }