package ai import ( "context" "errors" "strings" "testing" ) func TestParseVerdictOnTask(t *testing.T) { v, err := parseVerdict(`{"on_task": true, "reason": ""}`) if err != nil { t.Fatalf("parse: %v", err) } if !v.OnTask { t.Fatalf("expected on-task, got %+v", v) } } func TestParseVerdictDriftingChatty(t *testing.T) { v, err := parseVerdict("Sure! here is the call:\n{\"on_task\": false, \"reason\": \"Reddit is unrelated\"}\nhope that helps") if err != nil { t.Fatalf("parse: %v", err) } if v.OnTask || v.Reason != "Reddit is unrelated" { t.Fatalf("bad verdict: %+v", v) } } func TestParseVerdictDriftingNeedsReason(t *testing.T) { if _, err := parseVerdict(`{"on_task": false}`); !errors.Is(err, ErrInvalidVerdict) { t.Fatalf("want ErrInvalidVerdict for reasonless drift, got %v", err) } } func TestParseVerdictEmpty(t *testing.T) { if _, err := parseVerdict(" "); !errors.Is(err, ErrEmptyResponse) { t.Fatalf("want ErrEmptyResponse, got %v", err) } } func TestParseVerdictNoJSON(t *testing.T) { if _, err := parseVerdict("I cannot help"); !errors.Is(err, ErrNoJSON) { t.Fatalf("want ErrNoJSON, got %v", err) } } func TestServiceJudgeDrift(t *testing.T) { fb := &fakeBackend{out: `{"on_task": false, "reason": "YouTube is off-task"}`} v, err := NewService(fb).JudgeDrift(context.Background(), "write the report", "firefox", "YouTube") if err != nil { t.Fatalf("judge: %v", err) } if v.OnTask || v.Reason == "" { t.Fatalf("bad verdict: %+v", v) } if !strings.Contains(fb.gotPrompt, "write the report") || !strings.Contains(fb.gotPrompt, "YouTube") { t.Fatalf("prompt should embed commitment and window: %s", fb.gotPrompt) } } func TestServiceJudgeDriftBackendError(t *testing.T) { fb := &fakeBackend{err: errors.New("boom")} if _, err := NewService(fb).JudgeDrift(context.Background(), "x", "c", "t"); err == nil { t.Fatal("want backend error") } }