...

Source file src/github.com/thoas/go-funk/chain_builder_test.go

Documentation: github.com/thoas/go-funk

     1  package funk
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  func 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  
    33  func 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  
    80  func 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  
   103  func 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  }
   125  func 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  
   147  func 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  
   171  func 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  
   195  func 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  
   222  func 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  
   249  func 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  
   288  func 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  
   315  func 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  
   337  func 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  
   361  func 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  
   383  func 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  
   410  func 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  
   431  func 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  
   458  func 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  
   485  func 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  
   548  func 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  
   599  func 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  
   622  func 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  
   644  func 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  
   686  func 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  
   709  func 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  
   751  func 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  
   774  func 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  
   795  func 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  
   816  func 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  
   853  func 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  
   879  func 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  
   900  func 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  
   937  func 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  
   963  func 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  
   984  func 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  
  1034  func 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  
  1055  func 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  
  1088  func 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  
  1112  func 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  
  1133  func 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  

View as plain text