...

Source file src/github.com/thoas/go-funk/lazy_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 TestLazyChunk(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 := LazyChain(tc.In).Chunk(tc.Size).Value()
    27  
    28  			is.Equal(expected, actual)
    29  		})
    30  	}
    31  }
    32  
    33  func TestLazyCompact(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 := LazyChain(tc.In).Compact().Value()
    74  
    75  			is.Equal(expected, actual)
    76  		})
    77  	}
    78  }
    79  
    80  func TestLazyDrop(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 := LazyChain(tc.In).Drop(tc.N).Value()
    97  
    98  			is.Equal(expected, actual)
    99  		})
   100  	}
   101  }
   102  
   103  func TestLazyFilter(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 := LazyChain(tc.In).Filter(tc.Predicate).Value()
   120  
   121  			is.Equal(expected, actual)
   122  		})
   123  	}
   124  }
   125  func TestLazyFilter_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  	LazyChain := LazyChain(in)
   134  	is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   135  
   136  	filtered := LazyChain.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 LazyChain.Value modified
   143  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   144  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in)
   145  }
   146  
   147  func TestLazyFlatten(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 := LazyChain(tc.In).Flatten().Value()
   165  
   166  			is.Equal(expected, actual)
   167  		})
   168  	}
   169  }
   170  
   171  func TestLazyFlattenDeep(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 := LazyChain(tc.In).FlattenDeep().Value()
   189  
   190  			is.Equal(expected, actual)
   191  		})
   192  	}
   193  }
   194  
   195  func TestLazyInitial(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 := LazyChain(tc.In).Initial().Value()
   216  
   217  			is.Equal(expected, actual)
   218  		})
   219  	}
   220  }
   221  
   222  func TestLazyIntersect(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 := LazyChain(tc.In).Intersect(tc.Sec).Value()
   243  
   244  			is.Equal(expected, actual)
   245  		})
   246  	}
   247  }
   248  
   249  func TestLazyMap(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 := LazyChain(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 TestLazyFlatMap(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 := Map(tc.In, tc.FlatMapFnc)
   308  			actual := LazyChain(tc.In).Map(tc.FlatMapFnc).Value()
   309  
   310  			is.ElementsMatch(expected, actual)
   311  		})
   312  	}
   313  }
   314  
   315  func TestLazyMap_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  	LazyChain := LazyChain(in)
   324  	is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   325  
   326  	mapped := LazyChain.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 LazyChain.Value modified
   333  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   334  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in)
   335  }
   336  
   337  func TestLazyReverse(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 := LazyChain(tc.In).Reverse().Value()
   355  
   356  			is.Equal(expected, actual)
   357  		})
   358  	}
   359  }
   360  
   361  func TestLazyShuffle(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 := LazyChain(tc.In).Shuffle().Value()
   376  
   377  			is.NotEqual(expected, actual)
   378  			is.ElementsMatch(expected, actual)
   379  		})
   380  	}
   381  }
   382  
   383  func TestLazyTail(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 := LazyChain(tc.In).Tail().Value()
   404  
   405  			is.Equal(expected, actual)
   406  		})
   407  	}
   408  }
   409  
   410  func TestLazyUniq(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 := LazyChain(tc.In).Uniq().Value()
   425  
   426  			is.Equal(expected, actual)
   427  		})
   428  	}
   429  }
   430  
   431  func TestLazyAll(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 := LazyChain(tc.In).All()
   452  
   453  			is.Equal(expected, actual)
   454  		})
   455  	}
   456  }
   457  
   458  func TestLazyAny(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 := LazyChain(tc.In).Any()
   479  
   480  			is.Equal(expected, actual)
   481  		})
   482  	}
   483  }
   484  
   485  func TestLazyContains(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 := LazyChain(tc.In).Contains(tc.Contains)
   542  
   543  			is.Equal(expected, actual)
   544  		})
   545  	}
   546  }
   547  
   548  func TestLazyEvery(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 := LazyChain(tc.In).Every(tc.Contains...)
   593  
   594  			is.Equal(expected, actual)
   595  		})
   596  	}
   597  }
   598  
   599  func TestLazyFind(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 := LazyChain(tc.In).Find(tc.Predicate)
   616  
   617  			is.Equal(expected, actual)
   618  		})
   619  	}
   620  }
   621  
   622  func TestLazyFind_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  	LazyChain := LazyChain(in)
   631  	is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   632  
   633  	result := LazyChain.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 LazyChain.Value modified
   640  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   641  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in)
   642  }
   643  
   644  func TestLazyForEach(t *testing.T) {
   645  	var expectedAcc, actualAcc []interface{}
   646  
   647  	testCases := []struct {
   648  		In                interface{}
   649  		FunkIterator      interface{}
   650  		LazyChainIterator 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  			LazyChainIterator: 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  			LazyChainIterator: 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  			LazyChain(tc.In).ForEach(tc.LazyChainIterator)
   680  
   681  			is.ElementsMatch(expectedAcc, actualAcc)
   682  		})
   683  	}
   684  }
   685  
   686  func TestLazyForEach_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  	LazyChain := LazyChain(in)
   696  	is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   697  
   698  	LazyChain.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 LazyChain.Value modified
   705  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   706  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in)
   707  }
   708  
   709  func TestLazyForEachRight(t *testing.T) {
   710  	var expectedAcc, actualAcc []interface{}
   711  
   712  	testCases := []struct {
   713  		In                interface{}
   714  		FunkIterator      interface{}
   715  		LazyChainIterator 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  			LazyChainIterator: 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  			LazyChainIterator: 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  			LazyChain(tc.In).ForEachRight(tc.LazyChainIterator)
   745  
   746  			is.ElementsMatch(expectedAcc, actualAcc)
   747  		})
   748  	}
   749  }
   750  
   751  func TestLazyForEachRight_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  	LazyChain := LazyChain(in)
   761  	is.Equal([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   762  
   763  	LazyChain.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 LazyChain.Value modified
   770  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, LazyChain.Value())
   771  	is.NotEqual([]*foo{&foo{"foo"}, &foo{"bar"}}, in)
   772  }
   773  
   774  func TestLazyHead(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 := LazyChain(tc.In).Head()
   789  
   790  			is.Equal(expected, actual)
   791  		})
   792  	}
   793  }
   794  
   795  func TestLazyKeys(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 := LazyChain(tc.In).Keys()
   810  
   811  			is.ElementsMatch(expected, actual)
   812  		})
   813  	}
   814  }
   815  
   816  func TestLazyIndexOf(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 := LazyChain(tc.In).IndexOf(tc.Item)
   847  
   848  			is.Equal(expected, actual)
   849  		})
   850  	}
   851  }
   852  
   853  func TestLazyIsEmpty(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 := LazyChain(tc.In).IsEmpty()
   873  
   874  			is.Equal(expected, actual)
   875  		})
   876  	}
   877  }
   878  
   879  func TestLazyLast(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 := LazyChain(tc.In).Last()
   894  
   895  			is.Equal(expected, actual)
   896  		})
   897  	}
   898  }
   899  
   900  func TestLazyLastIndexOf(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 := LazyChain(tc.In).LastIndexOf(tc.Item)
   931  
   932  			is.Equal(expected, actual)
   933  		})
   934  	}
   935  }
   936  
   937  func TestLazyNotEmpty(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 := LazyChain(tc.In).NotEmpty()
   957  
   958  			is.Equal(expected, actual)
   959  		})
   960  	}
   961  }
   962  
   963  func TestLazyProduct(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 := LazyChain(tc.In).Product()
   978  
   979  			is.Equal(expected, actual)
   980  		})
   981  	}
   982  }
   983  
   984  func TestLazyReduce(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 := LazyChain(tc.In).Reduce(tc.ReduceFunc, tc.Acc)
  1028  
  1029  			is.Equal(expected, actual)
  1030  		})
  1031  	}
  1032  }
  1033  
  1034  func TestLazySum(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 := LazyChain(tc.In).Sum()
  1049  
  1050  			is.Equal(expected, actual)
  1051  		})
  1052  	}
  1053  }
  1054  
  1055  func TestLazyType(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 := LazyChain(tc.In).Type()
  1082  
  1083  			is.Equal(reflect.TypeOf(tc.In), actual)
  1084  		})
  1085  	}
  1086  }
  1087  
  1088  func TestLazyValue(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 := LazyChain(tc.In).Value()
  1106  
  1107  			is.Equal(tc.In, actual)
  1108  		})
  1109  	}
  1110  }
  1111  
  1112  func TestLazyValues(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 := LazyChain(tc.In).Values()
  1127  
  1128  			is.ElementsMatch(expected, actual)
  1129  		})
  1130  	}
  1131  }
  1132  
  1133  func TestComplexLazyChaining(t *testing.T) {
  1134  	is := assert.New(t)
  1135  
  1136  	in := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  1137  	lazy := LazyChain(in)
  1138  	lazyWith := LazyChainWith(func() interface{} { return in })
  1139  
  1140  	// Without builder
  1141  	fa := Filter(in, func(x int) bool { return x%2 == 0 })
  1142  	fb := Map(fa, func(x int) int { return x * 2 })
  1143  	fc := Reverse(fa)
  1144  
  1145  	// With lazy chaining
  1146  	la := lazy.Filter(func(x int) bool { return x%2 == 0 })
  1147  	lb := la.Map(func(x int) int { return x * 2 })
  1148  	lc := la.Reverse()
  1149  
  1150  	// With lazy chaining with generator
  1151  	lwa := lazyWith.Filter(func(x int) bool { return x%2 == 0 })
  1152  	lwb := lwa.Map(func(x int) int { return x * 2 })
  1153  	lwc := lwa.Reverse()
  1154  
  1155  	is.Equal(fa, la.Value())
  1156  	is.Equal(fb, lb.Value())
  1157  	is.Equal(fc, lc.Value())
  1158  	is.Equal(fa, lwa.Value())
  1159  	is.Equal(fb, lwb.Value())
  1160  	is.Equal(fc, lwc.Value())
  1161  
  1162  	is.Equal(Contains(fb, 2), lb.Contains(2))
  1163  	is.Equal(Contains(fb, 4), lb.Contains(4))
  1164  	is.Equal(Sum(fb), lb.Sum())
  1165  	is.Equal(Head(fb), lb.Head())
  1166  	is.Equal(Head(fc), lc.Head())
  1167  	is.Equal(Contains(fb, 2), lwb.Contains(2))
  1168  	is.Equal(Contains(fb, 4), lwb.Contains(4))
  1169  	is.Equal(Sum(fb), lwb.Sum())
  1170  	is.Equal(Head(fb), lwb.Head())
  1171  	is.Equal(Head(fc), lwc.Head())
  1172  }
  1173  

View as plain text