Implement Publishers.SetFailureType (#28)
This commit is contained in:
committed by
GitHub
parent
74e1c1ae32
commit
5e3a18d8c7
@@ -742,48 +742,6 @@ final public class Future<Output, Failure> : Publisher where Failure : Error {
|
||||
final public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber
|
||||
}
|
||||
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that appears to send a specified failure type.
|
||||
///
|
||||
/// The publisher cannot actually fail with the specified type and instead just finishes normally. Use this publisher type when you need to match the error types for two mismatched publishers.
|
||||
public struct SetFailureType<Upstream, Failure> : Publisher where Upstream : Publisher, Failure : Error, Upstream.Failure == Never {
|
||||
|
||||
/// The kind of values published by this publisher.
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// Creates a publisher that appears to send a specified failure type.
|
||||
///
|
||||
/// - Parameter upstream: The publisher from which this publisher receives elements.
|
||||
public init(upstream: Upstream)
|
||||
|
||||
/// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)`
|
||||
///
|
||||
/// - SeeAlso: `subscribe(_:)`
|
||||
/// - Parameters:
|
||||
/// - subscriber: The subscriber to attach to this `Publisher`.
|
||||
/// once attached it can begin to receive values.
|
||||
public func receive<S>(subscriber: S) where Failure == S.Failure, S : Subscriber, Upstream.Output == S.Input
|
||||
|
||||
public func setFailureType<E>(to failure: E.Type) -> Publishers.SetFailureType<Upstream, E> where E : Error
|
||||
}
|
||||
}
|
||||
|
||||
extension Publisher where Self.Failure == Never {
|
||||
|
||||
/// Changes the failure type declared by the upstream publisher.
|
||||
///
|
||||
/// The publisher returned by this method cannot actually fail with the specified type and instead just finishes normally. Instead, you use this method when you need to match the error types of two mismatched publishers.
|
||||
///
|
||||
/// - Parameter failureType: The `Failure` type presented by this publisher.
|
||||
/// - Returns: A publisher that appears to send the specified failure type.
|
||||
public func setFailureType<E>(to failureType: E.Type) -> Publishers.SetFailureType<Self, E> where E : Error
|
||||
}
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that emits a Boolean value upon receiving an element that satisfies the predicate closure.
|
||||
@@ -3301,19 +3259,6 @@ extension Publishers.CombineLatest4 : Equatable where A : Equatable, B : Equatab
|
||||
public static func == (lhs: Publishers.CombineLatest4<A, B, C, D>, rhs: Publishers.CombineLatest4<A, B, C, D>) -> Bool
|
||||
}
|
||||
|
||||
extension Publishers.SetFailureType : Equatable where Upstream : Equatable {
|
||||
|
||||
/// Returns a Boolean value indicating whether two values are equal.
|
||||
///
|
||||
/// Equality is the inverse of inequality. For any values `a` and `b`,
|
||||
/// `a == b` implies that `a != b` is `false`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - lhs: A value to compare.
|
||||
/// - rhs: Another value to compare.
|
||||
public static func == (lhs: Publishers.SetFailureType<Upstream, Failure>, rhs: Publishers.SetFailureType<Upstream, Failure>) -> Bool
|
||||
}
|
||||
|
||||
extension Publishers.Collect : Equatable where Upstream : Equatable {
|
||||
|
||||
/// Returns a Boolean value indicating whether two values are equal.
|
||||
|
||||
@@ -39,7 +39,7 @@ extension AnyPublisher: Publisher {
|
||||
public func receive<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Output == SubscriberType.Input, Failure == SubscriberType.Failure
|
||||
{
|
||||
box.receive(subscriber: subscriber)
|
||||
box.subscribe(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,6 @@ internal final class PublisherBox<PublisherType: Publisher>
|
||||
override internal func receive<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Failure == SubscriberType.Failure, Output == SubscriberType.Input
|
||||
{
|
||||
base.receive(subscriber: subscriber)
|
||||
base.subscribe(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public final class AnySubject<Output, Failure: Error>: Subject {
|
||||
public func receive<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Output == SubscriberType.Input, Failure == SubscriberType.Failure
|
||||
{
|
||||
_box.receive(subscriber: subscriber)
|
||||
_box.subscribe(subscriber)
|
||||
}
|
||||
|
||||
public func send(_ value: Output) {
|
||||
@@ -78,7 +78,7 @@ private final class SubjectBox<SubjectType: Subject>
|
||||
override func receive<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Failure == SubscriberType.Failure, Output == SubscriberType.Input
|
||||
{
|
||||
base.receive(subscriber: subscriber)
|
||||
base.subscribe(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ extension Publishers {
|
||||
SubscriberType.Input == Output
|
||||
{
|
||||
let count = _Count<Upstream, SubscriberType>(downstream: subscriber)
|
||||
upstream.receive(subscriber: count)
|
||||
upstream.subscribe(count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ extension Publishers {
|
||||
downstream: subscriber,
|
||||
decoder: _decoder
|
||||
)
|
||||
upstream.receive(subscriber: decodeSubscriber)
|
||||
upstream.subscribe(decodeSubscriber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ extension Publishers {
|
||||
where Failure == SubscriberType.Failure, Output == SubscriberType.Input
|
||||
{
|
||||
let inner = Inner(downstream: subscriber, predicate: catching(predicate))
|
||||
upstream.receive(subscriber: inner)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ extension Publishers {
|
||||
where Output == SubscriberType.Input, SubscriberType.Failure == Error
|
||||
{
|
||||
let inner = Inner(downstream: subscriber, predicate: catching(predicate))
|
||||
upstream.receive(subscriber: inner)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ extension Publishers {
|
||||
downstream: subscriber,
|
||||
encoder: encoder
|
||||
)
|
||||
upstream.receive(subscriber: encodeSubscriber)
|
||||
upstream.subscribe(encodeSubscriber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,12 @@ extension Publishers {
|
||||
|
||||
/// The closure that transforms elements from the upstream publisher.
|
||||
public let transform: (Upstream.Output) -> Output
|
||||
|
||||
public init(upstream: Upstream,
|
||||
transform: @escaping (Upstream.Output) -> Output) {
|
||||
self.upstream = upstream
|
||||
self.transform = transform
|
||||
}
|
||||
}
|
||||
|
||||
/// A publisher that transforms all elements from the upstream publisher
|
||||
@@ -62,6 +68,12 @@ extension Publishers {
|
||||
/// The error-throwing closure that transforms elements from
|
||||
/// the upstream publisher.
|
||||
public let transform: (Upstream.Output) throws -> Output
|
||||
|
||||
public init(upstream: Upstream,
|
||||
transform: @escaping (Upstream.Output) throws -> Output) {
|
||||
self.upstream = upstream
|
||||
self.transform = transform
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +82,7 @@ extension Publishers.Map {
|
||||
where Output == Downstream.Input, Downstream.Failure == Upstream.Failure
|
||||
{
|
||||
let inner = Inner(downstream: subscriber, transform: catching(transform))
|
||||
upstream.receive(subscriber: inner)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
|
||||
public func map<Result>(
|
||||
@@ -92,7 +104,7 @@ extension Publishers.TryMap {
|
||||
where Output == Downstream.Input, Downstream.Failure == Error
|
||||
{
|
||||
let inner = Inner(downstream: subscriber, transform: catching(transform))
|
||||
upstream.receive(subscriber: inner)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
|
||||
public func map<Result>(
|
||||
|
||||
@@ -42,7 +42,7 @@ extension Publishers {
|
||||
downstream: subscriber,
|
||||
transform: transform
|
||||
)
|
||||
upstream.receive(subscriber: mapErrorSubscriber)
|
||||
upstream.subscribe(mapErrorSubscriber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ extension Publishers {
|
||||
where Failure == SubscriberType.Failure, Output == SubscriberType.Input
|
||||
{
|
||||
let inner = Inner(downstream: subscriber, prefix: prefix, stream: stream)
|
||||
upstream.receive(subscriber: inner)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Publishers.SetFailureType.swift
|
||||
//
|
||||
//
|
||||
// Created by Sergej Jaskiewicz on 08.07.2019.
|
||||
//
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that appears to send a specified failure type.
|
||||
///
|
||||
/// The publisher cannot actually fail with the specified type and instead
|
||||
/// just finishes normally. Use this publisher type when you need to match
|
||||
/// the error types for two mismatched publishers.
|
||||
public struct SetFailureType<Upstream: Publisher, Failure: Error>: Publisher
|
||||
where Upstream.Failure == Never
|
||||
{
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// Creates a publisher that appears to send a specified failure type.
|
||||
///
|
||||
/// - Parameter upstream: The publisher from which this publisher receives
|
||||
/// elements.
|
||||
public init(upstream: Upstream) {
|
||||
self.upstream = upstream
|
||||
}
|
||||
|
||||
public func receive<Downstream: Subscriber>(subscriber: Downstream)
|
||||
where Downstream.Failure == Failure, Downstream.Input == Output
|
||||
{
|
||||
let inner = Inner(downstream: subscriber)
|
||||
upstream.subscribe(inner)
|
||||
}
|
||||
|
||||
public func setFailureType<NewFailure: Error>(
|
||||
to failure: NewFailure.Type
|
||||
) -> Publishers.SetFailureType<Upstream, NewFailure> {
|
||||
return .init(upstream: upstream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.SetFailureType: Equatable where Upstream: Equatable {}
|
||||
|
||||
extension Publisher where Failure == Never {
|
||||
|
||||
/// Changes the failure type declared by the upstream publisher.
|
||||
///
|
||||
/// The publisher returned by this method cannot actually fail
|
||||
/// with the specified type and instead just finishes normally. Instead, you use
|
||||
/// this method when you need to match the error types of two mismatched publishers.
|
||||
///
|
||||
/// - Parameter failureType: The `Failure` type presented by this publisher.
|
||||
/// - Returns: A publisher that appears to send the specified failure type.
|
||||
public func setFailureType<NewFailure: Error>(
|
||||
to failureType: NewFailure.Type
|
||||
) -> Publishers.SetFailureType<Self, NewFailure> {
|
||||
return .init(upstream: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.SetFailureType {
|
||||
private final class Inner<Downstream: Subscriber>
|
||||
: OperatorSubscription<Downstream>,
|
||||
Subscriber,
|
||||
CustomStringConvertible
|
||||
where Upstream.Output == Downstream.Input
|
||||
{
|
||||
func receive(subscription: Subscription) {
|
||||
downstream.receive(subscription: subscription)
|
||||
}
|
||||
|
||||
func receive(_ input: Upstream.Output) -> Subscribers.Demand {
|
||||
return downstream.receive(input)
|
||||
}
|
||||
|
||||
func receive(completion: Subscribers.Completion<Never>) {
|
||||
downstream.receive(completion: .finished)
|
||||
}
|
||||
|
||||
var description: String { return "SetFailureType" }
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,7 @@ private final class Empty: Subscription, CustomStringConvertible, CustomReflecta
|
||||
|
||||
func cancel() {}
|
||||
|
||||
var combineIdentifier: CombineIdentifier { return CombineIdentifier() }
|
||||
|
||||
static let shared = Empty()
|
||||
fileprivate static let shared = Empty()
|
||||
|
||||
var description: String { return "Empty" }
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ final class AnySubscriberTests: XCTestCase {
|
||||
|
||||
publishEvents(events, erased)
|
||||
|
||||
let expectedEvents: [TrackingSubject.Event] =
|
||||
let expectedEvents: [TrackingSubject<Int>.Event] =
|
||||
events.compactMap(subscriberEventToSubjectEvent)
|
||||
|
||||
XCTAssertEqual(subject.history, expectedEvents)
|
||||
|
||||
@@ -31,15 +31,12 @@ import OpenCombine
|
||||
///
|
||||
/// assert(subscription.history == [.requested(.max(42)), .cancelled])
|
||||
@available(macOS 10.15, *)
|
||||
typealias CustomPublisher = CustomPublisherBase<Int>
|
||||
typealias CustomPublisher = CustomPublisherBase<Int, TestingError>
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
final class CustomPublisherBase<Value: Equatable>: Publisher {
|
||||
final class CustomPublisherBase<Output: Equatable, Failure: Error>: Publisher {
|
||||
|
||||
typealias Output = Value
|
||||
typealias Failure = TestingError
|
||||
|
||||
private(set) var subscriber: AnySubscriber<Value, TestingError>?
|
||||
private(set) var subscriber: AnySubscriber<Output, Failure>?
|
||||
private(set) var erasedSubscriber: Any?
|
||||
private let subscription: Subscription?
|
||||
|
||||
@@ -47,19 +44,19 @@ final class CustomPublisherBase<Value: Equatable>: Publisher {
|
||||
self.subscription = subscription
|
||||
}
|
||||
|
||||
func receive<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Failure == SubscriberType.Failure, Output == SubscriberType.Input
|
||||
func receive<Downstream: Subscriber>(subscriber: Downstream)
|
||||
where Failure == Downstream.Failure, Output == Downstream.Input
|
||||
{
|
||||
self.subscriber = AnySubscriber(subscriber)
|
||||
erasedSubscriber = subscriber
|
||||
subscription.map(subscriber.receive(subscription:))
|
||||
}
|
||||
|
||||
func send(_ value: Value) -> Subscribers.Demand {
|
||||
func send(_ value: Output) -> Subscribers.Demand {
|
||||
return subscriber?.receive(value) ?? .none
|
||||
}
|
||||
|
||||
func send(completion: Subscribers.Completion<TestingError>) {
|
||||
func send(completion: Subscribers.Completion<Failure>) {
|
||||
subscriber!.receive(completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,7 @@ typealias TrackingSubscriber = TrackingSubscriberBase<Int, TestingError>
|
||||
/// is considered equal to any other subscription no matter what the subscription object
|
||||
/// actually is.
|
||||
@available(macOS 10.15, *)
|
||||
final class TrackingSubscriberBase<Value: Equatable,
|
||||
Failure: Error>
|
||||
final class TrackingSubscriberBase<Value: Equatable, Failure: Error>
|
||||
: Subscriber,
|
||||
CustomStringConvertible
|
||||
{
|
||||
@@ -168,16 +167,17 @@ final class TrackingSubscriberBase<Value: Equatable,
|
||||
}
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
final class TrackingSubject<Value: Equatable>: Subject, CustomStringConvertible {
|
||||
|
||||
typealias Failure = TestingError
|
||||
|
||||
typealias Output = Value
|
||||
typealias TrackingSubject<Output: Equatable> = TrackingSubjectBase<Output, TestingError>
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
final class TrackingSubjectBase<Output: Equatable, Failure: Error>
|
||||
: Subject,
|
||||
CustomStringConvertible
|
||||
{
|
||||
enum Event: Equatable, CustomStringConvertible {
|
||||
case subscriber
|
||||
case value(Value)
|
||||
case completion(Subscribers.Completion<TestingError>)
|
||||
case value(Output)
|
||||
case completion(Subscribers.Completion<Failure>)
|
||||
|
||||
static func == (lhs: Event, rhs: Event) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
@@ -190,7 +190,7 @@ final class TrackingSubject<Value: Equatable>: Subject, CustomStringConvertible
|
||||
case (.finished, .finished):
|
||||
return true
|
||||
case let (.failure(lhs), .failure(rhs)):
|
||||
return lhs == rhs
|
||||
return (lhs as? TestingError) == (rhs as? TestingError)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -213,7 +213,7 @@ final class TrackingSubject<Value: Equatable>: Subject, CustomStringConvertible
|
||||
}
|
||||
}
|
||||
|
||||
private let _passthrough = PassthroughSubject<Value, TestingError>()
|
||||
private let _passthrough = PassthroughSubject<Output, Failure>()
|
||||
private(set) var history: [Event] = []
|
||||
private let _receiveSubscriber: ((CustomCombineIdentifierConvertible) -> Void)?
|
||||
private let _onDeinit: (() -> Void)?
|
||||
@@ -228,12 +228,12 @@ final class TrackingSubject<Value: Equatable>: Subject, CustomStringConvertible
|
||||
_onDeinit?()
|
||||
}
|
||||
|
||||
func send(_ value: Value) {
|
||||
func send(_ value: Output) {
|
||||
history.append(.value(value))
|
||||
_passthrough.send(value)
|
||||
}
|
||||
|
||||
func send(completion: Subscribers.Completion<TestingError>) {
|
||||
func send(completion: Subscribers.Completion<Failure>) {
|
||||
history.append(.completion(completion))
|
||||
_passthrough.send(completion: completion)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ final class DecodeTests: XCTestCase {
|
||||
|
||||
// `CustomPublisher` sends the subscription object it has been initialized with
|
||||
// to whoever subscribed to the `CustomPublisher`.
|
||||
let publisher = CustomPublisherBase<Int>(subscription: subscription)
|
||||
let publisher = CustomPublisherBase<Int, TestingError>(subscription: subscription)
|
||||
|
||||
// `_Decode` helper will receive the `CustomSubscription `
|
||||
let decode = publisher.decode(type: [String : String].self,
|
||||
|
||||
@@ -76,7 +76,9 @@ final class EncodeTests: XCTestCase {
|
||||
|
||||
// `CustomPublisher` sends the subscription object it has been initialized with
|
||||
// to whoever subscribed to the `CustomPublisher`.
|
||||
let publisher = CustomPublisherBase<[String: String]>(subscription: subscription)
|
||||
let publisher = CustomPublisherBase<[String: String], TestingError>(
|
||||
subscription: subscription
|
||||
)
|
||||
|
||||
// `_Encode` helper will receive the `CustomSubscription `
|
||||
let encode = publisher.encode(encoder: encoder)
|
||||
|
||||
@@ -169,18 +169,22 @@ final class MapTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testDemandSend() {
|
||||
// Given
|
||||
let expectedReceiveValueDemand = 4
|
||||
var expectedReceiveValueDemand = 4
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisher(subscription: subscription)
|
||||
let map = publisher.map { $0 * 2 }
|
||||
let tracking = TrackingSubscriber(
|
||||
receiveSubscription: { $0.request(.unlimited) },
|
||||
receiveValue: { _ in .max(expectedReceiveValueDemand) }
|
||||
)
|
||||
// When
|
||||
|
||||
map.subscribe(tracking)
|
||||
// Then
|
||||
XCTAssertEqual(publisher.send(0), .max(expectedReceiveValueDemand))
|
||||
|
||||
XCTAssertEqual(publisher.send(0), .max(4))
|
||||
|
||||
expectedReceiveValueDemand = 120
|
||||
|
||||
XCTAssertEqual(publisher.send(0), .max(120))
|
||||
}
|
||||
|
||||
func testCompletion() {
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
//
|
||||
// SetFailureTypeTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Sergej Jaskiewicz on 10.07.2019.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST
|
||||
import Combine
|
||||
#else
|
||||
import OpenCombine
|
||||
#endif
|
||||
|
||||
@available(macOS 10.15, *)
|
||||
final class SetFailureTypeTests: XCTestCase {
|
||||
|
||||
static let allTests = [
|
||||
("testEmpty", testEmpty),
|
||||
("testForwardingValues", testForwardingValues),
|
||||
("testNoDemand", testNoDemand),
|
||||
("testDemandSubscribe", testDemandSubscribe),
|
||||
("testDemandSend", testDemandSend),
|
||||
("testCompletion", testCompletion),
|
||||
("testCancel", testCancel),
|
||||
("testCancelAlreadyCancelled", testCancelAlreadyCancelled),
|
||||
]
|
||||
|
||||
func testEmpty() {
|
||||
let tracking = TrackingSubscriberBase<Int, TestingError>(
|
||||
receiveSubscription: { $0.request(.unlimited) }
|
||||
)
|
||||
let publisher = TrackingSubjectBase<Int, Never>(
|
||||
receiveSubscriber: {
|
||||
XCTAssertEqual(String(describing: $0), "SetFailureType")
|
||||
}
|
||||
)
|
||||
|
||||
publisher
|
||||
.setFailureType(to: Never.self)
|
||||
.setFailureType(to: TestingError.self)
|
||||
.subscribe(tracking)
|
||||
|
||||
XCTAssertEqual(tracking.history, [.subscription("PassthroughSubject")])
|
||||
}
|
||||
|
||||
func testForwardingValues() {
|
||||
let publisher = PassthroughSubject<Int, Never>()
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
let tracking = TrackingSubscriber(receiveSubscription: { $0.request(.unlimited) })
|
||||
|
||||
publisher.send(1)
|
||||
sft.subscribe(tracking)
|
||||
publisher.send(2)
|
||||
publisher.send(3)
|
||||
publisher.send(completion: .finished)
|
||||
publisher.send(5)
|
||||
|
||||
XCTAssertEqual(tracking.history, [
|
||||
.subscription("PassthroughSubject"),
|
||||
.value(2),
|
||||
.value(3),
|
||||
.completion(.finished)
|
||||
])
|
||||
}
|
||||
|
||||
func testNoDemand() {
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
let tracking = TrackingSubscriber()
|
||||
|
||||
sft.subscribe(tracking)
|
||||
|
||||
XCTAssert(subscription.history.isEmpty)
|
||||
}
|
||||
|
||||
func testDemandSubscribe() {
|
||||
let expectedSubscribeDemand = 42
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
|
||||
let tracking = TrackingSubscriber(
|
||||
receiveSubscription: { $0.request(.max(expectedSubscribeDemand)) }
|
||||
)
|
||||
|
||||
sft.subscribe(tracking)
|
||||
|
||||
XCTAssertEqual(subscription.history, [.requested(.max(expectedSubscribeDemand))])
|
||||
}
|
||||
|
||||
func testDemandSend() {
|
||||
|
||||
var expectedReceiveValueDemand = 4
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
let tracking = TrackingSubscriber(
|
||||
receiveSubscription: { $0.request(.unlimited) },
|
||||
receiveValue: { _ in .max(expectedReceiveValueDemand) }
|
||||
)
|
||||
|
||||
sft.subscribe(tracking)
|
||||
XCTAssertEqual(publisher.send(0), .max(4))
|
||||
|
||||
expectedReceiveValueDemand = 120
|
||||
|
||||
XCTAssertEqual(publisher.send(0), .max(120))
|
||||
}
|
||||
|
||||
func testCompletion() {
|
||||
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
let tracking = TrackingSubscriber(receiveSubscription: { $0.request(.unlimited) })
|
||||
|
||||
sft.subscribe(tracking)
|
||||
publisher.send(completion: .finished)
|
||||
|
||||
XCTAssertEqual(subscription.history, [.requested(.unlimited)])
|
||||
XCTAssertEqual(
|
||||
tracking.history,
|
||||
[.subscription("CustomSubscription"), .completion(.finished)]
|
||||
)
|
||||
}
|
||||
|
||||
func testCancel() throws {
|
||||
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
|
||||
var downstreamSubscription: Subscription?
|
||||
|
||||
let tracking = TrackingSubscriber(receiveSubscription: {
|
||||
$0.request(.unlimited)
|
||||
downstreamSubscription = $0
|
||||
})
|
||||
|
||||
sft.subscribe(tracking)
|
||||
try XCTUnwrap(downstreamSubscription).cancel()
|
||||
XCTAssertEqual(publisher.send(1), .none)
|
||||
publisher.send(completion: .finished)
|
||||
|
||||
XCTAssertEqual(subscription.history, [.requested(.unlimited), .cancelled])
|
||||
}
|
||||
|
||||
func testCancelAlreadyCancelled() throws {
|
||||
|
||||
let subscription = CustomSubscription()
|
||||
let publisher = CustomPublisherBase<Int, Never>(subscription: subscription)
|
||||
let sft = publisher.setFailureType(to: TestingError.self)
|
||||
var downstreamSubscription: Subscription?
|
||||
let tracking = TrackingSubscriber(receiveSubscription: {
|
||||
$0.request(.unlimited)
|
||||
downstreamSubscription = $0
|
||||
})
|
||||
|
||||
sft.subscribe(tracking)
|
||||
try XCTUnwrap(downstreamSubscription).cancel()
|
||||
downstreamSubscription?.request(.unlimited)
|
||||
try XCTUnwrap(downstreamSubscription).cancel()
|
||||
|
||||
XCTAssertEqual(subscription.history, [.requested(.unlimited),
|
||||
.cancelled,
|
||||
.requested(.unlimited),
|
||||
.cancelled])
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ public func allTests() -> [XCTestCaseEntry] {
|
||||
testCase(PrintTests.allTests),
|
||||
testCase(PublisherTests.allTests),
|
||||
testCase(ReplaceNilTests.allTests),
|
||||
testCase(SetFailureTypeTests.allTests),
|
||||
testCase(SequenceTests.allTests),
|
||||
testCase(SinkTests.allTests),
|
||||
testCase(SubscribersDemandTests.allTests),
|
||||
|
||||
Reference in New Issue
Block a user