This commit is contained in:
2026-06-23 05:02:15 +08:00
commit e6f1776d4f
264 changed files with 54215 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
package cc
import (
"context"
"errors"
"testing"
)
func withRunner(fn func(ctx context.Context, cwd string, args []string) ([]byte, []byte, error)) func() {
orig := RunClaude
RunClaude = fn
return func() { RunClaude = orig }
}
func TestSpawnClaude_CleanJSON(t *testing.T) {
restore := withRunner(func(_ context.Context, _ string, _ []string) ([]byte, []byte, error) {
return []byte(`{"result":"ok","session_id":"abc123"}`), nil, nil
})
defer restore()
res, err := SpawnClaude(context.Background(), Opts{Prompt: "hello"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res.SessionID != "abc123" {
t.Errorf("SessionID = %q, want abc123", res.SessionID)
}
if res.ResultText != "ok" {
t.Errorf("ResultText = %q, want ok", res.ResultText)
}
}
func TestSpawnClaude_NDJSONTail(t *testing.T) {
ndjson := `{"type":"progress","data":"thinking"}
{"type":"progress","data":"still thinking"}
{"result":"done","session_id":"sess99"}`
restore := withRunner(func(_ context.Context, _ string, _ []string) ([]byte, []byte, error) {
return []byte(ndjson), nil, nil
})
defer restore()
res, err := SpawnClaude(context.Background(), Opts{Prompt: "go"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if res.SessionID != "sess99" {
t.Errorf("SessionID = %q, want sess99", res.SessionID)
}
if res.ResultText != "done" {
t.Errorf("ResultText = %q, want done", res.ResultText)
}
}
func TestSpawnClaude_NonZeroExit(t *testing.T) {
restore := withRunner(func(_ context.Context, _ string, _ []string) ([]byte, []byte, error) {
return nil, []byte("something went wrong"), errors.New("exit status 1")
})
defer restore()
_, err := SpawnClaude(context.Background(), Opts{Prompt: "hi"})
if err == nil {
t.Fatal("expected error, got nil")
}
var ce *ClaudeError
if !errors.As(err, &ce) {
t.Errorf("expected ClaudeError, got %T: %v", err, err)
}
}
func TestSpawnClaude_Timeout(t *testing.T) {
restore := withRunner(func(ctx context.Context, _ string, _ []string) ([]byte, []byte, error) {
// Respect context cancellation — as the real runner would.
<-ctx.Done()
return nil, nil, ctx.Err()
})
defer restore()
_, err := SpawnClaude(context.Background(), Opts{Prompt: "slow", TimeoutMs: 1})
if err == nil {
t.Fatal("expected timeout error, got nil")
}
var te *ClaudeTimeoutError
if !errors.As(err, &te) {
t.Errorf("expected ClaudeTimeoutError, got %T: %v", err, err)
}
}