Skip to content

Commit 4c9e137

Browse files
author
Florian Rieger
authored
Merge pull request #15 from AppCron/improved-nserror-handling
Improved NSError handling
2 parents 2b07702 + bf8aebf commit 4c9e137

File tree

6 files changed

+256
-35
lines changed

6 files changed

+256
-35
lines changed

Sources/ErrorHandlerExtension.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,10 @@ public protocol ErrorHandler {
77

88
public extension ErrorHandler where Self: Interactor {
99

10+
@available(*, deprecated)
1011
func handleError(_ request: ErrorRequest, error: Error) {
11-
if let error = error as? InteractorError {
12-
request.onError?(error)
13-
} else {
14-
let nsError = error as NSError
15-
let errorWrapper = InteractorError(error: nsError)
16-
request.onError?(errorWrapper)
17-
}
12+
let error = error as InteractorError
13+
request.onError?(error)
1814
}
1915

2016
}

Sources/InteractorError.swift

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
11
import Foundation
22

3-
open class InteractorError: Error {
3+
public typealias InteractorError = NSError
4+
5+
public extension InteractorError {
6+
7+
private static let dictKey = "InteractorErrorDictKey"
8+
9+
// MARK: - Init
10+
11+
public convenience init(message: String, code: Int, dict: [String: Any]) {
12+
var infoDict = [String : Any]()
13+
infoDict[NSLocalizedDescriptionKey] = message
14+
infoDict[InteractorError.dictKey] = dict
15+
self.init(domain: "com.appcron.acinteractor", code: code, userInfo: infoDict)
16+
}
417

5-
open var message: String
6-
open var errorCode = 0
7-
open var nsError: NSError?
18+
public convenience init(message: String, code: Int) {
19+
self.init(message: message, code: code, dict: [String: Any]())
20+
}
821

9-
public init(message:String) {
10-
self.message = message
22+
public convenience init(message: String) {
23+
self.init(message: message, code: 0)
1124
}
1225

13-
public init(error:NSError) {
14-
self.message = error.localizedDescription
15-
self.errorCode = error.code
16-
self.nsError = error
26+
// MARK: - Message
27+
28+
public var message: String {
29+
get {
30+
return userInfo[NSLocalizedDescriptionKey] as? String ?? ""
31+
}
32+
}
33+
34+
// MARK: - Error Dict
35+
36+
public var dict: [String: Any] {
37+
get {
38+
guard let dict = userInfo[InteractorError.dictKey] as? [String: Any] else {
39+
return [String: Any]()
40+
}
41+
return dict
42+
}
1743
}
1844

1945
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import Foundation
2+
3+
public class MutableInteractorError: InteractorError {
4+
5+
private var mutableMessage: String
6+
private var mutableCode: Int
7+
private var mutableDict: [String : Any]
8+
9+
// MARK: - Init
10+
11+
public init(message: String, code: Int, dict: [String: Any]) {
12+
mutableMessage = message
13+
mutableCode = code
14+
mutableDict = dict
15+
super.init(domain: "com.appcron.acinteractor", code: code, userInfo: nil)
16+
}
17+
18+
public convenience init(message: String, code: Int) {
19+
self.init(message: message, code: code, dict: [String: Any]())
20+
}
21+
22+
public convenience init(message: String) {
23+
self.init(message: message, code: 0)
24+
}
25+
26+
public required init?(coder aDecoder: NSCoder) {
27+
fatalError("init(coder:) has not been implemented")
28+
}
29+
30+
public init(error: NSError) {
31+
mutableMessage = error.localizedDescription
32+
mutableCode = error.code
33+
mutableDict = error.dict
34+
super.init(domain: error.domain, code: error.code, userInfo: error.userInfo)
35+
}
36+
37+
// MARK: - Getter & Setter
38+
39+
public override var message: String {
40+
get {
41+
return mutableMessage
42+
}
43+
set {
44+
mutableMessage = newValue
45+
}
46+
}
47+
48+
public override var code: Int {
49+
get {
50+
return mutableCode
51+
}
52+
set {
53+
mutableCode = newValue
54+
}
55+
}
56+
57+
public override var dict: [String : Any] {
58+
get {
59+
return mutableDict
60+
}
61+
set {
62+
mutableDict = newValue
63+
}
64+
}
65+
66+
67+
}

Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import XCTest
22
@testable import ACInteractor
33

4+
@available(*, deprecated)
5+
46
class ErrorHandlerExtensionTests: XCTestCase {
57

68
let interactor = TestInteractor()
@@ -40,8 +42,7 @@ class ErrorHandlerExtensionTests: XCTestCase {
4042

4143
// Assert
4244
let errorResponse = onErrorResponse as? InteractorError
43-
XCTAssertEqual(errorResponse?.message, nsErrorMessage)
44-
XCTAssert(errorResponse?.nsError === nsError)
45+
XCTAssert(errorResponse === nsError)
4546
}
4647

4748

Tests/ACInteractorTests/InteractorErrorTests.swift

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,55 @@ import XCTest
33

44
class InteractorErrorTests: XCTestCase {
55

6-
let errorMessage = "errorMessage"
7-
var nsError: NSError!
6+
var testError: NSError?
7+
var testErrorDict = [String: Any]()
88

99
override func setUp() {
1010
super.setUp()
1111
// Put setup code here. This method is called before the invocation of each test method in the class.
1212

13-
self.nsError = NSError(domain: "com.appcron", code: 42, userInfo: [NSLocalizedDescriptionKey: errorMessage])
13+
testError = NSError(domain: "com.appcron", code: 42, userInfo: [NSLocalizedDescriptionKey: "testMessage"])
14+
15+
testErrorDict["key1"] = "value1"
16+
testErrorDict["key2"] = 2
1417
}
1518

16-
// MARK: init
19+
// MARK: - Init
1720

18-
func testInit_withMessage_setsMessage() {
21+
func testInit_withMessage_setsMessageAsLocalizedDescription() {
1922
// Act
20-
let error = InteractorError(message: errorMessage)
23+
let error = InteractorError(message: "testMessage")
2124

2225
// Assert
23-
XCTAssertEqual(error.message, errorMessage)
26+
XCTAssertEqual(error.localizedDescription, "testMessage")
27+
XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as? String, "testMessage")
2428
}
2529

26-
func testInit_withNsError_setsMessage() {
30+
func testInit_withCode_setsCode() {
2731
// Act
28-
let error = InteractorError(error: nsError)
32+
let error = InteractorError(message: "", code: 42)
2933

3034
// Assert
31-
XCTAssertEqual(error.message, errorMessage)
35+
XCTAssertEqual(error.code, 42)
3236
}
3337

34-
func testInit_withNsError_setsNsError() {
38+
func testInit_withDict_setsDict() {
3539
// Act
36-
let error = InteractorError(error: nsError)
40+
let error = InteractorError(message: "", code: 0, dict: testErrorDict)
3741

3842
// Assert
39-
XCTAssertEqual(error.nsError, nsError)
43+
XCTAssertEqual(error.dict["key1"] as? String, "value1")
44+
XCTAssertEqual(error.dict["key2"] as? Int, 2)
4045
}
4146

42-
func testInit_withNsError_setsErrorCode() {
47+
// MARK: - Message
48+
49+
func testMessage_returnsLocalizedDescription() {
4350
// Act
44-
let error = InteractorError(error: nsError)
51+
let message = testError?.message
4552

4653
// Assert
47-
XCTAssertEqual(error.errorCode, 42)
54+
XCTAssertEqual(message, "testMessage")
4855
}
4956

5057
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import XCTest
2+
@testable import ACInteractor
3+
4+
class MutableInteractorErrorTests: XCTestCase {
5+
6+
var testError: MutableInteractorError?
7+
var testErrorDict = [String: Any]()
8+
9+
override func setUp() {
10+
super.setUp()
11+
// Put setup code here. This method is called before the invocation of each test method in the class.
12+
13+
testError = MutableInteractorError(message: "")
14+
15+
testErrorDict["key1"] = "value1"
16+
testErrorDict["key2"] = 2
17+
}
18+
19+
// MARK: - Init
20+
21+
func testInit_withMessage_setsMessage() {
22+
// Act
23+
let error = MutableInteractorError(message: "testMessage")
24+
25+
// Assert
26+
XCTAssertEqual(error.message, "testMessage")
27+
}
28+
29+
func testInit_withCode_setsCode() {
30+
// Act
31+
let error = MutableInteractorError(message: "", code: 42)
32+
33+
// Assert
34+
XCTAssertEqual(error.code, 42)
35+
}
36+
37+
func testInit_withDict_setsDict() {
38+
// Act
39+
let error = MutableInteractorError(message: "", code: 0, dict: testErrorDict)
40+
41+
// Assert
42+
XCTAssertEqual(error.dict["key1"] as? String, "value1")
43+
XCTAssertEqual(error.dict["key2"] as? Int, 2)
44+
}
45+
46+
// MARK: - Init with Error
47+
48+
func testInit_withNsError_copiesValuesFromNsError() {
49+
// Arrange
50+
let userInfo: [String: Any] = [NSLocalizedDescriptionKey: "localizedTestDescription", "key2": 2]
51+
let nsError = NSError(domain: "nserror.domain", code: 13, userInfo: userInfo)
52+
53+
// Act
54+
let error = MutableInteractorError(error: nsError)
55+
56+
// Assert
57+
XCTAssertEqual(error.message, nsError.message)
58+
XCTAssertEqual(error.localizedDescription, nsError.localizedDescription)
59+
60+
XCTAssertEqual(error.code, nsError.code)
61+
XCTAssertEqual(error.domain, nsError.domain)
62+
63+
XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as? String, "localizedTestDescription")
64+
XCTAssertEqual(error.userInfo["key2"] as? Int, 2)
65+
}
66+
67+
func testInit_withInteractorError_copiesValuesFromInteractorError() {
68+
// Arrange
69+
let interactorError = InteractorError(message: "testMessage", code: 42, dict: testErrorDict)
70+
71+
// Act
72+
let error = MutableInteractorError(error: interactorError)
73+
74+
// Assert
75+
XCTAssertEqual(error.message, interactorError.message)
76+
XCTAssertEqual(error.localizedDescription, interactorError.localizedDescription)
77+
78+
XCTAssertEqual(error.code, interactorError.code)
79+
XCTAssertEqual(error.domain, interactorError.domain)
80+
81+
XCTAssertEqual(error.dict["key1"] as? String, "value1")
82+
XCTAssertEqual(error.dict["key2"] as? Int, 2)
83+
}
84+
85+
// MARK: - Setters
86+
87+
func testSetMessage_setsMessage() {
88+
// Act
89+
testError?.message = "newMessage"
90+
91+
// Assert
92+
XCTAssertEqual(testError?.message, "newMessage")
93+
}
94+
95+
func testSetCode_setCode() {
96+
// Act
97+
testError?.code = 42
98+
99+
// Assert
100+
XCTAssertEqual(testError?.code, 42)
101+
}
102+
103+
func testSetDict_setsDict() {
104+
// Act
105+
testError?.dict = testErrorDict
106+
107+
// Assert
108+
XCTAssertEqual(testError?.dict["key1"] as? String, "value1")
109+
XCTAssertEqual(testError?.dict["key2"] as? Int, 2)
110+
}
111+
112+
func testSetDictValue_addsDictValue() {
113+
// Arrange
114+
testError?.dict = testErrorDict
115+
116+
// Act
117+
testError?.dict["newKey"] = "newValue"
118+
119+
// Assert
120+
XCTAssertEqual(testError?.dict["newKey"] as? String, "newValue")
121+
XCTAssertEqual(testError?.dict.count, testErrorDict.count + 1)
122+
}
123+
124+
}

0 commit comments

Comments
 (0)