Skip to content

Commit 77cd0c9

Browse files
committed
Refactor: Split RFC-specific initializers into separate files and rename error type
- Extract RFC 5321, 5322, and 6531 initializers to EmailAddress+RFC*.swift files - Rename EmailAddressError to EmailAddress.Error (nested type) - Add comprehensive tests for RFC_2822.AddrSpec conversion - All 30 tests passing
1 parent 64bfad3 commit 77cd0c9

File tree

5 files changed

+124
-51
lines changed

5 files changed

+124
-51
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Foundation
2+
import RFC_5321
3+
import RFC_5322
4+
import RFC_6531
5+
6+
extension EmailAddress {
7+
/// Initialize from RFC5321
8+
public init(rfc5321: RFC_5321.EmailAddress) throws {
9+
self.rfc5321 = rfc5321
10+
self.rfc5322 = try? RFC_5322.EmailAddress(
11+
displayName: rfc5321.displayName,
12+
localPart: .init(rfc5321.localPart.stringValue),
13+
domain: .init(rfc5321.domain.name)
14+
)
15+
self.rfc6531 = try {
16+
guard
17+
let email = try? RFC_6531.EmailAddress(
18+
displayName: rfc5321.displayName,
19+
localPart: .init(rfc5321.localPart.stringValue),
20+
domain: .init(rfc5321.domain.name)
21+
)
22+
else {
23+
throw EmailAddress.Error.conversionFailure
24+
}
25+
return email
26+
}()
27+
self.displayName = rfc5321.displayName
28+
}
29+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Foundation
2+
import RFC_5321
3+
import RFC_5322
4+
import RFC_6531
5+
6+
extension EmailAddress {
7+
/// Initialize from RFC5322
8+
public init(rfc5322: RFC_5322.EmailAddress) throws {
9+
self.rfc5321 = try? rfc5322.toRFC5321()
10+
self.rfc5322 = rfc5322
11+
self.rfc6531 = try {
12+
guard
13+
let email = try? RFC_6531.EmailAddress(
14+
displayName: rfc5322.displayName,
15+
localPart: .init(rfc5322.localPart.stringValue),
16+
domain: rfc5322.domain
17+
)
18+
else {
19+
throw EmailAddress.Error.conversionFailure
20+
}
21+
return email
22+
}()
23+
self.displayName = rfc5322.displayName
24+
}
25+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Foundation
2+
import RFC_5321
3+
import RFC_5322
4+
import RFC_6531
5+
6+
extension EmailAddress {
7+
/// Initialize from RFC6531
8+
public init(rfc6531: RFC_6531.EmailAddress) {
9+
self.rfc5321 = try? rfc6531.toRFC5321()
10+
self.rfc5322 = try? rfc6531.toRFC5322()
11+
self.rfc6531 = rfc6531
12+
self.displayName = rfc6531.displayName
13+
}
14+
}

Sources/EmailAddress/EmailAddress.swift

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -71,55 +71,6 @@ public struct EmailAddress: Hashable, Sendable {
7171
)
7272
}
7373

74-
/// Initialize from RFC5321
75-
public init(rfc5321: RFC_5321.EmailAddress) throws {
76-
self.rfc5321 = rfc5321
77-
self.rfc5322 = try? RFC_5322.EmailAddress(
78-
displayName: rfc5321.displayName,
79-
localPart: .init(rfc5321.localPart.stringValue),
80-
domain: .init(rfc5321.domain.name)
81-
)
82-
self.rfc6531 = try {
83-
guard
84-
let email = try? RFC_6531.EmailAddress(
85-
displayName: rfc5321.displayName,
86-
localPart: .init(rfc5321.localPart.stringValue),
87-
domain: .init(rfc5321.domain.name)
88-
)
89-
else {
90-
throw EmailAddressError.conversionFailure
91-
}
92-
return email
93-
}()
94-
self.displayName = rfc5321.displayName
95-
}
96-
97-
/// Initialize from RFC5322
98-
public init(rfc5322: RFC_5322.EmailAddress) throws {
99-
self.rfc5321 = try? rfc5322.toRFC5321()
100-
self.rfc5322 = rfc5322
101-
self.rfc6531 = try {
102-
guard
103-
let email = try? RFC_6531.EmailAddress(
104-
displayName: rfc5322.displayName,
105-
localPart: .init(rfc5322.localPart.stringValue),
106-
domain: rfc5322.domain
107-
)
108-
else {
109-
throw EmailAddressError.conversionFailure
110-
}
111-
return email
112-
}()
113-
self.displayName = rfc5322.displayName
114-
}
115-
116-
/// Initialize from RFC6531
117-
public init(rfc6531: RFC_6531.EmailAddress) {
118-
self.rfc5321 = try? rfc6531.toRFC5321()
119-
self.rfc5322 = try? rfc6531.toRFC5322()
120-
self.rfc6531 = rfc6531
121-
self.displayName = rfc6531.displayName
122-
}
12374
}
12475

