github.com/lingyao2333/mo-zero@v1.4.1/core/fx/stream_test.go (about) 1 package fx 2 3 import ( 4 "io" 5 "log" 6 "math/rand" 7 "reflect" 8 "runtime" 9 "sort" 10 "sync" 11 "sync/atomic" 12 "testing" 13 "time" 14 15 "github.com/lingyao2333/mo-zero/core/stringx" 16 "github.com/stretchr/testify/assert" 17 "go.uber.org/goleak" 18 ) 19 20 func TestBuffer(t *testing.T) { 21 runCheckedTest(t, func(t *testing.T) { 22 const N = 5 23 var count int32 24 var wait sync.WaitGroup 25 wait.Add(1) 26 From(func(source chan<- interface{}) { 27 ticker := time.NewTicker(10 * time.Millisecond) 28 defer ticker.Stop() 29 30 for i := 0; i < 2*N; i++ { 31 select { 32 case source <- i: 33 atomic.AddInt32(&count, 1) 34 case <-ticker.C: 35 wait.Done() 36 return 37 } 38 } 39 }).Buffer(N).ForAll(func(pipe <-chan interface{}) { 40 wait.Wait() 41 // why N+1, because take one more to wait for sending into the channel 42 assert.Equal(t, int32(N+1), atomic.LoadInt32(&count)) 43 }) 44 }) 45 } 46 47 func TestBufferNegative(t *testing.T) { 48 runCheckedTest(t, func(t *testing.T) { 49 var result int 50 Just(1, 2, 3, 4).Buffer(-1).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 51 for item := range pipe { 52 result += item.(int) 53 } 54 return result, nil 55 }) 56 assert.Equal(t, 10, result) 57 }) 58 } 59 60 func TestCount(t *testing.T) { 61 runCheckedTest(t, func(t *testing.T) { 62 tests := []struct { 63 name string 64 elements []interface{} 65 }{ 66 { 67 name: "no elements with nil", 68 }, 69 { 70 name: "no elements", 71 elements: []interface{}{}, 72 }, 73 { 74 name: "1 element", 75 elements: []interface{}{1}, 76 }, 77 { 78 name: "multiple elements", 79 elements: []interface{}{1, 2, 3}, 80 }, 81 } 82 83 for _, test := range tests { 84 t.Run(test.name, func(t *testing.T) { 85 val := Just(test.elements...).Count() 86 assert.Equal(t, len(test.elements), val) 87 }) 88 } 89 }) 90 } 91 92 func TestDone(t *testing.T) { 93 runCheckedTest(t, func(t *testing.T) { 94 var count int32 95 Just(1, 2, 3).Walk(func(item interface{}, pipe chan<- interface{}) { 96 time.Sleep(time.Millisecond * 100) 97 atomic.AddInt32(&count, int32(item.(int))) 98 }).Done() 99 assert.Equal(t, int32(6), count) 100 }) 101 } 102 103 func TestJust(t *testing.T) { 104 runCheckedTest(t, func(t *testing.T) { 105 var result int 106 Just(1, 2, 3, 4).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 107 for item := range pipe { 108 result += item.(int) 109 } 110 return result, nil 111 }) 112 assert.Equal(t, 10, result) 113 }) 114 } 115 116 func TestDistinct(t *testing.T) { 117 runCheckedTest(t, func(t *testing.T) { 118 var result int 119 Just(4, 1, 3, 2, 3, 4).Distinct(func(item interface{}) interface{} { 120 return item 121 }).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 122 for item := range pipe { 123 result += item.(int) 124 } 125 return result, nil 126 }) 127 assert.Equal(t, 10, result) 128 }) 129 } 130 131 func TestFilter(t *testing.T) { 132 runCheckedTest(t, func(t *testing.T) { 133 var result int 134 Just(1, 2, 3, 4).Filter(func(item interface{}) bool { 135 return item.(int)%2 == 0 136 }).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 137 for item := range pipe { 138 result += item.(int) 139 } 140 return result, nil 141 }) 142 assert.Equal(t, 6, result) 143 }) 144 } 145 146 func TestFirst(t *testing.T) { 147 runCheckedTest(t, func(t *testing.T) { 148 assert.Nil(t, Just().First()) 149 assert.Equal(t, "foo", Just("foo").First()) 150 assert.Equal(t, "foo", Just("foo", "bar").First()) 151 }) 152 } 153 154 func TestForAll(t *testing.T) { 155 runCheckedTest(t, func(t *testing.T) { 156 var result int 157 Just(1, 2, 3, 4).Filter(func(item interface{}) bool { 158 return item.(int)%2 == 0 159 }).ForAll(func(pipe <-chan interface{}) { 160 for item := range pipe { 161 result += item.(int) 162 } 163 }) 164 assert.Equal(t, 6, result) 165 }) 166 } 167 168 func TestGroup(t *testing.T) { 169 runCheckedTest(t, func(t *testing.T) { 170 var groups [][]int 171 Just(10, 11, 20, 21).Group(func(item interface{}) interface{} { 172 v := item.(int) 173 return v / 10 174 }).ForEach(func(item interface{}) { 175 v := item.([]interface{}) 176 var group []int 177 for _, each := range v { 178 group = append(group, each.(int)) 179 } 180 groups = append(groups, group) 181 }) 182 183 assert.Equal(t, 2, len(groups)) 184 for _, group := range groups { 185 assert.Equal(t, 2, len(group)) 186 assert.True(t, group[0]/10 == group[1]/10) 187 } 188 }) 189 } 190 191 func TestHead(t *testing.T) { 192 runCheckedTest(t, func(t *testing.T) { 193 var result int 194 Just(1, 2, 3, 4).Head(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 195 for item := range pipe { 196 result += item.(int) 197 } 198 return result, nil 199 }) 200 assert.Equal(t, 3, result) 201 }) 202 } 203 204 func TestHeadZero(t *testing.T) { 205 runCheckedTest(t, func(t *testing.T) { 206 assert.Panics(t, func() { 207 Just(1, 2, 3, 4).Head(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 208 return nil, nil 209 }) 210 }) 211 }) 212 } 213 214 func TestHeadMore(t *testing.T) { 215 runCheckedTest(t, func(t *testing.T) { 216 var result int 217 Just(1, 2, 3, 4).Head(6).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 218 for item := range pipe { 219 result += item.(int) 220 } 221 return result, nil 222 }) 223 assert.Equal(t, 10, result) 224 }) 225 } 226 227 func TestLast(t *testing.T) { 228 runCheckedTest(t, func(t *testing.T) { 229 goroutines := runtime.NumGoroutine() 230 assert.Nil(t, Just().Last()) 231 assert.Equal(t, "foo", Just("foo").Last()) 232 assert.Equal(t, "bar", Just("foo", "bar").Last()) 233 // let scheduler schedule first 234 runtime.Gosched() 235 assert.Equal(t, goroutines, runtime.NumGoroutine()) 236 }) 237 } 238 239 func TestMap(t *testing.T) { 240 runCheckedTest(t, func(t *testing.T) { 241 log.SetOutput(io.Discard) 242 243 tests := []struct { 244 mapper MapFunc 245 expect int 246 }{ 247 { 248 mapper: func(item interface{}) interface{} { 249 v := item.(int) 250 return v * v 251 }, 252 expect: 30, 253 }, 254 { 255 mapper: func(item interface{}) interface{} { 256 v := item.(int) 257 if v%2 == 0 { 258 return 0 259 } 260 return v * v 261 }, 262 expect: 10, 263 }, 264 { 265 mapper: func(item interface{}) interface{} { 266 v := item.(int) 267 if v%2 == 0 { 268 panic(v) 269 } 270 return v * v 271 }, 272 expect: 10, 273 }, 274 } 275 276 // Map(...) works even WithWorkers(0) 277 for i, test := range tests { 278 t.Run(stringx.Rand(), func(t *testing.T) { 279 var result int 280 var workers int 281 if i%2 == 0 { 282 workers = 0 283 } else { 284 workers = runtime.NumCPU() 285 } 286 From(func(source chan<- interface{}) { 287 for i := 1; i < 5; i++ { 288 source <- i 289 } 290 }).Map(test.mapper, WithWorkers(workers)).Reduce( 291 func(pipe <-chan interface{}) (interface{}, error) { 292 for item := range pipe { 293 result += item.(int) 294 } 295 return result, nil 296 }) 297 298 assert.Equal(t, test.expect, result) 299 }) 300 } 301 }) 302 } 303 304 func TestMerge(t *testing.T) { 305 runCheckedTest(t, func(t *testing.T) { 306 Just(1, 2, 3, 4).Merge().ForEach(func(item interface{}) { 307 assert.ElementsMatch(t, []interface{}{1, 2, 3, 4}, item.([]interface{})) 308 }) 309 }) 310 } 311 312 func TestParallelJust(t *testing.T) { 313 runCheckedTest(t, func(t *testing.T) { 314 var count int32 315 Just(1, 2, 3).Parallel(func(item interface{}) { 316 time.Sleep(time.Millisecond * 100) 317 atomic.AddInt32(&count, int32(item.(int))) 318 }, UnlimitedWorkers()) 319 assert.Equal(t, int32(6), count) 320 }) 321 } 322 323 func TestReverse(t *testing.T) { 324 runCheckedTest(t, func(t *testing.T) { 325 Just(1, 2, 3, 4).Reverse().Merge().ForEach(func(item interface{}) { 326 assert.ElementsMatch(t, []interface{}{4, 3, 2, 1}, item.([]interface{})) 327 }) 328 }) 329 } 330 331 func TestSort(t *testing.T) { 332 runCheckedTest(t, func(t *testing.T) { 333 var prev int 334 Just(5, 3, 7, 1, 9, 6, 4, 8, 2).Sort(func(a, b interface{}) bool { 335 return a.(int) < b.(int) 336 }).ForEach(func(item interface{}) { 337 next := item.(int) 338 assert.True(t, prev < next) 339 prev = next 340 }) 341 }) 342 } 343 344 func TestSplit(t *testing.T) { 345 runCheckedTest(t, func(t *testing.T) { 346 assert.Panics(t, func() { 347 Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(0).Done() 348 }) 349 var chunks [][]interface{} 350 Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item interface{}) { 351 chunk := item.([]interface{}) 352 chunks = append(chunks, chunk) 353 }) 354 assert.EqualValues(t, [][]interface{}{ 355 {1, 2, 3, 4}, 356 {5, 6, 7, 8}, 357 {9, 10}, 358 }, chunks) 359 }) 360 } 361 362 func TestTail(t *testing.T) { 363 runCheckedTest(t, func(t *testing.T) { 364 var result int 365 Just(1, 2, 3, 4).Tail(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 366 for item := range pipe { 367 result += item.(int) 368 } 369 return result, nil 370 }) 371 assert.Equal(t, 7, result) 372 }) 373 } 374 375 func TestTailZero(t *testing.T) { 376 runCheckedTest(t, func(t *testing.T) { 377 assert.Panics(t, func() { 378 Just(1, 2, 3, 4).Tail(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) { 379 return nil, nil 380 }) 381 }) 382 }) 383 } 384 385 func TestWalk(t *testing.T) { 386 runCheckedTest(t, func(t *testing.T) { 387 var result int 388 Just(1, 2, 3, 4, 5).Walk(func(item interface{}, pipe chan<- interface{}) { 389 if item.(int)%2 != 0 { 390 pipe <- item 391 } 392 }, UnlimitedWorkers()).ForEach(func(item interface{}) { 393 result += item.(int) 394 }) 395 assert.Equal(t, 9, result) 396 }) 397 } 398 399 func TestStream_AnyMach(t *testing.T) { 400 runCheckedTest(t, func(t *testing.T) { 401 assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool { 402 return item.(int) == 4 403 })) 404 assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool { 405 return item.(int) == 0 406 })) 407 assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool { 408 return item.(int) == 2 409 })) 410 assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool { 411 return item.(int) == 2 412 })) 413 }) 414 } 415 416 func TestStream_AllMach(t *testing.T) { 417 runCheckedTest(t, func(t *testing.T) { 418 assetEqual( 419 t, true, Just(1, 2, 3).AllMach(func(item interface{}) bool { 420 return true 421 }), 422 ) 423 assetEqual( 424 t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool { 425 return false 426 }), 427 ) 428 assetEqual( 429 t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool { 430 return item.(int) == 1 431 }), 432 ) 433 }) 434 } 435 436 func TestStream_NoneMatch(t *testing.T) { 437 runCheckedTest(t, func(t *testing.T) { 438 assetEqual( 439 t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { 440 return false 441 }), 442 ) 443 assetEqual( 444 t, false, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { 445 return true 446 }), 447 ) 448 assetEqual( 449 t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { 450 return item.(int) == 4 451 }), 452 ) 453 }) 454 } 455 456 func TestConcat(t *testing.T) { 457 runCheckedTest(t, func(t *testing.T) { 458 a1 := []interface{}{1, 2, 3} 459 a2 := []interface{}{4, 5, 6} 460 s1 := Just(a1...) 461 s2 := Just(a2...) 462 stream := Concat(s1, s2) 463 var items []interface{} 464 for item := range stream.source { 465 items = append(items, item) 466 } 467 sort.Slice(items, func(i, j int) bool { 468 return items[i].(int) < items[j].(int) 469 }) 470 ints := make([]interface{}, 0) 471 ints = append(ints, a1...) 472 ints = append(ints, a2...) 473 assetEqual(t, ints, items) 474 }) 475 } 476 477 func TestStream_Skip(t *testing.T) { 478 runCheckedTest(t, func(t *testing.T) { 479 assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count()) 480 assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count()) 481 assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count()) 482 equal(t, Just(1, 2, 3, 4).Skip(3), []interface{}{4}) 483 assert.Panics(t, func() { 484 Just(1, 2, 3, 4).Skip(-1) 485 }) 486 }) 487 } 488 489 func TestStream_Concat(t *testing.T) { 490 runCheckedTest(t, func(t *testing.T) { 491 stream := Just(1).Concat(Just(2), Just(3)) 492 var items []interface{} 493 for item := range stream.source { 494 items = append(items, item) 495 } 496 sort.Slice(items, func(i, j int) bool { 497 return items[i].(int) < items[j].(int) 498 }) 499 assetEqual(t, []interface{}{1, 2, 3}, items) 500 501 just := Just(1) 502 equal(t, just.Concat(just), []interface{}{1}) 503 }) 504 } 505 506 func BenchmarkParallelMapReduce(b *testing.B) { 507 b.ReportAllocs() 508 509 mapper := func(v interface{}) interface{} { 510 return v.(int64) * v.(int64) 511 } 512 reducer := func(input <-chan interface{}) (interface{}, error) { 513 var result int64 514 for v := range input { 515 result += v.(int64) 516 } 517 return result, nil 518 } 519 b.ResetTimer() 520 From(func(input chan<- interface{}) { 521 b.RunParallel(func(pb *testing.PB) { 522 for pb.Next() { 523 input <- int64(rand.Int()) 524 } 525 }) 526 }).Map(mapper).Reduce(reducer) 527 } 528 529 func BenchmarkMapReduce(b *testing.B) { 530 b.ReportAllocs() 531 532 mapper := func(v interface{}) interface{} { 533 return v.(int64) * v.(int64) 534 } 535 reducer := func(input <-chan interface{}) (interface{}, error) { 536 var result int64 537 for v := range input { 538 result += v.(int64) 539 } 540 return result, nil 541 } 542 b.ResetTimer() 543 From(func(input chan<- interface{}) { 544 for i := 0; i < b.N; i++ { 545 input <- int64(rand.Int()) 546 } 547 }).Map(mapper).Reduce(reducer) 548 } 549 550 func assetEqual(t *testing.T, except, data interface{}) { 551 if !reflect.DeepEqual(except, data) { 552 t.Errorf(" %v, want %v", data, except) 553 } 554 } 555 556 func equal(t *testing.T, stream Stream, data []interface{}) { 557 items := make([]interface{}, 0) 558 for item := range stream.source { 559 items = append(items, item) 560 } 561 if !reflect.DeepEqual(items, data) { 562 t.Errorf(" %v, want %v", items, data) 563 } 564 } 565 566 func runCheckedTest(t *testing.T, fn func(t *testing.T)) { 567 defer goleak.VerifyNone(t) 568 fn(t) 569 }