package testutils import ( "fmt" "strings" "time" "veza-backend-api/internal/models" "github.com/google/uuid" "gorm.io/gorm" ) // CreateTestUser crée un utilisateur de test avec des valeurs par défaut func CreateTestUser(db *gorm.DB) (*models.User, error) { // Make username and email unique to avoid constraint violations when tests share the same DB uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "") uniqueUsername := fmt.Sprintf("testuser_%s", uniqueID) uniqueEmail := fmt.Sprintf("test_%s@example.com", uniqueID) // Slug must also be unique - use the same uniqueID to ensure uniqueness uniqueSlug := fmt.Sprintf("testuser-%s", uniqueID) user := &models.User{ Username: uniqueUsername, Slug: uniqueSlug, Email: uniqueEmail, PasswordHash: "$2a$10$examplehash", // Hash bcrypt factice TokenVersion: 0, FirstName: "Test", LastName: "User", Role: "user", IsActive: true, IsVerified: true, IsAdmin: false, } if err := db.Create(user).Error; err != nil { return nil, err } return user, nil } // CreateTestUserWithCustomData crée un utilisateur de test avec des données personnalisées func CreateTestUserWithCustomData(db *gorm.DB, username, email string) (*models.User, error) { // Make username and email unique to avoid constraint violations // Username must match ^[a-zA-Z0-9_]{3,30}$ (no dashes, only alphanum + underscore) uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "") // Remove dashes from UUID // Ensure username doesn't exceed 30 chars (constraint limit) maxUsernameLen := 30 uniqueUsername := fmt.Sprintf("%s_%s", username, uniqueID) if len(uniqueUsername) > maxUsernameLen { // Truncate username part if needed maxUsernamePartLen := maxUsernameLen - len(uniqueID) - 1 // -1 for underscore if maxUsernamePartLen < 1 { maxUsernamePartLen = 1 } uniqueUsername = fmt.Sprintf("%s_%s", username[:maxUsernamePartLen], uniqueID) } // Extract email parts and add unique ID emailParts := strings.Split(email, "@") if len(emailParts) != 2 { return nil, fmt.Errorf("invalid email format: %s", email) } uniqueEmail := fmt.Sprintf("%s_%s@%s", emailParts[0], uniqueID, emailParts[1]) // Slug must also be unique - generate from username with uniqueID // Slugify converts underscores to dashes, so "customuser_abc123" becomes "customuser-abc123" uniqueSlug := fmt.Sprintf("%s-%s", strings.ToLower(username), uniqueID) user := &models.User{ Username: uniqueUsername, Slug: uniqueSlug, Email: uniqueEmail, PasswordHash: "$2a$10$examplehash", TokenVersion: 0, FirstName: "Test", LastName: "User", Role: "user", IsActive: true, IsVerified: true, IsAdmin: false, } if err := db.Create(user).Error; err != nil { return nil, err } return user, nil } // CreateTestAdmin crée un utilisateur administrateur de test func CreateTestAdmin(db *gorm.DB) (*models.User, error) { // Make username and email unique to avoid constraint violations when tests share the same DB uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "") uniqueUsername := fmt.Sprintf("admin_%s", uniqueID) uniqueEmail := fmt.Sprintf("admin_%s@example.com", uniqueID) // Slug must also be unique - use the same uniqueID to ensure uniqueness uniqueSlug := fmt.Sprintf("admin-%s", uniqueID) user := &models.User{ Username: uniqueUsername, Slug: uniqueSlug, Email: uniqueEmail, PasswordHash: "$2a$10$examplehash", TokenVersion: 0, FirstName: "Admin", LastName: "User", Role: "admin", IsActive: true, IsVerified: true, IsAdmin: true, } if err := db.Create(user).Error; err != nil { return nil, err } return user, nil } // CreateTestTrack crée un track de test func CreateTestTrack(db *gorm.DB, userID uuid.UUID) (*models.Track, error) { track := &models.Track{ UserID: userID, Title: "Test Track", Artist: "Test Artist", Duration: 180, // 3 minutes FilePath: "uploads/test_track.mp3", FileSize: 1024 * 1024 * 5, // 5MB Format: "mp3", } if err := db.Create(track).Error; err != nil { return nil, err } return track, nil } // CreateTestTrackWithCustomData crée un track de test avec des données personnalisées func CreateTestTrackWithCustomData(db *gorm.DB, userID uuid.UUID, title, artist string) (*models.Track, error) { track := &models.Track{ UserID: userID, Title: title, Artist: artist, Duration: 180, FilePath: "uploads/test_track.mp3", FileSize: 1024 * 1024 * 5, Format: "mp3", } if err := db.Create(track).Error; err != nil { return nil, err } return track, nil } // CreateTestPlaylist crée une playlist de test func CreateTestPlaylist(db *gorm.DB, userID uuid.UUID) (*models.Playlist, error) { playlist := &models.Playlist{ UserID: userID, Title: "Test Playlist", Description: "A test playlist", } if err := db.Create(playlist).Error; err != nil { return nil, err } return playlist, nil } // CreateTestRoom crée une room de test func CreateTestRoom(db *gorm.DB, createdBy uuid.UUID) (*models.Room, error) { room := &models.Room{ Name: "Test Room", Description: "A test room", Type: "public", IsPrivate: false, CreatedBy: createdBy, } if err := db.Create(room).Error; err != nil { return nil, err } return room, nil } // CreateTestMessage crée un message de test func CreateTestMessage(db *gorm.DB, roomID uuid.UUID, userID uuid.UUID, content string) (*models.Message, error) { message := &models.Message{ RoomID: roomID, UserID: userID, Content: content, Type: "text", IsEdited: false, IsDeleted: false, } if err := db.Create(message).Error; err != nil { return nil, err } return message, nil } // CreateTestSession crée une session de test func CreateTestSession(db *gorm.DB, userID uuid.UUID) (*models.Session, error) { session := &models.Session{ UserID: userID, Token: "test_hash_" + uuid.New().String(), IPAddress: "127.0.0.1", UserAgent: "test-agent", ExpiresAt: time.Now().Add(24 * time.Hour), } if err := db.Create(session).Error; err != nil { return nil, err } return session, nil } // CreateMultipleTestUsers crée plusieurs utilisateurs de test func CreateMultipleTestUsers(db *gorm.DB, count int) ([]*models.User, error) { users := make([]*models.User, 0, count) for i := 1; i <= count; i++ { // Make username and email unique to avoid constraint violations when tests share the same DB uniqueID := strings.ReplaceAll(uuid.New().String()[:8], "-", "") uniqueUsername := fmt.Sprintf("testuser%d_%s", i, uniqueID) uniqueEmail := fmt.Sprintf("test%d_%s@example.com", i, uniqueID) uniqueSlug := fmt.Sprintf("testuser%d-%s", i, uniqueID) user := &models.User{ Username: uniqueUsername, Slug: uniqueSlug, Email: uniqueEmail, PasswordHash: "$2a$10$examplehash", TokenVersion: 0, FirstName: "Test", LastName: "User", Role: "user", IsActive: true, IsVerified: true, IsAdmin: false, } if err := db.Create(user).Error; err != nil { return nil, err } users = append(users, user) } return users, nil } // CreateMultipleTestTracks crée plusieurs tracks de test pour un créateur func CreateMultipleTestTracks(db *gorm.DB, userID uuid.UUID, count int) ([]*models.Track, error) { tracks := make([]*models.Track, 0, count) for i := 1; i <= count; i++ { track := &models.Track{ UserID: userID, Title: fmt.Sprintf("Test Track %d", i), Artist: "Test Artist", Duration: 180, FilePath: "uploads/test_track.mp3", FileSize: 1024 * 1024, Format: "mp3", } if err := db.Create(track).Error; err != nil { return nil, err } tracks = append(tracks, track) } return tracks, nil } // UserFactory crée des utilisateurs de test avec pattern Builder type UserFactory struct { user *models.User } // NewUserFactory crée un nouveau factory avec valeurs par défaut func NewUserFactory() *UserFactory { return &UserFactory{ user: &models.User{ Username: "testuser", Email: "test@example.com", PasswordHash: "$2a$10$examplehash", TokenVersion: 0, FirstName: "Test", LastName: "User", Role: "user", IsActive: true, IsVerified: true, IsAdmin: false, }, } } // WithUsername définit le username func (f *UserFactory) WithUsername(username string) *UserFactory { f.user.Username = username return f } // WithEmail définit l'email func (f *UserFactory) WithEmail(email string) *UserFactory { f.user.Email = email return f } // WithRole définit le rôle func (f *UserFactory) WithRole(role string) *UserFactory { f.user.Role = role if role == "admin" { f.user.IsAdmin = true } return f } // WithPasswordHash définit le hash du mot de passe func (f *UserFactory) WithPasswordHash(hash string) *UserFactory { f.user.PasswordHash = hash return f } // WithFirstName définit le prénom func (f *UserFactory) WithFirstName(firstName string) *UserFactory { f.user.FirstName = firstName return f } // WithLastName définit le nom func (f *UserFactory) WithLastName(lastName string) *UserFactory { f.user.LastName = lastName return f } // WithIsActive définit si l'utilisateur est actif func (f *UserFactory) WithIsActive(isActive bool) *UserFactory { f.user.IsActive = isActive return f } // WithIsVerified définit si l'utilisateur est vérifié func (f *UserFactory) WithIsVerified(isVerified bool) *UserFactory { f.user.IsVerified = isVerified return f } // Build construit l'utilisateur sans sauvegarder func (f *UserFactory) Build() *models.User { return f.user } // MustBuild construit et sauvegarde en DB func (f *UserFactory) MustBuild(db *gorm.DB) *models.User { user := f.Build() if err := db.Create(user).Error; err != nil { panic(err) } return user } // TrackFactory crée des tracks de test avec pattern Builder type TrackFactory struct { track *models.Track } // NewTrackFactory crée un nouveau factory avec valeurs par défaut func NewTrackFactory(userID uuid.UUID) *TrackFactory { return &TrackFactory{ track: &models.Track{ UserID: userID, Title: "Test Track", Artist: "Test Artist", Duration: 180, // 3 minutes FilePath: "uploads/test_track.mp3", FileSize: 1024 * 1024, Format: "mp3", }, } } // WithTitle définit le titre func (f *TrackFactory) WithTitle(title string) *TrackFactory { f.track.Title = title return f } // WithArtist définit l'artiste func (f *TrackFactory) WithArtist(artist string) *TrackFactory { f.track.Artist = artist return f } // WithDuration définit la durée en secondes func (f *TrackFactory) WithDuration(duration int) *TrackFactory { f.track.Duration = duration return f } // Build construit le track sans sauvegarder func (f *TrackFactory) Build() *models.Track { return f.track } // MustBuild construit et sauvegarde en DB func (f *TrackFactory) MustBuild(db *gorm.DB) *models.Track { track := f.Build() if err := db.Create(track).Error; err != nil { panic(err) } return track } // PlaylistFactory crée des playlists de test avec pattern Builder type PlaylistFactory struct { playlist *models.Playlist } // NewPlaylistFactory crée un nouveau factory avec valeurs par défaut func NewPlaylistFactory(userID uuid.UUID) *PlaylistFactory { return &PlaylistFactory{ playlist: &models.Playlist{ UserID: userID, Title: "Test Playlist", Description: "A test playlist", }, } } // WithName définit le titre (Mapped to Title) func (f *PlaylistFactory) WithName(name string) *PlaylistFactory { f.playlist.Title = name return f } // WithDescription définit la description func (f *PlaylistFactory) WithDescription(description string) *PlaylistFactory { f.playlist.Description = description return f } // Build construit la playlist sans sauvegarder func (f *PlaylistFactory) Build() *models.Playlist { return f.playlist } // MustBuild construit et sauvegarde en DB func (f *PlaylistFactory) MustBuild(db *gorm.DB) *models.Playlist { playlist := f.Build() if err := db.Create(playlist).Error; err != nil { panic(err) } return playlist } // CreateUsers crée N utilisateurs avec factories func CreateUsers(db *gorm.DB, count int) []*models.User { users := make([]*models.User, count) for i := 0; i < count; i++ { factory := NewUserFactory(). WithUsername(fmt.Sprintf("user%d", i)). WithEmail(fmt.Sprintf("user%d@example.com", i)) users[i] = factory.MustBuild(db) } return users } // CreateTracks crée N tracks avec factories func CreateTracks(db *gorm.DB, userID uuid.UUID, count int) []*models.Track { tracks := make([]*models.Track, count) for i := 0; i < count; i++ { factory := NewTrackFactory(userID). WithTitle(fmt.Sprintf("Test Track %d", i+1)). WithArtist(fmt.Sprintf("Test Artist %d", i+1)) tracks[i] = factory.MustBuild(db) } return tracks }