Files

95 lines
3.5 KiB
Swift

#if canImport(Combine)
import XCTest
// The Finished expectation waits for the publisher to complete, and throws an
// error if and only if the publisher fails with an error.
//
// It is not derived from the Recording expectation, because Finished does not
// throw RecordingError.notCompleted if the publisher does not complete on time.
// It only triggers a timeout test failure.
//
// This allows to write tests for publishers that should not complete:
//
// // SUCCESS: no timeout, no error
// func testPassthroughSubjectDoesNotFinish() throws {
// let publisher = PassthroughSubject<String, Never>()
// let recorder = publisher.record()
// try wait(for: recorder.finished.inverted, timeout: 1)
// }
@available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
extension PublisherExpectations {
/// A publisher expectation which waits for the recorded publisher
/// to complete.
///
/// When waiting for this expectation, the publisher error is thrown if the
/// publisher fails.
///
/// For example:
///
/// // SUCCESS: no timeout, no error
/// func testArrayPublisherFinishesWithoutError() throws {
/// let publisher = ["foo", "bar", "baz"].publisher
/// let recorder = publisher.record()
/// try wait(for: recorder.finished, timeout: 1)
/// }
///
/// This publisher expectation can be inverted:
///
/// // SUCCESS: no timeout, no error
/// func testPassthroughSubjectDoesNotFinish() throws {
/// let publisher = PassthroughSubject<String, Never>()
/// let recorder = publisher.record()
/// try wait(for: recorder.finished.inverted, timeout: 1)
/// }
public struct Finished<Input, Failure: Error>: PublisherExpectation {
let recorder: Recorder<Input, Failure>
public func _setup(_ expectation: XCTestExpectation) {
recorder.fulfillOnCompletion(expectation)
}
/// Returns the expected output, or throws an error if the
/// expectation fails.
///
/// For example:
///
/// // SUCCESS: no error
/// func testArrayPublisherSynchronouslyFinishesWithoutError() throws {
/// let publisher = ["foo", "bar", "baz"].publisher
/// let recorder = publisher.record()
/// try recorder.finished.get()
/// }
public func get() throws {
try recorder.value { (_, completion, remainingElements, consume) in
guard let completion else {
consume(remainingElements.count)
return
}
if case let .failure(error) = completion {
throw error
}
}
}
/// Returns an inverted publisher expectation which waits for a
/// publisher to complete successfully.
///
/// When waiting for this expectation, an error is thrown if the
/// publisher fails with an error.
///
/// For example:
///
/// // SUCCESS: no timeout, no error
/// func testPassthroughSubjectDoesNotFinish() throws {
/// let publisher = PassthroughSubject<String, Never>()
/// let recorder = publisher.record()
/// try wait(for: recorder.finished.inverted, timeout: 1)
/// }
public var inverted: Inverted<Self> {
return Inverted(base: self)
}
}
}
#endif