Files
mailx/smtp/html_email_test.go
T
2025-11-21 14:01:43 +08:00

367 lines
8.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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客户端
_, err := smtpClient.SetOption(ctx, func(opt *interfaces.Options) {
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()
_, err := smtpClient.SetOption(ctx, func(opt *interfaces.Options) {
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)
}
}