Files
swift-mirror/test/stdlib/Result.swift
Doug Gregor 7d74b3ba5c [SE-0413] Adopt typed throws in Result
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.
2024-01-13 06:45:08 -08:00

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()