package web import ( "net/http" "net/http/httptest" "path/filepath" "strings" "testing" "antidrift/internal/domain" "antidrift/internal/session" "github.com/gin-gonic/gin" ) func newTestServer(t *testing.T) *Server { t.Helper() gin.SetMode(gin.TestMode) path := filepath.Join(t.TempDir(), "state.json") ctrl, err := session.New(path) if err != nil { t.Fatalf("controller: %v", err) } return NewServer(ctrl) } func post(t *testing.T, r http.Handler, path, body string) *httptest.ResponseRecorder { t.Helper() req := httptest.NewRequest(http.MethodPost, path, strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() r.ServeHTTP(w, req) return w } func TestPlanningThenCommitmentReachesActive(t *testing.T) { s := newTestServer(t) r := s.Router() if w := post(t, r, "/planning", ""); w.Code != http.StatusOK { t.Fatalf("/planning code %d", w.Code) } body := `{"next_action":"Build web","success_condition":"web tests pass","timebox_secs":1500}` if w := post(t, r, "/commitment", body); w.Code != http.StatusOK { t.Fatalf("/commitment code %d body %s", w.Code, w.Body.String()) } if s.ctrl.State().RuntimeState != domain.RuntimeActive { t.Fatalf("expected Active, got %s", s.ctrl.State().RuntimeState) } } func TestCommitmentRejectsInvalidInput(t *testing.T) { s := newTestServer(t) r := s.Router() _ = post(t, r, "/planning", "") body := `{"next_action":"","success_condition":"x","timebox_secs":1500}` w := post(t, r, "/commitment", body) if w.Code != http.StatusBadRequest { t.Fatalf("expected 400, got %d", w.Code) } } func TestIllegalTransitionReturns409(t *testing.T) { s := newTestServer(t) r := s.Router() // /complete from Locked is illegal. w := post(t, r, "/complete", "") if w.Code != http.StatusConflict { t.Fatalf("expected 409, got %d", w.Code) } }