1package funk 2 3import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9) 10 11func TestChainChunk(t *testing.T) { 12 testCases := []struct { 13 In interface{} 14 Size int 15 }{ 16 {In: []int{0, 1, 2, 3, 4}, Size: 2}, 17 {In: []int{}, Size: 2}, 18 {In: []int{1}, Size: 2}, 19 } 20 21 for idx, tc := range testCases { 22 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 23 is := assert.New(t) 24 25 expected := Chunk(tc.In, tc.Size) 26 actual := Chain(tc.In).Chunk(tc.Size).Value() 27 28 is.Equal(expected, actual) 29 }) 30 } 31} 32 33func TestChainCompact(t *testing.T) { 34 var emptyFunc func() bool 35 emptyFuncPtr := &emptyFunc 36 37 nonEmptyFunc := func() bool { return true } 38 nonEmptyFuncPtr := &nonEmptyFunc 39 40 nonEmptyMap := map[int]int{1: 2} 41 nonEmptyMapPtr := &nonEmptyMap 42 43 var emptyMap map[int]int 44 emptyMapPtr := &emptyMap 45 46 var emptyChan chan bool 47 nonEmptyChan := make(chan bool, 1) 48 nonEmptyChan <- true 49 50 emptyChanPtr := &emptyChan 51 nonEmptyChanPtr := &nonEmptyChan 52 53 var emptyString string 54 emptyStringPtr := &emptyString 55 56 nonEmptyString := "42" 57 nonEmptyStringPtr := &nonEmptyString 58 59 testCases := []struct { 60 In interface{} 61 }{ 62 {In: []interface{}{42, nil, (*int)(nil)}}, 63 {In: []interface{}{42, emptyFuncPtr, emptyFunc, nonEmptyFuncPtr}}, 64 {In: []interface{}{42, [2]int{}, map[int]int{}, []string{}, nonEmptyMapPtr, emptyMap, emptyMapPtr, nonEmptyMap, nonEmptyChan, emptyChan, emptyChanPtr, nonEmptyChanPtr}}, 65 {In: []interface{}{true, 0, float64(0), "", "42", emptyStringPtr, nonEmptyStringPtr, false}}, 66 } 67 68 for idx, tc := range testCases { 69 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 70 is := assert.New(t) 71 72 expected := Compact(tc.In) 73 actual := Chain(tc.In).Compact().Value() 74 75 is.Equal(expected, actual) 76 }) 77 } 78} 79 80func TestChainDrop(t *testing.T) { 81 testCases := []struct { 82 In interface{} 83 N int 84 }{ 85 {In: []int{0, 1, 1, 2, 3, 0, 0, 12}, N: 3}, 86 // Bug: Issues from go-funk (n parameter can be greater than len(in)) 87 // {In: []int{0, 1}, N: 3}, 88 // {In: []int{}, N: 3}, 89 } 90 91 for idx, tc := range testCases { 92 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 93 is := assert.New(t) 94 95 expected := Drop(tc.In, tc.N) 96 actual := Chain(tc.In).Drop(tc.N).Value() 97 98 is.Equal(expected, actual) 99 }) 100 } 101} 102 103func TestChainFilter(t *testing.T) { 104 testCases := []struct { 105 In interface{} 106 Predicate interface{} 107 }{ 108 { 109 In: []int{1, 2, 3, 4}, 110 Predicate: func(x int) bool { return x%2 == 0 }, 111 }, 112 } 113 114 for idx, tc := range testCases { 115 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 116 is := assert.New(t) 117 118 expected := Filter(tc.In, tc.Predicate) 119 actual := Chain(tc.In).Filter(tc.Predicate).Value() 120 121 is.Equal(expected, actual) 122 }) 123 } 124} 125func TestChainFilter_SideEffect(t *testing.T) { 126 is := assert.New(t) 127 128 type foo struct { 129 bar string 130 } 131 in := []*foo{&foo{"foo"}, &foo{"bar"}} 132 133 chain := Chain(in) 134 is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 135 136 filtered := chain.Filter(func(x *foo) bool { 137 x.bar = "__" + x.bar + "__" 138 return x.bar == "foo" 139 }) 140 is.Equal([]*foo{}, filtered.Value()) 141 142 // Side effect: in and chain.Value modified 143 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 144 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in) 145} 146 147func TestChainFlatten(t *testing.T) { 148 testCases := []struct { 149 In interface{} 150 }{ 151 { 152 In: [][]int{{1, 2}, {3, 4}}, 153 }, 154 { 155 In: [][][]int{{{1, 2}, {3, 4}}, {{5, 6}}}, 156 }, 157 } 158 159 for idx, tc := range testCases { 160 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 161 is := assert.New(t) 162 163 expected := Flatten(tc.In) 164 actual := Chain(tc.In).Flatten().Value() 165 166 is.Equal(expected, actual) 167 }) 168 } 169} 170 171func TestChainFlattenDeep(t *testing.T) { 172 testCases := []struct { 173 In interface{} 174 }{ 175 { 176 In: [][]int{{1, 2}, {3, 4}}, 177 }, 178 { 179 In: [][][]int{{{1, 2}, {3, 4}}, {{5, 6}}}, 180 }, 181 } 182 183 for idx, tc := range testCases { 184 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 185 is := assert.New(t) 186 187 expected := FlattenDeep(tc.In) 188 actual := Chain(tc.In).FlattenDeep().Value() 189 190 is.Equal(expected, actual) 191 }) 192 } 193} 194 195func TestChainInitial(t *testing.T) { 196 testCases := []struct { 197 In interface{} 198 }{ 199 { 200 In: []int{}, 201 }, 202 { 203 In: []int{0}, 204 }, 205 { 206 In: []int{0, 1, 2, 3}, 207 }, 208 } 209 210 for idx, tc := range testCases { 211 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 212 is := assert.New(t) 213 214 expected := Initial(tc.In) 215 actual := Chain(tc.In).Initial().Value() 216 217 is.Equal(expected, actual) 218 }) 219 } 220} 221 222func TestChainIntersect(t *testing.T) { 223 testCases := []struct { 224 In interface{} 225 Sec interface{} 226 }{ 227 { 228 In: []int{1, 2, 3, 4}, 229 Sec: []int{2, 4, 6}, 230 }, 231 { 232 In: []string{"foo", "bar", "hello", "bar"}, 233 Sec: []string{"foo", "bar"}, 234 }, 235 } 236 237 for idx, tc := range testCases { 238 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 239 is := assert.New(t) 240 241 expected := Intersect(tc.In, tc.Sec) 242 actual := Chain(tc.In).Intersect(tc.Sec).Value() 243 244 is.Equal(expected, actual) 245 }) 246 } 247} 248 249func TestChainMap(t *testing.T) { 250 testCases := []struct { 251 In interface{} 252 MapFnc interface{} 253 }{ 254 { 255 In: []int{1, 2, 3, 4}, 256 MapFnc: func(x int) string { return "Hello" }, 257 }, 258 { 259 In: []int{1, 2, 3, 4}, 260 MapFnc: func(x int) (int, int) { return x, x }, 261 }, 262 { 263 In: map[int]string{1: "Florent", 2: "Gilles"}, 264 MapFnc: func(k int, v string) int { return k }, 265 }, 266 { 267 In: map[int]string{1: "Florent", 2: "Gilles"}, 268 MapFnc: func(k int, v string) (string, string) { return fmt.Sprintf("%d", k), v }, 269 }, 270 } 271 272 for idx, tc := range testCases { 273 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 274 is := assert.New(t) 275 276 expected := Map(tc.In, tc.MapFnc) 277 actual := Chain(tc.In).Map(tc.MapFnc).Value() 278 279 if reflect.TypeOf(expected).Kind() == reflect.Map { 280 is.Equal(expected, actual) 281 } else { 282 is.ElementsMatch(expected, actual) 283 } 284 }) 285 } 286} 287 288func TestChainFlatMap(t *testing.T) { 289 testCases := []struct { 290 In interface{} 291 FlatMapFnc interface{} 292 }{ 293 { 294 In: [][]int{{1}, {2}, {3}, {4}}, 295 FlatMapFnc: func(x []int) []int { return x }, 296 }, 297 { 298 In: map[string][]int{"Florent": {1}, "Gilles": {2}}, 299 FlatMapFnc: func(k string, v []int) []int { return v }, 300 }, 301 } 302 303 for idx, tc := range testCases { 304 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 305 is := assert.New(t) 306 307 expected := FlatMap(tc.In, tc.FlatMapFnc) 308 actual := Chain(tc.In).FlatMap(tc.FlatMapFnc).Value() 309 310 is.ElementsMatch(expected, actual) 311 }) 312 } 313} 314 315func TestChainMap_SideEffect(t *testing.T) { 316 is := assert.New(t) 317 318 type foo struct { 319 bar string 320 } 321 in := []*foo{&foo{"foo"}, &foo{"bar"}} 322 323 chain := Chain(in) 324 is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 325 326 mapped := chain.Map(func(x *foo) (string, bool) { 327 x.bar = "__" + x.bar + "__" 328 return x.bar, x.bar == "foo" 329 }) 330 is.Equal(map[string]bool{"__foo__": false, "__bar__": false}, mapped.Value()) 331 332 // Side effect: in and chain.Value modified 333 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 334 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in) 335} 336 337func TestChainReverse(t *testing.T) { 338 testCases := []struct { 339 In interface{} 340 }{ 341 { 342 In: []int{0, 1, 2, 3, 4}, 343 }, 344 { 345 In: "abcdefg", 346 }, 347 } 348 349 for idx, tc := range testCases { 350 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 351 is := assert.New(t) 352 353 expected := Reverse(tc.In) 354 actual := Chain(tc.In).Reverse().Value() 355 356 is.Equal(expected, actual) 357 }) 358 } 359} 360 361func TestChainShuffle(t *testing.T) { 362 testCases := []struct { 363 In interface{} 364 }{ 365 { 366 In: []int{0, 1, 2, 3, 4}, 367 }, 368 } 369 370 for idx, tc := range testCases { 371 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 372 is := assert.New(t) 373 374 expected := Shuffle(tc.In) 375 actual := Chain(tc.In).Shuffle().Value() 376 377 is.NotEqual(expected, actual) 378 is.ElementsMatch(expected, actual) 379 }) 380 } 381} 382 383func TestChainTail(t *testing.T) { 384 testCases := []struct { 385 In interface{} 386 }{ 387 { 388 In: []int{}, 389 }, 390 { 391 In: []int{0}, 392 }, 393 { 394 In: []int{0, 1, 2, 3}, 395 }, 396 } 397 398 for idx, tc := range testCases { 399 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 400 is := assert.New(t) 401 402 expected := Tail(tc.In) 403 actual := Chain(tc.In).Tail().Value() 404 405 is.Equal(expected, actual) 406 }) 407 } 408} 409 410func TestChainUniq(t *testing.T) { 411 testCases := []struct { 412 In interface{} 413 }{ 414 { 415 In: []int{0, 1, 1, 2, 3, 0, 0, 12}, 416 }, 417 } 418 419 for idx, tc := range testCases { 420 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 421 is := assert.New(t) 422 423 expected := Uniq(tc.In) 424 actual := Chain(tc.In).Uniq().Value() 425 426 is.Equal(expected, actual) 427 }) 428 } 429} 430 431func TestChainAll(t *testing.T) { 432 testCases := []struct { 433 In []interface{} 434 }{ 435 {In: []interface{}{"foo", "bar"}}, 436 {In: []interface{}{"foo", ""}}, 437 {In: []interface{}{"", ""}}, 438 {In: []interface{}{}}, 439 {In: []interface{}{true, "foo", 6}}, 440 {In: []interface{}{true, "", 6}}, 441 {In: []interface{}{true, "foo", 0}}, 442 {In: []interface{}{false, "foo", 6}}, 443 {In: []interface{}{false, "", 0}}, 444 } 445 446 for idx, tc := range testCases { 447 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 448 is := assert.New(t) 449 450 expected := All(tc.In...) 451 actual := Chain(tc.In).All() 452 453 is.Equal(expected, actual) 454 }) 455 } 456} 457 458func TestChainAny(t *testing.T) { 459 testCases := []struct { 460 In []interface{} 461 }{ 462 {In: []interface{}{"foo", "bar"}}, 463 {In: []interface{}{"foo", ""}}, 464 {In: []interface{}{"", ""}}, 465 {In: []interface{}{}}, 466 {In: []interface{}{true, "foo", 6}}, 467 {In: []interface{}{true, "", 6}}, 468 {In: []interface{}{true, "foo", 0}}, 469 {In: []interface{}{false, "foo", 6}}, 470 {In: []interface{}{false, "", 0}}, 471 } 472 473 for idx, tc := range testCases { 474 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 475 is := assert.New(t) 476 477 expected := Any(tc.In...) 478 actual := Chain(tc.In).Any() 479 480 is.Equal(expected, actual) 481 }) 482 } 483} 484 485func TestChainContains(t *testing.T) { 486 testCases := []struct { 487 In interface{} 488 Contains interface{} 489 }{ 490 { 491 In: []string{"foo", "bar"}, 492 Contains: "bar", 493 }, 494 { 495 In: []string{"foo", "bar"}, 496 Contains: func (value string) bool { 497 return value == "bar" 498 }, 499 }, 500 { 501 In: results, 502 Contains: f, 503 }, 504 { 505 In: results, 506 Contains: nil, 507 }, 508 { 509 In: results, 510 Contains: b, 511 }, 512 { 513 In: "florent", 514 Contains: "rent", 515 }, 516 { 517 In: "florent", 518 Contains: "gilles", 519 }, 520 { 521 In: map[int]*Foo{1: f, 3: c}, 522 Contains: 1, 523 }, 524 { 525 In: map[int]*Foo{1: f, 3: c}, 526 Contains: 2, 527 }, 528 { 529 In: map[int]*Foo{1: f, 3: c}, 530 Contains: func (key int, foo *Foo) bool { 531 return key == 3 && foo.FirstName == "Harald" 532 }, 533 }, 534 } 535 536 for idx, tc := range testCases { 537 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 538 is := assert.New(t) 539 540 expected := Contains(tc.In, tc.Contains) 541 actual := Chain(tc.In).Contains(tc.Contains) 542 543 is.Equal(expected, actual) 544 }) 545 } 546} 547 548func TestChainEvery(t *testing.T) { 549 testCases := []struct { 550 In interface{} 551 Contains []interface{} 552 }{ 553 { 554 In: []string{"foo", "bar", "baz"}, 555 Contains: []interface{}{"bar", "foo"}, 556 }, 557 { 558 In: results, 559 Contains: []interface{}{f, c}, 560 }, 561 { 562 In: results, 563 Contains: []interface{}{nil}, 564 }, 565 { 566 In: results, 567 Contains: []interface{}{f, b}, 568 }, 569 { 570 In: "florent", 571 Contains: []interface{}{"rent", "flo"}, 572 }, 573 { 574 In: "florent", 575 Contains: []interface{}{"rent", "gilles"}, 576 }, 577 { 578 In: map[int]*Foo{1: f, 3: c}, 579 Contains: []interface{}{1, 3}, 580 }, 581 { 582 In: map[int]*Foo{1: f, 3: c}, 583 Contains: []interface{}{2, 3}, 584 }, 585 } 586 587 for idx, tc := range testCases { 588 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 589 is := assert.New(t) 590 591 expected := Every(tc.In, tc.Contains...) 592 actual := Chain(tc.In).Every(tc.Contains...) 593 594 is.Equal(expected, actual) 595 }) 596 } 597} 598 599func TestChainFind(t *testing.T) { 600 testCases := []struct { 601 In interface{} 602 Predicate interface{} 603 }{ 604 { 605 In: []int{1, 2, 3, 4}, 606 Predicate: func(x int) bool { return x%2 == 0 }, 607 }, 608 } 609 610 for idx, tc := range testCases { 611 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 612 is := assert.New(t) 613 614 expected := Find(tc.In, tc.Predicate) 615 actual := Chain(tc.In).Find(tc.Predicate) 616 617 is.Equal(expected, actual) 618 }) 619 } 620} 621 622func TestChainFind_SideEffect(t *testing.T) { 623 is := assert.New(t) 624 625 type foo struct { 626 bar string 627 } 628 in := []*foo{&foo{"foo"}, &foo{"bar"}} 629 630 chain := Chain(in) 631 is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 632 633 result := chain.Find(func(x *foo) bool { 634 x.bar = "__" + x.bar + "__" 635 return x.bar == "foo" 636 }) 637 is.Nil(result) 638 639 // Side effect: in and chain.Value modified 640 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 641 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in) 642} 643 644func TestChainForEach(t *testing.T) { 645 var expectedAcc, actualAcc []interface{} 646 647 testCases := []struct { 648 In interface{} 649 FunkIterator interface{} 650 ChainIterator interface{} 651 }{ 652 { 653 In: []int{1, 2, 3, 4}, 654 FunkIterator: func(x int) { 655 if x%2 == 0 { 656 expectedAcc = append(expectedAcc, x) 657 } 658 }, 659 ChainIterator: func(x int) { 660 if x%2 == 0 { 661 actualAcc = append(actualAcc, x) 662 } 663 }, 664 }, 665 { 666 In: map[int]string{1: "Florent", 2: "Gilles"}, 667 FunkIterator: func(k int, v string) { expectedAcc = append(expectedAcc, fmt.Sprintf("%d:%s", k, v)) }, 668 ChainIterator: func(k int, v string) { actualAcc = append(actualAcc, fmt.Sprintf("%d:%s", k, v)) }, 669 }, 670 } 671 672 for idx, tc := range testCases { 673 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 674 is := assert.New(t) 675 expectedAcc = []interface{}{} 676 actualAcc = []interface{}{} 677 678 ForEach(tc.In, tc.FunkIterator) 679 Chain(tc.In).ForEach(tc.ChainIterator) 680 681 is.ElementsMatch(expectedAcc, actualAcc) 682 }) 683 } 684} 685 686func TestChainForEach_SideEffect(t *testing.T) { 687 is := assert.New(t) 688 689 type foo struct { 690 bar string 691 } 692 var out []*foo 693 in := []*foo{&foo{"foo"}, &foo{"bar"}} 694 695 chain := Chain(in) 696 is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 697 698 chain.ForEach(func(x *foo) { 699 x.bar = "__" + x.bar + "__" 700 out = append(out, x) 701 }) 702 is.Equal([]*foo{&foo{"__foo__"}, &foo{"__bar__"}}, out) 703 704 // Side effect: in and chain.Value modified 705 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 706 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in) 707} 708 709func TestChainForEachRight(t *testing.T) { 710 var expectedAcc, actualAcc []interface{} 711 712 testCases := []struct { 713 In interface{} 714 FunkIterator interface{} 715 ChainIterator interface{} 716 }{ 717 { 718 In: []int{1, 2, 3, 4}, 719 FunkIterator: func(x int) { 720 if x%2 == 0 { 721 expectedAcc = append(expectedAcc, x) 722 } 723 }, 724 ChainIterator: func(x int) { 725 if x%2 == 0 { 726 actualAcc = append(actualAcc, x) 727 } 728 }, 729 }, 730 { 731 In: map[int]string{1: "Florent", 2: "Gilles"}, 732 FunkIterator: func(k int, v string) { expectedAcc = append(expectedAcc, fmt.Sprintf("%d:%s", k, v)) }, 733 ChainIterator: func(k int, v string) { actualAcc = append(actualAcc, fmt.Sprintf("%d:%s", k, v)) }, 734 }, 735 } 736 737 for idx, tc := range testCases { 738 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 739 is := assert.New(t) 740 expectedAcc = []interface{}{} 741 actualAcc = []interface{}{} 742 743 ForEachRight(tc.In, tc.FunkIterator) 744 Chain(tc.In).ForEachRight(tc.ChainIterator) 745 746 is.ElementsMatch(expectedAcc, actualAcc) 747 }) 748 } 749} 750 751func TestChainForEachRight_SideEffect(t *testing.T) { 752 is := assert.New(t) 753 754 type foo struct { 755 bar string 756 } 757 var out []*foo 758 in := []*foo{&foo{"foo"}, &foo{"bar"}} 759 760 chain := Chain(in) 761 is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 762 763 chain.ForEachRight(func(x *foo) { 764 x.bar = "__" + x.bar + "__" 765 out = append(out, x) 766 }) 767 is.Equal([]*foo{&foo{"__bar__"}, &foo{"__foo__"}}, out) 768 769 // Side effect: in and chain.Value modified 770 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, chain.Value()) 771 is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in) 772} 773 774func TestChainHead(t *testing.T) { 775 testCases := []struct { 776 In interface{} 777 }{ 778 { 779 In: []int{1, 2, 3, 4}, 780 }, 781 } 782 783 for idx, tc := range testCases { 784 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 785 is := assert.New(t) 786 787 expected := Head(tc.In) 788 actual := Chain(tc.In).Head() 789 790 is.Equal(expected, actual) 791 }) 792 } 793} 794 795func TestChainKeys(t *testing.T) { 796 testCases := []struct { 797 In interface{} 798 }{ 799 {In: map[string]int{"one": 1, "two": 2}}, 800 {In: &map[string]int{"one": 1, "two": 2}}, 801 {In: map[int]complex128{5: 1 + 8i, 3: 2}}, 802 } 803 804 for idx, tc := range testCases { 805 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 806 is := assert.New(t) 807 808 expected := Keys(tc.In) 809 actual := Chain(tc.In).Keys() 810 811 is.ElementsMatch(expected, actual) 812 }) 813 } 814} 815 816func TestChainIndexOf(t *testing.T) { 817 testCases := []struct { 818 In interface{} 819 Item interface{} 820 }{ 821 { 822 In: []string{"foo", "bar"}, 823 Item: "bar", 824 }, 825 { 826 In: []string{"foo", "bar"}, 827 Item: func (value string) bool { 828 return value == "bar" 829 }, 830 }, 831 { 832 In: results, 833 Item: f, 834 }, 835 { 836 In: results, 837 Item: b, 838 }, 839 } 840 841 for idx, tc := range testCases { 842 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 843 is := assert.New(t) 844 845 expected := IndexOf(tc.In, tc.Item) 846 actual := Chain(tc.In).IndexOf(tc.Item) 847 848 is.Equal(expected, actual) 849 }) 850 } 851} 852 853func TestChainIsEmpty(t *testing.T) { 854 testCases := []struct { 855 In interface{} 856 }{ 857 {In: ""}, 858 {In: [0]interface{}{}}, 859 {In: []interface{}(nil)}, 860 {In: map[interface{}]interface{}(nil)}, 861 {In: "s"}, 862 {In: [1]interface{}{1}}, 863 {In: []interface{}{}}, 864 {In: map[interface{}]interface{}{}}, 865 } 866 867 for idx, tc := range testCases { 868 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 869 is := assert.New(t) 870 871 expected := IsEmpty(tc.In) 872 actual := Chain(tc.In).IsEmpty() 873 874 is.Equal(expected, actual) 875 }) 876 } 877} 878 879func TestChainLast(t *testing.T) { 880 testCases := []struct { 881 In interface{} 882 }{ 883 { 884 In: []int{1, 2, 3, 4}, 885 }, 886 } 887 888 for idx, tc := range testCases { 889 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 890 is := assert.New(t) 891 892 expected := Last(tc.In) 893 actual := Chain(tc.In).Last() 894 895 is.Equal(expected, actual) 896 }) 897 } 898} 899 900func TestChainLastIndexOf(t *testing.T) { 901 testCases := []struct { 902 In interface{} 903 Item interface{} 904 }{ 905 { 906 In: []string{"foo", "bar", "bar"}, 907 Item: "bar", 908 }, 909 { 910 In: []string{"foo", "bar", "bar"}, 911 Item: func (value string) bool { 912 return value == "bar" 913 }, 914 }, 915 { 916 In: []int{1, 2, 2, 3}, 917 Item: 2, 918 }, 919 { 920 In: []int{1, 2, 2, 3}, 921 Item: 4, 922 }, 923 } 924 925 for idx, tc := range testCases { 926 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 927 is := assert.New(t) 928 929 expected := LastIndexOf(tc.In, tc.Item) 930 actual := Chain(tc.In).LastIndexOf(tc.Item) 931 932 is.Equal(expected, actual) 933 }) 934 } 935} 936 937func TestChainNotEmpty(t *testing.T) { 938 testCases := []struct { 939 In interface{} 940 }{ 941 {In: ""}, 942 {In: [0]interface{}{}}, 943 {In: []interface{}(nil)}, 944 {In: map[interface{}]interface{}(nil)}, 945 {In: "s"}, 946 {In: [1]interface{}{1}}, 947 {In: []interface{}{}}, 948 {In: map[interface{}]interface{}{}}, 949 } 950 951 for idx, tc := range testCases { 952 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 953 is := assert.New(t) 954 955 expected := NotEmpty(tc.In) 956 actual := Chain(tc.In).NotEmpty() 957 958 is.Equal(expected, actual) 959 }) 960 } 961} 962 963func TestChainProduct(t *testing.T) { 964 testCases := []struct { 965 In interface{} 966 }{ 967 {In: []int{0, 1, 2, 3}}, 968 {In: &[]int{0, 1, 2, 3}}, 969 {In: []interface{}{1, 2, 3, 0.5}}, 970 } 971 972 for idx, tc := range testCases { 973 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 974 is := assert.New(t) 975 976 expected := Product(tc.In) 977 actual := Chain(tc.In).Product() 978 979 is.Equal(expected, actual) 980 }) 981 } 982} 983 984func TestChainReduce(t *testing.T) { 985 testCases := []struct { 986 In interface{} 987 ReduceFunc interface{} 988 Acc interface{} 989 }{ 990 { 991 In: []int{1, 2, 3, 4}, 992 ReduceFunc: func(acc, elem int) int { return acc + elem }, 993 Acc: 0, 994 }, 995 { 996 In: &[]int16{1, 2, 3, 4}, 997 ReduceFunc: '+', 998 Acc: 5, 999 }, 1000 { 1001 In: []float64{1.1, 2.2, 3.3}, 1002 ReduceFunc: '+', 1003 Acc: 0, 1004 }, 1005 { 1006 In: &[]int{1, 2, 3, 5}, 1007 ReduceFunc: func(acc int8, elem int16) int32 { return int32(acc) * int32(elem) }, 1008 Acc: 1, 1009 }, 1010 { 1011 In: []interface{}{1, 2, 3.3, 4}, 1012 ReduceFunc: '*', 1013 Acc: 1, 1014 }, 1015 { 1016 In: []string{"1", "2", "3", "4"}, 1017 ReduceFunc: func(acc string, elem string) string { return acc + elem }, 1018 Acc: "", 1019 }, 1020 } 1021 1022 for idx, tc := range testCases { 1023 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 1024 is := assert.New(t) 1025 1026 expected := Reduce(tc.In, tc.ReduceFunc, tc.Acc) 1027 actual := Chain(tc.In).Reduce(tc.ReduceFunc, tc.Acc) 1028 1029 is.Equal(expected, actual) 1030 }) 1031 } 1032} 1033 1034func TestChainSum(t *testing.T) { 1035 testCases := []struct { 1036 In interface{} 1037 }{ 1038 {In: []int{0, 1, 2, 3}}, 1039 {In: &[]int{0, 1, 2, 3}}, 1040 {In: []interface{}{1, 2, 3, 0.5}}, 1041 } 1042 1043 for idx, tc := range testCases { 1044 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 1045 is := assert.New(t) 1046 1047 expected := Sum(tc.In) 1048 actual := Chain(tc.In).Sum() 1049 1050 is.Equal(expected, actual) 1051 }) 1052 } 1053} 1054 1055func TestChainType(t *testing.T) { 1056 type key string 1057 var x key 1058 1059 testCases := []struct { 1060 In interface{} 1061 }{ 1062 {In: []string{}}, 1063 {In: []int{}}, 1064 {In: []bool{}}, 1065 {In: []interface{}{}}, 1066 {In: &[]interface{}{}}, 1067 {In: map[int]string{}}, 1068 {In: map[complex128]int{}}, 1069 {In: map[string]string{}}, 1070 {In: map[int]interface{}{}}, 1071 {In: map[key]interface{}{}}, 1072 {In: &map[key]interface{}{}}, 1073 {In: ""}, 1074 {In: &x}, 1075 } 1076 1077 for idx, tc := range testCases { 1078 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 1079 is := assert.New(t) 1080 1081 actual := Chain(tc.In).Type() 1082 1083 is.Equal(reflect.TypeOf(tc.In), actual) 1084 }) 1085 } 1086} 1087 1088func TestChainValue(t *testing.T) { 1089 testCases := []struct { 1090 In interface{} 1091 }{ 1092 {In: []int{0, 1, 2, 3}}, 1093 {In: []string{"foo", "bar"}}, 1094 {In: &[]string{"foo", "bar"}}, 1095 {In: map[int]string{1: "foo", 2: "bar"}}, 1096 {In: map[string]string{"foo": "foo", "bar": "bar"}}, 1097 {In: &map[string]string{"foo": "foo", "bar": "bar"}}, 1098 {In: "foo"}, 1099 } 1100 1101 for idx, tc := range testCases { 1102 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 1103 is := assert.New(t) 1104 1105 actual := Chain(tc.In).Value() 1106 1107 is.Equal(tc.In, actual) 1108 }) 1109 } 1110} 1111 1112func TestChainValues(t *testing.T) { 1113 testCases := []struct { 1114 In interface{} 1115 }{ 1116 {In: map[string]int{"one": 1, "two": 2}}, 1117 {In: &map[string]int{"one": 1, "two": 2}}, 1118 {In: map[int]complex128{5: 1 + 8i, 3: 2}}, 1119 } 1120 1121 for idx, tc := range testCases { 1122 t.Run(fmt.Sprintf("test case #%d", idx+1), func(t *testing.T) { 1123 is := assert.New(t) 1124 1125 expected := Values(tc.In) 1126 actual := Chain(tc.In).Values() 1127 1128 is.ElementsMatch(expected, actual) 1129 }) 1130 } 1131} 1132 1133func TestComplexChaining(t *testing.T) { 1134 is := assert.New(t) 1135 1136 in := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 1137 chain := Chain(in) 1138 1139 // Without builder 1140 fa := Filter(in, func(x int) bool { return x%2 == 0 }) 1141 fb := Map(fa, func(x int) int { return x * 2 }) 1142 fc := Reverse(fa) 1143 1144 // With simple chaining 1145 ca := chain.Filter(func(x int) bool { return x%2 == 0 }) 1146 cb := ca.Map(func(x int) int { return x * 2 }) 1147 cc := ca.Reverse() 1148 1149 is.Equal(fa, ca.Value()) 1150 is.Equal(fb, cb.Value()) 1151 is.Equal(fc, cc.Value()) 1152 1153 is.Equal(Contains(fb, 2), cb.Contains(2)) 1154 is.Equal(Contains(fb, 4), cb.Contains(4)) 1155 is.Equal(Sum(fb), cb.Sum()) 1156 is.Equal(Head(fb), cb.Head()) 1157 is.Equal(Head(fc), cc.Head()) 1158} 1159