package stario import ( "context" "errors" "testing" "time" ) func TestWaitUntilContextReturnsWorkerError(t *testing.T) { want := errors.New("worker failed") err := WaitUntilContext(context.Background(), func(ctx context.Context) error { return want }) if !errors.Is(err, want) { t.Fatalf("unexpected error: got %v want %v", err, want) } } func TestWaitUntilContextReturnsDeadlineExceeded(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) defer cancel() workerReturned := make(chan struct{}) err := WaitUntilContext(ctx, func(ctx context.Context) error { <-ctx.Done() close(workerReturned) return nil }) if !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("unexpected context error: %v", err) } select { case <-workerReturned: case <-time.After(200 * time.Millisecond): t.Fatal("worker did not return after context deadline") } } func TestWaitUntilContextFinishedReturnsCanceled(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() result := WaitUntilContextFinished(ctx, func(ctx context.Context) error { <-ctx.Done() return nil }) err, ok := <-result if !ok { t.Fatal("result channel closed without value") } if !errors.Is(err, context.Canceled) { t.Fatalf("unexpected context error: %v", err) } if _, ok := <-result; ok { t.Fatal("result channel should be closed after delivering the outcome") } } func TestWaitUntilContextDoneBridgesDoneChannel(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) doneClosed := make(chan struct{}) go func() { time.Sleep(20 * time.Millisecond) cancel() }() err := WaitUntilContextDone(ctx, func(done <-chan struct{}) error { <-done close(doneClosed) return nil }) if !errors.Is(err, context.Canceled) { t.Fatalf("unexpected context error: %v", err) } select { case <-doneClosed: case <-time.After(200 * time.Millisecond): t.Fatal("done channel was not closed when context canceled") } } func TestWaitUntilContextDoneFinishedReturnsCanceled(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) doneClosed := make(chan struct{}) go func() { time.Sleep(20 * time.Millisecond) cancel() }() result := WaitUntilContextDoneFinished(ctx, func(done <-chan struct{}) error { <-done close(doneClosed) return nil }) err, ok := <-result if !ok { t.Fatal("result channel closed without value") } if !errors.Is(err, context.Canceled) { t.Fatalf("unexpected context error: %v", err) } select { case <-doneClosed: case <-time.After(200 * time.Millisecond): t.Fatal("done channel was not closed when context canceled") } if _, ok := <-result; ok { t.Fatal("result channel should be closed after delivering the outcome") } } func TestWaitUntilTimeoutReturnsWorkerError(t *testing.T) { want := errors.New("worker failed") err := WaitUntilTimeout(time.Second, func(stop chan struct{}) error { return want }) if !errors.Is(err, want) { t.Fatalf("unexpected error: got %v want %v", err, want) } } func TestWaitUntilTimeoutTimesOutWithoutBlockingWorkerReturn(t *testing.T) { workerReturned := make(chan struct{}) err := WaitUntilTimeout(20*time.Millisecond, func(stop chan struct{}) error { <-stop close(workerReturned) return nil }) if !errors.Is(err, ERR_TIMEOUT) { t.Fatalf("unexpected timeout error: %v", err) } select { case <-workerReturned: case <-time.After(200 * time.Millisecond): t.Fatal("worker did not return after timeout signal") } } func TestWaitUntilFinishedReturnsWorkerError(t *testing.T) { want := errors.New("worker failed") err := <-WaitUntilFinished(func() error { return want }) if !errors.Is(err, want) { t.Fatalf("unexpected error: got %v want %v", err, want) } } func TestWaitUntilTimeoutFinishedReturnsTimeout(t *testing.T) { result := WaitUntilTimeoutFinished(20*time.Millisecond, func(stop chan struct{}) error { <-stop return nil }) err, ok := <-result if !ok { t.Fatal("result channel closed without value") } if !errors.Is(err, ERR_TIMEOUT) { t.Fatalf("unexpected timeout error: %v", err) } if _, ok := <-result; ok { t.Fatal("result channel should be closed after delivering the outcome") } } func TestWaitUntilTimeoutFinishedReturnsWorkerError(t *testing.T) { want := errors.New("worker failed") err, ok := <-WaitUntilTimeoutFinished(time.Second, func(stop chan struct{}) error { return want }) if !ok { t.Fatal("result channel closed without value") } if !errors.Is(err, want) { t.Fatalf("unexpected error: got %v want %v", err, want) } }