veza/veza-backend-api/internal/validators/email_validator_test.go

325 lines
6.5 KiB
Go
Raw Permalink Normal View History

2025-12-03 19:29:37 +00:00
package validators
import (
"strings"
"testing"
"veza-backend-api/internal/models"
"github.com/stretchr/testify/assert"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// setupTestDB crée une base de données de test
func setupTestDB(t *testing.T) *gorm.DB {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("Failed to open test database: %v", err)
}
// Auto-migrate
err = db.AutoMigrate(&models.User{})
if err != nil {
t.Fatalf("Failed to migrate: %v", err)
}
return db
}
func TestEmailValidator_ValidateFormat(t *testing.T) {
db := setupTestDB(t)
validator := NewEmailValidator(db)
tests := []struct {
name string
email string
want bool
}{
{
name: "valid email",
email: "test@example.com",
want: true,
},
{
name: "valid email with subdomain",
email: "user@mail.example.com",
want: true,
},
{
name: "valid email with plus",
email: "user+tag@example.com",
want: true,
},
{
name: "valid email with dots",
email: "first.last@example.com",
want: true,
},
{
name: "valid email with numbers",
email: "user123@example.com",
want: true,
},
{
name: "valid email with underscore",
email: "user_name@example.com",
want: true,
},
{
name: "invalid email - no @",
email: "invalidemail.com",
want: false,
},
{
name: "invalid email - no domain",
email: "invalid@",
want: false,
},
{
name: "invalid email - no local part",
email: "@example.com",
want: false,
},
{
name: "invalid email - no TLD",
email: "invalid@example",
want: false,
},
{
name: "invalid email - too long",
email: strings.Repeat("a", 250) + "@example.com",
want: false,
},
{
name: "invalid email - local part starts with dot",
email: ".user@example.com",
want: false,
},
{
name: "invalid email - local part ends with dot",
email: "user.@example.com",
want: false,
},
{
name: "invalid email - domain starts with dot",
email: "user@.example.com",
want: false,
},
{
name: "invalid email - domain ends with dot",
email: "user@example.com.",
want: false,
},
{
name: "invalid email - domain starts with hyphen",
email: "user@-example.com",
want: false,
},
{
name: "invalid email - domain ends with hyphen",
email: "user@example.com-",
want: false,
},
{
name: "invalid email - empty string",
email: "",
want: false,
},
{
name: "invalid email - only spaces",
email: " ",
want: false,
},
{
name: "valid email - trimmed spaces",
email: " test@example.com ",
want: true,
},
{
name: "valid email - case insensitive",
email: "TEST@EXAMPLE.COM",
want: true,
},
{
name: "valid email - with percent",
email: "user%tag@example.com",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := validator.ValidateFormat(tt.email)
assert.Equal(t, tt.want, got, "ValidateFormat(%q) = %v, want %v", tt.email, got, tt.want)
})
}
}
func TestEmailValidator_IsUnique(t *testing.T) {
db := setupTestDB(t)
validator := NewEmailValidator(db)
// Créer un utilisateur de test
user := &models.User{
Email: "existing@example.com",
Username: "existing",
Role: "user",
}
err := db.Create(user).Error
assert.NoError(t, err)
tests := []struct {
name string
email string
want bool
wantErr bool
}{
{
name: "unique email",
email: "new@example.com",
want: true,
wantErr: false,
},
{
name: "existing email",
email: "existing@example.com",
want: false,
wantErr: false,
},
{
name: "existing email - case insensitive",
email: "EXISTING@EXAMPLE.COM",
want: false,
wantErr: false,
},
{
name: "existing email - with spaces",
email: " existing@example.com ",
want: false,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := validator.IsUnique(tt.email)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, got, "IsUnique(%q) = %v, want %v", tt.email, got, tt.want)
}
})
}
}
func TestEmailValidator_Validate(t *testing.T) {
db := setupTestDB(t)
validator := NewEmailValidator(db)
// Créer un utilisateur de test
user := &models.User{
Email: "existing@example.com",
Username: "existing",
Role: "user",
}
err := db.Create(user).Error
assert.NoError(t, err)
tests := []struct {
name string
email string
wantErr bool
errMsg string
}{
{
name: "valid and unique email",
email: "new@example.com",
wantErr: false,
},
{
name: "invalid format",
email: "invalid-email",
wantErr: true,
errMsg: "invalid email format",
},
{
name: "existing email",
email: "existing@example.com",
wantErr: true,
errMsg: "email already exists",
},
{
name: "empty email",
email: "",
wantErr: true,
errMsg: "invalid email format",
},
{
name: "email with invalid format - no @",
email: "invalidemail.com",
wantErr: true,
errMsg: "invalid email format",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validator.Validate(tt.email)
if tt.wantErr {
assert.Error(t, err)
if tt.errMsg != "" {
assert.Contains(t, err.Error(), tt.errMsg)
}
} else {
assert.NoError(t, err)
}
})
}
}
func TestEmailValidator_ValidateFormat_EdgeCases(t *testing.T) {
db := setupTestDB(t)
validator := NewEmailValidator(db)
tests := []struct {
name string
email string
want bool
}{
{
name: "email at max length (254 chars)",
email: strings.Repeat("a", 64) + "@" + strings.Repeat("b", 186) + ".co",
want: true,
},
{
name: "email over max length (255 chars)",
email: strings.Repeat("a", 64) + "@" + strings.Repeat("b", 187) + ".co",
want: false,
},
{
name: "local part at max length (64 chars)",
email: strings.Repeat("a", 64) + "@example.com",
want: true,
},
{
name: "local part over max length (65 chars)",
email: strings.Repeat("a", 65) + "@example.com",
want: false,
},
{
name: "domain at max length (253 chars)",
email: "user@" + strings.Repeat("a", 253),
want: false, // Domain doit avoir au moins un point
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := validator.ValidateFormat(tt.email)
assert.Equal(t, tt.want, got, "ValidateFormat(%q) = %v, want %v", tt.email, got, tt.want)
})
}
}