From ba47b5892fe94c593f726a5a82cb47a761df9137 Mon Sep 17 00:00:00 2001 From: Suyeol Jeon Date: Thu, 27 Oct 2016 06:51:42 +0900 Subject: [PATCH] Add support chaining --- Sources/Fallback.swift | 47 ++++++ Tests/FallbackTests/FallbackTests.swift | 185 +++++++++++++++++++++++- 2 files changed, 225 insertions(+), 7 deletions(-) diff --git a/Sources/Fallback.swift b/Sources/Fallback.swift index c585ac6..25add55 100644 --- a/Sources/Fallback.swift +++ b/Sources/Fallback.swift @@ -89,3 +89,50 @@ public func fallback( throw error } } + +public enum Tryable { + case success(T) + case failure(Error) + + public func `catch`(_ closure: @escaping (Error) throws -> T) -> Tryable { + switch self { + case .success: + return self + + case .failure(let error): + do { + return .success(try closure(error)) + } catch (let error) { + return .failure(error) + } + } + } + + public func rethrow() throws -> T { + switch self { + case .success(let value): + return value + + case .failure(let error): + throw error + } + } + + public func finally(_ closure: @escaping (Error) -> T) -> T { + switch self { + case .success(let value): + return value + + case .failure(let error): + return closure(error) + } + } +} + +public func fallback(_ closure: () throws -> T) -> Tryable { + do { + return .success(try closure()) + } catch (let error) { + return .failure(error) + } +} diff --git a/Tests/FallbackTests/FallbackTests.swift b/Tests/FallbackTests/FallbackTests.swift index 1196df9..39b961b 100644 --- a/Tests/FallbackTests/FallbackTests.swift +++ b/Tests/FallbackTests/FallbackTests.swift @@ -8,6 +8,13 @@ struct TestError: Error { } } +func get(_ value: T, throws: Bool) throws -> T { + if `throws` { + throw TestError(value) + } + return value +} + final class FallbackTests: XCTestCase { static var allTests: [(String, (FallbackTests) -> () throws -> Void)] { @@ -20,13 +27,6 @@ final class FallbackTests: XCTestCase { ] } - func get(_ value: T, throws: Bool) throws -> T { - if `throws` { - throw TestError(value) - } - return value - } - func testFallback_throws() { XCTAssertThrowsError( try fallback( @@ -256,4 +256,175 @@ final class FallbackTests: XCTestCase { ) } + func testFallbackTryableRethrow_throws() { + XCTAssertThrowsError( + try fallback { + return try get("a", throws: true) + }.rethrow() + ) + XCTAssertThrowsError( + try fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: true) + }.rethrow() + ) + XCTAssertThrowsError( + try fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: true) + }.catch { error in + return try get("c", throws: true) + }.rethrow() + ) + } + + func testFallbackTryableRethrow() { + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.rethrow(), + "a" + ) + + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: true) + }.rethrow(), + "a" + ) + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: false) + }.rethrow(), + "a" + ) + + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: true) + }.catch { error in + return try get("c", throws: true) + }.rethrow(), + "a" + ) + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: false) + }.catch { error in + return try get("c", throws: true) + }.rethrow(), + "a" + ) + XCTAssertEqual( + try fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: false) + }.catch { error in + return try get("c", throws: false) + }.rethrow(), + "a" + ) + XCTAssertEqual( + try fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: false) + }.catch { error in + return try get("c", throws: false) + }.rethrow(), + "b" + ) + XCTAssertEqual( + try fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: true) + }.catch { error in + return try get("c", throws: false) + }.rethrow(), + "c" + ) + } + + func testFallbackTryableFinally() { + XCTAssertEqual( + fallback { + return try get("a", throws: true) + }.finally { error in + return "none" + }, + "none" + ) + XCTAssertEqual( + fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: true) + }.finally { error in + return "none" + }, + "none" + ) + XCTAssertEqual( + fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: true) + }.catch { error in + return try get("c", throws: true) + }.finally { error in + return "none" + }, + "none" + ) + + XCTAssertEqual( + fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: true) + }.catch { error in + return try get("c", throws: true) + }.finally { error in + return "none" + }, + "a" + ) + XCTAssertEqual( + fallback { + return try get("a", throws: false) + }.catch { error in + return try get("b", throws: false) + }.catch { error in + return try get("c", throws: true) + }.finally { error in + return "none" + }, + "a" + ) + XCTAssertEqual( + fallback { + return try get("a", throws: true) + }.catch { error in + return try get("b", throws: false) + }.catch { error in + return try get("c", throws: false) + }.finally { error in + return "none" + }, + "b" + ) + } + }