// internal/ai/ambient_test.go package ai import ( "context" "errors" "strings" "testing" ) func TestServiceAmbientDriftSuccess(t *testing.T) { fb := &fakeBackend{out: `{"drifting": true, "message": "deep in YouTube, none of today's goals"}`} line, err := NewService(fb).AmbientDrift(context.Background(), "## Goals\nship keel", []string{"YouTube - Brave"}) if err != nil { t.Fatalf("ambient drift: %v", err) } if line == "" { t.Fatal("expected a non-empty drift line") } if !strings.Contains(fb.gotPrompt, "ship keel") { t.Fatalf("prompt should embed the frame, got: %s", fb.gotPrompt) } if !strings.Contains(fb.gotPrompt, "YouTube - Brave") { t.Fatalf("prompt should embed the recent titles, got: %s", fb.gotPrompt) } } func TestServiceAmbientDriftBackendError(t *testing.T) { fb := &fakeBackend{err: errors.New("boom")} if _, err := NewService(fb).AmbientDrift(context.Background(), "frame", []string{"x"}); err == nil { t.Fatal("want backend error") } } func TestParseAmbientDrift(t *testing.T) { tests := []struct { name string in string want string wantErr error }{ {"on track yields empty", `{"drifting": false, "message": ""}`, "", nil}, {"drift returns message", `{"drifting": true, "message": "watching unrelated videos"}`, "watching unrelated videos", nil}, {"drift is trimmed", `{"drifting": true, "message": " slid "}`, "slid", nil}, {"drift without message degrades to silence", `{"drifting": true, "message": ""}`, "", nil}, {"json embedded in prose", `ok: {"drifting": true, "message": "off track"} done`, "off track", nil}, {"empty response", " ", "", ErrEmptyResponse}, {"no json", "no braces here", "", ErrNoJSON}, {"malformed json", `{"drifting": true, "message":`, "", ErrInvalidAmbientDrift}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := parseAmbientDrift(tt.in) if tt.wantErr != nil { if !errors.Is(err, tt.wantErr) { t.Fatalf("err = %v, want %v", err, tt.wantErr) } return } if err != nil { t.Fatalf("unexpected err: %v", err) } if got != tt.want { t.Fatalf("got %q, want %q", got, tt.want) } }) } }