From a067d9777ebc6b717a2518e0c8f87eb363fea8d5 Mon Sep 17 00:00:00 2001 From: Roman Podymov Date: Fri, 10 Mar 2023 11:02:54 +0100 Subject: [PATCH 1/3] Future extensions --- Sources/Combine.swift | 37 +++++++++ Tests/CorePromise/CombineTests.swift | 114 +++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/Sources/Combine.swift b/Sources/Combine.swift index 901497eb7..e24940377 100644 --- a/Sources/Combine.swift +++ b/Sources/Combine.swift @@ -25,5 +25,42 @@ public extension Promise { } } } + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) +public extension Future { + func promise() -> PromiseKit.Promise { + return .init { [weak self] resolver in + var cancellable: AnyCancellable? + cancellable = self?.sink(receiveCompletion: { completion in + cancellable?.cancel() + cancellable = nil + switch completion { + case .failure(let error): + resolver.reject(error) + case .finished: + break + } + }, receiveValue: { value in + cancellable?.cancel() + cancellable = nil + resolver.fulfill(value) + }) + } + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) +public extension Future where Failure == Never { + func guarantee() -> Guarantee { + return .init { [weak self] resolver in + var cancellable: AnyCancellable? + cancellable = self?.sink(receiveValue: { value in + cancellable?.cancel() + cancellable = nil + resolver(value) + }) + } + } +} #endif #endif diff --git a/Tests/CorePromise/CombineTests.swift b/Tests/CorePromise/CombineTests.swift index ea27af45b..18c8d8637 100644 --- a/Tests/CorePromise/CombineTests.swift +++ b/Tests/CorePromise/CombineTests.swift @@ -115,4 +115,118 @@ class CombineTests: XCTestCase { wait(for: [ex], timeout: 1) } + + func testPromiseCombineValue() { + let ex = expectation(description: "") + #if swift(>=4.1) + #if canImport(Combine) + if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) { + let promise = Future { resolver in + resolver(.success(1)) + }.delay(for: 5, scheduler: RunLoop.main).future().promise() + promise.done { + XCTAssertEqual($0, 1) + ex.fulfill() + }.catch { _ in + XCTAssert(false) + ex.fulfill() + } + } else { + ex.fulfill() + } + #else + ex.fulfill() + #endif + #else + ex.fulfill() + #endif + + wait(for: [ex], timeout: 10) + } + + func testGuaranteeCombineValue() { + let ex = expectation(description: "") + #if swift(>=4.1) + #if canImport(Combine) + if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) { + let guarantee = Future { resolver in + resolver(.success(1)) + }.delay(for: 5, scheduler: RunLoop.main).future().guarantee() + guarantee.done { + XCTAssertEqual($0, 1) + ex.fulfill() + } + } else { + ex.fulfill() + } + #else + ex.fulfill() + #endif + #else + ex.fulfill() + #endif + + wait(for: [ex], timeout: 10) + } + + func testPromiseCombineThrows() { + let ex = expectation(description: "") + #if swift(>=4.1) + #if canImport(Combine) + if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) { + let promise = Future { resolver in + resolver(.failure(.dummy)) + }.delay(for: 5, scheduler: RunLoop.main).map { _ in + 100 + }.future().promise() + promise.done { _ in + XCTAssert(false) + ex.fulfill() + }.catch { error in + switch error as? Error { + case .dummy: + XCTAssert(true) + default: + XCTAssert(false) + } + ex.fulfill() + } + } else { + ex.fulfill() + } + #else + ex.fulfill() + #endif + #else + ex.fulfill() + #endif + + wait(for: [ex], timeout: 10) + } +} + +/// https://stackoverflow.com/a/60444607/2229783 +private extension Publisher { + func future() -> Future { + return Future { promise in + var ticket: AnyCancellable? = nil + ticket = sink( + receiveCompletion: { + ticket?.cancel() + ticket = nil + switch $0 { + case .failure(let error): + promise(.failure(error)) + case .finished: + break + } + }, + receiveValue: { + ticket?.cancel() + ticket = nil + promise(.success($0)) + } + ) + } + } } From df0b3e54b9d67c0c34d35a0d2d438d760ef2b09c Mon Sep 17 00:00:00 2001 From: Roman Podymov Date: Fri, 10 Mar 2023 11:14:25 +0100 Subject: [PATCH 2/3] swift test --generate-linuxmain --- Tests/CorePromise/XCTestManifests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/CorePromise/XCTestManifests.swift b/Tests/CorePromise/XCTestManifests.swift index 8785e2c41..cb0347965 100644 --- a/Tests/CorePromise/XCTestManifests.swift +++ b/Tests/CorePromise/XCTestManifests.swift @@ -74,6 +74,9 @@ extension CombineTests { ("testCombineGuaranteeValue", testCombineGuaranteeValue), ("testCombinePromiseThrow", testCombinePromiseThrow), ("testCombinePromiseValue", testCombinePromiseValue), + ("testGuaranteeCombineValue", testGuaranteeCombineValue), + ("testPromiseCombineThrows", testPromiseCombineThrows), + ("testPromiseCombineValue", testPromiseCombineValue), ] } From 589dc34736734e19f0f2e530c9ac22d761e75ed9 Mon Sep 17 00:00:00 2001 From: Roman Podymov Date: Fri, 10 Mar 2023 11:34:17 +0100 Subject: [PATCH 3/3] Fix tests --- Tests/CorePromise/CombineTests.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/CorePromise/CombineTests.swift b/Tests/CorePromise/CombineTests.swift index 18c8d8637..d435518d2 100644 --- a/Tests/CorePromise/CombineTests.swift +++ b/Tests/CorePromise/CombineTests.swift @@ -205,7 +205,10 @@ class CombineTests: XCTestCase { } } +#if swift(>=4.1) +#if canImport(Combine) /// https://stackoverflow.com/a/60444607/2229783 +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) private extension Publisher { func future() -> Future { return Future { promise in @@ -230,3 +233,5 @@ private extension Publisher { } } } +#endif +#endif