github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/loop/test/api_test.go (about)

     1  package test
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	breakLoop "github.com/m4gshm/gollections/break/loop"
    12  	"github.com/m4gshm/gollections/c"
    13  	"github.com/m4gshm/gollections/convert/as"
    14  	kvloop "github.com/m4gshm/gollections/kv/loop"
    15  	kvloopgroup "github.com/m4gshm/gollections/kv/loop/group"
    16  	"github.com/m4gshm/gollections/loop"
    17  	"github.com/m4gshm/gollections/loop/conv"
    18  	"github.com/m4gshm/gollections/loop/convert"
    19  	"github.com/m4gshm/gollections/loop/filter"
    20  	"github.com/m4gshm/gollections/loop/first"
    21  	"github.com/m4gshm/gollections/loop/flat"
    22  	"github.com/m4gshm/gollections/loop/range_"
    23  	"github.com/m4gshm/gollections/op"
    24  	"github.com/m4gshm/gollections/predicate/eq"
    25  	"github.com/m4gshm/gollections/predicate/more"
    26  	"github.com/m4gshm/gollections/slice"
    27  )
    28  
    29  func Test_ReduceSum(t *testing.T) {
    30  	s := loop.Of(1, 3, 5, 7, 9, 11)
    31  	r := loop.Reduce(s, op.Sum[int])
    32  	assert.Equal(t, 1+3+5+7+9+11, r)
    33  }
    34  
    35  func Test_ReduceeSum(t *testing.T) {
    36  	s := loop.Of(1, 3, 5, 7, 9, 11)
    37  	r, err := loop.Reducee(s, func(i1, i2 int) (int, error) { return i1 + i2, nil })
    38  	assert.Equal(t, 1+3+5+7+9+11, r)
    39  	assert.Nil(t, err)
    40  }
    41  
    42  func Test_EmptyLoop(t *testing.T) {
    43  	s := loop.Of[int]()
    44  	r := loop.Reduce(s, op.Sum[int])
    45  	assert.Equal(t, 0, r)
    46  }
    47  
    48  func Test_NilLoop(t *testing.T) {
    49  	var s loop.Loop[int]
    50  	r := loop.Reduce(s, op.Sum[int])
    51  	assert.Equal(t, 0, r)
    52  }
    53  
    54  func Test_ConvertAndReduce(t *testing.T) {
    55  	s := loop.Of(1, 3, 5, 7, 9, 11)
    56  	r := convert.AndReduce(s, func(i int) int { return i * i }, op.Sum[int])
    57  	assert.Equal(t, 1+3*3+5*5+7*7+9*9+11*11, r)
    58  }
    59  
    60  func Test_ConvAndReduce(t *testing.T) {
    61  	s := loop.Of("1", "3", "5", "7", "9", "11")
    62  	r, err := conv.AndReduce(s, strconv.Atoi, op.Sum[int])
    63  	assert.NoError(t, err)
    64  	assert.Equal(t, 1+3+5+7+9+11, r)
    65  }
    66  
    67  func Test_Sum(t *testing.T) {
    68  	s := loop.Of(1, 3, 5, 7, 9, 11)
    69  	r := loop.Sum(s)
    70  	assert.Equal(t, 1+3+5+7+9+11, r)
    71  }
    72  
    73  func Test_First(t *testing.T) {
    74  	s := loop.Of(1, 3, 5, 7, 9, 11)
    75  	r, ok := first.Of(s, func(i int) bool { return i > 5 })
    76  	assert.True(t, ok)
    77  	assert.Equal(t, 7, r)
    78  
    79  	_, nook := loop.First(s, func(i int) bool { return i > 12 })
    80  	assert.False(t, nook)
    81  }
    82  
    83  func Test_FirstConverted(t *testing.T) {
    84  	s := loop.Of(1, 3, 5, 7, 9, 11)
    85  	r, ok := first.Converted(s, func(i int) bool { return i > 5 }, strconv.Itoa)
    86  	assert.True(t, ok)
    87  	assert.Equal(t, "7", r)
    88  }
    89  
    90  func Test_NotNil(t *testing.T) {
    91  	type entity struct{ val string }
    92  	var (
    93  		source   = loop.Of([]*entity{{"first"}, nil, {"third"}, nil, {"fifth"}}...)
    94  		result   = loop.NotNil(source)
    95  		expected = []*entity{{"first"}, {"third"}, {"fifth"}}
    96  	)
    97  	assert.Equal(t, expected, loop.Slice(result))
    98  }
    99  
   100  func Test_ConvertPointersToValues(t *testing.T) {
   101  	type entity struct{ val string }
   102  	var (
   103  		source   = loop.Of([]*entity{{"first"}, nil, {"third"}, nil, {"fifth"}}...)
   104  		result   = loop.PtrVal(source)
   105  		expected = []entity{{"first"}, {}, {"third"}, {}, {"fifth"}}
   106  	)
   107  	assert.Equal(t, expected, loop.Slice(result))
   108  }
   109  
   110  func Test_ConvertNotnilPointersToValues(t *testing.T) {
   111  	type entity struct{ val string }
   112  	var (
   113  		source   = loop.Of([]*entity{{"first"}, nil, {"third"}, nil, {"fifth"}}...)
   114  		result   = loop.NoNilPtrVal(source)
   115  		expected = []entity{{"first"}, {"third"}, {"fifth"}}
   116  	)
   117  	assert.Equal(t, expected, loop.Slice(result))
   118  }
   119  
   120  func Test_Convert(t *testing.T) {
   121  	s := loop.Of(1, 3, 5, 7, 9, 11)
   122  	r := loop.Convert(s, strconv.Itoa)
   123  	assert.Equal(t, []string{"1", "3", "5", "7", "9", "11"}, loop.Slice(r))
   124  }
   125  
   126  func Test_IterWitErr(t *testing.T) {
   127  	s := loop.Of("1", "3", "5", "7eee", "9", "11")
   128  	r := []int{}
   129  	var outErr error
   130  	for {
   131  		it := loop.Conv(s, strconv.Atoi)
   132  		i, ok, err := it()
   133  		if !ok && err == nil {
   134  			break
   135  		}
   136  		if err != nil {
   137  			outErr = err
   138  			break
   139  		}
   140  		r = append(r, i)
   141  	}
   142  
   143  	assert.Error(t, outErr)
   144  	assert.Equal(t, []int{1, 3, 5}, r)
   145  
   146  	s = loop.Of("1", "3", "5", "7eee", "9", "11")
   147  	r = []int{}
   148  	//ignore err
   149  	for {
   150  		it := loop.Conv(s, strconv.Atoi)
   151  		i, ok, err := it()
   152  		if !ok && err == nil {
   153  			break
   154  		}
   155  		if err == nil {
   156  			r = append(r, i)
   157  		}
   158  	}
   159  	assert.Equal(t, []int{1, 3, 5, 9, 11}, r)
   160  }
   161  
   162  func Test_IterStart(t *testing.T) {
   163  	l := loop.Convert(loop.Of(1, 3, 5, 7, 9, 11), strconv.Itoa)
   164  	r := []string{}
   165  
   166  	for {
   167  		i, ok := l()
   168  		if !ok {
   169  			break
   170  		}
   171  		r = append(r, i)
   172  	}
   173  	assert.Equal(t, []string{"1", "3", "5", "7", "9", "11"}, r)
   174  }
   175  
   176  func Test_ConvertNotNil(t *testing.T) {
   177  	type entity struct{ val string }
   178  	var (
   179  		source   = loop.Of([]*entity{{"first"}, nil, {"third"}, nil, {"fifth"}}...)
   180  		result   = convert.NotNil(source, func(e *entity) string { return e.val })
   181  		expected = []string{"first", "third", "fifth"}
   182  	)
   183  	assert.Equal(t, expected, loop.Slice(result))
   184  }
   185  
   186  func Test_ConvertToNotNil(t *testing.T) {
   187  	type entity struct{ val *string }
   188  	var (
   189  		first    = "first"
   190  		third    = "third"
   191  		fifth    = "fifth"
   192  		source   = loop.Of([]entity{{&first}, {}, {&third}, {}, {&fifth}}...)
   193  		result   = convert.ToNotNil(source, func(e entity) *string { return e.val })
   194  		expected = []*string{&first, &third, &fifth}
   195  	)
   196  	assert.Equal(t, expected, loop.Slice(result))
   197  }
   198  
   199  func Test_ConvertNilSafe(t *testing.T) {
   200  	type entity struct{ val *string }
   201  	var (
   202  		first    = "first"
   203  		third    = "third"
   204  		fifth    = "fifth"
   205  		source   = loop.Of([]*entity{{&first}, {}, {&third}, nil, {&fifth}}...)
   206  		result   = convert.NilSafe(source, func(e *entity) *string { return e.val })
   207  		expected = []*string{&first, &third, &fifth}
   208  	)
   209  	assert.Equal(t, expected, loop.Slice(result))
   210  }
   211  
   212  var even = func(v int) bool { return v%2 == 0 }
   213  
   214  func Test_ConvertFiltered(t *testing.T) {
   215  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   216  	r := loop.FilterAndConvert(s, even, strconv.Itoa)
   217  	assert.Equal(t, []string{"4", "8"}, loop.Slice(r))
   218  }
   219  
   220  func Test_ConvertFilteredInplace(t *testing.T) {
   221  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   222  	r := loop.ConvertCheck(s, func(i int) (string, bool) { return strconv.Itoa(i), even(i) })
   223  	assert.Equal(t, []string{"4", "8"}, loop.Slice(r))
   224  }
   225  
   226  func Test_Flat(t *testing.T) {
   227  	md := loop.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...)
   228  	f := loop.Flat(md, func(i []int) []int { return i })
   229  	e := []int{1, 2, 3, 4, 5, 6}
   230  	assert.Equal(t, e, loop.Slice(f))
   231  }
   232  
   233  func Test_FlatAndConvert(t *testing.T) {
   234  	md := loop.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...)
   235  	f := flat.AndConvert(md, func(i []int) []int { return i }, strconv.Itoa)
   236  	e := []string{"1", "2", "3", "4", "5", "6"}
   237  	assert.Equal(t, e, loop.Slice(f))
   238  }
   239  
   240  func Test_FlatFilter(t *testing.T) {
   241  	md := loop.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...)
   242  	f := loop.FilterAndFlat(md, func(from []int) bool { return len(from) > 1 }, func(i []int) []int { return i })
   243  	e := []int{1, 2, 3, 5, 6}
   244  	assert.Equal(t, e, loop.Slice(f))
   245  }
   246  
   247  func Test_FlattElemFilter(t *testing.T) {
   248  	md := loop.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...)
   249  	f := loop.FlattAndFilter(md, func(i []int) []int { return i }, even)
   250  	e := []int{2, 4, 6}
   251  	assert.Equal(t, e, loop.Slice(f))
   252  }
   253  
   254  func Test_FilterAndFlattFilt(t *testing.T) {
   255  	md := loop.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...)
   256  	f := loop.FilterFlatFilter(md, func(from []int) bool { return len(from) > 1 }, func(i []int) []int { return i }, even)
   257  	e := []int{2, 6}
   258  	assert.Equal(t, e, loop.Slice(f))
   259  }
   260  
   261  func Test_Filter(t *testing.T) {
   262  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   263  	r := loop.Filter(s, even)
   264  	assert.Equal(t, slice.Of(4, 8), loop.Slice(r))
   265  }
   266  
   267  func Test_FilterConvertFilter(t *testing.T) {
   268  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   269  	r := filter.ConvertFilter(s, even, func(i int) int { return i * 2 }, even)
   270  	assert.Equal(t, slice.Of(8, 16), loop.Slice(r))
   271  }
   272  
   273  func Test_Filt(t *testing.T) {
   274  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   275  	l := loop.Filt(s, func(i int) (bool, error) { return even(i), op.IfElse(i > 7, errors.New("abort"), nil) })
   276  	r, err := breakLoop.Slice(l)
   277  	assert.Error(t, err)
   278  	assert.Equal(t, slice.Of(4, 8), r)
   279  }
   280  
   281  func Test_Filt2(t *testing.T) {
   282  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   283  	l := loop.Filt(s, func(i int) (bool, error) {
   284  		ok := i <= 7
   285  		return ok && even(i), op.IfElse(ok, nil, errors.New("abort"))
   286  	})
   287  	r, err := breakLoop.Slice(l)
   288  	assert.Error(t, err)
   289  	assert.Equal(t, slice.Of(4), r)
   290  }
   291  
   292  func Test_FiltAndConv(t *testing.T) {
   293  	s := loop.Of(1, 3, 4, 5, 7, 8, 9, 11)
   294  	r := loop.FiltAndConv(s, func(v int) (bool, error) { return v%2 == 0, nil }, func(i int) (int, error) { return i * 2, nil })
   295  	o, _ := breakLoop.Slice(r)
   296  	assert.Equal(t, slice.Of(8, 16), o)
   297  }
   298  
   299  func Test_Filtering(t *testing.T) {
   300  	r := loop.Filter(loop.Of(1, 2, 3, 4, 5, 6), func(i int) bool { return i%2 == 0 })
   301  	assert.Equal(t, []int{2, 4, 6}, loop.Slice(r))
   302  }
   303  
   304  type rows[T any] struct {
   305  	row    []T
   306  	cursor int
   307  }
   308  
   309  func (r *rows[T]) hasNext() bool    { return r.cursor < len(r.row) }
   310  func (r *rows[T]) next() (T, error) { e := r.row[r.cursor]; r.cursor++; return e, nil }
   311  
   312  func Test_OfLoop(t *testing.T) {
   313  	stream := loop.Of(1, 2, 3)
   314  	result := loop.Slice(stream)
   315  
   316  	assert.Equal(t, slice.Of(1, 2, 3), result)
   317  }
   318  
   319  func Test_MatchAny(t *testing.T) {
   320  	elements := loop.Of(1, 2, 3, 4)
   321  
   322  	ok := loop.HasAny(elements, eq.To(4))
   323  	assert.True(t, ok)
   324  
   325  	noOk := loop.HasAny(elements, more.Than(5))
   326  	assert.False(t, noOk)
   327  }
   328  
   329  type Role struct {
   330  	name string
   331  }
   332  
   333  type User struct {
   334  	name  string
   335  	age   int
   336  	roles []Role
   337  }
   338  
   339  func (u User) Name() string  { return u.name }
   340  func (u User) Age() int      { return u.age }
   341  func (u User) Roles() []Role { return u.roles }
   342  
   343  var users = []User{
   344  	{name: "Bob", age: 26, roles: []Role{{"Admin"}, {"manager"}}},
   345  	{name: "Alice", age: 35, roles: []Role{{"Manager"}}},
   346  	{name: "Tom", age: 18}, {},
   347  }
   348  
   349  func Test_KeyValuer(t *testing.T) {
   350  	m := kvloop.Group(loop.KeyValue(loop.Of(users...), User.Name, User.Age))
   351  
   352  	assert.Equal(t, m["Alice"], slice.Of(35))
   353  	assert.Equal(t, m["Bob"], slice.Of(26))
   354  	assert.Equal(t, m["Tom"], slice.Of(18))
   355  
   356  	g := loop.Group(loop.Of(users...), User.Name, User.Age)
   357  	assert.Equal(t, m, g)
   358  }
   359  
   360  func Test_Keyer(t *testing.T) {
   361  	m := kvloop.Group(loop.ExtraKey(loop.Of(users...), User.Name))
   362  
   363  	assert.Equal(t, m["Alice"], slice.Of(users[1]))
   364  	assert.Equal(t, m["Bob"], slice.Of(users[0]))
   365  	assert.Equal(t, m["Tom"], slice.Of(users[2]))
   366  
   367  	g := loop.Group(loop.Of(users...), User.Name, as.Is)
   368  	assert.Equal(t, m, g)
   369  }
   370  
   371  func Test_Valuer(t *testing.T) {
   372  	bob, bobRoles, _ := loop.ExtraValue(loop.Of(users...), User.Roles)()
   373  
   374  	assert.Equal(t, bob, users[0])
   375  	assert.Equal(t, bobRoles, users[0].roles)
   376  }
   377  
   378  func Test_MultiValuer(t *testing.T) {
   379  	l := loop.ExtraVals(loop.Of(users...), User.Roles)
   380  	bob, bobRole, _ := l()
   381  	bob2, bobRole2, _ := l()
   382  
   383  	assert.Equal(t, bob, users[0])
   384  	assert.Equal(t, bob2, users[0])
   385  	assert.Equal(t, bobRole, users[0].roles[0])
   386  	assert.Equal(t, bobRole2, users[0].roles[1])
   387  }
   388  
   389  func Test_MultipleKeyValuer(t *testing.T) {
   390  	m := kvloop.Group(loop.KeysValues(loop.Of(users...),
   391  		func(u User) []string {
   392  			return slice.Convert(u.roles, func(r Role) string { return strings.ToLower(r.name) })
   393  		},
   394  		func(u User) []string { return []string{u.name, strings.ToLower(u.name)} },
   395  	))
   396  
   397  	assert.Equal(t, m["admin"], slice.Of("Bob", "bob"))
   398  	assert.Equal(t, m["manager"], slice.Of("Bob", "bob", "Alice", "alice"))
   399  	assert.Equal(t, m[""], slice.Of("Tom", "tom", "", ""))
   400  }
   401  
   402  func Test_Range(t *testing.T) {
   403  	assert.Equal(t, slice.Of(-1, 0, 1, 2, 3), loop.Slice(range_.Of(-1, 4)))
   404  	assert.Equal(t, slice.Of(3, 2, 1, 0, -1), loop.Slice(range_.Of(3, -2)))
   405  	assert.Nil(t, loop.Slice(range_.Of(1, 1)))
   406  }
   407  
   408  func Test_RangeClosed(t *testing.T) {
   409  	assert.Equal(t, slice.Of(-1, 0, 1, 2, 3), loop.Slice(range_.Closed(-1, 3)))
   410  	assert.Equal(t, slice.Of(3, 2, 1, 0, -1), loop.Slice(range_.Closed(3, -1)))
   411  	assert.Equal(t, slice.Of(1), loop.Slice(range_.Closed(1, 1)))
   412  }
   413  
   414  func Test_Sequence(t *testing.T) {
   415  	assert.Equal(t, slice.Of(-1, 0, 1, 2, 3), loop.Slice(loop.Sequence(-1, func(prev int) (int, bool) { return prev + 1, prev < 3 })))
   416  }
   417  
   418  func Test_OfIndexed(t *testing.T) {
   419  	indexed := slice.Of("0", "1", "2", "3", "4")
   420  	result := loop.Slice(loop.OfIndexed(len(indexed), func(i int) string { return indexed[i] }))
   421  	assert.Equal(t, indexed, result)
   422  }
   423  
   424  func Test_ConvertIndexed(t *testing.T) {
   425  	indexed := slice.Of(10, 11, 12, 13, 14)
   426  	result := loop.Slice(convert.FromIndexed(len(indexed), func(i int) int { return indexed[i] }, strconv.Itoa))
   427  	assert.Equal(t, slice.Of("10", "11", "12", "13", "14"), result)
   428  }
   429  
   430  func Test_ConvIndexed(t *testing.T) {
   431  	indexed := slice.Of("10", "11", "12", "13", "14")
   432  	result, err := breakLoop.Slice(conv.FromIndexed(len(indexed), func(i int) string { return indexed[i] }, strconv.Atoi))
   433  	assert.NoError(t, err)
   434  	assert.Equal(t, slice.Of(10, 11, 12, 13, 14), result)
   435  }
   436  
   437  func Test_Containt(t *testing.T) {
   438  	assert.True(t, loop.Contains(loop.Of(1, 2, 3), 3))
   439  	assert.False(t, loop.Contains(loop.Of(1, 2, 3), 0))
   440  }
   441  
   442  func Test_New(t *testing.T) {
   443  	source := []string{"one", "two", "three"}
   444  	i := 0
   445  	l := loop.New(source, func(s []string) bool { return i < len(s) }, func(s []string) string { o := s[i]; i++; return o })
   446  
   447  	assert.Equal(t, source, loop.Slice(l))
   448  }
   449  
   450  func Test_For(t *testing.T) {
   451  	var out []int
   452  	err := loop.For(loop.Of(1, 2, 3, 4), func(i int) error {
   453  		if i == 3 {
   454  			return c.Break
   455  		}
   456  		out = append(out, i)
   457  		return nil
   458  	})
   459  	assert.NoError(t, err)
   460  	assert.Equal(t, slice.Of(1, 2), out)
   461  }
   462  
   463  func Test_ForEachFiltered(t *testing.T) {
   464  	var out []int
   465  	loop.ForEachFiltered(loop.Of(1, 2, 3, 4), even, func(i int) { out = append(out, i) })
   466  	assert.Equal(t, slice.Of(2, 4), out)
   467  }
   468  
   469  func Test_FlatValues(t *testing.T) {
   470  	g := kvloopgroup.Of(loop.KeyValues(loop.Of(users...), func(u User) string { return u.name }, func(u User) []int { return slice.Of(u.age) }))
   471  
   472  	assert.Equal(t, g["Bob"], slice.Of(26))
   473  }
   474  
   475  func Test_FlatKeys(t *testing.T) {
   476  	g := kvloopgroup.Of(loop.KeysValue(loop.Of(users...), func(u User) []string { return slice.Of(u.name) }, func(u User) int { return u.age }))
   477  	assert.Equal(t, g["Alice"], slice.Of(35))
   478  }