diff --git a/Sources/ErrorHandlerExtension.swift b/Sources/ErrorHandlerExtension.swift index d18ca09..367d87e 100644 --- a/Sources/ErrorHandlerExtension.swift +++ b/Sources/ErrorHandlerExtension.swift @@ -7,14 +7,10 @@ public protocol ErrorHandler { public extension ErrorHandler where Self: Interactor { + @available(*, deprecated) func handleError(_ request: ErrorRequest, error: Error) { - if let error = error as? InteractorError { - request.onError?(error) - } else { - let nsError = error as NSError - let errorWrapper = InteractorError(error: nsError) - request.onError?(errorWrapper) - } + let error = error as InteractorError + request.onError?(error) } } diff --git a/Sources/InteractorError.swift b/Sources/InteractorError.swift index 40b8df9..0390f84 100644 --- a/Sources/InteractorError.swift +++ b/Sources/InteractorError.swift @@ -1,19 +1,45 @@ import Foundation -open class InteractorError: Error { +public typealias InteractorError = NSError + +public extension InteractorError { + + private static let dictKey = "InteractorErrorDictKey" + + // MARK: - Init + + public convenience init(message: String, code: Int, dict: [String: Any]) { + var infoDict = [String : Any]() + infoDict[NSLocalizedDescriptionKey] = message + infoDict[InteractorError.dictKey] = dict + self.init(domain: "com.appcron.acinteractor", code: code, userInfo: infoDict) + } - open var message: String - open var errorCode = 0 - open var nsError: NSError? + public convenience init(message: String, code: Int) { + self.init(message: message, code: code, dict: [String: Any]()) + } - public init(message:String) { - self.message = message + public convenience init(message: String) { + self.init(message: message, code: 0) } - public init(error:NSError) { - self.message = error.localizedDescription - self.errorCode = error.code - self.nsError = error + // MARK: - Message + + public var message: String { + get { + return userInfo[NSLocalizedDescriptionKey] as? String ?? "" + } + } + + // MARK: - Error Dict + + public var dict: [String: Any] { + get { + guard let dict = userInfo[InteractorError.dictKey] as? [String: Any] else { + return [String: Any]() + } + return dict + } } } diff --git a/Sources/MutableInteractorError.swift b/Sources/MutableInteractorError.swift new file mode 100644 index 0000000..7e6fcd4 --- /dev/null +++ b/Sources/MutableInteractorError.swift @@ -0,0 +1,67 @@ +import Foundation + +public class MutableInteractorError: InteractorError { + + private var mutableMessage: String + private var mutableCode: Int + private var mutableDict: [String : Any] + + // MARK: - Init + + public init(message: String, code: Int, dict: [String: Any]) { + mutableMessage = message + mutableCode = code + mutableDict = dict + super.init(domain: "com.appcron.acinteractor", code: code, userInfo: nil) + } + + public convenience init(message: String, code: Int) { + self.init(message: message, code: code, dict: [String: Any]()) + } + + public convenience init(message: String) { + self.init(message: message, code: 0) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public init(error: NSError) { + mutableMessage = error.localizedDescription + mutableCode = error.code + mutableDict = error.dict + super.init(domain: error.domain, code: error.code, userInfo: error.userInfo) + } + + // MARK: - Getter & Setter + + public override var message: String { + get { + return mutableMessage + } + set { + mutableMessage = newValue + } + } + + public override var code: Int { + get { + return mutableCode + } + set { + mutableCode = newValue + } + } + + public override var dict: [String : Any] { + get { + return mutableDict + } + set { + mutableDict = newValue + } + } + + +} diff --git a/Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift b/Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift index 99751da..47dac34 100644 --- a/Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift +++ b/Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift @@ -1,6 +1,8 @@ import XCTest @testable import ACInteractor +@available(*, deprecated) + class ErrorHandlerExtensionTests: XCTestCase { let interactor = TestInteractor() @@ -40,8 +42,7 @@ class ErrorHandlerExtensionTests: XCTestCase { // Assert let errorResponse = onErrorResponse as? InteractorError - XCTAssertEqual(errorResponse?.message, nsErrorMessage) - XCTAssert(errorResponse?.nsError === nsError) + XCTAssert(errorResponse === nsError) } diff --git a/Tests/ACInteractorTests/InteractorErrorTests.swift b/Tests/ACInteractorTests/InteractorErrorTests.swift index 60e0954..c38bb82 100644 --- a/Tests/ACInteractorTests/InteractorErrorTests.swift +++ b/Tests/ACInteractorTests/InteractorErrorTests.swift @@ -3,48 +3,55 @@ import XCTest class InteractorErrorTests: XCTestCase { - let errorMessage = "errorMessage" - var nsError: NSError! + var testError: NSError? + var testErrorDict = [String: Any]() override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. - self.nsError = NSError(domain: "com.appcron", code: 42, userInfo: [NSLocalizedDescriptionKey: errorMessage]) + testError = NSError(domain: "com.appcron", code: 42, userInfo: [NSLocalizedDescriptionKey: "testMessage"]) + + testErrorDict["key1"] = "value1" + testErrorDict["key2"] = 2 } - // MARK: init + // MARK: - Init - func testInit_withMessage_setsMessage() { + func testInit_withMessage_setsMessageAsLocalizedDescription() { // Act - let error = InteractorError(message: errorMessage) + let error = InteractorError(message: "testMessage") // Assert - XCTAssertEqual(error.message, errorMessage) + XCTAssertEqual(error.localizedDescription, "testMessage") + XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as? String, "testMessage") } - func testInit_withNsError_setsMessage() { + func testInit_withCode_setsCode() { // Act - let error = InteractorError(error: nsError) + let error = InteractorError(message: "", code: 42) // Assert - XCTAssertEqual(error.message, errorMessage) + XCTAssertEqual(error.code, 42) } - func testInit_withNsError_setsNsError() { + func testInit_withDict_setsDict() { // Act - let error = InteractorError(error: nsError) + let error = InteractorError(message: "", code: 0, dict: testErrorDict) // Assert - XCTAssertEqual(error.nsError, nsError) + XCTAssertEqual(error.dict["key1"] as? String, "value1") + XCTAssertEqual(error.dict["key2"] as? Int, 2) } - func testInit_withNsError_setsErrorCode() { + // MARK: - Message + + func testMessage_returnsLocalizedDescription() { // Act - let error = InteractorError(error: nsError) + let message = testError?.message // Assert - XCTAssertEqual(error.errorCode, 42) + XCTAssertEqual(message, "testMessage") } } diff --git a/Tests/ACInteractorTests/MutableInteractorErrorTests.swift b/Tests/ACInteractorTests/MutableInteractorErrorTests.swift new file mode 100644 index 0000000..78dad31 --- /dev/null +++ b/Tests/ACInteractorTests/MutableInteractorErrorTests.swift @@ -0,0 +1,124 @@ +import XCTest +@testable import ACInteractor + +class MutableInteractorErrorTests: XCTestCase { + + var testError: MutableInteractorError? + var testErrorDict = [String: Any]() + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + + testError = MutableInteractorError(message: "") + + testErrorDict["key1"] = "value1" + testErrorDict["key2"] = 2 + } + + // MARK: - Init + + func testInit_withMessage_setsMessage() { + // Act + let error = MutableInteractorError(message: "testMessage") + + // Assert + XCTAssertEqual(error.message, "testMessage") + } + + func testInit_withCode_setsCode() { + // Act + let error = MutableInteractorError(message: "", code: 42) + + // Assert + XCTAssertEqual(error.code, 42) + } + + func testInit_withDict_setsDict() { + // Act + let error = MutableInteractorError(message: "", code: 0, dict: testErrorDict) + + // Assert + XCTAssertEqual(error.dict["key1"] as? String, "value1") + XCTAssertEqual(error.dict["key2"] as? Int, 2) + } + + // MARK: - Init with Error + + func testInit_withNsError_copiesValuesFromNsError() { + // Arrange + let userInfo: [String: Any] = [NSLocalizedDescriptionKey: "localizedTestDescription", "key2": 2] + let nsError = NSError(domain: "nserror.domain", code: 13, userInfo: userInfo) + + // Act + let error = MutableInteractorError(error: nsError) + + // Assert + XCTAssertEqual(error.message, nsError.message) + XCTAssertEqual(error.localizedDescription, nsError.localizedDescription) + + XCTAssertEqual(error.code, nsError.code) + XCTAssertEqual(error.domain, nsError.domain) + + XCTAssertEqual(error.userInfo[NSLocalizedDescriptionKey] as? String, "localizedTestDescription") + XCTAssertEqual(error.userInfo["key2"] as? Int, 2) + } + + func testInit_withInteractorError_copiesValuesFromInteractorError() { + // Arrange + let interactorError = InteractorError(message: "testMessage", code: 42, dict: testErrorDict) + + // Act + let error = MutableInteractorError(error: interactorError) + + // Assert + XCTAssertEqual(error.message, interactorError.message) + XCTAssertEqual(error.localizedDescription, interactorError.localizedDescription) + + XCTAssertEqual(error.code, interactorError.code) + XCTAssertEqual(error.domain, interactorError.domain) + + XCTAssertEqual(error.dict["key1"] as? String, "value1") + XCTAssertEqual(error.dict["key2"] as? Int, 2) + } + + // MARK: - Setters + + func testSetMessage_setsMessage() { + // Act + testError?.message = "newMessage" + + // Assert + XCTAssertEqual(testError?.message, "newMessage") + } + + func testSetCode_setCode() { + // Act + testError?.code = 42 + + // Assert + XCTAssertEqual(testError?.code, 42) + } + + func testSetDict_setsDict() { + // Act + testError?.dict = testErrorDict + + // Assert + XCTAssertEqual(testError?.dict["key1"] as? String, "value1") + XCTAssertEqual(testError?.dict["key2"] as? Int, 2) + } + + func testSetDictValue_addsDictValue() { + // Arrange + testError?.dict = testErrorDict + + // Act + testError?.dict["newKey"] = "newValue" + + // Assert + XCTAssertEqual(testError?.dict["newKey"] as? String, "newValue") + XCTAssertEqual(testError?.dict.count, testErrorDict.count + 1) + } + +}