Skip to content

Commit ac15e9a

Browse files
committed
Wrap .org XML RPC error enum in an Error-conforming struct
Jumping through this hoop was necessary to avoid the Swift compiler automatically generating an error domain for the `Error` and making it impossible to successfully redefine the domain at the `CustomNSError` conformance site.
1 parent f6f0c1c commit ac15e9a

7 files changed

+83
-47
lines changed

CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ _None._
3030
3131
-->
3232

33+
## Unreleased
34+
35+
### Breaking Changes
36+
37+
- The Objective-C-visible `WordPressOrgXMLRPCError` `enum` has been renamed to `WordPressOrgXMLRPCErrorCode` [#790]
38+
39+
### New Features
40+
41+
_None._
42+
43+
### Bug Fixes
44+
45+
_None._
46+
47+
### Internal Changes
48+
49+
_None._
50+
3351
## 17.0.0
3452

3553
### Breaking Changes

Sources/CoreAPI/WordPressOrgXMLRPCApi.swift

+15-40
Original file line numberDiff line numberDiff line change
@@ -288,43 +288,6 @@ private class SessionDelegate: NSObject, URLSessionDelegate {
288288
}
289289
}
290290
}
291-
292-
// Hack to avoid the Swift compiler generating a domain constant for us that would then conflict with the one we define in APIInterface.
293-
// The automatic generation occurs, as far as I can tell, because of @objc and Error, neither of which we can remove.
294-
// Reminder: We define our own constant for the domain so that we can conform WordPressOrgXMLRPCApiError to CustomNSError.
295-
typealias WordPressOrgXMLRPCApiError = WordPressOrgXMLRPCAPIError
296-
297-
/// Error constants for the WordPress XML-RPC API
298-
@objc public enum WordPressOrgXMLRPCAPIError: Int, Error, CaseIterable {
299-
/// An error HTTP status code was returned.
300-
case httpErrorStatusCode
301-
/// The serialization of the request failed.
302-
case requestSerializationFailed
303-
/// The serialization of the response failed.
304-
case responseSerializationFailed
305-
/// An unknown error occurred.
306-
case unknown
307-
}
308-
309-
extension WordPressOrgXMLRPCApiError: LocalizedError {
310-
public var errorDescription: String? {
311-
return NSLocalizedString("There was a problem communicating with the site.", comment: "A general error message shown to the user when there was an API communication failure.")
312-
}
313-
314-
public var failureReason: String? {
315-
switch self {
316-
case .httpErrorStatusCode:
317-
return NSLocalizedString("An HTTP error code was returned.", comment: "A failure reason for when an error HTTP status code was returned from the site.")
318-
case .requestSerializationFailed:
319-
return NSLocalizedString("The serialization of the request failed.", comment: "A failure reason for when the request couldn't be serialized.")
320-
case .responseSerializationFailed:
321-
return NSLocalizedString("The serialization of the response failed.", comment: "A failure reason for when the response couldn't be serialized.")
322-
case .unknown:
323-
return NSLocalizedString("An unknown error occurred.", comment: "A failure reason for when the error that occured wasn't able to be determined.")
324-
}
325-
}
326-
}
327-
328291
public struct WordPressOrgXMLRPCApiFault: LocalizedError, HTTPURLResponseProviding {
329292
public var response: HTTPAPIResponse<Data>
330293
public let code: Int?
@@ -352,7 +315,13 @@ private extension WordPressAPIResult<HTTPAPIResponse<Data>, WordPressOrgXMLRPCAp
352315
// https://github.com/wordpress-mobile/WordPressKit-iOS/blob/11.0.0/WordPressKit/WordPressOrgXMLRPCApi.swift#L265
353316
flatMap { response in
354317
guard let contentType = response.response.allHeaderFields["Content-Type"] as? String else {
355-
return .failure(.unparsableResponse(response: response.response, body: response.body, underlyingError: WordPressOrgXMLRPCApiError.unknown))
318+
return .failure(
319+
.unparsableResponse(
320+
response: response.response,
321+
body: response.body,
322+
underlyingError: WordPressOrgXMLRPCApiError(code: .unknown)
323+
)
324+
)
356325
}
357326

358327
if (400..<600).contains(response.response.statusCode) {
@@ -366,7 +335,13 @@ private extension WordPressAPIResult<HTTPAPIResponse<Data>, WordPressOrgXMLRPCAp
366335
}
367336

368337
guard contentType.hasPrefix("application/xml") || contentType.hasPrefix("text/xml") else {
369-
return .failure(.unparsableResponse(response: response.response, body: response.body, underlyingError: WordPressOrgXMLRPCApiError.unknown))
338+
return .failure(
339+
.unparsableResponse(
340+
response: response.response,
341+
body: response.body,
342+
underlyingError: WordPressOrgXMLRPCApiError(code: .unknown)
343+
)
344+
)
370345
}
371346

372347
guard let decoder = WPXMLRPCDecoder(data: response.body) else {
@@ -418,7 +393,7 @@ private extension WordPressAPIError where EndpointError == WordPressOrgXMLRPCApi
418393
data = fault.response.body
419394
statusCode = nil
420395
case let .unacceptableStatusCode(response, body):
421-
error = WordPressOrgXMLRPCApiError.httpErrorStatusCode as NSError
396+
error = WordPressOrgXMLRPCApiError(code: .httpErrorStatusCode) as NSError
422397
data = body
423398
statusCode = response.statusCode
424399
case let .unparsableResponse(_, body, underlyingError):

Sources/CoreAPI/WordPressOrgXMLRPCApiError+NSErrorBridge.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ extension WordPressOrgXMLRPCApiError: CustomNSError {
88

99
public static let errorDomain = WordPressOrgXMLRPCApiErrorDomain
1010

11-
public var errorCode: Int { self.rawValue }
11+
public var errorCode: Int { code.rawValue }
1212

1313
public var errorUserInfo: [String: Any] { [:] }
1414
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Foundation
2+
3+
/// Error constants for the WordPress XML-RPC API
4+
@objc public enum WordPressOrgXMLRPCApiErrorCode: Int, CaseIterable {
5+
/// An error HTTP status code was returned.
6+
case httpErrorStatusCode
7+
/// The serialization of the request failed.
8+
case requestSerializationFailed
9+
/// The serialization of the response failed.
10+
case responseSerializationFailed
11+
/// An unknown error occurred.
12+
case unknown
13+
}
14+
15+
public struct WordPressOrgXMLRPCApiError: Error {
16+
let code: WordPressOrgXMLRPCApiErrorCode
17+
}
18+
19+
extension WordPressOrgXMLRPCApiError: LocalizedError {
20+
public var errorDescription: String? {
21+
return NSLocalizedString(
22+
"There was a problem communicating with the site.",
23+
comment: "A general error message shown to the user when there was an API communication failure."
24+
)
25+
}
26+
27+
public var failureReason: String? {
28+
switch code {
29+
case .httpErrorStatusCode:
30+
return NSLocalizedString("An HTTP error code was returned.", comment: "A failure reason for when an error HTTP status code was returned from the site.")
31+
case .requestSerializationFailed:
32+
return NSLocalizedString("The serialization of the request failed.", comment: "A failure reason for when the request couldn't be serialized.")
33+
case .responseSerializationFailed:
34+
return NSLocalizedString("The serialization of the response failed.", comment: "A failure reason for when the response couldn't be serialized.")
35+
case .unknown:
36+
return NSLocalizedString("An unknown error occurred.", comment: "A failure reason for when the error that occured wasn't able to be determined.")
37+
}
38+
}
39+
}

Tests/CoreAPITests/WordPressOrgXMLRPCApiErrorTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import XCTest
99
class WordPressOrgXMLRPCApiErrorTests: XCTestCase {
1010

1111
func testNSErrorBridging() throws {
12-
for error in WordPressOrgXMLRPCApiError.allCases {
13-
let xmlRPCError = try XCTUnwrap(WordPressOrgXMLRPCApiError(rawValue: error.rawValue))
12+
for error in WordPressOrgXMLRPCApiErrorCode.allCases {
13+
let xmlRPCError = try XCTUnwrap(WordPressOrgXMLRPCApiError(code: error))
1414
let apiError = WordPressAPIError.endpointError(xmlRPCError)
1515
let newNSError = apiError as NSError
1616

Tests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class WordPressOrgXMLRPCApiTests: XCTestCase {
6565
failure: { (error, _) in
6666
expect.fulfill()
6767
XCTAssertEqual(error.domain, WordPressOrgXMLRPCApiErrorDomain)
68-
XCTAssertEqual(error.code, WordPressOrgXMLRPCApiError.httpErrorStatusCode.rawValue)
68+
XCTAssertEqual(error.code, WordPressOrgXMLRPCApiErrorCode.httpErrorStatusCode.rawValue)
6969
XCTAssertEqual(error.localizedFailureReason, "An HTTP error code 404 was returned.")
7070
XCTAssertNotNil(error.userInfo[WordPressOrgXMLRPCApi.WordPressOrgXMLRPCApiErrorKeyData as String])
7171
XCTAssertNotNil(error.userInfo[WordPressOrgXMLRPCApi.WordPressOrgXMLRPCApiErrorKeyStatusCode as String])
@@ -119,10 +119,10 @@ class WordPressOrgXMLRPCApiTests: XCTestCase {
119119
failure: { (error, _) in
120120
expect.fulfill()
121121

122-
XCTAssertTrue(error is WordPressOrgXMLRPCApiError)
123122
XCTAssertEqual(error.domain, WordPressOrgXMLRPCApiErrorDomain)
124-
XCTAssertEqual(error.code, WordPressOrgXMLRPCApiError.unknown.rawValue)
125-
XCTAssertEqual(error.localizedFailureReason, WordPressOrgXMLRPCApiError.unknown.failureReason)
123+
let errorUnknonw = WordPressOrgXMLRPCApiError(code: .unknown)
124+
XCTAssertEqual(error.code, errorUnknonw.code.rawValue)
125+
XCTAssertEqual(error.localizedFailureReason, errorUnknonw.failureReason)
126126
XCTAssertNotNil(error.userInfo[WordPressOrgXMLRPCApi.WordPressOrgXMLRPCApiErrorKeyData as String])
127127
XCTAssertNil(error.userInfo[WordPressOrgXMLRPCApi.WordPressOrgXMLRPCApiErrorKeyStatusCode as String])
128128
}

WordPressKit.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
3F8308A729EE683500354497 /* ActivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8308A629EE683500354497 /* ActivityTests.swift */; };
7171
3FA4258F2BCCFDA6007539BF /* WordPressComRestApiErrorDomain.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FA4258E2BCCFDA6007539BF /* WordPressComRestApiErrorDomain.h */; settings = {ATTRIBUTES = (Public, ); }; };
7272
3FA425A72BCF7EDC007539BF /* WordPressOrgXMLRPCApiErrorDomain.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FA425A62BCF7E7C007539BF /* WordPressOrgXMLRPCApiErrorDomain.h */; settings = {ATTRIBUTES = (Public, ); }; };
73+
3FA425A92BCF8721007539BF /* WordPressOrgXMLRPCApiError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FA425A82BCF8721007539BF /* WordPressOrgXMLRPCApiError.swift */; };
7374
3FB8642C2888089F003A86BE /* BuildkiteTestCollector in Frameworks */ = {isa = PBXBuildFile; productRef = 3FB8642B2888089F003A86BE /* BuildkiteTestCollector */; };
7475
3FD634E52BC3A55F00CEDF5E /* WordPressOrgXMLRPCValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FD634E32BC3A55F00CEDF5E /* WordPressOrgXMLRPCValidator.swift */; };
7576
3FD634E62BC3A55F00CEDF5E /* Date+WordPressCom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FD634E42BC3A55F00CEDF5E /* Date+WordPressCom.swift */; };
@@ -821,6 +822,7 @@
821822
3F8308A629EE683500354497 /* ActivityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTests.swift; sourceTree = "<group>"; };
822823
3FA4258E2BCCFDA6007539BF /* WordPressComRestApiErrorDomain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WordPressComRestApiErrorDomain.h; sourceTree = "<group>"; };
823824
3FA425A62BCF7E7C007539BF /* WordPressOrgXMLRPCApiErrorDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WordPressOrgXMLRPCApiErrorDomain.h; sourceTree = "<group>"; };
825+
3FA425A82BCF8721007539BF /* WordPressOrgXMLRPCApiError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressOrgXMLRPCApiError.swift; sourceTree = "<group>"; };
824826
3FB8642D288813E9003A86BE /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
825827
3FD634E32BC3A55F00CEDF5E /* WordPressOrgXMLRPCValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordPressOrgXMLRPCValidator.swift; sourceTree = "<group>"; };
826828
3FD634E42BC3A55F00CEDF5E /* Date+WordPressCom.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+WordPressCom.swift"; sourceTree = "<group>"; };
@@ -2143,6 +2145,7 @@
21432145
3FE2E97A2BC3A332002CA2E1 /* WordPressComRestApi.swift */,
21442146
4A05E7992B2FDC3200C25E3B /* WordPressOrgRestApi.swift */,
21452147
93BD27791EE73944002BB00B /* WordPressOrgXMLRPCApi.swift */,
2148+
3FA425A82BCF8721007539BF /* WordPressOrgXMLRPCApiError.swift */,
21462149
3F6128122BCB31660063810D /* WordPressOrgXMLRPCApiError+NSErrorBridge.swift */,
21472150
3FD634E32BC3A55F00CEDF5E /* WordPressOrgXMLRPCValidator.swift */,
21482151
93BD277B1EE73944002BB00B /* WordPressRSDParser.swift */,
@@ -3314,6 +3317,7 @@
33143317
9AB6D647218705E90008F274 /* RemoteDiff.swift in Sources */,
33153318
93BD277C1EE73944002BB00B /* HTTPAuthenticationAlertController.swift in Sources */,
33163319
7433BC011EFC4505002D9E92 /* PlanServiceRemote.swift in Sources */,
3320+
3FA425A92BCF8721007539BF /* WordPressOrgXMLRPCApiError.swift in Sources */,
33173321
4041405E220F9EF500CF7C5B /* StatsDotComFollowersInsight.swift in Sources */,
33183322
74650F721F0EA1A700188EDB /* GravatarServiceRemote.swift in Sources */,
33193323
B5969E1D20A49AC4005E9DF1 /* NSString+MD5.m in Sources */,

0 commit comments

Comments
 (0)