Skip to content

Commit

Permalink
add sync overloads
Browse files Browse the repository at this point in the history
  • Loading branch information
Oguz Yuksel committed Feb 8, 2025
1 parent d8fef20 commit da4c3b5
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 11 deletions.
12 changes: 12 additions & 0 deletions Sources/FoundationExtensions/Combine/Promise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ extension Publishers {
)
}

@inlinable
public init(_ operation: @escaping @Sendable () throws -> Output) where Failure == Error {
self.init(.init(catching: operation))
}

@_disfavoredOverload
@inlinable
public init(_ asyncFunc: @escaping @Sendable () async throws -> Output) where Failure == Error {
self.init { promise in
Expand All @@ -70,6 +76,12 @@ extension Publishers {
}
}

@inlinable
public init(_ operation: @escaping @Sendable () -> Output) where Failure == Never {
self.init(value: operation())
}

@_disfavoredOverload
@inlinable
public init(_ asyncFunc: @escaping @Sendable () async -> Output) where Failure == Never {
self.init { promise in
Expand Down
96 changes: 85 additions & 11 deletions Tests/FoundationExtensionsTests/Combine/PromiseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,32 +52,87 @@ final class PromiseTests: XCTestCase {
XCTAssertEqual(resultExpectations2, .completed)
XCTAssertEqual(resultExpectationPromise2ReceiveValue, .timedOut, "Expectation was unexpectedly fulfilled")

let expectationPromise3ReceiveCompletion = XCTestExpectation(description: "promise 3 finished")
let promise3 = Publishers.Promise<Int, Error> { 100 }
var value3: Int?
let cancellable3 = promise3.sink(
receiveCompletion: { completion in
if case .finished = completion {
expectationPromise3ReceiveCompletion.fulfill()
}
},
receiveValue: { value in
value3 = value
}
)
let resultExpectationPromise3ReceiveCompletion = XCTWaiter.wait(for: [expectationPromise3ReceiveCompletion], timeout: 0.1)
XCTAssertEqual(resultExpectationPromise3ReceiveCompletion, .completed)
XCTAssertEqual(value3, 100)

let expectationPromise4ReceiveCompletion = XCTestExpectation(description: "promise 4 failed")
let promise4 = Publishers.Promise<Int, Error> {
throw MockError.foo
}
var value4: Int?
let cancellable4 = promise4.sink(
receiveCompletion: { completion in
if case .failure(MockError.foo) = completion {
expectationPromise4ReceiveCompletion.fulfill()
}
},
receiveValue: { value in
value4 = value
}
)
let resultExpectationPromise4ReceiveCompletion = XCTWaiter.wait(for: [expectationPromise4ReceiveCompletion], timeout: 0.1)
XCTAssertEqual(resultExpectationPromise4ReceiveCompletion, .completed)
XCTAssertNil(value4)

let expectationPromise5ReceiveCompletion = XCTestExpectation(description: "promise 5 finished")
let promise5 = Publishers.Promise<Int, Never> { 200 }
var value5: Int?
let cancellable5 = promise5.sink(
receiveCompletion: { _ in
expectationPromise5ReceiveCompletion.fulfill()
},
receiveValue: { value in
value5 = value
}
)
let resultExpectationPromise5ReceiveCompletion = XCTWaiter.wait(for: [expectationPromise5ReceiveCompletion], timeout: 0.1)
XCTAssertEqual(resultExpectationPromise5ReceiveCompletion, .completed)
XCTAssertEqual(value5, 200)

// Test cancellation
let expectationPromise3Operation = XCTestExpectation(description: "promise3 operation executed")
let expectationPromise3Cancellation = XCTestExpectation(description: "promise3 cancelled")
let expectationPromise6Operation = XCTestExpectation(description: "promise6 operation executed")
let expectationPromise6Cancellation = XCTestExpectation(description: "promise6 cancelled")

let promise3 = Publishers.Promise<Int, MockError> { _ in
expectationPromise3Operation.fulfill()
let promise6 = Publishers.Promise<Int, MockError> { _ in
expectationPromise6Operation.fulfill()
return AnyCancellable {
expectationPromise3Cancellation.fulfill()
expectationPromise6Cancellation.fulfill()
}
}

let cancellable3 = promise3.sink(
let cancellable6 = promise6.sink(
receiveCompletion: { _ in },
receiveValue: { _ in }
)

cancellable3.cancel()
cancellable6.cancel()

let resultExpectations3 = XCTWaiter.wait(for: [
expectationPromise3Operation,
expectationPromise3Cancellation
let resultExpectations6 = XCTWaiter.wait(for: [
expectationPromise6Operation,
expectationPromise6Cancellation
], timeout: 0.1)
XCTAssertEqual(resultExpectations3, .completed)
XCTAssertEqual(resultExpectations6, .completed)

_ = cancellable1
_ = cancellable2
_ = cancellable3
_ = cancellable4
_ = cancellable5
_ = cancellable6
}

@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
Expand Down Expand Up @@ -118,8 +173,27 @@ final class PromiseTests: XCTestCase {
XCTAssertEqual(resultExpectationPromise2ReceiveCompletion, .completed)
XCTAssertEqual(resultExpectationPromise2ReceiveValue, .timedOut, "Expectation was unexpectedly fulfilled")

let expectationPromise3ReceiveCompletion = XCTestExpectation(description: "promise 3 completes")
let promise3 = Publishers.Promise<Int, Never> {
try? await Task.sleep(nanoseconds: 1_000_000)
return 300
}
var value3: Int?
let cancellable3 = promise3.sink(
receiveCompletion: { _ in
expectationPromise3ReceiveCompletion.fulfill()
},
receiveValue: { value in
value3 = value
}
)
let resultExpectationPromise3ReceiveCompletion = XCTWaiter.wait(for: [expectationPromise3ReceiveCompletion], timeout: 1.0)
XCTAssertEqual(resultExpectationPromise3ReceiveCompletion, .completed)
XCTAssertEqual(value3, 300)

_ = cancellable1
_ = cancellable2
_ = cancellable3
}

func testPromise_Value() {
Expand Down

0 comments on commit da4c3b5

Please sign in to comment.