iop/apps/node/internal/adapters/cli/internal/testutil/testutil.go
toki 0988942b07 refactor: reorganize CLI adapter into subpackages
- Move cli_test.go to internal/, lifecycle/, onshot/, persistent/
- Restructure CLI adapter modules into organized subdirectories
2026-05-03 18:19:00 +09:00

85 lines
1.5 KiB
Go

package testutil
import (
"context"
"os"
"runtime"
"strings"
"sync"
"testing"
"time"
noderuntime "iop/apps/node/internal/runtime"
)
type FakeSink struct {
mu sync.Mutex
events []noderuntime.RuntimeEvent
}
func (f *FakeSink) Emit(_ context.Context, e noderuntime.RuntimeEvent) error {
f.mu.Lock()
defer f.mu.Unlock()
f.events = append(f.events, e)
return nil
}
func (f *FakeSink) Events() []noderuntime.RuntimeEvent {
f.mu.Lock()
defer f.mu.Unlock()
cp := make([]noderuntime.RuntimeEvent, len(f.events))
copy(cp, f.events)
return cp
}
func RequireUnixShell(t *testing.T) {
t.Helper()
if runtime.GOOS == "windows" {
t.Skip("Unix shell required")
}
}
func RequirePTYSupport(t *testing.T) {
t.Helper()
if runtime.GOOS == "windows" {
t.Skip("PTY not supported on Windows")
}
}
func CollectDeltas(events []noderuntime.RuntimeEvent) string {
deltas := make([]string, 0, len(events))
for _, e := range events {
if e.Type == noderuntime.EventTypeDelta {
deltas = append(deltas, e.Delta)
}
}
return strings.Join(deltas, "")
}
func RequireEventually(t *testing.T, timeout, interval time.Duration, fn func() bool) {
t.Helper()
timer := time.NewTimer(timeout)
defer timer.Stop()
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
if fn() {
return
}
select {
case <-timer.C:
t.Fatal("condition not satisfied within timeout")
case <-ticker.C:
}
}
}
func ReadMarker(path string) string {
data, err := os.ReadFile(path)
if err != nil {
return ""
}
return strings.TrimSpace(string(data))
}