mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Make `init(catching:)` and `get()` use typed throws. The former infers the `Failure` type from the closure provided (once full type inference is in place) and the latter only throws errors of the `Failure` type.
211 lines
4.8 KiB
Swift
211 lines
4.8 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import Swift
|
|
|
|
let ResultTests = TestSuite("Result")
|
|
|
|
fileprivate enum Err: Error, Equatable {
|
|
case err
|
|
case derr
|
|
}
|
|
|
|
fileprivate let string = "string"
|
|
|
|
fileprivate extension Result {
|
|
var success: Success? {
|
|
switch self {
|
|
case let .success(success):
|
|
return success
|
|
case .failure:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var failure: Failure? {
|
|
switch self {
|
|
case .success:
|
|
return nil
|
|
case let .failure(failure):
|
|
return failure
|
|
}
|
|
}
|
|
}
|
|
|
|
ResultTests.test("Construction") {
|
|
let result1: Result<String, Err> = .success(string)
|
|
let result2: Result<String, Err> = .failure(.err)
|
|
let string1: String? = {
|
|
switch result1 {
|
|
case let .success(string):
|
|
return string
|
|
case .failure:
|
|
expectUnreachable()
|
|
return nil
|
|
}
|
|
}()
|
|
let error: Err? = {
|
|
switch result2 {
|
|
case let .failure(failure):
|
|
return failure
|
|
case .success:
|
|
expectUnreachable()
|
|
return nil
|
|
}
|
|
}()
|
|
|
|
expectEqual(string, string1)
|
|
expectEqual(.err, error)
|
|
}
|
|
|
|
ResultTests.test("Throwing Initialization and Unwrapping") {
|
|
func notThrowing() throws -> String {
|
|
return string
|
|
}
|
|
|
|
func throwing() throws -> String {
|
|
throw Err.err
|
|
}
|
|
|
|
func throwingTyped() throws(Err) -> String {
|
|
throw .err
|
|
}
|
|
|
|
func knownNotThrowing() -> String { return string }
|
|
|
|
let result1 = Result { try throwing() }
|
|
let result2 = Result { try notThrowing() }
|
|
|
|
expectEqual(result1.failure as? Err, Err.err)
|
|
expectEqual(result2.success, string)
|
|
|
|
do {
|
|
_ = try result1.get()
|
|
} catch let error as Err {
|
|
expectEqual(error, Err.err)
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
|
|
do {
|
|
let unwrapped = try result2.get()
|
|
expectEqual(unwrapped, string)
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
|
|
// Test unwrapping strongly typed error.
|
|
let result3 = Result<String, Err>.failure(Err.err)
|
|
do {
|
|
_ = try result3.get()
|
|
} catch let error as Err {
|
|
expectEqual(error, Err.err)
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
|
|
// Test strongly typed error via closure.
|
|
// FIXME: Type inference should eliminate the need for the throws(Err)
|
|
// annotations below.
|
|
let result4 = Result { () throws(Err) in try throwingTyped() }
|
|
let _: Result<String, Err> = result4 // check the type
|
|
expectEqual(result4.failure, .err)
|
|
do throws(Err) {
|
|
_ = try result4.get()
|
|
} catch let error {
|
|
expectEqual(error, .err)
|
|
}
|
|
|
|
let result5 = Result { knownNotThrowing() }
|
|
let _: Result<String, Never> = result5 // check the type
|
|
_ = result5.get() // no need for 'try'
|
|
}
|
|
|
|
ResultTests.test("Functional Transforms") {
|
|
func transformDouble(_ int: Int) -> Int {
|
|
return 2 * int
|
|
}
|
|
|
|
func transformTriple(_ int: Int) -> Int {
|
|
return 3 * int
|
|
}
|
|
|
|
func transformError(_ err: Err) -> Err {
|
|
if err == .err {
|
|
return .derr
|
|
} else {
|
|
return .err
|
|
}
|
|
}
|
|
|
|
func resultValueTransform(_ int: Int) -> Result<Int, Err> {
|
|
return .success(transformDouble(int))
|
|
}
|
|
|
|
func resultErrorTransform(_ err: Err) -> Result<Int, Err> {
|
|
return .failure(transformError(err))
|
|
}
|
|
|
|
let result1: Result<Int, Err> = .success(1)
|
|
let newResult1 = result1.map(transformDouble)
|
|
|
|
expectEqual(newResult1, .success(2))
|
|
|
|
let result2: Result<Int, Err> = .failure(.err)
|
|
let newResult2 = result2.mapError(transformError)
|
|
|
|
expectEqual(newResult2, .failure(.derr))
|
|
|
|
let result3: Result<Int, Err> = .success(1)
|
|
let newResult3 = result3.flatMap(resultValueTransform)
|
|
|
|
expectEqual(newResult3, .success(2))
|
|
|
|
let result4: Result<Int, Err> = .failure(.derr)
|
|
let newResult4 = result4.flatMapError(resultErrorTransform)
|
|
|
|
expectEqual(newResult4, .failure(.err))
|
|
}
|
|
|
|
ResultTests.test("Equatable") {
|
|
let result1: Result<Int, Err> = .success(1)
|
|
let result2: Result<Int, Err> = .failure(.err)
|
|
|
|
expectEqual(result1, .success(1))
|
|
expectNotEqual(result1, .success(2))
|
|
expectNotEqual(result1, .failure(.err))
|
|
expectNotEqual(result1, .failure(.derr))
|
|
|
|
expectNotEqual(result2, .success(1))
|
|
expectNotEqual(result2, .success(2))
|
|
expectEqual(result2, .failure(.err))
|
|
expectNotEqual(result2, .failure(.derr))
|
|
|
|
let confusables: [Result<Err, Err>] = [
|
|
.success(.err),
|
|
.success(.derr),
|
|
.failure(.err),
|
|
.failure(.derr)
|
|
]
|
|
|
|
checkEquatable(confusables, oracle: { $0 == $1 })
|
|
}
|
|
|
|
ResultTests.test("Hashable") {
|
|
let result1: Result<Int, Err> = .success(1)
|
|
let result2: Result<Int, Err> = .success(2)
|
|
let result3: Result<Int, Err> = .failure(.err)
|
|
checkHashable([result1, result2, result3], equalityOracle: { $0 == $1 })
|
|
|
|
let confusables: [Result<Err, Err>] = [
|
|
.success(.err),
|
|
.success(.derr),
|
|
.failure(.err),
|
|
.failure(.derr)
|
|
]
|
|
checkHashable(confusables, equalityOracle: { $0 == $1 })
|
|
}
|
|
|
|
runAllTests()
|