package v1 import ( "bytes" "fmt" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/suite" "gorm.io/driver/sqlite" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" "github.com/gochat/gochat/internal/service" ) type CaptainScenarioHandlerTestSuite struct { suite.Suite db *gorm.DB handler *CaptainScenarioHandler router *gin.Engine account *model.Account } func (s *CaptainScenarioHandlerTestSuite) SetupSuite() { s.db, _ = gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) s.db.AutoMigrate(&model.Account{}, &model.CaptainAssistant{}, &model.CaptainScenario{}) repo := repository.NewCaptainScenarioRepo(s.db) svc := service.NewCaptainScenarioService(repo) s.handler = NewCaptainScenarioHandler(svc) gin.SetMode(gin.TestMode) r := gin.New() // Handler Create/Update/Delete read :id (account) and :assistant_id // Handler Get reads :id (scenario ID, same key as account group — Gin conflict) // Handler List reads :assistant_id ag := r.Group("/api/v1/accounts/:id") assistants := ag.Group("/captain_assistants/:assistant_id") assistants.POST("/scenarios", s.handler.Create) assistants.GET("/scenarios", s.handler.List) assistants.PUT("/scenarios/:id", s.handler.Update) assistants.DELETE("/scenarios/:id", s.handler.Delete) // Separate route for Get since it reads c.Param("id") as scenario ID r.GET("/api/v1/captain/scenarios/:id", s.handler.Get) s.router = r s.account = &model.Account{Name: "TestAccount"} s.db.Create(s.account) } func (s *CaptainScenarioHandlerTestSuite) SetupTest() { s.db.Exec("DELETE FROM captain_scenarios") } func TestCaptainScenarioHandlerTestSuite(t *testing.T) { suite.Run(t, new(CaptainScenarioHandlerTestSuite)) } func (s *CaptainScenarioHandlerTestSuite) TestCreate_InvalidAccountID() { w := httptest.NewRecorder() body := bytes.NewBufferString(`{"name":"scenario1","description":"desc"}`) req := httptest.NewRequest(http.MethodPost, "/api/v1/accounts/abc/captain_assistants/1/scenarios", body) req.Header.Set("Content-Type", "application/json") s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *CaptainScenarioHandlerTestSuite) TestCreate_InvalidAssistantID() { w := httptest.NewRecorder() body := bytes.NewBufferString(`{"name":"scenario1","description":"desc"}`) req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/captain_assistants/abc/scenarios", s.account.ID), body) req.Header.Set("Content-Type", "application/json") s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *CaptainScenarioHandlerTestSuite) TestGet_InvalidID() { // Get reads c.Param("id") as scenario ID from separate route w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/api/v1/captain/scenarios/abc", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *CaptainScenarioHandlerTestSuite) TestList_InvalidAssistantID() { // List reads c.Param("assistant_id") — not account_id w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/captain_assistants/abc/scenarios", s.account.ID), nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *CaptainScenarioHandlerTestSuite) TestUpdate_InvalidAccountID() { w := httptest.NewRecorder() body := bytes.NewBufferString(`{"name":"updated"}`) req := httptest.NewRequest(http.MethodPut, "/api/v1/accounts/abc/captain_assistants/1/scenarios/1", body) req.Header.Set("Content-Type", "application/json") s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) } func (s *CaptainScenarioHandlerTestSuite) TestDelete_InvalidAccountID() { w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodDelete, "/api/v1/accounts/abc/captain_assistants/1/scenarios/1", nil) s.router.ServeHTTP(w, req) s.Equal(http.StatusBadRequest, w.Code) }