package service import ( "bytes" "context" "errors" "testing" "github.com/gochat/gochat/internal/channel" "github.com/gochat/gochat/internal/model" channelmodel "github.com/gochat/gochat/internal/model/channel" "github.com/gochat/gochat/internal/repository" "github.com/gochat/gochat/internal/search" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/gorm" ) // ============================================================ // InboxService tests — targeting 0% methods // ============================================================ func TestInboxService_Create_WebWidget_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Widget Inbox", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) assert.NotZero(t, inbox.ID) assert.Equal(t, "web_widget", inbox.ChannelType) assert.True(t, inbox.Enabled) } func TestInboxService_Create_API_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelAPI{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "API Inbox", ChannelType: "api", Enabled: true, Channel: map[string]any{"webhook_url": "https://example.com/wh"}, }) require.NoError(t, err) assert.NotZero(t, inbox.ID) assert.Equal(t, "api", inbox.ChannelType) assert.NotEmpty(t, inbox.Secret) } func TestInboxService_Create_Email_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Email Inbox", ChannelType: "email", Enabled: true, Channel: map[string]any{"email": "test@example.com"}, }) require.NoError(t, err) assert.Equal(t, "email", inbox.ChannelType) } func TestInboxService_Create_InvalidChannelType_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Bad", ChannelType: "invalid_type", }) require.Error(t, err) } func TestInboxService_Create_NameTooShort_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "A", ChannelType: "web_widget", }) require.Error(t, err) } func TestInboxService_Create_DefaultName_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) assert.Equal(t, "Website", inbox.Name) } func TestInboxService_Create_WithGreeting_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) greetingEnabled := true greetingMsg := "Hello there!" inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Greeting Inbox", ChannelType: "web_widget", GreetingEnabled: &greetingEnabled, GreetingMessage: &greetingMsg, }) require.NoError(t, err) assert.True(t, inbox.GreetingEnabled) assert.Equal(t, "Hello there!", inbox.GreetingMessage) } func TestInboxService_Create_WithWorkingHours_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WorkingHour{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "WH Inbox", ChannelType: "web_widget", Enabled: true, WorkingHours: []repository.WorkingHourUpdateParam{ {DayOfWeek: 1, ClosedAllDay: false, OpenAllDay: true}, }, }) require.NoError(t, err) assert.NotZero(t, inbox.ID) } func TestInboxService_GetByAccountAndID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) got, err := svc.GetByAccountAndID(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Equal(t, inbox.ID, got.ID) } func TestInboxService_GetByAccountAndID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.GetByAccountAndID(context.Background(), 1, 99999) require.Error(t, err) } func TestInboxService_Update_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Original", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) enabled := false updated, err := svc.Update(context.Background(), 1, inbox.ID, UpdateInboxRequest{ Name: "Updated Name", Enabled: &enabled, }) require.NoError(t, err) assert.Equal(t, "Updated Name", updated.Name) } func TestInboxService_Update_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.Update(context.Background(), 1, 99999, UpdateInboxRequest{ Name: "X", }) require.Error(t, err) } func TestInboxService_Update_WithChannel_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelAPI{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "API", ChannelType: "api", Enabled: true, }) require.NoError(t, err) updated, err := svc.Update(context.Background(), 1, inbox.ID, UpdateInboxRequest{ Channel: map[string]any{"webhook_url": "https://new.example.com/wh"}, }) require.NoError(t, err) assert.Equal(t, "https://new.example.com/wh", updated.WebhookURL) } func TestInboxService_Delete_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Del", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) err = svc.Delete(context.Background(), inbox.ID) require.NoError(t, err) } func TestInboxService_DeleteByAccount_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Del", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) err = svc.DeleteByAccount(context.Background(), 1, inbox.ID) require.NoError(t, err) } func TestInboxService_DeleteByAccount_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) err := svc.DeleteByAccount(context.Background(), 1, 99999) require.Error(t, err) } func TestInboxService_EnsureCanCreateInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) err := svc.EnsureCanCreateInbox(context.Background(), 1) require.NoError(t, err) } func TestInboxService_EnsureCanCreateInbox_LimitExceeded_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active", InboxLimit: 1}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) // Create one inbox to fill the limit _, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "First", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) err = svc.EnsureCanCreateInbox(context.Background(), 1) require.Error(t, err) assert.True(t, IsInboxLimitExceeded(err)) } func TestInboxService_EnsureCanCreateInbox_NilRepo_Cov18(t *testing.T) { svc := NewInboxService(nil, nil, nil, nil, nil, nil, nil) err := svc.EnsureCanCreateInbox(context.Background(), 1) require.NoError(t, err) // nil repo → returns nil } func TestInboxService_BindChannel_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Bind", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) updated, err := svc.BindChannel(context.Background(), 1, inbox.ID, 42, map[string]any{"key": "value"}) require.NoError(t, err) assert.Equal(t, uint(42), updated.ChannelID) } func TestInboxService_BindChannel_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.BindChannel(context.Background(), 1, 99999, 42, nil) require.Error(t, err) } func TestInboxService_CreateWebWidgetInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateWebWidgetInbox(context.Background(), 1, CreateWebWidgetInboxRequest{ Name: "Widget", WidgetColor: "#ff0000", }) require.NoError(t, err) assert.Equal(t, "web_widget", inbox.ChannelType) assert.NotEmpty(t, inbox.ChannelConfig) } func TestInboxService_GetWebWidgetConfig_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateWebWidgetInbox(context.Background(), 1, CreateWebWidgetInboxRequest{ Name: "Widget", WidgetColor: "#ff0000", }) require.NoError(t, err) config, err := svc.GetWebWidgetConfig(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Equal(t, "#ff0000", config.WidgetColor) } func TestInboxService_GetWebWidgetConfig_NotWidget_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelAPI{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "API", ChannelType: "api", Enabled: true, }) require.NoError(t, err) _, err = svc.GetWebWidgetConfig(context.Background(), 1, inbox.ID) require.Error(t, err) } func TestInboxService_UpdateWebWidgetConfig_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateWebWidgetInbox(context.Background(), 1, CreateWebWidgetInboxRequest{ Name: "Widget", }) require.NoError(t, err) newColor := "#00ff00" updated, err := svc.UpdateWebWidgetConfig(context.Background(), 1, inbox.ID, UpdateWebWidgetConfigRequest{ WidgetColor: &newColor, }) require.NoError(t, err) assert.NotZero(t, updated.ID) } func TestInboxService_CreateTelegramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Telegram Bot", BotToken: "123:abc", }) require.NoError(t, err) assert.Equal(t, "telegram", inbox.ChannelType) } func TestInboxService_GetTelegramInboxConfig_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Telegram Bot", BotToken: "123:abc", }) require.NoError(t, err) config, _, err := svc.GetTelegramInboxConfig(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Equal(t, "123:abc", config.BotToken) } func TestInboxService_UpdateTelegramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Telegram Bot", BotToken: "123:abc", }) require.NoError(t, err) newToken := "456:def" updated, err := svc.UpdateTelegramInbox(context.Background(), 1, inbox.ID, UpdateTelegramInboxRequest{ BotToken: &newToken, }) require.NoError(t, err) _ = updated } func TestInboxService_DeleteTelegramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Telegram Bot", BotToken: "123:abc", }) require.NoError(t, err) err = svc.DeleteTelegramInbox(context.Background(), 1, inbox.ID) require.NoError(t, err) } func TestInboxService_FindTelegramInboxByBotToken_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Telegram Bot", BotToken: "token123", }) require.NoError(t, err) inbox, err := svc.FindTelegramInboxByBotToken(context.Background(), "token123") require.NoError(t, err) assert.Equal(t, "telegram", inbox.ChannelType) } func TestInboxService_FindTelegramInboxByBotToken_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.FindTelegramInboxByBotToken(context.Background(), "nonexistent") require.Error(t, err) } func TestInboxService_UpdateTelegramConfig_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Bot", BotToken: "tok", }) require.NoError(t, err) updated, err := svc.UpdateTelegramConfig(context.Background(), 1, inbox.ID, TelegramInboxConfig{ BotToken: "newtok", WelcomeMessage: "Welcome!", }) require.NoError(t, err) _ = updated } func TestInboxService_ReauthorizeTelegramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateTelegramInbox(context.Background(), 1, CreateTelegramInboxRequest{ Name: "Bot", BotToken: "tok", }) require.NoError(t, err) _, err = svc.ReauthorizeTelegramInbox(context.Background(), 1, inbox.ID) require.NoError(t, err) } func TestInboxService_CreateInstagramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) igRepo := repository.NewChannelInstagramRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateInstagramInbox(context.Background(), 1, CreateInstagramInboxRequest{ Name: "IG Inbox", InstagramAccountID: "123456", PageAccessToken: "token", ConnectedFBPageID: "page1", }, igRepo) require.NoError(t, err) assert.Equal(t, "instagram", inbox.ChannelType) assert.NotZero(t, inbox.ChannelID) } func TestInboxService_GetInstagramInboxConfig_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) igRepo := repository.NewChannelInstagramRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateInstagramInbox(context.Background(), 1, CreateInstagramInboxRequest{ Name: "IG Inbox", InstagramAccountID: "123456", PageAccessToken: "token", ConnectedFBPageID: "page1", }, igRepo) require.NoError(t, err) config, _, err := svc.GetInstagramInboxConfig(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Equal(t, "123456", config.InstagramAccountID) } func TestInboxService_UpdateInstagramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) igRepo := repository.NewChannelInstagramRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateInstagramInbox(context.Background(), 1, CreateInstagramInboxRequest{ Name: "IG Inbox", InstagramAccountID: "123456", PageAccessToken: "token", ConnectedFBPageID: "page1", }, igRepo) require.NoError(t, err) newName := "Updated IG" updated, err := svc.UpdateInstagramInbox(context.Background(), 1, inbox.ID, UpdateInstagramInboxRequest{ Name: &newName, }) require.NoError(t, err) assert.Equal(t, "Updated IG", updated.Name) } func TestInboxService_DeleteInstagramInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) igRepo := repository.NewChannelInstagramRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateInstagramInbox(context.Background(), 1, CreateInstagramInboxRequest{ Name: "IG Inbox", InstagramAccountID: "123456", PageAccessToken: "token", ConnectedFBPageID: "page1", }, igRepo) require.NoError(t, err) err = svc.DeleteInstagramInbox(context.Background(), 1, inbox.ID, igRepo) require.NoError(t, err) } func TestInboxService_CreateFacebookInbox_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelFacebook{}) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) fbRepo := repository.NewChannelFacebookRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.CreateFacebookInbox(context.Background(), 1, CreateFacebookInboxRequest{ Name: "FB Inbox", PageID: "page123", PageAccessToken: "token", }, fbRepo) require.NoError(t, err) assert.Equal(t, "facebook", inbox.ChannelType) } func TestInboxService_DeleteAvatar_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) updated, err := svc.DeleteAvatar(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Empty(t, updated.AvatarURL) } func TestInboxService_DeleteAvatar_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.DeleteAvatar(context.Background(), 1, 99999) require.Error(t, err) } func TestInboxService_SetWorkerPool_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) svc.SetWorkerPool(nil) // should not panic } func TestInboxService_ListCampaigns_InboxNotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) _, err := svc.ListCampaigns(context.Background(), 1, 99999) require.Error(t, err) } func TestInboxService_Health_NonWhatsApp_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) _, err = svc.Health(context.Background(), 1, inbox.ID) require.Error(t, err) } func TestInboxService_SyncTemplates_NonWhatsApp_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) err = svc.SyncTemplates(context.Background(), 1, inbox.ID) require.Error(t, err) } func TestInboxService_RegisterWebhook_NonWhatsApp_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) svc := NewInboxService(repo, nil, nil, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) err = svc.RegisterWebhook(context.Background(), 1, inbox.ID, RegisterWebhookRequest{ URL: "https://example.com/wh", }) require.Error(t, err) } func TestInboxService_SetAgentBot_RemoveBot_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) agentBotInboxRepo := repository.NewAgentBotInboxRepo(db) agentBotRepo := repository.NewAgentBotRepo(db) svc := NewInboxService(repo, agentBotInboxRepo, agentBotRepo, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) _, err = svc.SetAgentBot(context.Background(), 1, inbox.ID, SetAgentBotRequest{}) require.NoError(t, err) } func TestInboxService_SetAgentBot_AssignBot_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) agentBotInboxRepo := repository.NewAgentBotInboxRepo(db) agentBotRepo := repository.NewAgentBotRepo(db) svc := NewInboxService(repo, agentBotInboxRepo, agentBotRepo, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) bot, err := NewAgentBotService(agentBotRepo).Create(context.Background(), CreateAgentBotRequest{ Name: "Test Bot", }) require.NoError(t, err) binding, err := svc.SetAgentBot(context.Background(), 1, inbox.ID, SetAgentBotRequest{ AgentBotID: &bot.ID, }) require.NoError(t, err) assert.NotNil(t, binding) } func TestInboxService_GetAgentBot_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) agentBotInboxRepo := repository.NewAgentBotInboxRepo(db) agentBotRepo := repository.NewAgentBotRepo(db) svc := NewInboxService(repo, agentBotInboxRepo, agentBotRepo, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) // No bot assigned → returns nil, nil bot, err := svc.GetAgentBot(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.Nil(t, bot) } func TestInboxService_GetAgentBot_WithBot_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewInboxRepo(db) agentBotInboxRepo := repository.NewAgentBotInboxRepo(db) agentBotRepo := repository.NewAgentBotRepo(db) svc := NewInboxService(repo, agentBotInboxRepo, agentBotRepo, nil, nil, nil, nil) inbox, err := svc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Test", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) bot, err := NewAgentBotService(agentBotRepo).Create(context.Background(), CreateAgentBotRequest{ Name: "Bot", }) require.NoError(t, err) _, err = svc.SetAgentBot(context.Background(), 1, inbox.ID, SetAgentBotRequest{ AgentBotID: &bot.ID, }) require.NoError(t, err) gotBot, err := svc.GetAgentBot(context.Background(), 1, inbox.ID) require.NoError(t, err) assert.NotNil(t, gotBot) } // ============================================================ // ConversationService tests — targeting 0% methods // ============================================================ func setupConvServiceCov18(t *testing.T) (*ConversationService, *gorm.DB) { t.Helper() db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) require.NoError(t, db.Create(&model.Inbox{AccountID: 1, Name: "Inbox", ChannelType: "web_widget", Enabled: true}).Error) require.NoError(t, db.Create(&model.Contact{AccountID: 1, Name: "Contact"}).Error) convRepo := repository.NewConversationRepo(db) msgRepo := repository.NewMessageRepo(db) dispatcher := channel.NewDispatcher() svc := NewConversationService(convRepo, msgRepo, dispatcher, nil, nil, nil, nil) return svc, db } func TestConversationService_Create_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) assert.NotZero(t, conv.ID) assert.Equal(t, "open", conv.Status) } func TestConversationService_Create_WithMessage_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, MessageContent: "Hello!", MessageType: "outgoing", }) require.NoError(t, err) assert.NotZero(t, conv.ID) } func TestConversationService_Create_WithPriority_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, Priority: "urgent", }) require.NoError(t, err) assert.Equal(t, "urgent", conv.Priority) } func TestConversationService_Create_WithStatus_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, Status: "pending", }) require.NoError(t, err) assert.Equal(t, "pending", conv.Status) } func TestConversationService_GetByID_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) got, err := svc.GetByID(context.Background(), conv.ID) require.NoError(t, err) assert.Equal(t, conv.ID, got.ID) } func TestConversationService_GetByID_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestConversationService_GetByAccountAndID_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) got, err := svc.GetByAccountAndID(context.Background(), 1, conv.ID) require.NoError(t, err) assert.Equal(t, conv.ID, got.ID) } func TestConversationService_GetByAccountAndID_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.GetByAccountAndID(context.Background(), 1, 99999) require.Error(t, err) } func TestConversationService_ListByAccount_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) convs, total, err := svc.ListByAccount(context.Background(), 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, convs, 1) } func TestConversationService_ListByInbox_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) convs, total, err := svc.ListByInbox(context.Background(), 1, 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, convs, 1) } func TestConversationService_ListByStatus_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, Status: "open", }) require.NoError(t, err) convs, total, err := svc.ListByStatus(context.Background(), 1, "open", 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, convs, 1) } func TestConversationService_Update_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.Update(context.Background(), 1, conv.ID, UpdateConversationRequest{ Status: "resolved", }) require.NoError(t, err) assert.Equal(t, "resolved", updated.Status) } func TestConversationService_Update_Priority_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.Update(context.Background(), 1, conv.ID, UpdateConversationRequest{ Priority: "high", }) require.NoError(t, err) assert.Equal(t, "high", updated.Priority) } func TestConversationService_Update_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Update(context.Background(), 1, 99999, UpdateConversationRequest{ Status: "resolved", }) require.Error(t, err) } func TestConversationService_Delete_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) err = svc.Delete(context.Background(), 1, conv.ID) require.NoError(t, err) } func TestConversationService_Delete_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) err := svc.Delete(context.Background(), 1, 99999) require.Error(t, err) } func TestConversationService_Mute_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) muted, err := svc.Mute(context.Background(), 1, conv.ID) require.NoError(t, err) assert.True(t, muted.Muted) assert.Equal(t, "resolved", muted.Status) } func TestConversationService_Mute_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Mute(context.Background(), 1, 99999) require.Error(t, err) } func TestConversationService_Unmute_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) _, err = svc.Mute(context.Background(), 1, conv.ID) require.NoError(t, err) unmuted, err := svc.Unmute(context.Background(), 1, conv.ID) require.NoError(t, err) assert.False(t, unmuted.Muted) } func TestConversationService_Unmute_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Unmute(context.Background(), 1, 99999) require.Error(t, err) } func TestConversationService_ToggleStatus_OpenToResolved_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.ToggleStatus(context.Background(), 1, conv.ID, ToggleStatusRequest{ Status: "resolved", }) require.NoError(t, err) assert.Equal(t, "resolved", updated.Status) } func TestConversationService_ToggleStatus_ResolvedToOpen_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, Status: "resolved", }) require.NoError(t, err) updated, err := svc.ToggleStatus(context.Background(), 1, conv.ID, ToggleStatusRequest{ Status: "open", }) require.NoError(t, err) assert.Equal(t, "open", updated.Status) } func TestConversationService_ToggleStatus_EmptyStatus_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.ToggleStatus(context.Background(), 1, conv.ID, ToggleStatusRequest{}) require.NoError(t, err) assert.Equal(t, "resolved", updated.Status) // open → resolved } func TestConversationService_ToggleStatus_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.ToggleStatus(context.Background(), 1, 99999, ToggleStatusRequest{ Status: "resolved", }) require.Error(t, err) } func TestConversationService_ToggleStatus_Snoozed_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) until := int64(9999999999) updated, err := svc.ToggleStatus(context.Background(), 1, conv.ID, ToggleStatusRequest{ Status: "snoozed", SnoozedUntil: &until, }) require.NoError(t, err) assert.Equal(t, "snoozed", updated.Status) } func TestConversationService_UpdatePriority_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.UpdatePriority(context.Background(), 1, conv.ID, "urgent") require.NoError(t, err) assert.Equal(t, "urgent", updated.Priority) } func TestConversationService_UpdatePriority_Empty_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.UpdatePriority(context.Background(), 1, conv.ID, "") require.NoError(t, err) assert.Equal(t, "none", updated.Priority) } func TestConversationService_UpdatePriority_Invalid_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) _, err = svc.UpdatePriority(context.Background(), 1, conv.ID, "invalid") require.Error(t, err) } func TestConversationService_UpdatePriority_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.UpdatePriority(context.Background(), 1, 99999, "urgent") require.Error(t, err) } func TestConversationService_UpdateLabels_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) updated, err := svc.UpdateLabels(context.Background(), 1, conv.ID, []string{"support", "bug"}) require.NoError(t, err) assert.Contains(t, updated.Labels, "support") } func TestConversationService_UpdateLabels_NotFound_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.UpdateLabels(context.Background(), 1, 99999, []string{"label"}) require.Error(t, err) } func TestConversationService_UnassignAgent_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) // Without dispatcher, accountUserRepo, inboxMemberSvc — unassign (id=0) should work updated, err := svc.UnassignAgent(context.Background(), 1, conv.ID) require.NoError(t, err) _ = updated } func TestConversationService_AssignAgentBot_RemoveBot_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) _, _, err = svc.AssignAgentBot(context.Background(), 1, conv.ID, 0) require.NoError(t, err) } func TestConversationService_ListMessages_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) msgs, total, err := svc.ListMessages(context.Background(), conv.ID, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), total) assert.Empty(t, msgs) } func TestConversationService_ListRecentByContact_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) convs, err := svc.ListRecentByContact(context.Background(), 1, 1, nil, 10) require.NoError(t, err) assert.Len(t, convs, 1) } func TestConversationService_ListUnassigned_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) convs, total, err := svc.ListUnassigned(context.Background(), 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, convs, 1) } func TestConversationService_DB_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) assert.NotNil(t, svc.DB()) } func TestConversationService_DB_Nil_Cov18(t *testing.T) { var svc *ConversationService assert.Nil(t, svc.DB()) } func TestConversationService_SetSearchIndexer_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) svc.SetSearchIndexer(nil) // should not panic } func TestConversationService_SetAppliedSlaService_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) svc.SetAppliedSlaService(nil) // should not panic } func TestConversationService_SetTranscriptDeliverer_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) svc.SetTranscriptDeliverer(nil) // should not panic } func TestConversationService_GetByAccountAndDisplayIDOrID_Cov18(t *testing.T) { svc, _ := setupConvServiceCov18(t) conv, err := svc.Create(context.Background(), 1, CreateConversationRequest{ InboxID: 1, ContactID: 1, }) require.NoError(t, err) got, err := svc.GetByAccountAndDisplayIDOrID(context.Background(), 1, conv.ID) require.NoError(t, err) assert.Equal(t, conv.ID, got.ID) } // ============================================================ // WidgetService tests — targeting 0% methods // ============================================================ func setupWidgetServiceCov18(t *testing.T) (*WidgetService, *gorm.DB) { t.Helper() db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) inboxRepo := repository.NewInboxRepo(db) contactRepo := repository.NewContactRepo(db) contactInboxRepo := repository.NewContactInboxRepo(db) convRepo := repository.NewConversationRepo(db) msgRepo := repository.NewMessageRepo(db) // Create a web_widget inbox with website_token in channel_config inboxSvc := NewInboxService(inboxRepo, nil, nil, nil, nil, nil, nil) inbox, err := inboxSvc.Create(context.Background(), 1, CreateInboxRequest{ Name: "Widget", ChannelType: "web_widget", Enabled: true, }) require.NoError(t, err) _ = inbox svc := NewWidgetService(inboxRepo, contactRepo, contactInboxRepo, convRepo, msgRepo, nil, nil, nil, nil, nil, nil, nil, nil) return svc, db } func TestWidgetService_SetWorkerPool_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) svc.SetWorkerPool(nil) // should not panic } func TestWidgetService_SetTranscriptDeliverer_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) svc.SetTranscriptDeliverer(nil) // should not panic } func TestWidgetService_SetDispatcher_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) svc.SetDispatcher(nil) // should not panic } func TestWidgetService_Init_NoToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.Init(context.Background(), WidgetInitRequest{}) require.Error(t, err) } func TestWidgetService_Init_InvalidToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: "invalid_token", }) require.Error(t, err) } func TestWidgetService_Init_ValidToken_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) // Find the inbox we created and extract website_token from channel_config var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) require.NotEmpty(t, config.WebsiteToken) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, }) require.NoError(t, err) assert.NotEmpty(t, resp.WidgetToken) assert.NotZero(t, resp.ContactID) assert.Equal(t, inbox.ID, resp.InboxID) } func TestWidgetService_Init_WithContactInfo_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, ContactName: "John", ContactEmail: "john@example.com", }) require.NoError(t, err) assert.Equal(t, "John", resp.Contact.Name) } func TestWidgetService_SendMessage_NoToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.SendMessage(context.Background(), WidgetSendMessageRequest{ Content: "Hello", }) require.Error(t, err) } func TestWidgetService_SendMessage_EmptyContent_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: "token", }) require.Error(t, err) } func TestWidgetService_SendMessage_ContentTooLong_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) longContent := make([]rune, widgetMessageContentLimit+1) for i := range longContent { longContent[i] = 'x' } _, err := svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: "token", Content: string(longContent), }) require.Error(t, err) assert.True(t, errors.Is(err, ErrWidgetMessageContentTooLong)) } func TestWidgetService_SendMessage_InvalidToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: "invalid", Content: "Hello", }) require.Error(t, err) } func TestWidgetService_SendMessage_Valid_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, }) require.NoError(t, err) msgResp, err := svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: resp.WidgetToken, Content: "Hello World", }) require.NoError(t, err) assert.NotZero(t, msgResp.ConversationID) assert.Equal(t, "Hello World", msgResp.Message.Content) } func TestWidgetService_GetConversations_InvalidToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.GetConversations(context.Background(), "invalid") require.Error(t, err) } func TestWidgetService_GetConversations_Valid_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, }) require.NoError(t, err) // Send a message to create a conversation _, err = svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: resp.WidgetToken, Content: "Test", }) require.NoError(t, err) convs, err := svc.GetConversations(context.Background(), resp.WidgetToken) require.NoError(t, err) assert.NotEmpty(t, convs) } func TestWidgetService_GetLatestConversation_InvalidToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.GetLatestConversation(context.Background(), "invalid") require.Error(t, err) } func TestWidgetService_GetLatestConversation_NoConversation_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, }) require.NoError(t, err) _, err = svc.GetLatestConversation(context.Background(), resp.WidgetToken) require.Error(t, err) assert.True(t, errors.Is(err, ErrWidgetConversationNotFound)) } func TestWidgetService_GetLatestConversation_Valid_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) resp, err := svc.Init(context.Background(), WidgetInitRequest{ WebsiteToken: config.WebsiteToken, }) require.NoError(t, err) _, err = svc.SendMessage(context.Background(), WidgetSendMessageRequest{ WidgetToken: resp.WidgetToken, Content: "Test", }) require.NoError(t, err) conv, err := svc.GetLatestConversation(context.Background(), resp.WidgetToken) require.NoError(t, err) assert.NotZero(t, conv.ID) } func TestWidgetService_GetConversation_InvalidToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.GetConversation(context.Background(), "invalid", 1) require.Error(t, err) } func TestWidgetService_GetInboxMembers_NoMembers_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) members, err := svc.GetInboxMembersByWebsiteToken(context.Background(), config.WebsiteToken) require.NoError(t, err) assert.Empty(t, members) } func TestWidgetService_GetCampaigns_NoCampaigns_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) campaigns, err := svc.GetCampaignsByWebsiteToken(context.Background(), config.WebsiteToken) require.NoError(t, err) assert.Empty(t, campaigns) } func TestWidgetService_TrackEvent_NoToken_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) err := svc.TrackEvent(context.Background(), "", "token", "event", nil) require.Error(t, err) } func TestWidgetService_TrackEvent_NoName_Cov18(t *testing.T) { svc, db := setupWidgetServiceCov18(t) var inbox model.Inbox require.NoError(t, db.First(&inbox).Error) config, err := ParseWebWidgetConfig(inbox.ChannelConfig) require.NoError(t, err) err = svc.TrackEvent(context.Background(), config.WebsiteToken, "token", "", nil) require.Error(t, err) } func TestWidgetService_AddLabel_EmptyLabel_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) err := svc.AddLabelToLatestConversation(context.Background(), "token", "") require.NoError(t, err) // empty label → no-op } func TestWidgetService_RemoveLabel_EmptyLabel_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) err := svc.RemoveLabelFromLatestConversation(context.Background(), "token", "") require.NoError(t, err) // empty label → no-op } func TestWidgetService_PublicGetInbox_InvalidIdentifier_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, _, err := svc.PublicGetInbox(context.Background(), "nonexistent") require.Error(t, err) } func TestWidgetService_PublicCreateContact_InvalidIdentifier_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.PublicCreateContact(context.Background(), "nonexistent", PublicContactRequest{}) require.Error(t, err) } func TestWidgetService_PublicGetContact_InvalidIdentifier_Cov18(t *testing.T) { svc, _ := setupWidgetServiceCov18(t) _, err := svc.PublicGetContact(context.Background(), "nonexistent", "source") require.Error(t, err) } // ============================================================ // ContactService tests — targeting 0% methods // ============================================================ func setupContactServiceCov18(t *testing.T) (*ContactService, *gorm.DB) { t.Helper() db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) repo := repository.NewContactRepo(db) contactInboxRepo := repository.NewContactInboxRepo(db) noteRepo := repository.NewNoteRepo(db) contactInboxSvc := NewContactInboxService(contactInboxRepo) svc := NewContactService(repo, contactInboxSvc, noteRepo) return svc, db } func TestContactService_Create_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "John Doe", Email: "john@example.com", }) require.NoError(t, err) assert.NotZero(t, contact.ID) assert.Equal(t, "John Doe", contact.Name) } func TestContactService_Create_WithInbox_Cov18(t *testing.T) { svc, db := setupContactServiceCov18(t) require.NoError(t, db.Create(&model.Inbox{AccountID: 1, Name: "Inbox", ChannelType: "web_widget", Enabled: true}).Error) inboxID := uint(1) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "John", Email: "john@test.com", InboxID: &inboxID, }) require.NoError(t, err) assert.NotZero(t, contact.ID) } func TestContactService_Create_ValidationError_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "", // required }) require.Error(t, err) } func TestContactService_GetByID_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "John", }) require.NoError(t, err) got, err := svc.GetByID(context.Background(), contact.ID) require.NoError(t, err) assert.Equal(t, contact.ID, got.ID) } func TestContactService_GetByID_NotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestContactService_GetByAccountAndID_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "John", }) require.NoError(t, err) got, err := svc.GetByAccountAndID(context.Background(), 1, contact.ID) require.NoError(t, err) assert.Equal(t, contact.ID, got.ID) } func TestContactService_GetByAccountAndID_NotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.GetByAccountAndID(context.Background(), 1, 99999) require.Error(t, err) } func TestContactService_ListByAccount_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1", Email: "c1@test.com"}) require.NoError(t, err) _, err = svc.Create(context.Background(), 1, CreateContactRequest{Name: "C2", Email: "c2@test.com"}) require.NoError(t, err) contacts, total, err := svc.ListByAccount(context.Background(), 1, 0, 10, "") require.NoError(t, err) assert.Equal(t, int64(2), total) assert.Len(t, contacts, 2) } func TestContactService_Update_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "Original", }) require.NoError(t, err) updated, err := svc.Update(context.Background(), 1, contact.ID, UpdateContactRequest{ Name: "Updated", Email: "updated@example.com", }) require.NoError(t, err) assert.Equal(t, "Updated", updated.Name) assert.Equal(t, "updated@example.com", updated.Email) } func TestContactService_Update_NotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.Update(context.Background(), 1, 99999, UpdateContactRequest{ Name: "X", }) require.Error(t, err) } func TestContactService_Delete_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "Delete Me", }) require.NoError(t, err) err = svc.Delete(context.Background(), 1, contact.ID) require.NoError(t, err) } func TestContactService_Delete_NotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) err := svc.Delete(context.Background(), 1, 99999) require.Error(t, err) } func TestContactService_Ready_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) assert.True(t, svc.Ready()) } func TestContactService_Ready_Nil_Cov18(t *testing.T) { var svc *ContactService assert.False(t, svc.Ready()) } func TestContactService_DB_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) assert.NotNil(t, svc.DB()) } func TestContactService_DB_Nil_Cov18(t *testing.T) { var svc *ContactService assert.Nil(t, svc.DB()) } func TestContactService_Search_EmptyQuery_Cov18(t *testing.T) { t.Skip("SQLite search issue") svc, _ := setupContactServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1"}) require.NoError(t, err) contacts, total, err := svc.Search(context.Background(), 1, "", 0, 10, "", search.SearchModeILike) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, contacts, 1) } func TestContactService_CreateNote_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1"}) require.NoError(t, err) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 1, CreateNoteRequest{ Content: "Test note", }) require.NoError(t, err) assert.NotZero(t, note.ID) assert.Equal(t, "Test note", note.Content) } func TestContactService_CreateNote_ContactNotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.CreateNote(context.Background(), 1, 99999, 1, CreateNoteRequest{ Content: "Test", }) require.Error(t, err) } func TestContactService_ListNotes_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1"}) require.NoError(t, err) _, err = svc.CreateNote(context.Background(), 1, contact.ID, 1, CreateNoteRequest{ Content: "Note 1", }) require.NoError(t, err) notes, err := svc.ListNotes(context.Background(), 1, contact.ID) require.NoError(t, err) assert.Len(t, notes, 1) } func TestContactService_ListNotes_ContactNotFound_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.ListNotes(context.Background(), 1, 99999) require.Error(t, err) } func TestContactService_UpdateNote_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1"}) require.NoError(t, err) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 1, CreateNoteRequest{ Content: "Original", }) require.NoError(t, err) updated, err := svc.UpdateNote(context.Background(), 1, contact.ID, note.ID, CreateNoteRequest{ Content: "Updated", }) require.NoError(t, err) assert.Equal(t, "Updated", updated.Content) } func TestContactService_DeleteNote_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) contact, err := svc.Create(context.Background(), 1, CreateContactRequest{Name: "C1"}) require.NoError(t, err) note, err := svc.CreateNote(context.Background(), 1, contact.ID, 1, CreateNoteRequest{ Content: "Delete me", }) require.NoError(t, err) err = svc.DeleteNote(context.Background(), 1, contact.ID, note.ID) require.NoError(t, err) } func TestContactService_ExportCSV_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) _, err := svc.Create(context.Background(), 1, CreateContactRequest{ Name: "Export", Email: "export@test.com", }) require.NoError(t, err) var buf bytes.Buffer err = svc.ExportCSV(context.Background(), 1, &buf) require.NoError(t, err) assert.NotEmpty(t, buf.Bytes()) } func TestContactService_SetSearchIndexer_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) svc.SetSearchIndexer(nil) // should not panic } func TestContactService_SetSearchReader_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) svc.SetSearchReader(nil) // should not panic } func TestContactService_SetContactExportMailer_Cov18(t *testing.T) { svc, _ := setupContactServiceCov18(t) svc.SetContactExportMailer(nil) // should not panic } // ============================================================ // AccountService tests — targeting 0% methods // ============================================================ func TestAccountService_GetByID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) account, err := svc.GetByID(context.Background(), 1) require.NoError(t, err) assert.Equal(t, "Test", account.Name) } func TestAccountService_GetByID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewAccountService(repository.NewAccountRepo(db)) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestAccountService_DB_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewAccountService(repository.NewAccountRepo(db)) assert.NotNil(t, svc.DB()) } func TestAccountService_DB_Nil_Cov18(t *testing.T) { var svc *AccountService assert.Nil(t, svc.DB()) } func TestAccountService_Create_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.User{Name: "User"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) account, err := svc.Create(context.Background(), 1, CreateAccountRequest{ Name: "New Account", }) require.NoError(t, err) assert.NotZero(t, account.ID) assert.Equal(t, "New Account", account.Name) } func TestAccountService_Create_NoName_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewAccountService(repository.NewAccountRepo(db)) _, err := svc.Create(context.Background(), 1, CreateAccountRequest{}) require.Error(t, err) } func TestAccountService_Update_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) updated, err := svc.Update(context.Background(), 1, UpdateAccountRequest{ Name: "Updated Account", }) require.NoError(t, err) assert.Equal(t, "Updated Account", updated.Name) } func TestAccountService_Update_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewAccountService(repository.NewAccountRepo(db)) _, err := svc.Update(context.Background(), 99999, UpdateAccountRequest{ Name: "X", }) require.Error(t, err) } func TestAccountService_Delete_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) err := svc.Delete(context.Background(), 1) require.NoError(t, err) } func TestAccountService_ListByUser_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.User{Name: "User"}).Error) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) require.NoError(t, db.Create(&model.AccountUser{AccountID: 1, UserID: 1, Role: "administrator"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) accounts, total, err := svc.ListByUser(context.Background(), 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, accounts, 1) } func TestAccountService_HelpCenterGenerationStatus_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) require.NoError(t, db.Create(&model.Account{Name: "Test", Status: "active"}).Error) svc := NewAccountService(repository.NewAccountRepo(db)) status, err := svc.HelpCenterGenerationStatus(context.Background(), 1) require.NoError(t, err) assert.NotNil(t, status) } func TestAccountService_SetWorkerPool_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewAccountService(repository.NewAccountRepo(db)) svc.SetWorkerPool(nil) // should not panic } // ============================================================ // WhatsAppCallService tests — targeting 0% methods // ============================================================ func TestWhatsAppCallService_CreateFromRequest_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) call, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) assert.NotZero(t, call.ID) assert.Equal(t, "call_123", call.CallID) } func TestWhatsAppCallService_CreateFromRequest_InvalidStatus_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", CallStatus: "invalid", }) require.Error(t, err) } func TestWhatsAppCallService_GetByCallID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) call, err := svc.GetByCallID(context.Background(), "call_123") require.NoError(t, err) assert.Equal(t, "call_123", call.CallID) } func TestWhatsAppCallService_GetByCallID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.GetByCallID(context.Background(), "nonexistent") require.Error(t, err) } func TestWhatsAppCallService_ListByConversation_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) calls, err := svc.ListByConversation(context.Background(), 1) require.NoError(t, err) assert.Len(t, calls, 1) } func TestWhatsAppCallService_UpdateByCallID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) call, err := svc.UpdateByCallID(context.Background(), "call_123", "active", 30) require.NoError(t, err) assert.Equal(t, "active", call.CallStatus) assert.Equal(t, 30, call.Duration) } func TestWhatsAppCallService_UpdateByCallID_InvalidStatus_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) _, err = svc.UpdateByCallID(context.Background(), "call_123", "invalid", 0) require.Error(t, err) } func TestWhatsAppCallService_DeleteByCallID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.CreateFromRequest(context.Background(), &WhatsAppCallCreateRequest{ CallID: "call_123", InboxID: 1, ConversationID: 1, CallStatus: "ringing", }) require.NoError(t, err) err = svc.DeleteByCallID(context.Background(), "call_123") require.NoError(t, err) } func TestWhatsAppCallService_DeleteByCallID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) err := svc.DeleteByCallID(context.Background(), "nonexistent") require.Error(t, err) } func TestWhatsAppCallService_Initiate_NoSDP_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.Initiate(context.Background(), 1, WhatsAppCallInitiateRequest{ ConversationID: 1, SDPOffer: "", }) require.Error(t, err) } func TestWhatsAppCallService_Accept_NoSDP_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &model.WhatsAppCall{}) repo := repository.NewWhatsAppCallRepo(db) svc := NewWhatsAppCallService(repo) _, err := svc.Accept(context.Background(), 1, 1, 1, "") require.Error(t, err) } // ============================================================ // ArticleService tests — targeting 0% methods // ============================================================ func TestArticleService_Create_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) article, err := svc.Create(context.Background(), 1, 1, &CreateArticleRequest{ Title: "Test Article", Content: "Content here", }) require.NoError(t, err) assert.NotZero(t, article.ID) assert.Equal(t, "Test Article", article.Title) } func TestArticleService_GetByID_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) article, err := svc.Create(context.Background(), 1, 1, &CreateArticleRequest{ Title: "Test", }) require.NoError(t, err) got, err := svc.GetByID(context.Background(), article.ID) require.NoError(t, err) assert.Equal(t, article.ID, got.ID) } func TestArticleService_GetByID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestArticleService_Update_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) article, err := svc.Create(context.Background(), 1, 1, &CreateArticleRequest{ Title: "Original", }) require.NoError(t, err) newTitle := "Updated" updated, err := svc.Update(context.Background(), article.ID, &UpdateArticleRequest{ Title: &newTitle, }) require.NoError(t, err) assert.Equal(t, "Updated", updated.Title) } func TestArticleService_Update_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) _, err := svc.Update(context.Background(), 99999, &UpdateArticleRequest{}) require.Error(t, err) } func TestArticleService_Delete_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) article, err := svc.Create(context.Background(), 1, 1, &CreateArticleRequest{ Title: "Delete Me", }) require.NoError(t, err) err = svc.Delete(context.Background(), article.ID) require.NoError(t, err) } func TestArticleService_SetSearchIndexer_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) svc.SetSearchIndexer(nil) // should not panic } func TestArticleService_SetWorkerPool_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) svc.SetWorkerPool(nil) // should not panic } func TestArticleService_SetArticleTranslationBackend_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) svc.SetArticleTranslationBackend(nil) // should not panic } func TestArticleService_EmbeddingReindexStatus_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) status := svc.EmbeddingReindexStatus() assert.False(t, status.Running) } func TestArticleService_StartEmbeddingReindex_NotConfigured_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewArticleRepo(db) svc := NewArticleService(repo) _, err := svc.StartEmbeddingReindex() require.Error(t, err) } // ============================================================ // ChannelInstagramService tests — targeting 0% methods // ============================================================ func TestChannelInstagramService_GetByID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.GetByID(context.Background(), 99999) require.Error(t, err) } func TestChannelInstagramService_GetByInboxID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.GetByInboxID(context.Background(), 99999) require.Error(t, err) } func TestChannelInstagramService_GetByAccountAndInboxID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.GetByAccountAndInboxID(context.Background(), 1, 99999) require.Error(t, err) } func TestChannelInstagramService_FindByInstagramAccountID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.FindByInstagramAccountID(context.Background(), "nonexistent") require.Error(t, err) } func TestChannelInstagramService_FindByConnectedFBPageID_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.FindByConnectedFBPageID(context.Background(), "nonexistent") require.Error(t, err) } func TestChannelInstagramService_Update_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) _, err := svc.Update(context.Background(), 1, 99999, UpdateInstagramChannelRequest{}) require.Error(t, err) } func TestChannelInstagramService_ListByAccount_Empty_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) channels, err := svc.ListByAccount(context.Background(), 1) require.NoError(t, err) assert.Empty(t, channels) } func TestChannelInstagramService_MarkReauthorization_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t, &channelmodel.ChannelInstagram{}) repo := repository.NewChannelInstagramRepo(db) svc := NewChannelInstagramService(repo, nil) err := svc.MarkReauthorizationRequired(context.Background(), 99999) require.Error(t, err) } // ============================================================ // AppliedSlaService tests — targeting 0% methods // ============================================================ func TestAppliedSlaService_ValidateSlaPolicy_NotFound_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) repo := repository.NewAppliedSlaRepo(db) slaEventRepo := repository.NewSlaEventRepo(db) slaPolicyRepo := repository.NewSlaPolicyRepo(db) convRepo := repository.NewConversationRepo(db) svc := NewAppliedSlaService(repo, slaEventRepo, slaPolicyRepo, convRepo) err := svc.ValidateSlaPolicy(context.Background(), 1, 99999) require.Error(t, err) } // ============================================================ // RBACService tests // ============================================================ func TestRBACService_New_Cov18(t *testing.T) { db := newSimpleServiceTestDB(t) svc := NewRBACService(db) assert.NotNil(t, svc) }