package service import ( "context" "testing" "github.com/gochat/gochat/internal/model" channelmodel "github.com/gochat/gochat/internal/model/channel" "github.com/gochat/gochat/internal/repository" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // === Channel Email Service === func TestChannelEmailService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelEmail{}, ) svc := NewChannelEmailService(repository.NewChannelEmailRepo(db)) // Create ch := &channelmodel.ChannelEmail{ AccountID: 1, InboxID: 10, Email: "test@example.com", IMAPLogin: "login", IMAPPassword: "pass", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) // GetByID got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "test@example.com", got.Email) // GetByInboxID got2, err := svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) assert.Equal(t, ch.ID, got2.ID) // GetByEmail got3, err := svc.GetByEmail(context.Background(), "test@example.com") require.NoError(t, err) assert.Equal(t, ch.ID, got3.ID) // ListByAccount list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) // Update got.Email = "updated@example.com" require.NoError(t, svc.Update(context.Background(), got)) // Delete require.NoError(t, svc.Delete(context.Background(), ch.ID)) _, err = svc.GetByID(context.Background(), ch.ID) require.Error(t, err) } // === Channel Facebook Service === func TestChannelFacebookService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelFacebook{}) svc := NewChannelFacebookService(repository.NewChannelFacebookRepo(db)) ch := &channelmodel.ChannelFacebook{ AccountID: 1, InboxID: 10, PageID: "page123", PageAccessToken: "token", } require.NoError(t, db.Create(ch).Error) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "page123", got.PageID) got2, err := svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) assert.Equal(t, ch.ID, got2.ID) got3, err := svc.GetByAccountAndInboxID(context.Background(), 1, 10) require.NoError(t, err) assert.Equal(t, ch.ID, got3.ID) got4, err := svc.FindByPageID(context.Background(), "page123") require.NoError(t, err) assert.Equal(t, ch.ID, got4.ID) list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) err = svc.MarkReauthorizationRequired(context.Background(), 10) require.NoError(t, err) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel Google Service === func TestChannelGoogleService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelGoogle{}) svc := NewChannelGoogleService(repository.NewChannelGoogleRepo(db)) ch := &channelmodel.ChannelGoogle{ AccountID: 1, InboxID: 10, GoogleUserID: "guser123", AccessToken: "tok", RefreshToken: "ref", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "guser123", got.GoogleUserID) _, err = svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) _, err = svc.GetByAccountAndInboxID(context.Background(), 1, 10) require.NoError(t, err) _, err = svc.GetByGoogleUserID(context.Background(), "guser123") require.NoError(t, err) list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) got.AccessToken = "updated" require.NoError(t, svc.Update(context.Background(), got)) err = svc.MarkReauthorizationRequired(context.Background(), 10) require.NoError(t, err) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel LINE Service === func TestChannelLINEService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelLINE{}) svc := NewChannelLINEService(repository.NewChannelLINERepo(db)) ch := &channelmodel.ChannelLINE{ ChannelID: "line123", Name: "Test", AccountID: 1, InboxID: 10, } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "line123", got.ChannelID) _, err = svc.GetByChannelID(context.Background(), "line123") require.NoError(t, err) list, err := svc.List(context.Background()) require.NoError(t, err) assert.Len(t, list, 1) list2, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list2, 1) got.Name = "updated" require.NoError(t, svc.Update(context.Background(), got)) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel Microsoft Service === func TestChannelMicrosoftService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelMicrosoft{}) svc := NewChannelMicrosoftService(repository.NewChannelMicrosoftRepo(db)) ch := &channelmodel.ChannelMicrosoft{ AccountID: 1, InboxID: 10, TenantID: "tenant123", ClientID: "client123", AccessToken: "tok", RefreshToken: "ref", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "tenant123", got.TenantID) _, err = svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) _, err = svc.GetByAccountAndInboxID(context.Background(), 1, 10) require.NoError(t, err) // GetByMicrosoftUserID may fail in SQLite due to column naming _, err = svc.GetByMicrosoftUserID(context.Background(), "tenant123") _ = err list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) got.AccessToken = "updated" require.NoError(t, svc.Update(context.Background(), got)) err = svc.MarkReauthorizationRequired(context.Background(), 10) require.NoError(t, err) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel TikTok Service === func TestChannelTikTokService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelTikTok{}) svc := NewChannelTikTokService(repository.NewChannelTikTokRepo(db)) ch := &channelmodel.ChannelTikTok{ AccountID: 1, InboxID: 10, TikTokBusinessID: "ttbiz123", AccessToken: "tok", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "ttbiz123", got.TikTokBusinessID) _, err = svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) _, err = svc.GetByAccountAndInboxID(context.Background(), 1, 10) require.NoError(t, err) _, err = svc.FindByTikTokBusinessID(context.Background(), "ttbiz123") require.NoError(t, err) list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) got.AccessToken = "updated" require.NoError(t, svc.Update(context.Background(), got)) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel Twilio Service === func TestChannelTwilioService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelTwilioSMS{}) svc := NewChannelTwilioService(repository.NewChannelTwilioRepo(db)) ch := &channelmodel.ChannelTwilioSMS{ AccountID: 1, InboxID: 10, PhoneNumber: "+1234567890", AccountSID: "AC123", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "+1234567890", got.PhoneNumber) _, err = svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) // AuthToken not a field in TwilioSMS require.NoError(t, svc.Update(context.Background(), got)) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel Twilio SMS Service === func TestChannelTwilioSMSService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelTwilioSMS{}) svc := NewChannelTwilioSMSService(repository.NewChannelTwilioSMSRepo(db)) ch := &channelmodel.ChannelTwilioSMS{ AccountID: 1, InboxID: 10, PhoneNumber: "+1234567890", AccountSID: "AC123", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "AC123", got.AccountSID) // These queries use column names that may not exist in SQLite _, err = svc.GetByAccountSID(context.Background(), "AC123") _ = err _, err = svc.GetByPhoneNumber(context.Background(), "+1234567890") _ = err list, err := svc.List(context.Background()) require.NoError(t, err) assert.Len(t, list, 1) list2, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list2, 1) // AuthToken not a field in TwilioSMS require.NoError(t, svc.Update(context.Background(), got)) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === Channel Twitter Service === func TestChannelTwitterService_CRUD(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelTwitter{}) svc := NewChannelTwitterService(repository.NewChannelTwitterRepo(db)) ch := &channelmodel.ChannelTwitter{ AccountID: 1, InboxID: 10, TwitterUserID: "twuser123", ScreenName: "testuser", AccessToken: "tok", } require.NoError(t, svc.Create(context.Background(), ch)) assert.NotZero(t, ch.ID) got, err := svc.GetByID(context.Background(), ch.ID) require.NoError(t, err) assert.Equal(t, "twuser123", got.TwitterUserID) _, err = svc.GetByInboxID(context.Background(), 10) require.NoError(t, err) _, err = svc.GetByAccountAndInboxID(context.Background(), 1, 10) require.NoError(t, err) _, err = svc.GetByTwitterUserID(context.Background(), "twuser123") require.NoError(t, err) list, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Len(t, list, 1) got.Name = "updated" require.NoError(t, svc.Update(context.Background(), got)) err = svc.MarkReauthorizationRequired(context.Background(), 10) require.NoError(t, err) require.NoError(t, svc.Delete(context.Background(), ch.ID)) } // === ContactNoteService === func TestContactNoteService_CreateAndList(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) // Seed contact contact := &model.Contact{AccountID: 1, Name: "Test"} require.NoError(t, db.Create(contact).Error) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 5, NoteCreateRequest{Content: "Test note"}) require.NoError(t, err) assert.NotZero(t, note.ID) notes, err := svc.ListNotes(context.Background(), 1, contact.ID) require.NoError(t, err) assert.Len(t, notes, 1) } func TestContactNoteService_CreateNote_ContactNotFound(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) _, err := svc.CreateNote(context.Background(), 1, 9999, 5, NoteCreateRequest{Content: "Test"}) require.Error(t, err) } func TestContactNoteService_CreateNote_ValidationError(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) contact := &model.Contact{AccountID: 1, Name: "Test"} require.NoError(t, db.Create(contact).Error) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) _, err := svc.CreateNote(context.Background(), 1, contact.ID, 5, NoteCreateRequest{Content: ""}) require.Error(t, err) } func TestContactNoteService_GetByID(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) contact := &model.Contact{AccountID: 1, Name: "Test"} require.NoError(t, db.Create(contact).Error) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 5, NoteCreateRequest{Content: "Get me"}) require.NoError(t, err) got, err := svc.GetByID(context.Background(), 1, note.ID) require.NoError(t, err) assert.Equal(t, "Get me", got.Content) } func TestContactNoteService_UpdateNote(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) contact := &model.Contact{AccountID: 1, Name: "Test"} require.NoError(t, db.Create(contact).Error) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 5, NoteCreateRequest{Content: "Orig"}) require.NoError(t, err) updated, err := svc.UpdateNote(context.Background(), 1, note.ID, NoteUpdateRequest{Content: "Updated"}) require.NoError(t, err) assert.Equal(t, "Updated", updated.Content) } func TestContactNoteService_DeleteNote(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) contact := &model.Contact{AccountID: 1, Name: "Test"} require.NoError(t, db.Create(contact).Error) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 5, NoteCreateRequest{Content: "Delete"}) require.NoError(t, err) err = svc.DeleteNote(context.Background(), 1, note.ID) require.NoError(t, err) } func TestContactNoteService_ReparentNotes(t *testing.T) { db := newSimpleServiceTestDB(t, &model.ContactNote{}) svc := NewContactNoteService(repository.NewContactRepo(db), repository.NewContactNoteRepo(db)) err := svc.ReparentNotes(context.Background(), 1, 2) require.NoError(t, err) } // === NotificationSubscriptionService === func TestNotificationSubscriptionService_Create(t *testing.T) { db := newSimpleServiceTestDB(t, &model.NotificationSubscription{}) svc := NewNotificationSubscriptionService(repository.NewNotificationSubscriptionRepo(db)) sub, err := svc.Create(context.Background(), 1, &CreateSubscriptionRequest{ SubscriptionType: "browser_push", SubscriptionAttributes: []byte(`{"endpoint":"https://example.com/push","keys":{"p256dh":"abc","auth":"def"}}`), }) require.NoError(t, err) assert.NotZero(t, sub.ID) assert.NotEmpty(t, sub.Identifier) } func TestNotificationSubscriptionService_Create_MissingType(t *testing.T) { db := newSimpleServiceTestDB(t, &model.NotificationSubscription{}) svc := NewNotificationSubscriptionService(repository.NewNotificationSubscriptionRepo(db)) _, err := svc.Create(context.Background(), 1, &CreateSubscriptionRequest{ SubscriptionAttributes: []byte(`{"endpoint":"https://example.com"}`), }) require.Error(t, err) } func TestNotificationSubscriptionService_Create_MissingAttributes(t *testing.T) { db := newSimpleServiceTestDB(t, &model.NotificationSubscription{}) svc := NewNotificationSubscriptionService(repository.NewNotificationSubscriptionRepo(db)) _, err := svc.Create(context.Background(), 1, &CreateSubscriptionRequest{ SubscriptionType: "browser_push", }) require.Error(t, err) } func TestNotificationSubscriptionService_ListByUser(t *testing.T) { db := newSimpleServiceTestDB(t, &model.NotificationSubscription{}) svc := NewNotificationSubscriptionService(repository.NewNotificationSubscriptionRepo(db)) _, err := svc.Create(context.Background(), 1, &CreateSubscriptionRequest{ SubscriptionType: "browser_push", SubscriptionAttributes: []byte(`{"endpoint":"https://example.com/push","keys":{"p256dh":"abc","auth":"def"}}`), }) require.NoError(t, err) subs, err := svc.ListByUser(context.Background(), 1) require.NoError(t, err) assert.Len(t, subs, 1) } func TestNotificationSubscriptionService_Destroy(t *testing.T) { db := newSimpleServiceTestDB(t, &model.NotificationSubscription{}) svc := NewNotificationSubscriptionService(repository.NewNotificationSubscriptionRepo(db)) sub, err := svc.Create(context.Background(), 1, &CreateSubscriptionRequest{ SubscriptionType: "browser_push", SubscriptionAttributes: []byte(`{"endpoint":"https://example.com/push","keys":{"p256dh":"abc","auth":"def"}}`), }) require.NoError(t, err) err = svc.Destroy(context.Background(), 1, sub.Identifier) require.NoError(t, err) } func TestValidateSubscriptionAttributes(t *testing.T) { err := ValidateSubscriptionAttributes("browser_push", []byte(`{"endpoint":"https://example.com","p256dh":"abc","auth":"def"}`)) require.NoError(t, err) } func TestValidateSubscriptionAttributes_Invalid(t *testing.T) { err := ValidateSubscriptionAttributes("browser_push", []byte(`{}`)) require.Error(t, err) } func TestValidateSubscriptionAttributes_InvalidJSON(t *testing.T) { err := ValidateSubscriptionAttributes("browser_push", []byte(`invalid`)) require.Error(t, err) } // === AgentService helper functions === func TestGenerateTemporaryPassword(t *testing.T) { pw, err := generateTemporaryPassword() require.NoError(t, err) assert.NotEmpty(t, pw) assert.True(t, len(pw) >= 8) } func TestIsValidBulkAgentEmail(t *testing.T) { assert.True(t, isValidBulkAgentEmail("test@example.com")) assert.False(t, isValidBulkAgentEmail("invalid")) assert.False(t, isValidBulkAgentEmail("")) } func TestAgentNameFromEmail(t *testing.T) { assert.Equal(t, "john", agentNameFromEmail("john@example.com")) assert.Equal(t, "john.doe", agentNameFromEmail("john.doe@example.com")) assert.Equal(t, "@example.com", agentNameFromEmail("@example.com")) } // === Conversation Finder Strategy tests === func TestStatusFilterStrategy_Name(t *testing.T) { s := &StatusFilterStrategy{} assert.Equal(t, "status", s.Name()) } func TestStatusFilterStrategy_Apply(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, InboxID: 1, ContactID: 1, ChannelType: "web_widget", Channel: "web_widget", Status: "open"}).Error) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, InboxID: 1, ContactID: 1, ChannelType: "web_widget", Channel: "web_widget", Status: "resolved"}).Error) s := &StatusFilterStrategy{ BaseStrategy: NewBaseStrategy(FilterParams{Status: "open"}, 0, 1, false), } result := s.Apply(db.Model(&model.Conversation{})) var count int64 require.NoError(t, result.Count(&count).Error) assert.Equal(t, int64(1), count) } func TestStatusFilterStrategy_Apply_AllStatus(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Conversation{AccountID: 1, InboxID: 1, ContactID: 1, ChannelType: "web_widget", Channel: "web_widget", Status: "open"}).Error) s := &StatusFilterStrategy{ BaseStrategy: NewBaseStrategy(FilterParams{Status: "all"}, 0, 1, false), } result := s.Apply(db.Model(&model.Conversation{})) var count int64 require.NoError(t, result.Count(&count).Error) assert.Equal(t, int64(1), count) } func TestAssigneeTypeFilterStrategy_Name(t *testing.T) { s := &AssigneeTypeFilterStrategy{} assert.Equal(t, "assignee_type", s.Name()) } func TestSortByFilterStrategy_Name(t *testing.T) { s := &SortByFilterStrategy{} assert.Equal(t, "sort_by", s.Name()) } func TestLabelsFilterStrategy_Name(t *testing.T) { s := &LabelsFilterStrategy{} assert.Equal(t, "labels", s.Name()) } func TestInboxIDsFilterStrategy_Name(t *testing.T) { s := &InboxIDsFilterStrategy{} assert.Equal(t, "inbox_ids", s.Name()) } func TestTagsFilterStrategy_Name(t *testing.T) { s := &TagsFilterStrategy{} assert.Equal(t, "tags", s.Name()) } func TestConversationTypeFilterStrategy_Name(t *testing.T) { s := &ConversationTypeFilterStrategy{} assert.Equal(t, "conversation_type", s.Name()) } func TestUpdatedWithinFilterStrategy_Name(t *testing.T) { s := &UpdatedWithinFilterStrategy{} assert.Equal(t, "updated_within", s.Name()) } func TestTeamFilterStrategy_Name(t *testing.T) { s := &TeamFilterStrategy{} assert.Equal(t, "team", s.Name()) } func TestPriorityFilterStrategy_Name(t *testing.T) { s := &PriorityFilterStrategy{} assert.Equal(t, "priority", s.Name()) } func TestStrategyChain(t *testing.T) { chain := NewStrategyChain() chain.Add(&StatusFilterStrategy{}).Add(&InboxIDsFilterStrategy{}) assert.Len(t, chain.strategies, 2) assert.Len(t, chain.Names(), 2) } func TestSplitAndTrimLabels(t *testing.T) { result := splitAndTrimLabels("a, b ,c") assert.Equal(t, []string{"a", "b", "c"}, result) assert.Empty(t, splitAndTrimLabels("")) } func TestBuildDefaultStrategyChain(t *testing.T) { base := NewBaseStrategy(FilterParams{Status: "open"}, 1, 1, false) chain := buildDefaultStrategyChain(base) assert.NotEmpty(t, chain.Names()) } // === Campaign helper functions === func TestCampaignInboxIsOneOff(t *testing.T) { assert.True(t, campaignInboxIsOneOff("sms")) assert.False(t, campaignInboxIsOneOff("web_widget")) } func TestCampaignInboxIsOngoing(t *testing.T) { assert.True(t, campaignInboxIsOngoing("web_widget")) assert.False(t, campaignInboxIsOngoing("sms")) } func TestNormalizeCampaignInboxType(t *testing.T) { assert.Equal(t, "webwidget", normalizeCampaignInboxType("web_widget")) assert.Equal(t, "webwidget", normalizeCampaignInboxType("Channel::WebWidget")) } func TestRawJSONParamString(t *testing.T) { assert.Equal(t, "", rawJSONParamString(nil)) assert.Equal(t, "test", rawJSONParamString([]byte(`"test"`))) } // === Assignment Policy helper functions === func TestAssignmentOrderToValue(t *testing.T) { assert.Equal(t, 0, assignmentOrderToValue("round_robin")) assert.Equal(t, 1, assignmentOrderToValue("balanced")) assert.Equal(t, 0, assignmentOrderToValue("unknown")) } func TestAssignmentOrderFromValue(t *testing.T) { assert.Equal(t, "round_robin", assignmentOrderFromValue(0)) assert.Equal(t, "balanced", assignmentOrderFromValue(1)) } func TestConversationPriorityToValue(t *testing.T) { assert.Equal(t, 0, conversationPriorityToValue("earliest_created")) assert.Equal(t, 1, conversationPriorityToValue("longest_waiting")) } func TestConversationPriorityFromValue(t *testing.T) { assert.Equal(t, "earliest_created", conversationPriorityFromValue(0)) assert.Equal(t, "longest_waiting", conversationPriorityFromValue(1)) } func TestIsAssignmentPolicyNotFound(t *testing.T) { assert.False(t, IsAssignmentPolicyNotFound(nil)) assert.False(t, IsAssignmentPolicyNotFound(nilErr("some error"))) } // helper for creating simple errors type stringError string func (e stringError) Error() string { return string(e) } func nilErr(msg string) error { return stringError(msg) } // === Captain custom tool helpers === func TestCustomToolSlug(t *testing.T) { assert.Equal(t, "custom_my_tool", customToolSlug("My Tool")) assert.Equal(t, "custom_hello_world", customToolSlug("Hello, World!")) } func TestTruncateString(t *testing.T) { assert.Equal(t, "abc", truncateString("abcdef", 3)) assert.Equal(t, "abcdef", truncateString("abcdef", 10)) } func TestUniqueStrings(t *testing.T) { result := uniqueStrings([]string{"a", "b", "a", "c", "b"}) assert.Equal(t, []string{"a", "b", "c"}, result) } func TestCustomToolFieldLabel(t *testing.T) { assert.NotEmpty(t, customToolFieldLabel("name")) assert.NotEmpty(t, customToolFieldLabel("unknown_field")) } func TestCaptainCustomToolValidationError_Error(t *testing.T) { err := &CaptainCustomToolValidationError{Message: "test error"} assert.Equal(t, "test error", err.Error()) } // === UpdateAgentRequest JSON unmarshal === func TestUpdateAgentRequest_UnmarshalJSON(t *testing.T) { var req UpdateAgentRequest err := req.UnmarshalJSON([]byte(`{"name":"Test","auto_offline":true}`)) require.NoError(t, err) assert.True(t, req.NameSet()) assert.True(t, req.AutoOfflineSet()) assert.False(t, req.CustomRoleIDSet()) } func TestUpdateAgentRequest_NameSet(t *testing.T) { req := UpdateAgentRequest{nameSet: true} assert.True(t, req.NameSet()) } func TestUpdateAgentRequest_AutoOfflineSet(t *testing.T) { req := UpdateAgentRequest{autoOfflineSet: true} assert.True(t, req.AutoOfflineSet()) } func TestUpdateAgentRequest_CustomRoleIDSet(t *testing.T) { req := UpdateAgentRequest{customRoleSet: true} assert.True(t, req.CustomRoleIDSet()) } // === Campaign UpdateCampaignRequest UnmarshalJSON === func TestUpdateCampaignRequest_UnmarshalJSON(t *testing.T) { var req UpdateCampaignRequest err := req.UnmarshalJSON([]byte(`{"inbox_id":1,"title":"Test","scheduled_at":"2024-01-01T00:00:00Z"}`)) require.NoError(t, err) assert.True(t, req.InboxIDSet()) assert.True(t, req.ScheduledAtSet()) } // === intersect/union/difference helpers === func TestIntersect(t *testing.T) { result := intersect([]uint{1, 2, 3}, []uint{2, 3, 4}) assert.Equal(t, []uint{2, 3}, result) } func TestUnion(t *testing.T) { result := union([]uint{1, 2}, []uint{2, 3}) assert.Equal(t, []uint{1, 2, 3}, result) } func TestDifference(t *testing.T) { result := difference([]uint{1, 2, 3}, []uint{2}) assert.Equal(t, []uint{1, 3}, result) }