package model_test import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/gochat/gochat/internal/model" ) // --- TableName Method Tests --- func TestAccountTableName(t *testing.T) { assert.Equal(t, "accounts", model.Account{}.TableName()) } func TestUserTableName(t *testing.T) { assert.Equal(t, "users", model.User{}.TableName()) } func TestInboxTableName(t *testing.T) { assert.Equal(t, "inboxes", model.Inbox{}.TableName()) } func TestConversationTableName(t *testing.T) { assert.Equal(t, "conversations", model.Conversation{}.TableName()) } func TestMessageTableName(t *testing.T) { assert.Equal(t, "messages", model.Message{}.TableName()) } func TestContactTableName(t *testing.T) { assert.Equal(t, "contacts", model.Contact{}.TableName()) } func TestAccountUserTableName(t *testing.T) { assert.Equal(t, "account_users", model.AccountUser{}.TableName()) } func TestInboxMemberTableName(t *testing.T) { assert.Equal(t, "inbox_members", model.InboxMember{}.TableName()) } func TestCustomRoleTableName(t *testing.T) { assert.Equal(t, "custom_roles", model.CustomRole{}.TableName()) } func TestAttachmentTableName(t *testing.T) { assert.Equal(t, "attachments", model.Attachment{}.TableName()) } func TestNotificationTableName(t *testing.T) { assert.Equal(t, "notifications", model.Notification{}.TableName()) } func TestNotificationPreferenceTableName(t *testing.T) { assert.Equal(t, "notification_preferences", model.NotificationPreference{}.TableName()) } func TestPlatformAppTableName(t *testing.T) { assert.Equal(t, "platform_apps", model.PlatformApp{}.TableName()) } func TestContactInboxTableName(t *testing.T) { assert.Equal(t, "contact_inboxes", model.ContactInbox{}.TableName()) } // --- AccountUser Method Tests --- func TestAccountUserIsAdministrator(t *testing.T) { au := &model.AccountUser{Role: "administrator"} assert.True(t, au.IsAdministrator()) au.Role = "agent" assert.False(t, au.IsAdministrator()) au.Role = "custom_role" assert.False(t, au.IsAdministrator()) } func TestAccountUserIsAgent(t *testing.T) { au := &model.AccountUser{Role: "agent"} assert.True(t, au.IsAgent()) au.Role = "administrator" assert.False(t, au.IsAgent()) } func TestAccountUserHasCustomRole(t *testing.T) { au := &model.AccountUser{Role: "agent", CustomRoleID: 5} assert.True(t, au.HasCustomRole()) au.Role = "agent" assert.True(t, au.HasCustomRole()) au.Role = "custom_role" au.CustomRoleID = 0 assert.False(t, au.HasCustomRole(), "custom_role with CustomRoleID=0 should not count") } func TestAccountUserIsOnline(t *testing.T) { au := &model.AccountUser{Availability: "online"} assert.True(t, au.IsOnline()) au.Availability = "offline" assert.False(t, au.IsOnline()) au.Availability = "busy" assert.False(t, au.IsOnline()) } // --- CustomRole Method Tests --- func TestCustomRoleGetPermissionMap(t *testing.T) { cr := &model.CustomRole{ Permissions: `["conversation_manage","contact_manage"]`, } pm, err := cr.GetPermissionMap() assert.NoError(t, err) assert.Equal(t, model.PermissionLevelFull, pm[model.DimensionConversationManage]) assert.Equal(t, model.PermissionLevelFull, pm[model.DimensionContactManage]) assert.Empty(t, pm[model.DimensionAutomationManage]) } func TestCustomRoleGetPermissionMapEmpty(t *testing.T) { cr := &model.CustomRole{Permissions: "{}"} pm, err := cr.GetPermissionMap() assert.NoError(t, err) assert.Empty(t, pm) cr.Permissions = "" pm, err = cr.GetPermissionMap() assert.NoError(t, err) assert.Empty(t, pm) } func TestCustomRoleGetPermissionMapInvalid(t *testing.T) { cr := &model.CustomRole{Permissions: "not json"} pm, err := cr.GetPermissionMap() assert.Error(t, err) assert.Nil(t, pm) } func TestCustomRoleSetPermissionMap(t *testing.T) { cr := &model.CustomRole{} pm := map[model.PermissionDimension]model.PermissionLevel{ model.DimensionConversationManage: model.PermissionLevelFull, model.DimensionContactManage: model.PermissionLevelRead, } err := cr.SetPermissionMap(pm) assert.NoError(t, err) assert.Contains(t, cr.Permissions, "conversation_manage") assert.Contains(t, cr.Permissions, "contact_manage") // Verify round-trip pm2, err := cr.GetPermissionMap() assert.NoError(t, err) assert.Equal(t, model.PermissionLevelFull, pm2[model.DimensionConversationManage]) assert.Equal(t, model.PermissionLevelFull, pm2[model.DimensionContactManage]) } func TestCustomRoleValidate(t *testing.T) { cr := &model.CustomRole{ Name: "Valid Role", Permissions: `["conversation_manage","contact_manage"]`, } assert.NoError(t, cr.Validate()) // Empty name cr.Name = "" assert.Error(t, cr.Validate()) // Invalid permission level cr.Name = "Invalid Role" cr.Permissions = `["conversation_delete"]` assert.Error(t, cr.Validate()) // Invalid JSON cr.Permissions = "bad json" cr.Name = "BadJSON Role" assert.Error(t, cr.Validate()) } // --- CopilotMessage Method Tests --- func TestCopilotMessageGetMessageContent(t *testing.T) { msg := &model.CopilotMessage{ Message: json.RawMessage(`{"content": "Hello from copilot", "role": "assistant"}`), } assert.Equal(t, "Hello from copilot", msg.GetMessageContent()) // No content field msg.Message = json.RawMessage(`{"role": "assistant"}`) assert.Equal(t, "", msg.GetMessageContent()) // Invalid JSON msg.Message = json.RawMessage(`invalid`) assert.Equal(t, "", msg.GetMessageContent()) } // --- CopilotThread PreviousHistory Method Test --- func TestCopilotThreadPreviousHistory(t *testing.T) { thread := &model.CopilotThread{} messages := []model.CopilotMessage{ { MessageType: model.CopilotMessageTypeUser, Message: json.RawMessage(`{"content": "User question"}`), }, { MessageType: model.CopilotMessageTypeAssistant, Message: json.RawMessage(`{"content": "AI answer"}`), }, { MessageType: model.CopilotMessageTypeAssistantThinking, Message: json.RawMessage(`{"content": "Thinking trace"}`), }, } history := thread.PreviousHistory(messages) assert.Len(t, history, 2, "assistant_thinking should be filtered out") assert.Equal(t, "user", history[0].Role) assert.Equal(t, "User question", history[0].Content) assert.Equal(t, "assistant", history[1].Role) assert.Equal(t, "AI answer", history[1].Content) } // --- Enum Constant Tests --- func TestConversationStatusConstants(t *testing.T) { assert.Equal(t, model.ConversationStatus("open"), model.ConversationStatusOpen) assert.Equal(t, model.ConversationStatus("resolved"), model.ConversationStatusResolved) assert.Equal(t, model.ConversationStatus("pending"), model.ConversationStatusPending) assert.Equal(t, model.ConversationStatus("snoozed"), model.ConversationStatusSnoozed) } func TestMessageTypeConstants(t *testing.T) { assert.Equal(t, model.MessageType("incoming"), model.MessageTypeIncoming) assert.Equal(t, model.MessageType("outgoing"), model.MessageTypeOutgoing) assert.Equal(t, model.MessageType("activity"), model.MessageTypeActivity) assert.Equal(t, model.MessageType("template"), model.MessageTypeTemplate) } func TestAccountUserRoleConstants(t *testing.T) { assert.Equal(t, model.AccountUserRole("agent"), model.AccountUserRoleAgent) assert.Equal(t, model.AccountUserRole("administrator"), model.AccountUserRoleAdministrator) } func TestUserAvailabilityConstants(t *testing.T) { assert.Equal(t, model.UserAvailability("online"), model.UserAvailabilityOnline) assert.Equal(t, model.UserAvailability("offline"), model.UserAvailabilityOffline) assert.Equal(t, model.UserAvailability("busy"), model.UserAvailabilityBusy) } func TestPermissionDimensionConstants(t *testing.T) { assert.Equal(t, model.PermissionDimension("conversation_manage"), model.DimensionConversationManage) assert.Equal(t, model.PermissionDimension("conversation_delete"), model.DimensionConversationDelete) assert.Equal(t, model.PermissionDimension("contact_manage"), model.DimensionContactManage) assert.Equal(t, model.PermissionDimension("report_manage"), model.DimensionReportManage) assert.Equal(t, model.PermissionDimension("knowledge_base_manage"), model.DimensionKnowledgeBaseManage) assert.Equal(t, model.PermissionDimension("automation_manage"), model.DimensionAutomationManage) } func TestPermissionLevelConstants(t *testing.T) { assert.Equal(t, model.PermissionLevel("full"), model.PermissionLevelFull) assert.Equal(t, model.PermissionLevel("read"), model.PermissionLevelRead) assert.Equal(t, model.PermissionLevel("none"), model.PermissionLevelNone) } // --- Model Struct Field Verification Tests --- func TestAccountStructFields(t *testing.T) { acc := model.Account{ Name: "Test", Domain: "test.com", Locale: "en", Timezone: "UTC", Active: true, Status: "active", FeatureFlags: `{"feature_x":true}`, AutoResolveDuration: 7, } assert.Equal(t, "Test", acc.Name) assert.Equal(t, "test.com", acc.Domain) assert.Equal(t, "en", acc.Locale) assert.Equal(t, "UTC", acc.Timezone) assert.True(t, acc.Active) assert.Equal(t, "active", acc.Status) assert.Contains(t, acc.FeatureFlags, "feature_x") assert.Equal(t, 7, acc.AutoResolveDuration) } func TestUserStructFields(t *testing.T) { user := model.User{ AccountID: 1, Name: "Agent", Email: "agent@test.com", Password: "secret", Provider: "email", UID: "ext123", AvatarURL: "https://img.test.com/avatar.png", Role: "agent", Active: true, Available: false, TOTPSecret: "otp_secret", TOTPEnabled: false, CustomRoleID: nil, SignInCount: 5, } assert.Equal(t, uint(1), user.AccountID) assert.Equal(t, "Agent", user.Name) assert.Equal(t, "agent@test.com", user.Email) assert.Equal(t, "email", user.Provider) assert.Nil(t, user.CustomRoleID) assert.Equal(t, 5, user.SignInCount) } func TestConversationStructFields(t *testing.T) { conv := model.Conversation{ AccountID: 1, InboxID: 2, ContactID: 3, Status: "open", ChannelType: "web_widget", Channel: "web_widget", } assert.Equal(t, uint(1), conv.AccountID) assert.Equal(t, uint(2), conv.InboxID) assert.Equal(t, uint(3), conv.ContactID) assert.Equal(t, "open", conv.Status) assert.Equal(t, "web_widget", conv.ChannelType) } func TestMessageStructFields(t *testing.T) { senderID := uint(10) msg := model.Message{ ConversationID: 1, AccountID: 2, InboxID: 3, SenderID: &senderID, SenderType: "agent", Content: "Hello", ContentType: "text", MessageType: "outgoing", Private: false, SourceID: "ext_src_1", External: true, } assert.Equal(t, uint(1), msg.ConversationID) assert.Equal(t, "agent", msg.SenderType) assert.Equal(t, "Hello", msg.Content) assert.Equal(t, uint(10), *msg.SenderID) assert.True(t, msg.External) } func TestContactStructFields(t *testing.T) { contact := model.Contact{ AccountID: 1, Name: "Alice", Email: "alice@test.com", PhoneNumber: "+1234567890", AvatarURL: "https://img.test.com/alice.png", Identifier: "ext_id_123", } assert.Equal(t, uint(1), contact.AccountID) assert.Equal(t, "Alice", contact.Name) assert.Equal(t, "alice@test.com", contact.Email) assert.Equal(t, "+1234567890", contact.PhoneNumber) } func TestInboxStructFields(t *testing.T) { inbox := model.Inbox{ AccountID: 1, Name: "Support", ChannelType: "web_widget", ChannelID: 5, EnableAutoAssignment: true, AutoAssignmentLimit: 10, Enabled: true, ChannelConfig: `{"color":"#1f93ff"}`, } assert.Equal(t, uint(1), inbox.AccountID) assert.Equal(t, "Support", inbox.Name) assert.True(t, inbox.EnableAutoAssignment) assert.Equal(t, 10, inbox.AutoAssignmentLimit) } func TestBaseStructFields(t *testing.T) { base := model.Base{} assert.Equal(t, uint(0), base.ID) assert.True(t, base.CreatedAt.IsZero()) assert.True(t, base.UpdatedAt.IsZero()) } func TestCustomRoleValidationError(t *testing.T) { err := &model.CustomRoleValidationError{ Dimension: "conversation_manage", Level: "invalid", Message: "not a valid level", } assert.Contains(t, err.Error(), "conversation_manage") assert.Contains(t, err.Error(), "invalid") assert.Contains(t, err.Error(), "not a valid level") }