diff --git a/Documentation/Maybe.md b/Documentation/Maybe.md index 10dfee6..412c08c 100644 --- a/Documentation/Maybe.md +++ b/Documentation/Maybe.md @@ -150,7 +150,7 @@ There are a few ways to get such a maybe publisher: The consequences of using `uncheckedMaybe()` on a publisher that does not publish exactly zero value, or one value, or an error, are undefined. -See also [Basic Maybe Publishers], [TraitPublishers.Maybe] and [TraitSubscriptions.Maybe]. +See also [Basic Maybe Publishers], [DeferredFutureMaybe] and [TraitSubscriptions.Maybe]. ### Basic Maybe Publishers @@ -178,16 +178,16 @@ func namePublisher() -> AnyMaybePublisher { } ``` -### TraitPublishers.Maybe +### DeferredFutureMaybe -`TraitPublishers.Maybe` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events. +`DeferredFutureMaybe` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events. It lets you easily create custom maybe publishers to wrap most non-publisher asynchronous work. You create this publisher by providing a closure. This closure runs when the publisher is subscribed to. It returns a cancellable object in which you define any cleanup actions to execute when the publisher completes, or when the subscription is canceled. ```swift -let publisher = TraitPublishers.Maybe { promise in +let publisher = DeferredFutureMaybe { promise in // Eventually send completion event, now or in the future: promise(.finished) // OR @@ -201,15 +201,17 @@ let publisher = TraitPublishers.Maybe { promise in } ``` -`TraitPublishers.Maybe` is a "deferred" maybe publisher: +`DeferredFutureMaybe` is a "deferred future" maybe publisher, because: -- Nothing happens until the publisher is subscribed to. A new job starts on each subscription. -- It can complete right on subscription, or at any time in the future. +- Like the [Deferred] Combine publisher, nothing happens until `DeferredFutureMaybe` is subscribed to. A new job starts on each subscription. +- Like the [Future] Combine publisher, It can complete any time, immediately after subscription, or in the future. -When needed, `TraitPublishers.Maybe` can forward its job to another maybe publisher: +However, `DeferredFutureMaybe` allows cancellation cleanup. + +When needed, `DeferredFutureMaybe` can forward its job to another maybe publisher: ```swift -let publisher = TraitPublishers.Maybe { promise in +let publisher = DeferredFutureMaybe { promise in return otherMaybePublisher.sinkMaybe(receive: promise) } ``` @@ -317,7 +319,9 @@ class MyViewController: UIViewController { [`sinkMaybe(receive:)`]: #sinkmaybereceive [Building Maybe Publishers]: #building-maybe-publishers [Basic Maybe Publishers]: #basic-maybe-publishers -[TraitPublishers.Maybe]: #TraitPublishersmaybe +[DeferredFutureMaybe]: #deferredfuturemaybe [TraitSubscriptions.Maybe]: #traitsubscriptionsmaybe [Publisher]: https://developer.apple.com/documentation/combine/publisher [Subscription]: https://developer.apple.com/documentation/combine/subscription +[Deferred]: https://developer.apple.com/documentation/combine/deferred +[Future]: https://developer.apple.com/documentation/combine/future diff --git a/Documentation/Single.md b/Documentation/Single.md index ab146ca..288a2ed 100644 --- a/Documentation/Single.md +++ b/Documentation/Single.md @@ -177,7 +177,7 @@ There are a few ways to get such a single publisher: The consequences of using `uncheckedSingle()` on a publisher that does not publish exactly one value, or an error, are undefined. -See also [Basic Single Publishers], [TraitPublishers.Single] and [TraitSubscriptions.Single]. +See also [Basic Single Publishers], [DeferredFutureSingle] and [TraitSubscriptions.Single]. ### Basic Single Publishers @@ -202,16 +202,16 @@ func namePublisher() -> AnySinglePublisher { } ``` -### TraitPublishers.Single +### DeferredFutureSingle -`TraitPublishers.Single` is a ready-made Combine [Publisher] which which allows you to dynamically send success or failure events. +`DeferredFutureSingle` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events. It lets you easily create custom single publishers to wrap most non-publisher asynchronous work. You create this publisher by providing a closure. This closure runs when the publisher is subscribed to. It returns a cancellable object in which you define any cleanup actions to execute when the publisher completes, or when the subscription is canceled. ```swift -let publisher = TraitPublishers.Single { promise in +let publisher = DeferredFutureSingle { promise in // Eventually send completion event, now or in the future: promise(.success("Alice")) // OR @@ -223,15 +223,17 @@ let publisher = TraitPublishers.Single { promise in } ``` -`TraitPublishers.Single` can be seen as a "deferred future" single publisher: +`DeferredFutureSingle` is a "deferred future" single publisher, because: -- Nothing happens until the publisher is subscribed to. A new job starts on each subscription. -- It can complete right on subscription, or at any time in the future. +- Like the [Deferred] Combine publisher, nothing happens until `DeferredFutureSingle` is subscribed to. A new job starts on each subscription. +- Like the [Future] Combine publisher, It can complete any time, immediately after subscription, or in the future. -When needed, `TraitPublishers.Single` can forward its job to another single publisher: +However, `DeferredFutureSingle` allows cancellation cleanup. + +When needed, `DeferredFutureSingle` can forward its job to another single publisher: ```swift -let publisher = TraitPublishers.Single { promise in +let publisher = DeferredFutureSingle { promise in return otherSinglePublisher.sinkSingle(receive: promise) } ``` @@ -340,7 +342,9 @@ class MyViewController: UIViewController { [Composing Single Publishers]: #composing-single-publishers [Building Single Publishers]: #building-single-publishers [Basic Single Publishers]: #basic-single-publishers -[TraitPublishers.Single]: #TraitPublisherssingle +[DeferredFutureSingle]: #deferredfuturesingle [TraitSubscriptions.Single]: #traitsubscriptionssingle [Publisher]: https://developer.apple.com/documentation/combine/publisher [Subscription]: https://developer.apple.com/documentation/combine/subscription +[Deferred]: https://developer.apple.com/documentation/combine/deferred +[Future]: https://developer.apple.com/documentation/combine/future diff --git a/Sources/CombineTraits/DeferredFutureMaybe.swift b/Sources/CombineTraits/DeferredFutureMaybe.swift new file mode 100644 index 0000000..a2e7d44 --- /dev/null +++ b/Sources/CombineTraits/DeferredFutureMaybe.swift @@ -0,0 +1,75 @@ +import Combine + +/// `DeferredFutureMaybe` is a ready-made Combine Publisher which allows you to +/// dynamically send success or failure events. +/// +/// It lets you easily create custom maybe publishers to wrap most +/// non-publisher asynchronous work. +/// +/// You create this publisher by providing a closure. This closure runs when +/// the publisher is subscribed to. It returns a cancellable object in which +/// you define any cleanup actions to execute when the publisher completes, +/// or when the subscription is canceled. +/// +/// let publisher = DeferredFutureMaybe { promise in +/// // Eventually send completion event, now or in the future: +/// promise(.finished) +/// // OR +/// promise(.success("Alice")) +/// // OR +/// promise(.failure(MyError())) +/// +/// return AnyCancellable { +/// // Perform cleanup +/// } +/// } +/// +/// `DeferredFutureMaybe` is a "deferred" maybe publisher: +/// +/// - Nothing happens until the publisher is subscribed to. A new job starts +/// on each subscription. +/// - It can complete right on subscription, or at any time in the future. +/// +/// When needed, `DeferredFutureMaybe` can forward its job to another +/// maybe publisher: +/// +/// let publisher = DeferredFutureMaybe { promise in +/// return otherMaybePublisher.sinkMaybe(receive: promise) +/// } +public struct DeferredFutureMaybe: MaybePublisher { + public typealias Promise = (MaybeResult) -> Void + typealias Start = (@escaping Promise) -> AnyCancellable + let start: Start + + // TODO: doc + // TODO: allow any cancellable + public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) { + self.start = start + } + + public func receive(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { + let subscription = Subscription( + downstream: subscriber, + context: start) + subscriber.receive(subscription: subscription) + } + + private class Subscription: + TraitSubscriptions.Maybe + where + Downstream.Input == Output, + Downstream.Failure == Failure + { + var cancellable: AnyCancellable? + + override func start(with start: @escaping Start) { + cancellable = start { result in + self.receive(result) + } + } + + override func didCancel(with start: @escaping Start) { + cancellable?.cancel() + } + } +} diff --git a/Sources/CombineTraits/DeferredFutureSingle.swift b/Sources/CombineTraits/DeferredFutureSingle.swift new file mode 100644 index 0000000..c128462 --- /dev/null +++ b/Sources/CombineTraits/DeferredFutureSingle.swift @@ -0,0 +1,73 @@ +import Combine + +/// `DeferredFutureSingle` is a ready-made Combine Publisher which allows you to +/// dynamically send success or failure events. +/// +/// It lets you easily create custom single publishers to wrap most +/// non-publisher asynchronous work. +/// +/// You create this publisher by providing a closure. This closure runs when +/// the publisher is subscribed to. It returns a cancellable object in which +/// you define any cleanup actions to execute when the publisher completes, +/// or when the subscription is canceled. +/// +/// let publisher = DeferredFutureSingle { promise in +/// // Eventually send completion event, now or in the future: +/// promise(.success("Alice")) +/// // OR +/// promise(.failure(MyError())) +/// +/// return AnyCancellable { +/// // Perform cleanup +/// } +/// } +/// +/// `DeferredFutureSingle` can be seen as a "deferred future" +/// single publisher: +/// +/// - Nothing happens until the publisher is subscribed to. A new job starts +/// on each subscription. +/// - It can complete right on subscription, or at any time in the future. +/// +/// When needed, `DeferredFutureSingle` can forward its job to another +/// single publisher: +/// +/// let publisher = DeferredFutureSingle { promise in +/// return otherSinglePublisher.sinkSingle(receive: promise) +/// } +public struct DeferredFutureSingle: SinglePublisher { + public typealias Promise = (Result) -> Void + typealias Start = (@escaping Promise) -> AnyCancellable + let start: Start + + // TODO: doc + public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) { + self.start = start + } + + public func receive(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { + let subscription = Subscription( + downstream: subscriber, + context: start) + subscriber.receive(subscription: subscription) + } + + private class Subscription: + TraitSubscriptions.Single + where + Downstream.Input == Output, + Downstream.Failure == Failure + { + var cancellable: AnyCancellable? + + override func start(with start: @escaping Start) { + cancellable = start { result in + self.receive(result) + } + } + + override func didCancel(with start: @escaping Start) { + cancellable?.cancel() + } + } +} diff --git a/Sources/CombineTraits/TraitPublishers/TraitPublishers.swift b/Sources/CombineTraits/TraitPublishers/TraitPublishers.swift deleted file mode 100644 index 9ba5edb..0000000 --- a/Sources/CombineTraits/TraitPublishers/TraitPublishers.swift +++ /dev/null @@ -1,2 +0,0 @@ -/// A namespace for publishers that conform to publisher traits. -public enum TraitPublishers { } diff --git a/Sources/CombineTraits/TraitPublishers/TraitPublishersMaybe.swift b/Sources/CombineTraits/TraitPublishers/TraitPublishersMaybe.swift deleted file mode 100644 index 80075ce..0000000 --- a/Sources/CombineTraits/TraitPublishers/TraitPublishersMaybe.swift +++ /dev/null @@ -1,77 +0,0 @@ -import Combine - -extension TraitPublishers { - /// `TraitPublishers.Maybe` is a ready-made Combine Publisher which allows - /// you to dynamically send success or failure events. - /// - /// It lets you easily create custom maybe publishers to wrap most - /// non-publisher asynchronous work. - /// - /// You create this publisher by providing a closure. This closure runs when - /// the publisher is subscribed to. It returns a cancellable object in which - /// you define any cleanup actions to execute when the publisher completes, - /// or when the subscription is canceled. - /// - /// let publisher = TraitPublishers.Maybe { promise in - /// // Eventually send completion event, now or in the future: - /// promise(.finished) - /// // OR - /// promise(.success("Alice")) - /// // OR - /// promise(.failure(MyError())) - /// - /// return AnyCancellable { - /// // Perform cleanup - /// } - /// } - /// - /// `TraitPublishers.Maybe` is a "deferred" maybe publisher: - /// - /// - Nothing happens until the publisher is subscribed to. A new job starts - /// on each subscription. - /// - It can complete right on subscription, or at any time in the future. - /// - /// When needed, `TraitPublishers.Maybe` can forward its job to another - /// maybe publisher: - /// - /// let publisher = TraitPublishers.Maybe { promise in - /// return otherMaybePublisher.sinkMaybe(receive: promise) - /// } - public struct Maybe: MaybePublisher { - public typealias Promise = (MaybeResult) -> Void - typealias Start = (@escaping Promise) -> AnyCancellable - let start: Start - - // TODO: doc - // TODO: allow any cancellable - public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) { - self.start = start - } - - public func receive(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { - let subscription = Subscription( - downstream: subscriber, - context: start) - subscriber.receive(subscription: subscription) - } - - private class Subscription: - TraitSubscriptions.Maybe - where - Downstream.Input == Output, - Downstream.Failure == Failure - { - var cancellable: AnyCancellable? - - override func start(with start: @escaping Start) { - cancellable = start { result in - self.receive(result) - } - } - - override func didCancel(with start: @escaping Start) { - cancellable?.cancel() - } - } - } -} diff --git a/Sources/CombineTraits/TraitPublishers/TraitPublishersSingle.swift b/Sources/CombineTraits/TraitPublishers/TraitPublishersSingle.swift deleted file mode 100644 index 238d4f2..0000000 --- a/Sources/CombineTraits/TraitPublishers/TraitPublishersSingle.swift +++ /dev/null @@ -1,75 +0,0 @@ -import Combine - -extension TraitPublishers { - /// `TraitPublishers.Single` is a ready-made Combine Publisher which which - /// allows you to dynamically send success or failure events. - /// - /// It lets you easily create custom single publishers to wrap most - /// non-publisher asynchronous work. - /// - /// You create this publisher by providing a closure. This closure runs when - /// the publisher is subscribed to. It returns a cancellable object in which - /// you define any cleanup actions to execute when the publisher completes, - /// or when the subscription is canceled. - /// - /// let publisher = TraitPublishers.Single { promise in - /// // Eventually send completion event, now or in the future: - /// promise(.success("Alice")) - /// // OR - /// promise(.failure(MyError())) - /// - /// return AnyCancellable { - /// // Perform cleanup - /// } - /// } - /// - /// `TraitPublishers.Single` can be seen as a "deferred future" - /// single publisher: - /// - /// - Nothing happens until the publisher is subscribed to. A new job starts - /// on each subscription. - /// - It can complete right on subscription, or at any time in the future. - /// - /// When needed, `TraitPublishers.Single` can forward its job to another - /// single publisher: - /// - /// let publisher = TraitPublishers.Single { promise in - /// return otherSinglePublisher.sinkSingle(receive: promise) - /// } - public struct Single: SinglePublisher { - public typealias Promise = (Result) -> Void - typealias Start = (@escaping Promise) -> AnyCancellable - let start: Start - - // TODO: doc - public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) { - self.start = start - } - - public func receive(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input { - let subscription = Subscription( - downstream: subscriber, - context: start) - subscriber.receive(subscription: subscription) - } - - private class Subscription: - TraitSubscriptions.Single - where - Downstream.Input == Output, - Downstream.Failure == Failure - { - var cancellable: AnyCancellable? - - override func start(with start: @escaping Start) { - cancellable = start { result in - self.receive(result) - } - } - - override func didCancel(with start: @escaping Start) { - cancellable?.cancel() - } - } - } -} diff --git a/Tests/CombineTraitsTests/PublisherTraitsMaybeTests.swift b/Tests/CombineTraitsTests/DeferredFutureMaybeTests.swift similarity index 81% rename from Tests/CombineTraitsTests/PublisherTraitsMaybeTests.swift rename to Tests/CombineTraitsTests/DeferredFutureMaybeTests.swift index 9184627..ce0e2b3 100644 --- a/Tests/CombineTraitsTests/PublisherTraitsMaybeTests.swift +++ b/Tests/CombineTraitsTests/DeferredFutureMaybeTests.swift @@ -2,19 +2,18 @@ import Combine import CombineTraits import XCTest -#warning("TODO: test multiple promise fulfilments? What should happen?") -class TraitPublishersMaybeTests: XCTestCase { - func test_TraitPublishersMaybe_is_a_MaybePublisher() { +class DeferredFutureMaybeTests: XCTestCase { + func test_DeferredFutureMaybe_is_a_MaybePublisher() { // This test passes if this test compiles func acceptSomeMaybePublisher(_ p: P) { } - func f(_ p: TraitPublishers.Maybe) { + func f(_ p: DeferredFutureMaybe) { acceptSomeMaybePublisher(p) } } - func test_TraitPublishersMaybe_is_deferred() { + func test_DeferredFutureMaybe_is_deferred() { var subscribed = false - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in subscribed = true return AnyCancellable({ }) } @@ -24,9 +23,9 @@ class TraitPublishersMaybeTests: XCTestCase { XCTAssertTrue(subscribed) } - func test_TraitPublishersMaybe_is_not_shared() { + func test_DeferredFutureMaybe_is_not_shared() { var subscriptionCount = 0 - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in subscriptionCount += 1 return AnyCancellable({ }) } @@ -38,8 +37,8 @@ class TraitPublishersMaybeTests: XCTestCase { XCTAssertEqual(subscriptionCount, 2) } - func test_TraitPublishersMaybe_as_never() { - let publisher = TraitPublishers.Maybe { promise in + func test_DeferredFutureMaybe_as_never() { + let publisher = DeferredFutureMaybe { promise in return AnyCancellable({ }) } @@ -64,8 +63,8 @@ class TraitPublishersMaybeTests: XCTestCase { } } - func test_TraitPublishersMaybe_as_just() { - let publisher = TraitPublishers.Maybe { promise in + func test_DeferredFutureMaybe_as_just() { + let publisher = DeferredFutureMaybe { promise in promise(.success(1)) return AnyCancellable({ }) } @@ -80,8 +79,8 @@ class TraitPublishersMaybeTests: XCTestCase { XCTAssertEqual(completion, .finished) } - func test_TraitPublishersMaybe_as_empty() { - let publisher = TraitPublishers.Maybe { promise in + func test_DeferredFutureMaybe_as_empty() { + let publisher = DeferredFutureMaybe { promise in promise(.finished) return AnyCancellable({ }) } @@ -96,9 +95,9 @@ class TraitPublishersMaybeTests: XCTestCase { XCTAssertEqual(completion, .finished) } - func test_TraitPublishersMaybe_as_fail() { + func test_DeferredFutureMaybe_as_fail() { struct TestError: Error { } - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in promise(.failure(TestError())) return AnyCancellable({ }) } @@ -118,8 +117,8 @@ class TraitPublishersMaybeTests: XCTestCase { } } - func test_TraitPublishersMaybe_as_delayed_just() { - let publisher = TraitPublishers.Maybe { promise in + func test_DeferredFutureMaybe_as_delayed_just() { + let publisher = DeferredFutureMaybe { promise in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { promise(.success(1)) } @@ -146,8 +145,8 @@ class TraitPublishersMaybeTests: XCTestCase { } } - func test_TraitPublishersMaybe_as_delayed_empty() { - let publisher = TraitPublishers.Maybe { promise in + func test_DeferredFutureMaybe_as_delayed_empty() { + let publisher = DeferredFutureMaybe { promise in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { promise(.finished) } @@ -174,9 +173,9 @@ class TraitPublishersMaybeTests: XCTestCase { } } - func test_TraitPublishersMaybe_as_delayed_fail() { + func test_DeferredFutureMaybe_as_delayed_fail() { struct TestError: Error { } - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { promise(.failure(TestError())) } @@ -210,7 +209,7 @@ class TraitPublishersMaybeTests: XCTestCase { func test_cancellation_after_completion() { var disposed = false - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in promise(.success(1)) return AnyCancellable({ disposed = true }) } @@ -224,7 +223,7 @@ class TraitPublishersMaybeTests: XCTestCase { func test_cancellation_before_completion() { var disposed = false - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in return AnyCancellable({ disposed = true }) } @@ -239,7 +238,7 @@ class TraitPublishersMaybeTests: XCTestCase { func test_forwarding() { let upstream = Just(1) - let publisher = TraitPublishers.Maybe { promise in + let publisher = DeferredFutureMaybe { promise in return upstream.sinkMaybe(receive: promise) } diff --git a/Tests/CombineTraitsTests/PublisherTraitsSingleTests.swift b/Tests/CombineTraitsTests/DeferredFutureSingleTests.swift similarity index 81% rename from Tests/CombineTraitsTests/PublisherTraitsSingleTests.swift rename to Tests/CombineTraitsTests/DeferredFutureSingleTests.swift index 6cebe03..2b87dde 100644 --- a/Tests/CombineTraitsTests/PublisherTraitsSingleTests.swift +++ b/Tests/CombineTraitsTests/DeferredFutureSingleTests.swift @@ -2,18 +2,18 @@ import Combine import CombineTraits import XCTest -class TraitPublishersSingleTests: XCTestCase { - func test_TraitPublishersSingle_is_a_SinglePublisher() { +class DeferredFutureSingleTests: XCTestCase { + func test_DeferredFutureSingle_is_a_SinglePublisher() { // This test passes if this test compiles func acceptSomeSinglePublisher(_ p: P) { } - func f(_ p: TraitPublishers.Single) { + func f(_ p: DeferredFutureSingle) { acceptSomeSinglePublisher(p) } } - func test_TraitPublishersSingle_is_deferred() { + func test_DeferredFutureSingle_is_deferred() { var subscribed = false - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in subscribed = true return AnyCancellable({ }) } @@ -23,9 +23,9 @@ class TraitPublishersSingleTests: XCTestCase { XCTAssertTrue(subscribed) } - func test_TraitPublishersSingle_is_not_shared() { + func test_DeferredFutureSingle_is_not_shared() { var subscriptionCount = 0 - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in subscriptionCount += 1 return AnyCancellable({ }) } @@ -37,8 +37,8 @@ class TraitPublishersSingleTests: XCTestCase { XCTAssertEqual(subscriptionCount, 2) } - func test_TraitPublishersSingle_as_never() { - let publisher = TraitPublishers.Single { promise in + func test_DeferredFutureSingle_as_never() { + let publisher = DeferredFutureSingle { promise in return AnyCancellable({ }) } @@ -63,8 +63,8 @@ class TraitPublishersSingleTests: XCTestCase { } } - func test_TraitPublishersSingle_as_just() { - let publisher = TraitPublishers.Single { promise in + func test_DeferredFutureSingle_as_just() { + let publisher = DeferredFutureSingle { promise in promise(.success(1)) return AnyCancellable({ }) } @@ -79,9 +79,9 @@ class TraitPublishersSingleTests: XCTestCase { XCTAssertEqual(completion, .finished) } - func test_TraitPublishersSingle_as_fail() { + func test_DeferredFutureSingle_as_fail() { struct TestError: Error { } - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in promise(.failure(TestError())) return AnyCancellable({ }) } @@ -101,8 +101,8 @@ class TraitPublishersSingleTests: XCTestCase { } } - func test_TraitPublishersSingle_as_delayed_just() { - let publisher = TraitPublishers.Single { promise in + func test_DeferredFutureSingle_as_delayed_just() { + let publisher = DeferredFutureSingle { promise in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { promise(.success(1)) } @@ -129,9 +129,9 @@ class TraitPublishersSingleTests: XCTestCase { } } - func test_TraitPublishersSingle_as_delayed_fail() { + func test_DeferredFutureSingle_as_delayed_fail() { struct TestError: Error { } - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { promise(.failure(TestError())) } @@ -165,7 +165,7 @@ class TraitPublishersSingleTests: XCTestCase { func test_cancellation_after_completion() { var disposed = false - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in promise(.success(1)) return AnyCancellable({ disposed = true }) } @@ -179,7 +179,7 @@ class TraitPublishersSingleTests: XCTestCase { func test_cancellation_before_completion() { var disposed = false - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in return AnyCancellable({ disposed = true }) } @@ -194,7 +194,7 @@ class TraitPublishersSingleTests: XCTestCase { func test_forwarding() { let upstream = Just(1) - let publisher = TraitPublishers.Single { promise in + let publisher = DeferredFutureSingle { promise in return upstream.sinkSingle(receive: promise) }