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 }