package handlers import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "go.uber.org/zap" "gorm.io/driver/sqlite" "gorm.io/gorm" "veza-backend-api/internal/database" "veza-backend-api/internal/dto" "veza-backend-api/internal/models" "veza-backend-api/internal/services" "veza-backend-api/internal/validators" ) func setupAuthTestDB() *gorm.DB { db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { panic("failed to connect database") } // Migrate the schema db.AutoMigrate(&models.User{}, &models.RefreshToken{}) return db } func setupAuthHandler(db *gorm.DB) *AuthHandler { logger := zap.NewNop() // Initialize dependencies emailValidator := validators.NewEmailValidator(db) passwordValidator := validators.NewPasswordValidator() passwordService := services.NewPasswordService(nil, logger) jwtService := services.NewJWTService("test-secret") refreshTokenService := services.NewRefreshTokenService(db) // Create database wrapper manually dbWrapper := &database.Database{GormDB: db} sessionService := services.NewSessionService(dbWrapper, logger) // We can pass nil for email services to simplify tests (logic handles nils safely) authService := services.NewAuthService( db, emailValidator, passwordValidator, passwordService, jwtService, refreshTokenService, nil, // emailVerificationService nil, // emailService logger, ) return NewAuthHandler(authService, sessionService, logger) } func TestRegister(t *testing.T) { db := setupAuthTestDB() handler := setupAuthHandler(db) gin.SetMode(gin.TestMode) r := gin.Default() r.POST("/auth/register", handler.Register) t.Run("Successful Registration", func(t *testing.T) { reqBody := dto.RegisterRequest{ Email: "newuser@example.com", Password: "Password123!", PasswordConfirm: "Password123!", Username: "newuser", } jsonBody, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "/auth/register", bytes.NewBuffer(jsonBody)) w := httptest.NewRecorder() r.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) var resp dto.RegisterResponse err := json.Unmarshal(w.Body.Bytes(), &resp) assert.NoError(t, err) assert.Equal(t, reqBody.Email, resp.User.Email) assert.NotEmpty(t, resp.Token.AccessToken) }) t.Run("Duplicate Email", func(t *testing.T) { // Create user first user := models.User{Email: "duplicate@example.com", Username: "dup", PasswordHash: "hash"} db.Create(&user) reqBody := dto.RegisterRequest{ Email: "duplicate@example.com", Password: "Password123!", PasswordConfirm: "Password123!", } jsonBody, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "/auth/register", bytes.NewBuffer(jsonBody)) w := httptest.NewRecorder() r.ServeHTTP(w, req) assert.NotEqual(t, http.StatusCreated, w.Code) }) } func TestLogin(t *testing.T) { db := setupAuthTestDB() handler := setupAuthHandler(db) // Pre-create a verified user passwordService := services.NewPasswordService(nil, zap.NewNop()) hashed, _ := passwordService.Hash("Password123!") user := models.User{ Email: "login@example.com", Username: "loginuser", PasswordHash: hashed, IsActive: true, IsVerified: true, // Crucial for login } db.Create(&user) gin.SetMode(gin.TestMode) r := gin.Default() r.POST("/auth/login", handler.Login) t.Run("Successful Login", func(t *testing.T) { reqBody := dto.LoginRequest{ Email: "login@example.com", Password: "Password123!", } jsonBody, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "/auth/login", bytes.NewBuffer(jsonBody)) w := httptest.NewRecorder() r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var resp dto.LoginResponse json.Unmarshal(w.Body.Bytes(), &resp) assert.NotEmpty(t, resp.Token.AccessToken) }) t.Run("Invalid Credentials", func(t *testing.T) { reqBody := dto.LoginRequest{ Email: "login@example.com", Password: "WrongPassword!", } jsonBody, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "/auth/login", bytes.NewBuffer(jsonBody)) w := httptest.NewRecorder() r.ServeHTTP(w, req) assert.Equal(t, http.StatusUnauthorized, w.Code) }) }