stario/fn_test.go
starainrt c8facb5a03
stario: 提升 Go 1.20 基线与交互/队列稳定性
- 提升 go.mod 基线到 Go 1.20,并补齐对应测试
  - 修正 Passwd / PasswdResponseSignal 语义,Ctrl+C 默认退出当前流程
  - 优化 raw terminal redraw、Restore 与 StopUntil 的边界行为
  - 新增 StarPipe、FrameReader/FrameWriter、ReadFullContext/WriteFullContext/CopyContext、IsTerminal/ReadPasswordContext
  - 收口 StarQueue / StarBuffer 语义,删除 EndWrite,统一 Close / Abort 行为
  - 补齐 signal、timeout、queue、terminal、pipe、buffer 的回归测试与 race 覆盖
2026-04-15 14:35:19 +08:00

175 lines
4.5 KiB
Go

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)
}
}