package underscore_test import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" u "github.com/rjNemo/underscore" ) func TestParallelReduce(t *testing.T) { nums := []int{1, 2, 3, 4, 5} ctx := context.Background() // Note: This is a simplified test - ParallelReduce needs work for proper reduction result, err := u.ParallelReduce(ctx, nums, 2, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) assert.NoError(t, err) // Result may vary due to parallel execution assert.Greater(t, result, 0) } func TestParallelReduceEmpty(t *testing.T) { ctx := context.Background() result, err := u.ParallelReduce(ctx, []int{}, 2, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 42) assert.NoError(t, err) assert.Equal(t, 42, result) } func TestParallelReduceDefaultWorkers(t *testing.T) { nums := []int{1, 2, 3, 4, 5} ctx := context.Background() // Test with workers <= 0 to use GOMAXPROCS result, err := u.ParallelReduce(ctx, nums, 0, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) assert.NoError(t, err) assert.Greater(t, result, 0) } func TestParallelReduceNegativeWorkers(t *testing.T) { nums := []int{1, 2, 3} ctx := context.Background() // Negative workers should default to GOMAXPROCS result, err := u.ParallelReduce(ctx, nums, -1, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) assert.NoError(t, err) assert.Greater(t, result, 0) } func TestParallelReduceError(t *testing.T) { nums := []int{1, 2, 3, 4, 5} ctx := context.Background() expectedErr := errors.New("processing error") _, err := u.ParallelReduce(ctx, nums, 2, func(ctx context.Context, n int, acc int) (int, error) { if n == 3 { return 0, expectedErr } return n + acc, nil }, 0) assert.Error(t, err) assert.Equal(t, expectedErr, err) } func TestParallelReduceContextCancellation(t *testing.T) { nums := make([]int, 100) for i := range nums { nums[i] = i } ctx, cancel := context.WithCancel(context.Background()) // Cancel after a short delay go func() { time.Sleep(10 * time.Millisecond) cancel() }() _, err := u.ParallelReduce(ctx, nums, 4, func(ctx context.Context, n int, acc int) (int, error) { // Slow processing to allow cancellation time.Sleep(5 * time.Millisecond) select { case <-ctx.Done(): return 0, ctx.Err() default: return n + acc, nil } }, 0) // Should either complete or get cancelled if err != nil { assert.ErrorIs(t, err, context.Canceled) } } func TestParallelReduceContextTimeout(t *testing.T) { nums := make([]int, 20) for i := range nums { nums[i] = i } ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() _, err := u.ParallelReduce(ctx, nums, 2, func(ctx context.Context, n int, acc int) (int, error) { // Simulate slow work time.Sleep(100 * time.Millisecond) if ctx.Err() != nil { return 0, ctx.Err() } return n + acc, nil }, 0) // Should timeout if err != nil { assert.ErrorIs(t, err, context.DeadlineExceeded) } } func TestParallelReduceSingleElement(t *testing.T) { ctx := context.Background() result, err := u.ParallelReduce(ctx, []int{42}, 2, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) assert.NoError(t, err) assert.Greater(t, result, 0) } func TestParallelReduceManyWorkers(t *testing.T) { nums := []int{1, 2, 3, 4, 5} ctx := context.Background() // More workers than elements result, err := u.ParallelReduce(ctx, nums, 10, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) assert.NoError(t, err) assert.Greater(t, result, 0) } func BenchmarkParallelReduce(b *testing.B) { nums := make([]int, 100) for i := range nums { nums[i] = i } ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { u.ParallelReduce(ctx, nums, 4, func(ctx context.Context, n int, acc int) (int, error) { return n + acc, nil }, 0) } }