Skip to content

Commit

Permalink
Merge pull request #15 from AppCron/improved-nserror-handling
Browse files Browse the repository at this point in the history
Improved NSError handling
  • Loading branch information
Florian Rieger authored Apr 21, 2017
2 parents 2b07702 + bf8aebf commit 4c9e137
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 35 deletions.
10 changes: 3 additions & 7 deletions Sources/ErrorHandlerExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

}
46 changes: 36 additions & 10 deletions Sources/InteractorError.swift
Original file line number Diff line number Diff line change
@@ -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
}
}

}
67 changes: 67 additions & 0 deletions Sources/MutableInteractorError.swift
Original file line number Diff line number Diff line change
@@ -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
}
}


}
5 changes: 3 additions & 2 deletions Tests/ACInteractorTests/ErrorHandlerExtensionTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import XCTest
@testable import ACInteractor

@available(*, deprecated)

class ErrorHandlerExtensionTests: XCTestCase {

let interactor = TestInteractor()
Expand Down Expand Up @@ -40,8 +42,7 @@ class ErrorHandlerExtensionTests: XCTestCase {

// Assert
let errorResponse = onErrorResponse as? InteractorError
XCTAssertEqual(errorResponse?.message, nsErrorMessage)
XCTAssert(errorResponse?.nsError === nsError)
XCTAssert(errorResponse === nsError)
}


Expand Down
39 changes: 23 additions & 16 deletions Tests/ACInteractorTests/InteractorErrorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

}
124 changes: 124 additions & 0 deletions Tests/ACInteractorTests/MutableInteractorErrorTests.swift
Original file line number Diff line number Diff line change
@@ -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)
}

}

0 comments on commit 4c9e137

Please sign in to comment.