package handlers import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func init() { gin.SetMode(gin.TestMode) } // ── Channel Request Validation ───────────────── func TestCreateChannelMissingTitle(t *testing.T) { h := NewChannelHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/v1/channels", strings.NewReader(`{}`)) c.Request.Header.Set("Content-Type", "application/json") h.CreateChannel(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400, got %d: %s", w.Code, w.Body.String()) } } func TestCreateChannelTitleTooLong(t *testing.T) { h := NewChannelHandler() longTitle := strings.Repeat("x", 501) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/v1/channels", strings.NewReader(`{"title":"`+longTitle+`"}`)) c.Request.Header.Set("Content-Type", "application/json") h.CreateChannel(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400 for title > 500 chars, got %d", w.Code) } } func TestUpdateChannelEmptyBody(t *testing.T) { h := NewChannelHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Set("user_id", "test-user-id") c.Params = gin.Params{{Key: "id", Value: "test-channel-id"}} c.Request = httptest.NewRequest("PUT", "/api/v1/channels/test-channel-id", strings.NewReader(`{}`)) c.Request.Header.Set("Content-Type", "application/json") // Without a DB connection, UpdateChannel will fail at ownership check. // Integration tests with a real DB would validate the "no fields" path. // Here we just confirm it doesn't return 400 for valid JSON. h.UpdateChannel(c) if w.Code == http.StatusBadRequest { t.Error("Empty JSON body should not be a parse error") } } // ── Message Request Validation ────────────── func TestCreateMessageMissingRole(t *testing.T) { h := NewMessageHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "test-channel"}} c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/messages", strings.NewReader(`{"content":"hello"}`)) c.Request.Header.Set("Content-Type", "application/json") h.CreateMessage(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400 for missing role, got %d: %s", w.Code, w.Body.String()) } } func TestCreateMessageInvalidRole(t *testing.T) { h := NewMessageHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "test-channel"}} c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/messages", strings.NewReader(`{"role":"invalid","content":"hello"}`)) c.Request.Header.Set("Content-Type", "application/json") h.CreateMessage(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400 for invalid role, got %d", w.Code) } } func TestCreateMessageMissingContent(t *testing.T) { h := NewMessageHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Params = gin.Params{{Key: "id", Value: "test-channel"}} c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/messages", strings.NewReader(`{"role":"user"}`)) c.Request.Header.Set("Content-Type", "application/json") h.CreateMessage(c) if w.Code != http.StatusBadRequest { t.Errorf("Expected 400 for missing content, got %d", w.Code) } } func TestCreateMessageValidRoles(t *testing.T) { // Valid roles should pass validation (not return 400). // They'll fail at ownership check (no DB), which is expected. t.Skip("requires database connection for ownership check") } // ── Regenerate Stub ───────────────────────── func TestRegenerateReturns501(t *testing.T) { h := NewMessageHandler() w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("POST", "/api/v1/channels/x/regenerate", nil) h.Regenerate(c) if w.Code != http.StatusNotImplemented { t.Errorf("Expected 501, got %d", w.Code) } } // ── Pagination Helpers ────────────────────── func TestParsePaginationDefaults(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("GET", "/api/v1/channels", nil) page, perPage, offset := parsePagination(c) if page != 1 { t.Errorf("Default page should be 1, got %d", page) } if perPage != 50 { t.Errorf("Default per_page should be 50, got %d", perPage) } if offset != 0 { t.Errorf("Default offset should be 0, got %d", offset) } } func TestParsePaginationCustom(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("GET", "/api/v1/channels?page=3&per_page=10", nil) page, perPage, offset := parsePagination(c) if page != 3 { t.Errorf("Page should be 3, got %d", page) } if perPage != 10 { t.Errorf("Per page should be 10, got %d", perPage) } if offset != 20 { t.Errorf("Offset should be 20, got %d", offset) } } func TestParsePaginationClampMax(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest("GET", "/api/v1/channels?per_page=500", nil) _, perPage, _ := parsePagination(c) if perPage != 100 { t.Errorf("Per page should be clamped to 100, got %d", perPage) } } // ── getUserID ─────────────────────────────── func TestGetUserID(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Set("user_id", "abc-123") uid := getUserID(c) if uid != "abc-123" { t.Errorf("Expected abc-123, got %s", uid) } } func TestGetUserIDMissing(t *testing.T) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) uid := getUserID(c) if uid != "" { t.Errorf("Expected empty string, got %s", uid) } }