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