Skip to content
This repository was archived by the owner on Mar 29, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions Sources/Fallback.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,50 @@ public func fallback<T>(
throw error
}
}

public enum Tryable<T> {
case success(T)
case failure(Error)

public func `catch`(_ closure: @escaping (Error) throws -> T) -> Tryable<T> {
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<T>(_ closure: () throws -> T) -> Tryable<T> {
do {
return .success(try closure())
} catch (let error) {
return .failure(error)
}
}
185 changes: 178 additions & 7 deletions Tests/FallbackTests/FallbackTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ struct TestError<T>: Error {
}
}

func get<T>(_ value: T, throws: Bool) throws -> T {
if `throws` {
throw TestError(value)
}
return value
}

final class FallbackTests: XCTestCase {

static var allTests: [(String, (FallbackTests) -> () throws -> Void)] {
Expand All @@ -20,13 +27,6 @@ final class FallbackTests: XCTestCase {
]
}

func get<T>(_ value: T, throws: Bool) throws -> T {
if `throws` {
throw TestError(value)
}
return value
}

func testFallback_throws() {
XCTAssertThrowsError(
try fallback(
Expand Down Expand Up @@ -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"
)
}

}