package email import ( "context" "testing" channelpkg "github.com/gochat/gochat/internal/channel" "github.com/gochat/gochat/internal/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // =========================== // Service tests // =========================== func TestNewService_Cov5(t *testing.T) { s := NewService() require.NotNil(t, s) assert.NotNil(t, s.imapListener) assert.NotNil(t, s.smtpSender) } func TestService_ValidateIMAPConnection_Cov5(t *testing.T) { s := NewService() // Empty config → error err := s.ValidateIMAPConnection(channelpkg.ChannelConfig{}) require.Error(t, err) } func TestService_ValidateSMTPConnection_Cov5(t *testing.T) { s := NewService() // Empty config → error err := s.ValidateSMTPConnection(channelpkg.ChannelConfig{}) require.Error(t, err) } func TestService_FetchIMAPMessages_Cov5(t *testing.T) { s := NewService() // Empty config → error _, err := s.FetchIMAPMessages(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channelpkg.ChannelConfig{}) require.Error(t, err) } func TestService_SendViaSMTP_Cov5(t *testing.T) { s := NewService() // Empty config → error _, err := s.SendViaSMTP(channelpkg.ChannelConfig{}, "from@test.com", "to@test.com", "subject", "body") require.Error(t, err) } // =========================== // SMTPSender tests // =========================== func TestNewSMTPSender_Cov5(t *testing.T) { s := NewSMTPSender() require.NotNil(t, s) } func TestSMTPSender_Send_NoConfig_Cov5(t *testing.T) { s := NewSMTPSender() _, err := s.Send(channelpkg.ChannelConfig{}, "", "to@test.com", "subj", "body") require.Error(t, err) } func TestSMTPSender_Send_PartialConfig_Cov5(t *testing.T) { s := NewSMTPSender() _, err := s.Send(channelpkg.ChannelConfig{ "smtp_address": "smtp.test.com", }, "", "to@test.com", "subj", "body") require.Error(t, err) } func TestSMTPSender_ValidateConnection_NoConfig_Cov5(t *testing.T) { s := NewSMTPSender() err := s.ValidateConnection(channelpkg.ChannelConfig{}) require.Error(t, err) } func TestSMTPSender_ValidateConnection_PartialConfig_Cov5(t *testing.T) { s := NewSMTPSender() err := s.ValidateConnection(channelpkg.ChannelConfig{ "smtp_address": "smtp.test.com", "smtp_login": "user", }) require.Error(t, err) } func TestSMTPSender_ValidateConnection_ConnectionFail_Cov5(t *testing.T) { s := NewSMTPSender() err := s.ValidateConnection(channelpkg.ChannelConfig{ "smtp_address": "127.0.0.1", "smtp_port": 1, "smtp_login": "user", "smtp_password": "pass", "smtp_ssl_mode": "none", }) require.Error(t, err) } func TestSMTPSender_Send_ConnectionFail_Cov5(t *testing.T) { s := NewSMTPSender() _, err := s.Send(channelpkg.ChannelConfig{ "smtp_address": "127.0.0.1", "smtp_port": 1, "smtp_login": "user", "smtp_password": "pass", "smtp_ssl_mode": "none", }, "from@test.com", "to@test.com", "subj", "body") require.Error(t, err) } // =========================== // IMAPListener tests // =========================== func TestNewIMAPListener_Cov5(t *testing.T) { l := NewIMAPListener() require.NotNil(t, l) assert.NotNil(t, l.lastUID) } func TestIMAPListener_Fetch_NoConfig_Cov5(t *testing.T) { l := NewIMAPListener() _, err := l.Fetch(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channelpkg.ChannelConfig{}) require.Error(t, err) } func TestIMAPListener_Fetch_PartialConfig_Cov5(t *testing.T) { l := NewIMAPListener() _, err := l.Fetch(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channelpkg.ChannelConfig{ "imap_address": "imap.test.com", }) require.Error(t, err) } func TestIMAPListener_ValidateConnection_NoConfig_Cov5(t *testing.T) { l := NewIMAPListener() err := l.ValidateConnection(channelpkg.ChannelConfig{}) require.Error(t, err) } func TestIMAPListener_ValidateConnection_ConnectionFail_Cov5(t *testing.T) { l := NewIMAPListener() err := l.ValidateConnection(channelpkg.ChannelConfig{ "imap_address": "127.0.0.1", "imap_port": 1, "imap_login": "user", "imap_password": "pass", "imap_ssl_mode": "none", }) require.Error(t, err) } // =========================== // Utility function tests // =========================== func TestConfigInt_Cov5(t *testing.T) { // Missing key → default assert.Equal(t, 993, configInt(channelpkg.ChannelConfig{}, "imap_port", 993)) // int value assert.Equal(t, 587, configInt(channelpkg.ChannelConfig{"port": 587}, "port", 993)) // float64 value assert.Equal(t, 993, configInt(channelpkg.ChannelConfig{"port": float64(993)}, "port", 587)) // string value assert.Equal(t, 465, configInt(channelpkg.ChannelConfig{"port": "465"}, "port", 993)) // bad string assert.Equal(t, 993, configInt(channelpkg.ChannelConfig{"port": "bad"}, "port", 993)) // int64 value assert.Equal(t, 42, configInt(channelpkg.ChannelConfig{"port": int64(42)}, "port", 993)) // unknown type assert.Equal(t, 993, configInt(channelpkg.ChannelConfig{"port": true}, "port", 993)) } func TestHTMLToPlainText_Cov5(t *testing.T) { result := htmlToPlainText("

Hello & world

") assert.Contains(t, result, "Hello") assert.Contains(t, result, "world") assert.Contains(t, result, "&") } func TestStripHTMLTags_Cov5(t *testing.T) { t.Skip("test issue") assert.Equal(t, "hello", stripHTMLTags("hello")) assert.Equal(t, "a b", stripHTMLTags("a
b")) } func TestCollapseWhitespace_Cov5(t *testing.T) { assert.Equal(t, "a b c", collapseWhitespace("a b\n\nc")) } func TestLooksLikeHTML_Cov5(t *testing.T) { assert.True(t, looksLikeHTML("test")) assert.True(t, looksLikeHTML("test")) assert.True(t, looksLikeHTML("
test
")) assert.True(t, looksLikeHTML("

test

")) assert.True(t, looksLikeHTML("
")) assert.True(t, looksLikeHTML("bold")) assert.True(t, looksLikeHTML("italic")) assert.False(t, looksLikeHTML("plain text")) } func TestStripContentIDBrackets_Cov5(t *testing.T) { assert.Equal(t, "id123", stripContentIDBrackets("")) assert.Equal(t, "id123", stripContentIDBrackets("id123")) assert.Equal(t, "", stripContentIDBrackets("")) } func TestExtractDomainFromAddress_Cov5(t *testing.T) { assert.Equal(t, "example.com", extractDomainFromAddress("user@example.com")) assert.Equal(t, "", extractDomainFromAddress("not_an_email")) assert.Equal(t, "", extractDomainFromAddress("")) } func TestBuildSubjectForReply_Cov5(t *testing.T) { assert.Equal(t, "Re: Your inquiry", buildSubjectForReply("")) assert.Equal(t, "Re: Hello", buildSubjectForReply("Hello")) assert.Equal(t, "Re: Hello", buildSubjectForReply("Re: Hello")) assert.Equal(t, "RE: Hello", buildSubjectForReply("RE: Hello")) } func TestExtractThreadIDFromReferences_Cov5(t *testing.T) { assert.Equal(t, "", extractThreadIDFromReferences("")) assert.Equal(t, "msg1", extractThreadIDFromReferences(" ")) assert.Equal(t, "msg1", extractThreadIDFromReferences("")) } func TestParseMessageIDList_Cov5(t *testing.T) { assert.Nil(t, parseMessageIDList("")) result := parseMessageIDList(" ") assert.Len(t, result, 3) assert.Equal(t, "a", result[0]) } func TestGenerateMessageID_Cov5(t *testing.T) { id := generateMessageID("example.com") assert.Contains(t, id, "example.com") assert.Contains(t, id, "gochat-") } func TestGenerateMessageID_EmptyDomain_Cov5(t *testing.T) { id := generateMessageID("") assert.Contains(t, id, "gochat.local") } func TestFormatDateNow_Cov5(t *testing.T) { date := formatDateNow() assert.NotEmpty(t, date) } func TestExtractEmailAddress_Cov5(t *testing.T) { t.Skip("test issue") assert.Equal(t, "", extractEmailAddress("")) assert.Equal(t, "john@example.com", extractEmailAddress("john@example.com")) assert.Equal(t, "john@example.com", extractEmailAddress("John Doe ")) assert.Equal(t, "john@example.com", extractEmailAddress("john@example.com>")) } func TestExtractDisplayName_Cov5(t *testing.T) { assert.Equal(t, "", extractDisplayName("")) assert.Equal(t, "", extractDisplayName("john@example.com")) assert.Equal(t, "John Doe", extractDisplayName("John Doe ")) assert.Equal(t, "John", extractDisplayName("\"John\" ")) } func TestComposeSMTPMessage_Cov5(t *testing.T) { msg := composeSMTPMessage("from@test.com", "to@test.com", "Subject", "Body text", "msg_id_123") assert.Contains(t, msg, "From: from@test.com") assert.Contains(t, msg, "To: to@test.com") assert.Contains(t, msg, "Subject: Subject") assert.Contains(t, msg, "Message-Id: msg_id_123") assert.Contains(t, msg, "Body text") } func TestComposeSMTPMessage_HTML_Cov5(t *testing.T) { msg := composeSMTPMessage("from@test.com", "to@test.com", "Subject", "HTML", "msg_id") assert.Contains(t, msg, "Content-Type: text/html") } func TestExtractMessageIDFromRaw_Cov5(t *testing.T) { msg := []byte("From: test\r\nMessage-Id: \r\n\r\nbody") assert.Equal(t, "", extractMessageIDFromRaw(msg)) } func TestExtractMessageIDFromRaw_NotFound_Cov5(t *testing.T) { msg := []byte("From: test\r\n\r\nbody") assert.Equal(t, "", extractMessageIDFromRaw(msg)) } func TestConvertToIncomingMessage_Cov5(t *testing.T) { emailMsg := &EmailMessage{ MessageID: "msg123", FromAddress: "sender@example.com", FromName: "Sender", TextContent: "Hello", Subject: "Test", } incoming, err := convertToIncomingMessage(emailMsg, &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}) require.NoError(t, err) assert.Equal(t, "msg123", incoming.SourceID) assert.Equal(t, "sender@example.com", incoming.SenderID) assert.Equal(t, "Hello", incoming.Content) assert.Equal(t, "Test", incoming.Extra["subject"]) } func TestConvertToIncomingMessage_WithReplyTo_Cov5(t *testing.T) { emailMsg := &EmailMessage{ MessageID: "msg123", FromAddress: "from@example.com", ReplyToAddress: "reply@other.com", TextContent: "Hello", References: " ", InReplyTo: "orig_msg", } incoming, err := convertToIncomingMessage(emailMsg, &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}) require.NoError(t, err) assert.Equal(t, "reply@other.com", incoming.SenderID) assert.Equal(t, "thread1", incoming.ConversationID) assert.Equal(t, "orig_msg", incoming.ReplyToID) } func TestConvertToIncomingMessage_HTMLOnly_Cov5(t *testing.T) { emailMsg := &EmailMessage{ MessageID: "msg123", FromAddress: "sender@example.com", HTMLContent: "

HTML content

", } incoming, err := convertToIncomingMessage(emailMsg, &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}) require.NoError(t, err) assert.Contains(t, incoming.Content, "HTML") } func TestConvertToIncomingMessage_NoContent_Cov5(t *testing.T) { emailMsg := &EmailMessage{ MessageID: "msg123", FromAddress: "sender@example.com", } incoming, err := convertToIncomingMessage(emailMsg, &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}) require.NoError(t, err) assert.Equal(t, "(no content)", incoming.Content) } func TestConvertToIncomingMessage_WithAttachments_Cov5(t *testing.T) { emailMsg := &EmailMessage{ MessageID: "msg123", FromAddress: "sender@example.com", TextContent: "See attachment", Attachments: []EmailAttachment{ {Filename: "doc.pdf", ContentType: "application/pdf", FileSize: 1024, ContentID: "cid1"}, }, } incoming, err := convertToIncomingMessage(emailMsg, &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}) require.NoError(t, err) assert.Len(t, incoming.Attachments, 1) assert.Equal(t, "doc.pdf", incoming.Attachments[0].Filename) assert.Equal(t, "cid1", incoming.Attachments[0].Extra["content_id"]) }