diff --git a/README.md b/README.md index d31aeac..aa8e5f5 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,16 @@ Observable .disposed(by: disposeBag) ``` + +### Bonus: Result Support + +```swift +let errorHandler = ErrorHandler.default(for: self) +let result: Result = .failure(NetworkError.authenticate) +let user: User? = result.get(onError: errorHandler) +``` + + ## Customization options ### The way actions are performed for errors diff --git a/Sources/SwiftErrorHandler/Extension/Result+ErrorHandler.swift b/Sources/SwiftErrorHandler/Extension/Result+ErrorHandler.swift new file mode 100644 index 0000000..8dd8da3 --- /dev/null +++ b/Sources/SwiftErrorHandler/Extension/Result+ErrorHandler.swift @@ -0,0 +1,20 @@ +// +// Result+ErrorHandler.swift +// SwiftErrorHandler +// +// Created by Stefan Renne on 30/12/2019. +// + +import Foundation + +public extension Result { + + func get(onError handler: ErrorHandler, onErrorCompleted: OnErrorHandled = nil) -> Success? { + do { + return try get() + } catch { + handler.handle(error: error, onCompleted: onErrorCompleted) + return nil + } + } +} diff --git a/Tests/SwiftErrorHandlerTests/Helpers/MockedView.swift b/Tests/SwiftErrorHandlerTests/Helpers/MockedView.swift index 26c9d41..f9783fe 100644 --- a/Tests/SwiftErrorHandlerTests/Helpers/MockedView.swift +++ b/Tests/SwiftErrorHandlerTests/Helpers/MockedView.swift @@ -16,7 +16,7 @@ class MockedView: ErrorHandlerView { private let onCompletedGroups: DispatchGroup var lastResult: UIAlertController? - init(numberExpectedPresentedAlerts: Int, numberExpectedCustomHandlers: Int, numberExpectedonCompleted: Int) { + init(numberExpectedPresentedAlerts: Int = 0, numberExpectedCustomHandlers: Int = 0, numberExpectedonCompleted: Int = 0) { presentedAlertsGroups = DispatchGroup.enter(number: numberExpectedPresentedAlerts) customHandlersGroup = DispatchGroup.enter(number: numberExpectedCustomHandlers) onCompletedGroups = DispatchGroup.enter(number: numberExpectedonCompleted) diff --git a/Tests/SwiftErrorHandlerTests/ResultErrorHandlerTests.swift b/Tests/SwiftErrorHandlerTests/ResultErrorHandlerTests.swift new file mode 100644 index 0000000..f741765 --- /dev/null +++ b/Tests/SwiftErrorHandlerTests/ResultErrorHandlerTests.swift @@ -0,0 +1,146 @@ +// +// ResultErrorHandlerTests.swift +// SwiftErrorHandlerTests +// +// Created by Stefan Renne on 30/12/2019. +// + +import XCTest +@testable import SwiftErrorHandler + +class ResultErrorHandlerTests: XCTestCase { + + func testItWontHandleSuccessResults() throws { + let view = MockedView() + let handler = ErrorHandler(for: view) + + let result: Result = .success("win") + XCTAssertNotNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + } + + func testItCanHandleSpecificErrors() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 1, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItCantHandleSpecificErrorsWhereThereAreNoSpecificHandlers() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 1, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error2) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertFalse(view.didHandleResult()) + } + + func testItCanFallbackToADefaultHandler() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 1, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.unexpectedHandlerExecuted)) + .onNoMatch(.perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error2) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItPrefersASpecficHandlerAboveTheDefaultHandler() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 1, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + .onNoMatch(.perform(action: view.unexpectedHandlerExecuted)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItCanExecuteMultupleMatches() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 2, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + .onNoMatch(.perform(action: view.unexpectedHandlerExecuted)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItCanHaveHandlersThatAlwaysGetExecuted() throws { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 2, numberExpectedonCompleted: 1) + let handler = ErrorHandler(for: view) + .on(error: .type(HandlerError1.error1), then: .perform(action: view.customHandler)) + .onNoMatch(.perform(action: view.unexpectedHandlerExecuted)) + .always(.perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: view.onCompleted)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItCanHaveMultipleAlwaysHandlers() { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 3, numberExpectedonCompleted: 0) + let handler = ErrorHandler(for: view) + .always(.perform(action: view.customHandler)) + .always(.perform(action: view.customHandler)) + .always(.perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: nil)) + + XCTAssertTrue(view.didHandleResult()) + } + + func testItCanHaveMultipleDefaultHandlers() { + let view = MockedView(numberExpectedPresentedAlerts: 0, numberExpectedCustomHandlers: 3, numberExpectedonCompleted: 0) + let handler = ErrorHandler(for: view) + .onNoMatch(.perform(action: view.customHandler)) + .onNoMatch(.perform(action: view.customHandler)) + .onNoMatch(.perform(action: view.customHandler)) + + let result: Result = .failure(HandlerError1.error1) + XCTAssertNil(result.get(onError: handler, onErrorCompleted: nil)) + + XCTAssertTrue(view.didHandleResult()) + } +} + +extension ResultErrorHandlerTests { + private enum HandlerError1: Error { + case error1 + case error2 + case error3 + } + + private enum HandlerError2: Error { + case error4 + } + +} + +extension ResultErrorHandlerTests { + + static var allTests = [ + ("testItWontHandleSuccessResults", testItWontHandleSuccessResults), + ("testItCanHandleSpecificErrors", testItCanHandleSpecificErrors), + ("testItCantHandleSpecificErrorsWhereThereAreNoSpecificHandlers", testItCantHandleSpecificErrorsWhereThereAreNoSpecificHandlers), + ("testItCanFallbackToADefaultHandler", testItCanFallbackToADefaultHandler), + ("testItPrefersASpecficHandlerAboveTheDefaultHandler", testItPrefersASpecficHandlerAboveTheDefaultHandler), + ("testItCanExecuteMultupleMatches", testItCanExecuteMultupleMatches), + ("testItCanHaveHandlersThatAlwaysGetExecuted", testItCanHaveHandlersThatAlwaysGetExecuted), + ("testItCanHaveMultipleAlwaysHandlers", testItCanHaveMultipleAlwaysHandlers), + ("testItCanHaveMultipleDefaultHandlers", testItCanHaveMultipleDefaultHandlers) + ] +} diff --git a/Tests/SwiftErrorHandlerTests/XCTestManifests.swift b/Tests/SwiftErrorHandlerTests/XCTestManifests.swift index 0dc9724..4123658 100644 --- a/Tests/SwiftErrorHandlerTests/XCTestManifests.swift +++ b/Tests/SwiftErrorHandlerTests/XCTestManifests.swift @@ -5,6 +5,7 @@ public func allTests() -> [XCTestCaseEntry] { return [ testCase(ActionHandlerTests.allTests), testCase(ErrorHandlerTests.allTests), + testCase(ResultErrorHandlerTests.allTests), testCase(ErrorMatcherTests.allTests) ] }