Skip to content

Commit 3a4d783

Browse files
author
Florian Rieger
authored
Merge pull request #10 from AppCron/generic-error-handling
Generic error handling
2 parents bcaecb0 + ab1cd8e commit 3a4d783

File tree

9 files changed

+140
-4
lines changed

9 files changed

+140
-4
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Foundation
2+
3+
public protocol ErrorHandler {
4+
func handleError(request: ErrorRequest, error: ErrorType)
5+
}
6+
7+
8+
public extension ErrorHandler where Self: Interactor {
9+
10+
func handleError(request: ErrorRequest, error: ErrorType) {
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+
}
18+
}
19+
20+
}

Sources/Interactor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
public protocol Interactor: AnyObject {
3+
public protocol Interactor: AnyObject, ErrorHandler {
44
associatedtype Request
55
func execute(request: Request)
66
}

Sources/InteractorError.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Foundation
33
public class InteractorError: ErrorType {
44

55
public var message: String
6+
public var errorCode = 0
67
public var nsError: NSError?
78

89
public init(message:String) {
@@ -11,6 +12,8 @@ public class InteractorError: ErrorType {
1112

1213
public init(error:NSError) {
1314
self.message = error.localizedDescription
15+
self.errorCode = error.code
1416
self.nsError = error
1517
}
16-
}
18+
19+
}

Sources/LazyInteractor.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,12 @@ class LazyInteractor<InteractorType: Interactor>: Interactor {
2525
}
2626

2727
}
28+
29+
30+
extension LazyInteractor: ErrorHandler {
31+
32+
func handleError(request: ErrorRequest, error: ErrorType) {
33+
self.getInteractor().handleError(request, error: error)
34+
}
35+
36+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import XCTest
2+
@testable import ACInteractor
3+
4+
class ErrorHandlerExtensionTests: XCTestCase {
5+
6+
let interactor = TestInteractor()
7+
let request = TestInteractor.Request()
8+
var onErrorResponse: ErrorType?
9+
10+
override func setUp() {
11+
super.setUp()
12+
// Put setup code here. This method is called before the invocation of each test method in the class.
13+
14+
request.onError = { [unowned self] (error: ErrorType) in
15+
self.onErrorResponse = error
16+
}
17+
}
18+
19+
// MARK: handleError()
20+
21+
func testHandleError_withInteractorError_callsOnError_withInteractorError() {
22+
// Arrange
23+
let error = InteractorError(message: "TestError")
24+
25+
// Act
26+
interactor.handleError(request, error: error)
27+
28+
// Assert
29+
let errorResponse = onErrorResponse as? InteractorError
30+
XCTAssert(errorResponse === error)
31+
}
32+
33+
func testHandleError_withNsError_callsOnError_withWrappedNsError() {
34+
// Arrange
35+
let nsErrorMessage = "NSError Message"
36+
let nsError = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: nsErrorMessage])
37+
38+
// Act
39+
interactor.handleError(request, error: nsError)
40+
41+
// Assert
42+
let errorResponse = onErrorResponse as? InteractorError
43+
XCTAssertEqual(errorResponse?.message, nsErrorMessage)
44+
XCTAssert(errorResponse?.nsError === nsError)
45+
}
46+
47+
48+
// MARK: Test Interactor
49+
50+
class TestInteractor: Interactor {
51+
class Request: InteractorRequest<Void> {
52+
}
53+
54+
func execute(request: Request) {
55+
}
56+
}
57+
58+
59+
// MARK: Test Error
60+
61+
class TestError: ErrorType {
62+
}
63+
64+
}

Tests/InteractorErrorTests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,12 @@ class InteractorErrorTests: XCTestCase {
3939
XCTAssertEqual(error.nsError, nsError)
4040
}
4141

42+
func testInit_withNsError_setsErrorCode() {
43+
// Act
44+
let error = InteractorError(error: nsError)
45+
46+
// Assert
47+
XCTAssertEqual(error.errorCode, 42)
48+
}
49+
4250
}

Tests/InteractorExecuterTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class InteractorTests: XCTestCase {
1616
super.setUp()
1717
// Put setup code here. This method is called before the invocation of each test method in the class.
1818

19-
firstRequest.onError = { (error: InteractorError) -> Void in
19+
firstRequest.onError = { [unowned self] (error: InteractorError) -> Void in
2020
self.errorMessageFromFirstRequest = error.message
2121
}
2222
}

Tests/LazyInteractorTests.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,33 @@ class LazyInteractorTests: XCTestCase {
6060
XCTAssert(interactor.executedRequest === request)
6161
}
6262

63+
// MARK: handleError()
6364

64-
// MARK: Test Interactors
65+
func testHandleError_callsHandleErrorOfInteractor() {
66+
// Arrange
67+
let request = TestInteractor.Request()
68+
let error = InteractorError(message: "TestError")
69+
70+
// Act
71+
lazyInteractor.handleError(request, error: error)
72+
73+
// Assert
74+
let interactor = lazyInteractor.getInteractor()
75+
XCTAssert(interactor.handledErrorRequest === request)
76+
XCTAssert(interactor.handledError as? AnyObject === error)
77+
}
78+
79+
80+
// MARK: Test Interactor
6581

6682
class TestInteractor: Interactor {
6783
let dependency: String
6884
var numberOfExceuteCalls = 0
6985
var executedRequest: Request?
7086

87+
var handledErrorRequest: ErrorRequest?
88+
var handledError: ErrorType?
89+
7190
init(dependency: String) {
7291
self.dependency = dependency
7392
}
@@ -79,6 +98,11 @@ class LazyInteractorTests: XCTestCase {
7998
self.numberOfExceuteCalls += 1
8099
self.executedRequest = request
81100
}
101+
102+
func handleError(request: ErrorRequest, error: ErrorType) {
103+
self.handledErrorRequest = request
104+
self.handledError = error
105+
}
82106
}
83107

84108
}

