Files
mailx/smtp/html_email_test.go
T

367 lines
8.8 KiB
Go
Raw Normal View History

2025-11-21 14:01:43 +08:00
package smtp
import (
"context"
"strings"
"testing"
"code.yun.ink/pkg/mailx/interfaces"
)
// 测试内容类型检测
func TestContentTypeDetection(t *testing.T) {
smtpClient := NewSmtp()
tests := []struct {
name string
body string
expected interfaces.ContentType
}{
{
name: "HTML with html tag",
body: "<html><body>Test</body></html>",
expected: interfaces.ContentTypeHTML,
},
{
name: "HTML with div tag",
body: "<div>Test content</div>",
expected: interfaces.ContentTypeHTML,
},
{
name: "HTML with img tag",
body: "Check this image: <img src='test.jpg'>",
expected: interfaces.ContentTypeHTML,
},
{
name: "Plain text",
body: "This is plain text without any HTML tags.",
expected: interfaces.ContentTypeText,
},
{
name: "Text with angle brackets",
body: "Price: 100 < 200, Quality: A > B",
expected: interfaces.ContentTypeText,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := smtpClient.detectContentType(tt.body)
if result != tt.expected {
t.Errorf("Expected %s, got %s for body: %s", tt.expected, result, tt.body)
}
})
}
}
// 测试邮件头构建
func TestBuildHeaders(t *testing.T) {
smtpClient := NewSmtp()
smtpClient.SetOption(context.Background(), interfaces.SetSmtp(&interfaces.EmailConfigDataSmtp{}))
boundary := "test-boundary"
tests := []struct {
name string
message interfaces.Message
expected string
}{
{
name: "HTML with inline images",
message: interfaces.Message{
Subject: "Test Subject",
InlineImage: []interfaces.Attachment{{Name: "test.jpg"}},
},
expected: "multipart/related",
},
{
name: "HTML with attachments",
message: interfaces.Message{
Subject: "Test Subject",
Attachment: []interfaces.Attachment{{Name: "test.pdf"}},
},
expected: "multipart/mixed",
},
{
name: "Simple message",
message: interfaces.Message{
Subject: "Test Subject",
},
expected: "multipart/alternative",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
headers := smtpClient.buildHeaders(tt.message, boundary)
contentType := headers["Content-Type"]
if !strings.Contains(contentType, tt.expected) {
t.Errorf("Expected Content-Type to contain %s, got %s", tt.expected, contentType)
}
})
}
}
// 测试附件类型处理
func TestAttachmentTypes(t *testing.T) {
tests := []struct {
name string
attachment interfaces.Attachment
expectCID bool
}{
{
name: "File attachment",
attachment: interfaces.Attachment{
Name: "document.pdf",
Type: interfaces.AttachmentTypeFile,
},
expectCID: false,
},
{
name: "Inline image",
attachment: interfaces.Attachment{
Name: "image.jpg",
Type: interfaces.AttachmentTypeInline,
CID: "test-image",
},
expectCID: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.expectCID && tt.attachment.CID == "" {
t.Error("Expected CID for inline attachment")
}
if !tt.expectCID && tt.attachment.Type == interfaces.AttachmentTypeFile {
// File attachments should not have CID
if tt.attachment.CID != "" {
t.Error("File attachment should not have CID")
}
}
})
}
}
// 测试消息验证
func TestMessageValidation2(t *testing.T) {
smtpClient := NewSmtp()
ctx := context.Background()
// 配置SMTP客户端
2025-11-21 15:54:49 +08:00
err := smtpClient.SetOption(ctx, func(opt *interfaces.Options) {
2025-11-21 14:01:43 +08:00
opt.Smtp = &interfaces.EmailConfigDataSmtp{
Host: "smtp.example.com",
Port: "587",
Username: "test@example.com",
Password: "password",
}
})
if err != nil {
t.Fatalf("Failed to configure SMTP: %v", err)
}
tests := []struct {
name string
message interfaces.Message
wantErr bool
}{
{
name: "Valid HTML message",
message: interfaces.Message{
To: []string{"test@example.com"},
Subject: "Test",
Body: "<h1>Test</h1>",
BodyType: interfaces.ContentTypeHTML,
},
wantErr: false,
},
{
name: "Valid text message",
message: interfaces.Message{
To: []string{"test@example.com"},
Subject: "Test",
Body: "Plain text",
BodyType: interfaces.ContentTypeText,
},
wantErr: false,
},
{
name: "Message with inline images",
message: interfaces.Message{
To: []string{"test@example.com"},
Subject: "Test",
Body: "<img src='cid:test'>",
InlineImage: []interfaces.Attachment{
{
Name: "test.jpg",
CID: "test",
Type: interfaces.AttachmentTypeInline,
},
},
},
wantErr: false,
},
{
name: "Empty recipients",
message: interfaces.Message{
Subject: "Test",
Body: "Test body",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := smtpClient.validateMessage(tt.message)
if (err != nil) != tt.wantErr {
t.Errorf("validateMessage() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
// 测试多部分邮件构建
func TestMultipartEmailConstruction2(t *testing.T) {
smtpClient := NewSmtp()
ctx := context.Background()
2025-11-21 15:54:49 +08:00
err := smtpClient.SetOption(ctx, func(opt *interfaces.Options) {
2025-11-21 14:01:43 +08:00
opt.Smtp = &interfaces.EmailConfigDataSmtp{
Host: "smtp.example.com",
Port: "587",
Username: "test@example.com",
Password: "password",
}
})
if err != nil {
t.Fatalf("Failed to configure SMTP: %v", err)
}
message := interfaces.Message{
To: []string{"recipient@example.com"},
Subject: "Multipart Test",
BodyType: interfaces.ContentTypeHTML,
Body: "<h1>HTML Content</h1><img src='cid:test-img'>",
TextBody: "Plain text version",
InlineImage: []interfaces.Attachment{
{
Data: []byte("fake-image-data"),
ContentType: "image/jpeg",
Name: "test.jpg",
CID: "test-img",
Type: interfaces.AttachmentTypeInline,
},
},
Attachment: []interfaces.Attachment{
{
Data: []byte("fake-pdf-data"),
ContentType: "application/pdf",
Name: "document.pdf",
Type: interfaces.AttachmentTypeFile,
},
},
}
// 测试邮件构建(不实际发送)
boundary := "test-boundary"
headers := smtpClient.buildHeaders(message, boundary)
// 验证Content-Type
contentType := headers["Content-Type"]
if !strings.Contains(contentType, "multipart/related") {
t.Errorf("Expected multipart/related for message with inline images, got %s", contentType)
}
// 验证必要的头部字段
requiredHeaders := []string{"From", "To", "Subject", "Date", "MIME-Version", "Content-Type"}
for _, header := range requiredHeaders {
if _, exists := headers[header]; !exists {
t.Errorf("Missing required header: %s", header)
}
}
}
// 测试字节数据附件
func TestByteDataAttachment(t *testing.T) {
attachment := interfaces.Attachment{
Data: []byte("test file content"),
ContentType: "text/plain",
Name: "test.txt",
Type: interfaces.AttachmentTypeFile,
}
if len(attachment.Data) == 0 {
t.Error("Attachment data should not be empty")
}
if attachment.ContentType != "text/plain" {
t.Errorf("Expected content type text/plain, got %s", attachment.ContentType)
}
}
// 基准测试:HTML邮件构建性能
func BenchmarkHTMLEmailConstruction(b *testing.B) {
smtpClient := NewSmtp()
ctx := context.Background()
smtpClient.SetOption(ctx, func(opt *interfaces.Options) {
opt.Smtp = &interfaces.EmailConfigDataSmtp{
Host: "smtp.example.com",
Port: "587",
Username: "test@example.com",
Password: "password",
}
})
message := interfaces.Message{
To: []string{"test@example.com"},
Subject: "Benchmark Test",
BodyType: interfaces.ContentTypeHTML,
Body: "<h1>Benchmark</h1><p>Performance test content</p>",
TextBody: "Benchmark - Performance test content",
InlineImage: []interfaces.Attachment{
{
Data: make([]byte, 1024), // 1KB fake image
ContentType: "image/jpeg",
Name: "test.jpg",
CID: "test-img",
Type: interfaces.AttachmentTypeInline,
},
},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
boundary := "benchmark-boundary"
headers := smtpClient.buildHeaders(message, boundary)
_ = headers
}
}
// 测试大附件处理
func TestLargeAttachmentHandling(t *testing.T) {
// 创建大附件数据(模拟)
largeData := make([]byte, 1024*1024) // 1MB
for i := range largeData {
largeData[i] = byte(i % 256)
}
attachment := interfaces.Attachment{
Data: largeData,
ContentType: "application/octet-stream",
Name: "large_file.bin",
Type: interfaces.AttachmentTypeFile,
}
if len(attachment.Data) != 1024*1024 {
t.Errorf("Expected 1MB data, got %d bytes", len(attachment.Data))
}
// 测试是否超过限制(25MB
maxSize := 25 * 1024 * 1024
if len(attachment.Data) > maxSize {
t.Errorf("Attachment size %d exceeds limit %d", len(attachment.Data), maxSize)
}
}