github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/slices/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 slices 6 7 import ( 8 "cmp" 9 "internal/race" 10 "internal/testenv" 11 "math" 12 "strings" 13 "testing" 14 ) 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(v1, v2 int) 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) { 108 t.Errorf("EqualFunc(%v, %v, offByOne) = true, want false", s1, s1) 109 } 110 if !EqualFunc(s1, s2, offByOne) { 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}, 144 []int{1}, 145 0, 146 }, 147 { 148 []int{1}, 149 []int{}, 150 1, 151 }, 152 { 153 []int{}, 154 []int{1}, 155 -1, 156 }, 157 { 158 []int{}, 159 []int{}, 160 0, 161 }, 162 { 163 []int{1, 2, 3}, 164 []int{1, 2, 3}, 165 0, 166 }, 167 { 168 []int{1, 2, 3}, 169 []int{1, 2, 3, 4}, 170 -1, 171 }, 172 { 173 []int{1, 2, 3, 4}, 174 []int{1, 2, 3}, 175 +1, 176 }, 177 { 178 []int{1, 2, 3}, 179 []int{1, 4, 3}, 180 -1, 181 }, 182 { 183 []int{1, 4, 3}, 184 []int{1, 2, 3}, 185 +1, 186 }, 187 { 188 []int{1, 4, 3}, 189 []int{1, 2, 3, 8, 9}, 190 +1, 191 }, 192 } 193 194 var compareFloatTests = []struct { 195 s1, s2 []float64 196 want int 197 }{ 198 { 199 []float64{}, 200 []float64{}, 201 0, 202 }, 203 { 204 []float64{1}, 205 []float64{1}, 206 0, 207 }, 208 { 209 []float64{math.NaN()}, 210 []float64{math.NaN()}, 211 0, 212 }, 213 { 214 []float64{1, 2, math.NaN()}, 215 []float64{1, 2, math.NaN()}, 216 0, 217 }, 218 { 219 []float64{1, math.NaN(), 3}, 220 []float64{1, math.NaN(), 4}, 221 -1, 222 }, 223 { 224 []float64{1, math.NaN(), 3}, 225 []float64{1, 2, 4}, 226 -1, 227 }, 228 { 229 []float64{1, math.NaN(), 3}, 230 []float64{1, 2, math.NaN()}, 231 -1, 232 }, 233 { 234 []float64{1, 2, 3}, 235 []float64{1, 2, math.NaN()}, 236 +1, 237 }, 238 { 239 []float64{1, 2, 3}, 240 []float64{1, math.NaN(), 3}, 241 +1, 242 }, 243 { 244 []float64{1, math.NaN(), 3, 4}, 245 []float64{1, 2, math.NaN()}, 246 -1, 247 }, 248 } 249 250 func TestCompare(t *testing.T) { 251 intWant := func(want bool) string { 252 if want { 253 return "0" 254 } 255 return "!= 0" 256 } 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)) 260 } 261 } 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)) 265 } 266 } 267 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) 271 } 272 } 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) 276 } 277 } 278 } 279 280 func equalToCmp[T comparable](eq func(T, T) bool) func(T, T) int { 281 return func(v1, v2 T) int { 282 if eq(v1, v2) { 283 return 0 284 } 285 return 1 286 } 287 } 288 289 func TestCompareFunc(t *testing.T) { 290 intWant := func(want bool) string { 291 if want { 292 return "0" 293 } 294 return "!= 0" 295 } 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)) 299 } 300 } 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)) 304 } 305 } 306 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) 310 } 311 } 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) 315 } 316 } 317 318 s1 := []int{1, 2, 3} 319 s2 := []int{2, 3, 4} 320 if got := CompareFunc(s1, s2, equalToCmp(offByOne)); got != 0 { 321 t.Errorf("CompareFunc(%v, %v, offByOne) = %d, want 0", s1, s2, got) 322 } 323 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) 328 } 329 330 compareLower := func(v1, v2 string) int { 331 return strings.Compare(strings.ToLower(v1), strings.ToLower(v2)) 332 } 333 if got := CompareFunc(s3, s4, compareLower); got != 0 { 334 t.Errorf("CompareFunc(%v, %v, compareLower) = %d, want 0", s3, s4, got) 335 } 336 337 cmpIntString := func(v1 int, v2 string) int { 338 return strings.Compare(string(rune(v1)-1+'a'), v2) 339 } 340 if got := CompareFunc(s1, s3, cmpIntString); got != 0 { 341 t.Errorf("CompareFunc(%v, %v, cmpIntString) = %d, want 0", s1, s3, got) 342 } 343 } 344 345 var indexTests = []struct { 346 s []int 347 v int 348 want int 349 }{ 350 { 351 nil, 352 0, 353 -1, 354 }, 355 { 356 []int{}, 357 0, 358 -1, 359 }, 360 { 361 []int{1, 2, 3}, 362 2, 363 1, 364 }, 365 { 366 []int{1, 2, 2, 3}, 367 2, 368 1, 369 }, 370 { 371 []int{1, 2, 3, 2}, 372 2, 373 1, 374 }, 375 } 376 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) 381 } 382 } 383 } 384 385 func equalToIndex[T any](f func(T, T) bool, v1 T) func(T) bool { 386 return func(v2 T) bool { 387 return f(v1, v2) 388 } 389 } 390 391 func BenchmarkIndex_Large(b *testing.B) { 392 type Large [4 * 1024]byte 393 394 ss := make([]Large, 1024) 395 for i := 0; i < b.N; i++ { 396 _ = Index(ss, Large{1}) 397 } 398 } 399 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) 404 } 405 } 406 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) 410 } 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) 413 } 414 } 415 416 func BenchmarkIndexFunc_Large(b *testing.B) { 417 type Large [4 * 1024]byte 418 419 ss := make([]Large, 1024) 420 for i := 0; i < b.N; i++ { 421 _ = IndexFunc(ss, func(e Large) bool { 422 return e == Large{1} 423 }) 424 } 425 } 426 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) 431 } 432 } 433 } 434 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) 439 } 440 } 441 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) 445 } 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) 448 } 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) 451 } 452 } 453 454 var insertTests = []struct { 455 s []int 456 i int 457 add []int 458 want []int 459 }{ 460 { 461 []int{1, 2, 3}, 462 0, 463 []int{4}, 464 []int{4, 1, 2, 3}, 465 }, 466 { 467 []int{1, 2, 3}, 468 1, 469 []int{4}, 470 []int{1, 4, 2, 3}, 471 }, 472 { 473 []int{1, 2, 3}, 474 3, 475 []int{4}, 476 []int{1, 2, 3, 4}, 477 }, 478 { 479 []int{1, 2, 3}, 480 2, 481 []int{4, 5}, 482 []int{1, 2, 4, 5, 3}, 483 }, 484 } 485 486 func TestInsert(t *testing.T) { 487 s := []int{1, 2, 3} 488 if got := Insert(s, 0); !Equal(got, s) { 489 t.Errorf("Insert(%v, 0) = %v, want %v", s, got, s) 490 } 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) 495 } 496 } 497 498 if !testenv.OptimizationOff() && !race.Enabled { 499 // Allocations should be amortized. 500 const count = 50 501 n := testing.AllocsPerRun(10, func() { 502 s := []int{1, 2, 3} 503 for i := 0; i < count; i++ { 504 s = Insert(s, 0, 1) 505 } 506 }) 507 if n > count/2 { 508 t.Errorf("too many allocations inserting %d elements: got %v, want less than %d", count, n, count/2) 509 } 510 } 511 } 512 513 func TestInsertOverlap(t *testing.T) { 514 const N = 10 515 a := make([]int, N) 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++ { 522 a[k] = k 523 } 524 want = want[:0] 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) 531 } 532 } 533 } 534 } 535 } 536 } 537 538 var deleteTests = []struct { 539 s []int 540 i, j int 541 want []int 542 }{ 543 { 544 []int{1, 2, 3}, 545 0, 546 0, 547 []int{1, 2, 3}, 548 }, 549 { 550 []int{1, 2, 3}, 551 0, 552 1, 553 []int{2, 3}, 554 }, 555 { 556 []int{1, 2, 3}, 557 3, 558 3, 559 []int{1, 2, 3}, 560 }, 561 { 562 []int{1, 2, 3}, 563 0, 564 2, 565 []int{3}, 566 }, 567 { 568 []int{1, 2, 3}, 569 0, 570 3, 571 []int{}, 572 }, 573 } 574 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) 580 } 581 } 582 } 583 584 var deleteFuncTests = []struct { 585 s []int 586 fn func(int) bool 587 want []int 588 }{ 589 { 590 nil, 591 func(int) bool { return true }, 592 nil, 593 }, 594 { 595 []int{1, 2, 3}, 596 func(int) bool { return true }, 597 nil, 598 }, 599 { 600 []int{1, 2, 3}, 601 func(int) bool { return false }, 602 []int{1, 2, 3}, 603 }, 604 { 605 []int{1, 2, 3}, 606 func(i int) bool { return i > 2 }, 607 []int{1, 2}, 608 }, 609 { 610 []int{1, 2, 3}, 611 func(i int) bool { return i < 2 }, 612 []int{2, 3}, 613 }, 614 { 615 []int{10, 2, 30}, 616 func(i int) bool { return i >= 10 }, 617 []int{2}, 618 }, 619 } 620 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) 626 } 627 } 628 } 629 630 func panics(f func()) (b bool) { 631 defer func() { 632 if x := recover(); x != nil { 633 b = true 634 } 635 }() 636 f() 637 return false 638 } 639 640 func TestDeletePanics(t *testing.T) { 641 for _, test := range []struct { 642 name string 643 s []int 644 i, j int 645 }{ 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}, 651 } { 652 if !panics(func() { Delete(test.s, test.i, test.j) }) { 653 t.Errorf("Delete %s: got no panic, want panic", test.name) 654 } 655 } 656 } 657 658 func TestClone(t *testing.T) { 659 s1 := []int{1, 2, 3} 660 s2 := Clone(s1) 661 if !Equal(s1, s2) { 662 t.Errorf("Clone(%v) = %v, want %v", s1, s2, s1) 663 } 664 s1[0] = 4 665 want := []int{1, 2, 3} 666 if !Equal(s2, want) { 667 t.Errorf("Clone(%v) changed unexpectedly to %v", want, s2) 668 } 669 if got := Clone([]int(nil)); got != nil { 670 t.Errorf("Clone(nil) = %#v, want nil", got) 671 } 672 if got := Clone(s1[:0]); got == nil || len(got) != 0 { 673 t.Errorf("Clone(%v) = %#v, want %#v", s1[:0], got, s1[:0]) 674 } 675 } 676 677 var compactTests = []struct { 678 name string 679 s []int 680 want []int 681 }{ 682 { 683 "nil", 684 nil, 685 nil, 686 }, 687 { 688 "one", 689 []int{1}, 690 []int{1}, 691 }, 692 { 693 "sorted", 694 []int{1, 2, 3}, 695 []int{1, 2, 3}, 696 }, 697 { 698 "1 item", 699 []int{1, 1, 2}, 700 []int{1, 2}, 701 }, 702 { 703 "unsorted", 704 []int{1, 2, 1}, 705 []int{1, 2, 1}, 706 }, 707 { 708 "many", 709 []int{1, 2, 2, 3, 3, 4}, 710 []int{1, 2, 3, 4}, 711 }, 712 } 713 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) 719 } 720 } 721 } 722 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++ { 728 ss = ss[:0] 729 ss = append(ss, c.s...) 730 _ = Compact(ss) 731 } 732 }) 733 } 734 } 735 736 func BenchmarkCompact_Large(b *testing.B) { 737 type Large [4 * 1024]byte 738 739 ss := make([]Large, 1024) 740 for i := 0; i < b.N; i++ { 741 _ = Compact(ss) 742 } 743 } 744 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) 750 } 751 } 752 753 s1 := []string{"a", "a", "A", "B", "b"} 754 copy := Clone(s1) 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) 758 } 759 } 760 761 func BenchmarkCompactFunc_Large(b *testing.B) { 762 type Large [4 * 1024]byte 763 764 ss := make([]Large, 1024) 765 for i := 0; i < b.N; i++ { 766 _ = CompactFunc(ss, func(a, b Large) bool { return a == b }) 767 } 768 } 769 770 func TestGrow(t *testing.T) { 771 s1 := []int{1, 2, 3} 772 773 copy := Clone(s1) 774 s2 := Grow(copy, 1000) 775 if !Equal(s1, s2) { 776 t.Errorf("Grow(%v) = %v, want %v", s1, s2, s1) 777 } 778 if cap(s2) < 1000+len(s1) { 779 t.Errorf("after Grow(%v) cap = %d, want >= %d", s1, cap(s2), 1000+len(s1)) 780 } 781 782 // Test mutation of elements between length and capacity. 783 copy = Clone(s1) 784 s3 := Grow(copy[:1], 2)[:3] 785 if !Equal(s1, s3) { 786 t.Errorf("Grow should not mutate elements between length and capacity") 787 } 788 s3 = Grow(copy[:1], 1000)[:3] 789 if !Equal(s1, s3) { 790 t.Errorf("Grow should not mutate elements between length and capacity") 791 } 792 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) 796 } 797 if n := testing.AllocsPerRun(100, func() { Grow(s2, cap(s2)-len(s2)+1) }); n != 1 { 798 errorf := t.Errorf 799 if race.Enabled || testenv.OptimizationOff() { 800 errorf = t.Logf // this allocates multiple times in race detector mode 801 } 802 errorf("Grow should allocate once when given insufficient capacity; allocated %v times", n) 803 } 804 805 // Test for negative growth sizes. 806 var gotPanic bool 807 func() { 808 defer func() { gotPanic = recover() != nil }() 809 Grow(s1, -1) 810 }() 811 if !gotPanic { 812 t.Errorf("Grow(-1) did not panic; expected a panic") 813 } 814 } 815 816 func TestClip(t *testing.T) { 817 s1 := []int{1, 2, 3, 4, 5, 6}[:3] 818 orig := Clone(s1) 819 if len(s1) != 3 { 820 t.Errorf("len(%v) = %d, want 3", s1, len(s1)) 821 } 822 if cap(s1) < 6 { 823 t.Errorf("cap(%v[:3]) = %d, want >= 6", orig, cap(s1)) 824 } 825 s2 := Clip(s1) 826 if !Equal(s1, s2) { 827 t.Errorf("Clip(%v) = %v, want %v", s1, s2, s1) 828 } 829 if cap(s2) != 3 { 830 t.Errorf("cap(Clip(%v)) = %d, want 3", orig, cap(s2)) 831 } 832 } 833 834 func TestReverse(t *testing.T) { 835 even := []int{3, 1, 4, 1, 5, 9} // len = 6 836 Reverse(even) 837 if want := []int{9, 5, 1, 4, 1, 3}; !Equal(even, want) { 838 t.Errorf("Reverse(even) = %v, want %v", even, want) 839 } 840 841 odd := []int{3, 1, 4, 1, 5, 9, 2} // len = 7 842 Reverse(odd) 843 if want := []int{2, 9, 5, 1, 4, 1, 3}; !Equal(odd, want) { 844 t.Errorf("Reverse(odd) = %v, want %v", odd, want) 845 } 846 847 words := strings.Fields("one two three") 848 Reverse(words) 849 if want := strings.Fields("three two one"); !Equal(words, want) { 850 t.Errorf("Reverse(words) = %v, want %v", words, want) 851 } 852 853 singleton := []string{"one"} 854 Reverse(singleton) 855 if want := []string{"one"}; !Equal(singleton, want) { 856 t.Errorf("Reverse(singeleton) = %v, want %v", singleton, want) 857 } 858 859 Reverse[string](nil) 860 } 861 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 { 864 s = Delete(s, i, j) 865 s = Insert(s, i, v...) 866 return s 867 } 868 869 func TestReplace(t *testing.T) { 870 for _, test := range []struct { 871 s, v []int 872 i, j int 873 }{ 874 {}, // all zero value 875 { 876 s: []int{1, 2, 3, 4}, 877 v: []int{5}, 878 i: 1, 879 j: 2, 880 }, 881 { 882 s: []int{1, 2, 3, 4}, 883 v: []int{5, 6, 7, 8}, 884 i: 1, 885 j: 2, 886 }, 887 { 888 s: func() []int { 889 s := make([]int, 3, 20) 890 s[0] = 0 891 s[1] = 1 892 s[2] = 2 893 return s 894 }(), 895 v: []int{3, 4, 5, 6, 7}, 896 i: 0, 897 j: 1, 898 }, 899 } { 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) 905 } 906 } 907 } 908 909 func TestReplacePanics(t *testing.T) { 910 for _, test := range []struct { 911 name string 912 s, v []int 913 i, j int 914 }{ 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}, 918 } { 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) 922 } 923 } 924 } 925 926 func TestReplaceOverlap(t *testing.T) { 927 const N = 10 928 a := make([]int, N) 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++ { 936 a[k] = k 937 } 938 want = want[:0] 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) 945 } 946 } 947 } 948 } 949 } 950 } 951 } 952 953 func BenchmarkReplace(b *testing.B) { 954 cases := []struct { 955 name string 956 s, v func() []int 957 i, j int 958 }{ 959 { 960 name: "fast", 961 s: func() []int { 962 return make([]int, 100) 963 }, 964 v: func() []int { 965 return make([]int, 20) 966 }, 967 i: 10, 968 j: 40, 969 }, 970 { 971 name: "slow", 972 s: func() []int { 973 return make([]int, 100) 974 }, 975 v: func() []int { 976 return make([]int, 20) 977 }, 978 i: 0, 979 j: 2, 980 }, 981 } 982 983 for _, c := range cases { 984 b.Run("naive-"+c.name, func(b *testing.B) { 985 for k := 0; k < b.N; k++ { 986 s := c.s() 987 v := c.v() 988 _ = naiveReplace(s, c.i, c.j, v...) 989 } 990 }) 991 b.Run("optimized-"+c.name, func(b *testing.B) { 992 for k := 0; k < b.N; k++ { 993 s := c.s() 994 v := c.v() 995 _ = Replace(s, c.i, c.j, v...) 996 } 997 }) 998 } 999 1000 } 1001 1002 func TestRotate(t *testing.T) { 1003 const N = 10 1004 s := make([]int, 0, N) 1005 for n := 0; n < N; n++ { 1006 for r := 0; r < n; r++ { 1007 s = s[:0] 1008 for i := 0; i < n; i++ { 1009 s = append(s, i) 1010 } 1011 rotateLeft(s, r) 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]) 1015 } 1016 } 1017 } 1018 } 1019 } 1020 1021 func TestInsertGrowthRate(t *testing.T) { 1022 b := make([]byte, 1) 1023 maxCap := cap(b) 1024 nGrow := 0 1025 const N = 1e6 1026 for i := 0; i < N; i++ { 1027 b = Insert(b, len(b)-1, 0) 1028 if cap(b) > maxCap { 1029 maxCap = cap(b) 1030 nGrow++ 1031 } 1032 } 1033 want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices 1034 if nGrow > want { 1035 t.Errorf("too many grows. got:%d want:%d", nGrow, want) 1036 } 1037 } 1038 1039 func TestReplaceGrowthRate(t *testing.T) { 1040 b := make([]byte, 2) 1041 maxCap := cap(b) 1042 nGrow := 0 1043 const N = 1e6 1044 for i := 0; i < N; i++ { 1045 b = Replace(b, len(b)-2, len(b)-1, 0, 0) 1046 if cap(b) > maxCap { 1047 maxCap = cap(b) 1048 nGrow++ 1049 } 1050 } 1051 want := int(math.Log(N) / math.Log(1.25)) // 1.25 == growth rate for large slices 1052 if nGrow > want { 1053 t.Errorf("too many grows. got:%d want:%d", nGrow, want) 1054 } 1055 }