veza/veza-backend-api/internal/handlers/validation_test.go
2025-12-12 21:34:34 -05:00

151 lines
3.9 KiB
Go

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"
"veza-backend-api/internal/dto"
)
func TestBindAndValidateJSON_Validation(t *testing.T) {
gin.SetMode(gin.TestMode)
logger := zap.NewNop()
commonHandler := NewCommonHandler(logger)
// Test case struct
type TestRequest struct {
Name string `json:"name" validate:"required,min=3"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"gte=18"`
}
tests := []struct {
name string
payload interface{}
expectedStatus int
expectedError string
checkDetails bool
}{
{
name: "Valid Request",
payload: TestRequest{
Name: "John Doe",
Email: "john@example.com",
Age: 25,
},
expectedStatus: http.StatusOK,
},
{
name: "Missing Required Fields",
payload: map[string]interface{}{
"age": 25,
},
expectedStatus: http.StatusBadRequest, // or 422 depending on implementation, BindAndValidateJSON returns 400 for validation error wrapper
expectedError: "Validation failed",
checkDetails: true,
},
{
name: "Invalid Email",
payload: TestRequest{
Name: "John",
Email: "not-an-email",
Age: 25,
},
expectedStatus: http.StatusBadRequest,
expectedError: "Validation failed",
checkDetails: true,
},
{
name: "Min Length Violation",
payload: TestRequest{
Name: "Jo",
Email: "john@example.com",
Age: 25,
},
expectedStatus: http.StatusBadRequest,
expectedError: "Validation failed",
checkDetails: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
jsonBytes, _ := json.Marshal(tt.payload)
c.Request = httptest.NewRequest("POST", "/test", bytes.NewBuffer(jsonBytes))
c.Request.Header.Set("Content-Type", "application/json")
var req TestRequest
appErr := commonHandler.BindAndValidateJSON(c, &req)
if tt.expectedStatus == http.StatusOK {
assert.Nil(t, appErr)
} else {
assert.NotNil(t, appErr)
// Verify error response format by actually calling RespondWithAppError logic simulation
// Or check AppError properties
assert.Contains(t, appErr.Message, tt.expectedError)
if tt.checkDetails {
// check logic in commonHandler.BindAndValidateJSON
// It returns apperrors.NewValidationError which puts details in Details field
assert.NotEmpty(t, appErr.Details, "Should have validation details")
}
}
})
}
}
func TestBindAndValidateJSON_DTOs(t *testing.T) {
// Verify actual DTOs used in handlers
gin.SetMode(gin.TestMode)
logger := zap.NewNop()
commonHandler := NewCommonHandler(logger)
t.Run("RegisterRequest_Invalid", func(t *testing.T) {
payload := dto.RegisterRequest{
Username: "ab", // Too short
Email: "bad-email",
Password: "short",
}
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
jsonBytes, _ := json.Marshal(commonHandler) // Mistake in previous line logic, fix payload
jsonBytes, _ = json.Marshal(payload)
c.Request = httptest.NewRequest("POST", "/register", bytes.NewBuffer(jsonBytes))
var req dto.RegisterRequest
appErr := commonHandler.BindAndValidateJSON(c, &req)
assert.NotNil(t, appErr)
// Should catch Username min, Email format, Password min
assert.NotEmpty(t, appErr.Details)
})
t.Run("LoginRequest_Invalid", func(t *testing.T) {
payload := dto.LoginRequest{
Email: "bad-email",
}
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
jsonBytes, _ := json.Marshal(payload)
c.Request = httptest.NewRequest("POST", "/login", bytes.NewBuffer(jsonBytes))
var req dto.LoginRequest
appErr := commonHandler.BindAndValidateJSON(c, &req)
assert.NotNil(t, appErr)
assert.NotEmpty(t, appErr.Details)
})
}