Xcode/ACInteractor.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
173A77D21D3849E200FF88BA /* ACInteractor.h in Headers */ = {isa = PBXBuildFile; fileRef = 173A77431D3849E100FF88BA /* ACInteractor.h */; settings = {ATTRIBUTES = (Public, ); }; };
1616
17567E551D3A61C900C464BB /* InteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17567E541D3A61C900C464BB /* InteractorError.swift */; };
1717
17567E591D3A640000C464BB /* InteractorErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17567E581D3A640000C464BB /* InteractorErrorTests.swift */; };
18+
1794818F1D57475000CA3590 /* ErrorHandlerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1794818E1D57475000CA3590 /* ErrorHandlerExtension.swift */; };
19+
179481921D5749A800CA3590 /* ErrorHandlerExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179481901D57490900CA3590 /* ErrorHandlerExtensionTests.swift */; };
1820
17B0BF701D3CD057004AA98B /* LazyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B0BF6F1D3CD057004AA98B /* LazyInteractor.swift */; };
1921
17B0BF721D3CD0A9004AA98B /* LazyInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B0BF711D3CD0A9004AA98B /* LazyInteractorTests.swift */; };
2022
/* End PBXBuildFile section */
@@ -40,6 +42,8 @@
4042
173A77D11D3849E200FF88BA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4143
17567E541D3A61C900C464BB /* InteractorError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractorError.swift; sourceTree = "<group>"; };
4244
17567E581D3A640000C464BB /* InteractorErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractorErrorTests.swift; sourceTree = "<group>"; };
45+
1794818E1D57475000CA3590 /* ErrorHandlerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorHandlerExtension.swift; sourceTree = "<group>"; };
46+
179481901D57490900CA3590 /* ErrorHandlerExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorHandlerExtensionTests.swift; sourceTree = "<group>"; };
4347
17B0BF6F1D3CD057004AA98B /* LazyInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyInteractor.swift; sourceTree = "<group>"; };
4448
17B0BF711D3CD0A9004AA98B /* LazyInteractorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyInteractorTests.swift; sourceTree = "<group>"; };
4549
/* End PBXFileReference section */
@@ -90,6 +94,7 @@
9094
17567E541D3A61C900C464BB /* InteractorError.swift */,
9195
173A77381D3844D400FF88BA /* InteractorExecuter.swift */,
9296
17B0BF6F1D3CD057004AA98B /* LazyInteractor.swift */,
97+
1794818E1D57475000CA3590 /* ErrorHandlerExtension.swift */,
9398
);
9499
name = Sources;
95100
path = ../Sources;
@@ -101,6 +106,7 @@
101106
173A77401D38461D00FF88BA /* InteractorExecuterTests.swift */,
102107
17567E581D3A640000C464BB /* InteractorErrorTests.swift */,
103108
17B0BF711D3CD0A9004AA98B /* LazyInteractorTests.swift */,
109+
179481901D57490900CA3590 /* ErrorHandlerExtensionTests.swift */,
104110
);
105111
name = Tests;
106112
path = ../Tests;
@@ -228,6 +234,7 @@
228234
173A773C1D3844D400FF88BA /* InteractorExecuter.swift in Sources */,
229235
173A773D1D3844D400FF88BA /* InteractorRequest.swift in Sources */,
230236
17B0BF701D3CD057004AA98B /* LazyInteractor.swift in Sources */,
237+
1794818F1D57475000CA3590 /* ErrorHandlerExtension.swift in Sources */,
231238
);
232239
runOnlyForDeploymentPostprocessing = 0;
233240
};
@@ -237,6 +244,7 @@
237244
files = (
238245
17B0BF721D3CD0A9004AA98B /* LazyInteractorTests.swift in Sources */,
239246
173A77411D38461D00FF88BA /* InteractorExecuterTests.swift in Sources */,
247+
179481921D5749A800CA3590 /* ErrorHandlerExtensionTests.swift in Sources */,
240248
17567E591D3A640000C464BB /* InteractorErrorTests.swift in Sources */,
241249
);
242250
runOnlyForDeploymentPostprocessing = 0;

0 commit comments

Comments
 (0)