import Testing import Foundation @testable import SMTPClient import Models @Suite("MessageFormatter") struct MessageFormatterTests { // MARK: - Basic Message Formatting @Test("formatted message contains all required headers") func basicHeaders() { let message = OutgoingMessage( from: EmailAddress(name: "Alice", address: "alice@example.com"), to: [EmailAddress(address: "bob@example.com")], subject: "Hello", bodyText: "Hi Bob", messageId: "test-id@example.com" ) let formatted = MessageFormatter.format(message) #expect(formatted.contains("From: \"Alice\" ")) #expect(formatted.contains("To: bob@example.com")) #expect(formatted.contains("Subject: Hello")) #expect(formatted.contains("Message-ID: ")) #expect(formatted.contains("MIME-Version: 1.0")) #expect(formatted.contains("Content-Type: text/plain; charset=utf-8")) #expect(formatted.contains("Content-Transfer-Encoding: quoted-printable")) #expect(formatted.contains("Date: ")) } // MARK: - Reply Headers @Test("reply includes In-Reply-To and References headers") func replyHeaders() { let message = OutgoingMessage( from: EmailAddress(address: "alice@example.com"), to: [EmailAddress(address: "bob@example.com")], subject: "Re: Hello", bodyText: "Thanks!", inReplyTo: "original-id@example.com", references: "", messageId: "reply-id@example.com" ) let formatted = MessageFormatter.format(message) #expect(formatted.contains("In-Reply-To: ")) #expect(formatted.contains("References: ")) } // MARK: - BCC Omitted @Test("BCC recipients are not included in formatted output") func bccOmitted() { let message = OutgoingMessage( from: EmailAddress(address: "alice@example.com"), to: [EmailAddress(address: "bob@example.com")], bcc: [EmailAddress(address: "secret@example.com")], subject: "Test", bodyText: "Body", messageId: "test@example.com" ) let formatted = MessageFormatter.format(message) #expect(!formatted.contains("Bcc")) #expect(!formatted.contains("secret@example.com")) } // MARK: - Multiple CC Recipients @Test("multiple CC recipients formatted correctly") func multipleCc() { let message = OutgoingMessage( from: EmailAddress(address: "alice@example.com"), to: [EmailAddress(address: "bob@example.com")], cc: [ EmailAddress(name: "Carol", address: "carol@example.com"), EmailAddress(address: "dave@example.com"), ], subject: "Test", bodyText: "Body", messageId: "test@example.com" ) let formatted = MessageFormatter.format(message) #expect(formatted.contains("Cc: \"Carol\" , dave@example.com")) } // MARK: - Quoted-Printable Encoding @Test("non-ASCII characters are quoted-printable encoded") func quotedPrintableNonAscii() { let encoded = MessageFormatter.quotedPrintableEncode("Grüße") // ü = C3 BC, ß = C3 9F, e is plain #expect(encoded.contains("=C3=BC")) // ü #expect(encoded.contains("=C3=9F")) // ß #expect(encoded.contains("Gr")) #expect(encoded.contains("e")) } @Test("equals sign is encoded in quoted-printable") func quotedPrintableEquals() { let encoded = MessageFormatter.quotedPrintableEncode("a=b") #expect(encoded == "a=3Db") } @Test("plain ASCII text passes through unchanged") func quotedPrintableAscii() { let encoded = MessageFormatter.quotedPrintableEncode("Hello World") #expect(encoded == "Hello World") } // MARK: - Domain Extraction @Test("domain extracted from email address") func domainExtraction() { #expect(MessageFormatter.domainFromEmail("alice@example.com") == "example.com") #expect(MessageFormatter.domainFromEmail("user@sub.domain.org") == "sub.domain.org") } @Test("domain extraction handles missing @ gracefully") func domainExtractionNoAt() { #expect(MessageFormatter.domainFromEmail("noatsign") == "noatsign") } // MARK: - Message-ID Generation @Test("generated message ID contains domain") func messageIdGeneration() { let id = MessageFormatter.generateMessageId(domain: "example.com") #expect(id.hasSuffix("@example.com")) #expect(id.count > "@example.com".count) } @Test("generated message IDs are unique") func messageIdUniqueness() { let id1 = MessageFormatter.generateMessageId(domain: "example.com") let id2 = MessageFormatter.generateMessageId(domain: "example.com") #expect(id1 != id2) } // MARK: - Address Formatting @Test("address with name formatted as quoted name angle-bracket") func addressWithName() { let addr = EmailAddress(name: "Alice Smith", address: "alice@example.com") #expect(MessageFormatter.formatAddress(addr) == "\"Alice Smith\" ") } @Test("address without name formatted as bare address") func addressWithoutName() { let addr = EmailAddress(address: "alice@example.com") #expect(MessageFormatter.formatAddress(addr) == "alice@example.com") } @Test("address with empty name formatted as bare address") func addressEmptyName() { let addr = EmailAddress(name: "", address: "alice@example.com") #expect(MessageFormatter.formatAddress(addr) == "alice@example.com") } // MARK: - RFC 2822 Date @Test("RFC 2822 date format is valid") func rfc2822DateFormat() { let dateString = MessageFormatter.formatRFC2822Date(Date()) // Should match pattern like "Fri, 14 Mar 2026 10:30:00 +0100" #expect(dateString.contains(",")) #expect(dateString.count > 20) } }