package api import ( "encoding/json" "errors" "net/http" "net/http/httptest" "testing" "github.com/thepeterstone/claudomator/internal/budget" ) type fakeBudget struct { hs []budget.Headroom err error } func (f fakeBudget) All() ([]budget.Headroom, error) { return f.hs, f.err } func TestHandleGetBudget_NoBudgetConfigured_ReturnsEmpty(t *testing.T) { srv, _ := testServer(t) req := httptest.NewRequest("GET", "/api/budget", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("status: want 200, got %d", w.Code) } var hs []budget.Headroom if err := json.Unmarshal(w.Body.Bytes(), &hs); err != nil { t.Fatalf("unmarshal: %v", err) } if len(hs) != 0 { t.Errorf("want empty list, got %+v", hs) } } func TestHandleGetBudget_ReportsHeadroom(t *testing.T) { srv, _ := testServer(t) srv.SetBudget(fakeBudget{hs: []budget.Headroom{ {Provider: "claude", Limited: true, Limit: 10, Spent: 4, Remaining: 6, Fraction: 0.6}, }}) req := httptest.NewRequest("GET", "/api/budget", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("status: want 200, got %d", w.Code) } var hs []budget.Headroom if err := json.Unmarshal(w.Body.Bytes(), &hs); err != nil { t.Fatalf("unmarshal: %v", err) } if len(hs) != 1 || hs[0].Provider != "claude" || hs[0].Remaining != 6 { t.Errorf("unexpected headroom: %+v", hs) } } func TestHandleGetBudget_ErrorReturns500(t *testing.T) { srv, _ := testServer(t) srv.SetBudget(fakeBudget{err: errors.New("db down")}) req := httptest.NewRequest("GET", "/api/budget", nil) w := httptest.NewRecorder() srv.Handler().ServeHTTP(w, req) if w.Code != http.StatusInternalServerError { t.Errorf("want 500, got %d", w.Code) } }