12576
// MARK: - Properties
@@ -200,7 +151,7 @@ extension EmailAddress {
200151

201152
// MARK: - Errors
202153
extension EmailAddress {
203-
public enum EmailAddressError: Error, Equatable, LocalizedError {
154+
public enum Error: Swift.Error, Equatable, LocalizedError {
204155
case conversionFailure
205156
case invalidFormat(description: String)
206157

@@ -251,7 +202,7 @@ extension EmailAddress {
251202
public static func ascii(_ string: String) throws -> Self {
252203
let email = try Self(string)
253204
guard email.isASCII else {
254-
throw EmailAddressError.invalidFormat(description: "Must be ASCII-only")
205+
throw Error.invalidFormat(description: "Must be ASCII-only")
255206
}
256207
return email
257208
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import Testing
2+
import Foundation
3+
@testable import EmailAddress
4+
import RFC_2822
5+
6+
@Suite("RFC 2822 AddrSpec Conversion Tests")
7+
struct RFC2822ConversionTests {
8+
9+
@Test("Convert EmailAddress to RFC_2822.AddrSpec")
10+
func emailAddressToAddrSpec() throws {
11+
let email = try EmailAddress("[email protected]")
12+
let addrSpec = try RFC_2822.AddrSpec(email)
13+
14+
#expect(addrSpec.localPart == "user")
15+
#expect(addrSpec.domain == "example.com")
16+
#expect(addrSpec.description == "[email protected]")
17+
}
18+
19+
@Test("Convert RFC_2822.AddrSpec to EmailAddress")
20+
func addrSpecToEmailAddress() throws {
21+
let addrSpec = try RFC_2822.AddrSpec(localPart: "test", domain: "example.org")
22+
let email = try EmailAddress(addrSpec)
23+
24+
#expect(email.rfc5322?.localPart.stringValue == "test")
25+
#expect(email.rfc5322?.domain.name == "example.org")
26+
}
27+
28+
@Test("Round-trip conversion EmailAddress -> AddrSpec -> EmailAddress")
29+
func roundTripConversion() throws {
30+
let original = try EmailAddress("[email protected]")
31+
let addrSpec = try RFC_2822.AddrSpec(original)
32+
let converted = try EmailAddress(addrSpec)
33+
34+
#expect(original == converted)
35+
}
36+
37+
@Test("Convert EmailAddress with subdomain to RFC_2822.AddrSpec")
38+
func emailWithSubdomainToAddrSpec() throws {
39+
let email = try EmailAddress("[email protected]")
40+
let addrSpec = try RFC_2822.AddrSpec(email)
41+
42+
#expect(addrSpec.localPart == "admin")
43+
#expect(addrSpec.domain == "mail.example.com")
44+
}
45+
46+
@Test("Convert EmailAddress with special characters to RFC_2822.AddrSpec")
47+
func emailWithSpecialCharsToAddrSpec() throws {
48+
let email = try EmailAddress("[email protected]")
49+
let addrSpec = try RFC_2822.AddrSpec(email)
50+
51+
#expect(addrSpec.localPart == "user+tag")
52+
#expect(addrSpec.domain == "example.com")
53+
}
54+
}

0 commit comments

Comments
 (0)