package ai import ( "os" "path/filepath" "testing" ) // writeLedger drops a crafted ai-calls.json into stateDir. The body is the // frozen on-disk shape, so hand-authoring it is safe. func writeLedger(t *testing.T, stateDir, body string) { t.Helper() if err := os.MkdirAll(stateDir, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(stateDir, AICallsFilename), []byte(body), 0o644); err != nil { t.Fatal(err) } } func TestSummarize_Aggregates(t *testing.T) { dir := t.TempDir() writeLedger(t, dir, `{"records":[ {"label":"a","provider":"anthropic","ran":true,"parked":false, "tokens":{"input":1000,"cached_input":200,"output":500},"ts":"2026-05-21T10:00:00Z"}, {"label":"b","provider":"cli","ran":true,"parked":false, "tokens":{"input":2000,"cached_input":0,"output":800},"ts":"2026-05-30T12:00:00Z"}, {"label":"c","provider":"anthropic","ran":false,"parked":true, "tokens":{"input":0,"cached_input":0,"output":0},"ts":"2026-05-25T09:00:00Z"} ]}`) s := Summarize(dir) if s.TotalCalls != 3 { t.Errorf("TotalCalls = %d, want 3", s.TotalCalls) } if s.Ran != 2 { t.Errorf("Ran = %d, want 2", s.Ran) } if s.Parked != 1 { t.Errorf("Parked = %d, want 1", s.Parked) } if s.Tokens.Input != 3000 || s.Tokens.CachedInput != 200 || s.Tokens.Output != 1300 { t.Errorf("Tokens = %+v, want {3000 200 1300}", s.Tokens) } if got := s.Tokens.Total(); got != 4500 { t.Errorf("Tokens.Total() = %d, want 4500", got) } if s.ByProvider["anthropic"] != 2 || s.ByProvider["cli"] != 1 { t.Errorf("ByProvider = %v, want anthropic:2 cli:1", s.ByProvider) } if s.FirstTS != "2026-05-21T10:00:00Z" { t.Errorf("FirstTS = %q, want 2026-05-21T10:00:00Z", s.FirstTS) } if s.LastTS != "2026-05-30T12:00:00Z" { t.Errorf("LastTS = %q, want 2026-05-30T12:00:00Z", s.LastTS) } } func TestSummarize_MissingFile(t *testing.T) { s := Summarize(t.TempDir()) if s.TotalCalls != 0 || s.Tokens.Total() != 0 || len(s.ByProvider) != 0 { t.Errorf("missing ledger should be the zero summary, got %+v", s) } if s.FirstTS != "" || s.LastTS != "" { t.Errorf("missing ledger should have empty range, got first=%q last=%q", s.FirstTS, s.LastTS) } } func TestSummarize_EmptyRecords(t *testing.T) { dir := t.TempDir() writeLedger(t, dir, `{"records":[]}`) s := Summarize(dir) if s.TotalCalls != 0 || s.Tokens.Total() != 0 { t.Errorf("empty ledger should be the zero summary, got %+v", s) } }