package testutil import ( "fmt" "testing" "github.com/stretchr/testify/assert" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/model/channel" ) // === Account fixtures === // NewAccountFixture returns a test Account without persisting it. func NewAccountFixture(name string) *model.Account { return &model.Account{ Name: name, Locale: "zh_CN", Timezone: "UTC", Active: true, } } // CreateAccountFixture creates and persists a test Account. func CreateAccountFixture(t *testing.T, db *gorm.DB, name string) *model.Account { t.Helper() acc := NewAccountFixture(name) if err := db.Create(acc).Error; err != nil { panic(fmt.Sprintf("failed to create test account: %v", err)) } return acc } // === User fixtures === // NewUserFixture returns a test User without persisting it. func NewUserFixture(accountID uint, name, email string) *model.User { return &model.User{ AccountID: accountID, Name: name, Email: email, Password: "hashed_password_placeholder", Provider: "email", Role: string(model.AccountUserRoleAgent), Active: true, } } // CreateUserFixture creates and persists a test User. func CreateUserFixture(t *testing.T, db *gorm.DB, accountID uint, name, email string) *model.User { t.Helper() user := NewUserFixture(accountID, name, email) if err := db.Create(user).Error; err != nil { panic(fmt.Sprintf("failed to create test user: %v", err)) } return user } // === AccountUser fixtures === // NewAccountUserFixture returns a test AccountUser without persisting it. func NewAccountUserFixture(userID, accountID uint, role string) *model.AccountUser { return &model.AccountUser{ UserID: userID, AccountID: accountID, Role: role, Availability: "online", } } // CreateAccountUserFixture creates and persists a test AccountUser. func CreateAccountUserFixture(t *testing.T, db *gorm.DB, userID, accountID uint, role string) *model.AccountUser { t.Helper() au := NewAccountUserFixture(userID, accountID, role) if err := db.Create(au).Error; err != nil { panic(fmt.Sprintf("failed to create test account_user: %v", err)) } return au } // === Inbox fixtures === // NewInboxFixture returns a test Inbox without persisting it. func NewInboxFixture(accountID uint, name, channelType string) *model.Inbox { return &model.Inbox{ AccountID: accountID, Name: name, ChannelType: channelType, } } // CreateInboxFixture creates and persists a test Inbox. func CreateInboxFixture(t *testing.T, db *gorm.DB, accountID uint, name, channelType string) *model.Inbox { t.Helper() inbox := NewInboxFixture(accountID, name, channelType) if err := db.Create(inbox).Error; err != nil { panic(fmt.Sprintf("failed to create test inbox: %v", err)) } return inbox } // === Contact fixtures === // NewContactFixture returns a test Contact without persisting it. func NewContactFixture(accountID uint, name string) *model.Contact { return &model.Contact{ AccountID: accountID, Name: name, } } // CreateContactFixture creates and persists a test Contact. func CreateContactFixture(t *testing.T, db *gorm.DB, accountID uint, name string) *model.Contact { t.Helper() contact := NewContactFixture(accountID, name) if err := db.Create(contact).Error; err != nil { panic(fmt.Sprintf("failed to create test contact: %v", err)) } return contact } // === Conversation fixtures === // NewConversationFixture returns a test Conversation without persisting it. func NewConversationFixture(accountID, inboxID, contactID uint, status string) *model.Conversation { return &model.Conversation{ AccountID: accountID, InboxID: inboxID, ContactID: contactID, Status: status, ChannelType: "web_widget", } } // CreateConversationFixture creates and persists a test Conversation. func CreateConversationFixture(t *testing.T, db *gorm.DB, accountID, inboxID, contactID uint, status string) *model.Conversation { t.Helper() conv := NewConversationFixture(accountID, inboxID, contactID, status) if err := db.Create(conv).Error; err != nil { panic(fmt.Sprintf("failed to create test conversation: %v", err)) } return conv } // === Message fixtures === // NewMessageFixture returns a test Message without persisting it. func NewMessageFixture(conversationID, accountID, inboxID uint, content string) *model.Message { return &model.Message{ ConversationID: conversationID, AccountID: accountID, InboxID: inboxID, Content: content, ContentType: string(model.MessageContentTypeText), MessageType: string(model.MessageTypeIncoming), SenderType: "contact", } } // CreateMessageFixture creates and persists a test Message. func CreateMessageFixture(t *testing.T, db *gorm.DB, conversationID, accountID, inboxID uint, content string) *model.Message { t.Helper() msg := NewMessageFixture(conversationID, accountID, inboxID, content) if err := db.Create(msg).Error; err != nil { panic(fmt.Sprintf("failed to create test message: %v", err)) } return msg } // === CustomRole fixtures === // NewCustomRoleFixture returns a test CustomRole without persisting it. func NewCustomRoleFixture(accountID uint, name string) *model.CustomRole { return &model.CustomRole{ AccountID: accountID, Name: name, } } // CreateCustomRoleFixture creates and persists a test CustomRole. func CreateCustomRoleFixture(t *testing.T, db *gorm.DB, accountID uint, name string) *model.CustomRole { t.Helper() role := NewCustomRoleFixture(accountID, name) if err := db.Create(role).Error; err != nil { panic(fmt.Sprintf("failed to create test custom_role: %v", err)) } return role } // === Channel fixtures === // NewChannelTelegramFixture returns a test ChannelTelegram without persisting it. func NewChannelTelegramFixture(accountID uint, botToken string) *channel.ChannelTelegram { return &channel.ChannelTelegram{ AccountID: accountID, BotToken: botToken, } } // CreateChannelTelegramFixture creates and persists a test ChannelTelegram. func CreateChannelTelegramFixture(t *testing.T, db *gorm.DB, accountID uint, botToken string) *channel.ChannelTelegram { t.Helper() ch := NewChannelTelegramFixture(accountID, botToken) if err := db.Create(ch).Error; err != nil { panic(fmt.Sprintf("failed to create test channel_telegram: %v", err)) } return ch } // NewChannelWebWidgetFixture returns a test ChannelWebWidget without persisting it. func NewChannelWebWidgetFixture(inboxID uint, websiteURL string) *channel.ChannelWebWidget { return &channel.ChannelWebWidget{ InboxID: inboxID, WebsiteURL: websiteURL, } } // CreateChannelWebWidgetFixture creates and persists a test ChannelWebWidget. func CreateChannelWebWidgetFixture(t *testing.T, db *gorm.DB, inboxID uint, websiteURL string) *channel.ChannelWebWidget { t.Helper() ch := NewChannelWebWidgetFixture(inboxID, websiteURL) if err := db.Create(ch).Error; err != nil { panic(fmt.Sprintf("failed to create test channel_web_widget: %v", err)) } return ch } // === Full seed chain === // SeedFullAccountChain creates a complete chain: Account → User → AccountUser // This is the minimal RBAC context needed for most tests. func SeedFullAccountChain(t *testing.T, db *gorm.DB) (*model.Account, *model.User, *model.AccountUser) { t.Helper() acc := CreateAccountFixture(t, db, "Test Account") user := CreateUserFixture(t, db, acc.ID, "Test User", "test@example.com") au := CreateAccountUserFixture(t, db, user.ID, acc.ID, string(model.AccountUserRoleAgent)) return acc, user, au } // SeedFullConversationChain creates: Account → Inbox → Contact → Conversation func SeedFullConversationChain(t *testing.T, db *gorm.DB) (*model.Account, *model.Inbox, *model.Contact, *model.Conversation) { t.Helper() acc := CreateAccountFixture(t, db, "Test Account") inbox := CreateInboxFixture(t, db, acc.ID, "Test Inbox", "web_widget") contact := CreateContactFixture(t, db, acc.ID, "Test Contact") conv := CreateConversationFixture(t, db, acc.ID, inbox.ID, contact.ID, string(model.ConversationStatusOpen)) return acc, inbox, contact, conv } // === Helpers for fixture assertions === // AssertFixtureCount asserts that a model table has the expected number of rows. func AssertFixtureCount(t *testing.T, db *gorm.DB, model interface{}, expected int64) { t.Helper() var count int64 err := db.Model(model).Count(&count).Error assert.NoError(t, err) assert.Equal(t, expected, count) }