// 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 = .success(string) let result2: Result = .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.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 = 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 = 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 { return .success(transformDouble(int)) } func resultErrorTransform(_ err: Err) -> Result { return .failure(transformError(err)) } let result1: Result = .success(1) let newResult1 = result1.map(transformDouble) expectEqual(newResult1, .success(2)) let result2: Result = .failure(.err) let newResult2 = result2.mapError(transformError) expectEqual(newResult2, .failure(.derr)) let result3: Result = .success(1) let newResult3 = result3.flatMap(resultValueTransform) expectEqual(newResult3, .success(2)) let result4: Result = .failure(.derr) let newResult4 = result4.flatMapError(resultErrorTransform) expectEqual(newResult4, .failure(.err)) } ResultTests.test("Equatable") { let result1: Result = .success(1) let result2: Result = .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] = [ .success(.err), .success(.derr), .failure(.err), .failure(.derr) ] checkEquatable(confusables, oracle: { $0 == $1 }) } ResultTests.test("Hashable") { let result1: Result = .success(1) let result2: Result = .success(2) let result3: Result = .failure(.err) checkHashable([result1, result2, result3], equalityOracle: { $0 == $1 }) let confusables: [Result] = [ .success(.err), .success(.derr), .failure(.err), .failure(.derr) ] checkHashable(confusables, equalityOracle: { $0 == $1 }) } runAllTests()