Implement Filter/TryFilter (#22)
* Adds filter and try filter implementations * Implement Filter * Remove @testable declaration * Fix linting * Updates tests and creates testing helper * Fix allTests to include all tests * Renames TestHelper to OperatorTestHelper and adds documentation * Adds more test coverage * Updates to use subclasses for filter / tryfilter * Adds subscription test * Fix subscriber demand to be lazy * Fix CustomPublisherBase changes from master * Fix iOS availability on test helper * Updates availability for test functions * Simplify Filter implementation, add more tests * Ensure test suite consistency on Darwin and Linux * Add missing tests to XCTestManifests.swift
This commit is contained in:
committed by
Sergej Jaskiewicz
parent
d2b8709afb
commit
d3888a3808
@@ -75,3 +75,17 @@ generic_type_name:
|
||||
attributes:
|
||||
always_on_line_above:
|
||||
- "@usableFromInline"
|
||||
|
||||
custom_rules:
|
||||
no_foundation_dependency:
|
||||
included: Sources/OpenCombine
|
||||
name: "No Foundation Dependency"
|
||||
regex: "^import.*Foundation.*$"
|
||||
message: "We don't want to depend on Foundation"
|
||||
severity: error
|
||||
no_dispatch_dependency:
|
||||
included: Sources/OpenCombine
|
||||
name: "No Dispatch Dependency"
|
||||
regex: "^import.*Dispatch.*$"
|
||||
message: "We don't want to depend on Dispatch"
|
||||
severity: error
|
||||
+4
-4
@@ -52,13 +52,13 @@ install:
|
||||
fi
|
||||
script:
|
||||
- if [[ $OPENCOMBINE_TEST == "YES" ]]; then
|
||||
swift test -c debug --enable-code-coverage --sanitize thread;
|
||||
make test-debug;
|
||||
fi
|
||||
- if [[ $OPENCOMBINE_TEST == "YES" ]]; then
|
||||
swift test -c release;
|
||||
make test-release;
|
||||
fi
|
||||
- if [[ $OPENCOMBINE_COMPATIBILITY_TEST == "YES" ]]; then
|
||||
swift package generate-xcodeproj --xcconfig-overrides iOS-Combine-Compatibility.xcconfig;
|
||||
make generate-compatibility-xcodeproj;
|
||||
set -o pipefail && xcodebuild -scheme OpenCombine-Package -sdk iphonesimulator13.0 -destination "platform=iOS Simulator,name=iPhone Xs,OS=13.0" build test | xcpretty;
|
||||
fi
|
||||
- if [[ $SWIFT_LINT == "YES" ]]; then
|
||||
@@ -69,7 +69,7 @@ script:
|
||||
fi
|
||||
after_success:
|
||||
- if [[ $CODE_COVERAGE == "YES" ]]; then
|
||||
swift package generate-xcodeproj --enable-code-coverage;
|
||||
make generate-xcodeproj;
|
||||
xcodebuild -scheme OpenCombine-Package build test | xcpretty;
|
||||
bash <(curl -s https://codecov.io/bash);
|
||||
fi
|
||||
|
||||
@@ -2,6 +2,33 @@ import Danger
|
||||
|
||||
let danger = Danger()
|
||||
|
||||
do {
|
||||
let addedTestFiles = danger
|
||||
.git
|
||||
.createdFiles
|
||||
.filter { $0.hasSuffix("Tests.swift") }
|
||||
|
||||
let modifiedXCTestManifests = danger
|
||||
.git
|
||||
.modifiedFiles
|
||||
.contains { $0.hasSuffix("XCTestManifests.swift") }
|
||||
|
||||
if !addedTestFiles.isEmpty && !modifiedXCTestManifests {
|
||||
|
||||
let addedTestsClasses = addedTestFiles.map {
|
||||
"- `\($0.split(separator: "/").last!.dropLast(6))`\n"
|
||||
}.joined()
|
||||
|
||||
fail("""
|
||||
You've added the following test classes:
|
||||
|
||||
\(addedTestsClasses)
|
||||
|
||||
but forgot to modify `XCTestManifests.swift`.
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
SwiftLint.lint(inline: true,
|
||||
configFile: ".swiftlint.yml",
|
||||
strict: true,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
debug:
|
||||
swift build -c debug
|
||||
|
||||
release:
|
||||
swift build -c release
|
||||
|
||||
test-debug:
|
||||
swift test -c debug --enable-code-coverage --sanitize thread
|
||||
|
||||
test-release:
|
||||
swift test -c release
|
||||
|
||||
swift-version:
|
||||
swift -version
|
||||
|
||||
test-compatibility:
|
||||
swift test -Xswiftc -DOPENCOMBINE_COMPATIBILITY_TEST
|
||||
|
||||
generate-compatibility-xcodeproj:
|
||||
swift package generate-xcodeproj --xcconfig-overrides Combine-Compatibility.xcconfig; \
|
||||
open OpenCombine.xcodeproj
|
||||
|
||||
generate-xcodeproj:
|
||||
swift package generate-xcodeproj --enable-code-coverage
|
||||
|
||||
.PHONY: debug release test-debug test-release swift-version test-compatibility-debug generate-compatibility-xcodeproj generate-xcodeproj
|
||||
@@ -115,82 +115,6 @@ extension Publisher {
|
||||
public func measureInterval<S>(using scheduler: S, options: S.SchedulerOptions? = nil) -> Publishers.MeasureInterval<Self, S> where S : Scheduler
|
||||
}
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that republishes all elements that match a provided closure.
|
||||
public struct Filter<Upstream> : Publisher where Upstream : Publisher {
|
||||
|
||||
/// The kind of values published by this publisher.
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The kind of errors this publisher might publish.
|
||||
///
|
||||
/// Use `Never` if this `Publisher` does not publish errors.
|
||||
public typealias Failure = Upstream.Failure
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// A closure that indicates whether to republish an element.
|
||||
public let isIncluded: (Upstream.Output) -> Bool
|
||||
|
||||
public init(upstream: Upstream, isIncluded: @escaping (Output) -> Bool)
|
||||
|
||||
/// 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 S : Subscriber, Upstream.Failure == S.Failure, Upstream.Output == S.Input
|
||||
}
|
||||
|
||||
/// A publisher that republishes all elements that match a provided error-throwing closure.
|
||||
public struct TryFilter<Upstream> : Publisher where Upstream : Publisher {
|
||||
|
||||
/// The kind of values published by this publisher.
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The kind of errors this publisher might publish.
|
||||
///
|
||||
/// Use `Never` if this `Publisher` does not publish errors.
|
||||
public typealias Failure = Error
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// A error-throwing closure that indicates whether to republish an element.
|
||||
public let isIncluded: (Upstream.Output) throws -> Bool
|
||||
|
||||
public init(upstream: Upstream, isIncluded: @escaping (Upstream.Output) throws -> Bool)
|
||||
|
||||
/// 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 S : Subscriber, Upstream.Output == S.Input, S.Failure == Publishers.TryFilter<Upstream>.Failure
|
||||
}
|
||||
}
|
||||
|
||||
extension Publisher {
|
||||
|
||||
/// Republishes all elements that match a provided closure.
|
||||
///
|
||||
/// - Parameter isIncluded: A closure that takes one element and returns a Boolean value indicating whether to republish the element.
|
||||
/// - Returns: A publisher that republishes all elements that satisfy the closure.
|
||||
public func filter(_ isIncluded: @escaping (Self.Output) -> Bool) -> Publishers.Filter<Self>
|
||||
|
||||
/// Republishes all elements that match a provided error-throwing closure.
|
||||
///
|
||||
/// If the `isIncluded` closure throws an error, the publisher fails with that error.
|
||||
///
|
||||
/// - Parameter isIncluded: A closure that takes one element and returns a Boolean value indicating whether to republish the element.
|
||||
/// - Returns: A publisher that republishes all elements that satisfy the closure.
|
||||
public func tryFilter(_ isIncluded: @escaping (Self.Output) throws -> Bool) -> Publishers.TryFilter<Self>
|
||||
}
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that raises a debugger signal when a provided closure needs to stop the process in the debugger.
|
||||
@@ -3196,20 +3120,6 @@ extension Publisher {
|
||||
public func tryFirst(where predicate: @escaping (Self.Output) throws -> Bool) -> Publishers.TryFirstWhere<Self>
|
||||
}
|
||||
|
||||
extension Publishers.Filter {
|
||||
|
||||
public func filter(_ isIncluded: @escaping (Publishers.Filter<Upstream>.Output) -> Bool) -> Publishers.Filter<Upstream>
|
||||
|
||||
public func tryFilter(_ isIncluded: @escaping (Publishers.Filter<Upstream>.Output) throws -> Bool) -> Publishers.TryFilter<Upstream>
|
||||
}
|
||||
|
||||
extension Publishers.TryFilter {
|
||||
|
||||
public func filter(_ isIncluded: @escaping (Publishers.TryFilter<Upstream>.Output) -> Bool) -> Publishers.TryFilter<Upstream>
|
||||
|
||||
public func tryFilter(_ isIncluded: @escaping (Publishers.TryFilter<Upstream>.Output) throws -> Bool) -> Publishers.TryFilter<Upstream>
|
||||
}
|
||||
|
||||
extension Just {
|
||||
|
||||
public func prepend(_ elements: Output...) -> Publishers.Sequence<[Output], Just<Output>.Failure>
|
||||
|
||||
@@ -139,9 +139,7 @@ public struct ImmediateScheduler: Scheduler {
|
||||
tolerance: SchedulerTimeType.Stride,
|
||||
options: SchedulerOptions?,
|
||||
_ action: @escaping () -> Void) {
|
||||
fatalError(
|
||||
"Attempt to schedule something in the future on the immediate scheduler"
|
||||
)
|
||||
action()
|
||||
}
|
||||
|
||||
/// Performs the action at some time after the specified date, at the specified
|
||||
@@ -151,8 +149,7 @@ public struct ImmediateScheduler: Scheduler {
|
||||
tolerance: SchedulerTimeType.Stride,
|
||||
options: SchedulerOptions?,
|
||||
_ action: @escaping () -> Void) -> Cancellable {
|
||||
fatalError(
|
||||
"Attempt to schedule something in the future on the immediate scheduler"
|
||||
)
|
||||
action()
|
||||
return Subscriptions.empty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// Publishers.Filter.swift
|
||||
//
|
||||
//
|
||||
// Created by Joseph Spadafora on 7/3/19.
|
||||
//
|
||||
|
||||
extension Publisher {
|
||||
|
||||
/// Republishes all elements that match a provided closure.
|
||||
///
|
||||
/// - Parameter isIncluded: A closure that takes one element and returns
|
||||
/// a Boolean value indicating whether to republish the element.
|
||||
/// - Returns: A publisher that republishes all elements that satisfy the closure.
|
||||
public func filter(
|
||||
_ isIncluded: @escaping (Output) -> Bool
|
||||
) -> Publishers.Filter<Self> {
|
||||
return Publishers.Filter(upstream: self, isIncluded: isIncluded)
|
||||
}
|
||||
|
||||
/// Republishes all elements that match a provided error-throwing closure.
|
||||
///
|
||||
/// If the `isIncluded` closure throws an error, the publisher fails with that error.
|
||||
///
|
||||
/// - Parameter isIncluded: A closure that takes one element and returns a
|
||||
/// Boolean value indicating whether to republish the element.
|
||||
/// - Returns: A publisher that republishes all elements that satisfy the closure.
|
||||
public func tryFilter(
|
||||
_ isIncluded: @escaping (Output) throws -> Bool
|
||||
) -> Publishers.TryFilter<Self> {
|
||||
return Publishers.TryFilter(upstream: self, isIncluded: isIncluded)
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.Filter {
|
||||
|
||||
public func filter(
|
||||
_ isIncluded: @escaping (Output) -> Bool
|
||||
) -> Publishers.Filter<Upstream> {
|
||||
return .init(upstream: upstream) { self.isIncluded($0) && isIncluded($0) }
|
||||
}
|
||||
|
||||
public func tryFilter(
|
||||
_ isIncluded: @escaping (Output) throws -> Bool
|
||||
) -> Publishers.TryFilter<Upstream> {
|
||||
return .init(upstream: upstream) { try self.isIncluded($0) && isIncluded($0) }
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.TryFilter {
|
||||
|
||||
public func filter(
|
||||
_ isIncluded: @escaping (Output) -> Bool
|
||||
) -> Publishers.TryFilter<Upstream> {
|
||||
return .init(upstream: upstream) { try self.isIncluded($0) && isIncluded($0) }
|
||||
}
|
||||
|
||||
public func tryFilter(
|
||||
_ isIncluded: @escaping (Output) throws -> Bool
|
||||
) -> Publishers.TryFilter<Upstream> {
|
||||
return .init(upstream: upstream) { try self.isIncluded($0) && isIncluded($0) }
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers {
|
||||
|
||||
/// A publisher that republishes all elements that match a provided closure.
|
||||
public struct Filter<Upstream: Publisher>: Publisher {
|
||||
|
||||
/// The kind of values published by this publisher.
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The kind of errors this publisher might publish.
|
||||
///
|
||||
/// Use `Never` if this `Publisher` does not publish errors.
|
||||
public typealias Failure = Upstream.Failure
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// A closure that indicates whether to republish an element.
|
||||
public let isIncluded: (Upstream.Output) -> Bool
|
||||
|
||||
public init(upstream: Upstream, isIncluded: @escaping (Output) -> Bool) {
|
||||
self.upstream = upstream
|
||||
self.isIncluded = isIncluded
|
||||
}
|
||||
|
||||
/// 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<SubscriberType: Subscriber>(subscriber: SubscriberType)
|
||||
where Upstream.Failure == SubscriberType.Failure,
|
||||
Upstream.Output == SubscriberType.Input
|
||||
{
|
||||
let filter = Inner(downstream: subscriber, isIncluded: catching(isIncluded))
|
||||
upstream.receive(subscriber: filter)
|
||||
}
|
||||
}
|
||||
|
||||
/// A publisher that republishes all elements that match
|
||||
/// a provided error-throwing closure.
|
||||
public struct TryFilter<Upstream> : Publisher where Upstream : Publisher {
|
||||
|
||||
/// The kind of values published by this publisher.
|
||||
public typealias Output = Upstream.Output
|
||||
|
||||
/// The kind of errors this publisher might publish.
|
||||
///
|
||||
/// Use `Never` if this `Publisher` does not publish errors.
|
||||
public typealias Failure = Error
|
||||
|
||||
/// The publisher from which this publisher receives elements.
|
||||
public let upstream: Upstream
|
||||
|
||||
/// A error-throwing closure that indicates whether to republish an element.
|
||||
public let isIncluded: (Upstream.Output) throws -> Bool
|
||||
|
||||
public init(upstream: Upstream,
|
||||
isIncluded: @escaping (Upstream.Output) throws -> Bool) {
|
||||
self.upstream = upstream
|
||||
self.isIncluded = isIncluded
|
||||
}
|
||||
|
||||
/// 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<Downstream: Subscriber>(subscriber: Downstream)
|
||||
where Upstream.Output == Downstream.Input,
|
||||
Downstream.Failure == Failure
|
||||
{
|
||||
let filter = Inner(downstream: subscriber, isIncluded: catching(isIncluded))
|
||||
upstream.receive(subscriber: filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class _Filter<Upstream: Publisher, Downstream: Subscriber>
|
||||
: OperatorSubscription<Downstream>,
|
||||
Subscription
|
||||
where Upstream.Output == Downstream.Input
|
||||
{
|
||||
typealias Input = Upstream.Output
|
||||
typealias Failure = Upstream.Failure
|
||||
typealias Predicate = (Input) -> Result<Bool, Downstream.Failure>
|
||||
|
||||
private var _isIncluded: Predicate?
|
||||
|
||||
var isFinished: Bool {
|
||||
return _isIncluded == nil
|
||||
}
|
||||
|
||||
init(downstream: Downstream, isIncluded: @escaping Predicate) {
|
||||
_isIncluded = isIncluded
|
||||
super.init(downstream: downstream)
|
||||
}
|
||||
|
||||
func receive(subscription: Subscription) {
|
||||
upstreamSubscription = subscription
|
||||
downstream.receive(subscription: self)
|
||||
}
|
||||
|
||||
func receive(_ input: Input) -> Subscribers.Demand {
|
||||
guard let isIncluded = _isIncluded else { return .none }
|
||||
switch isIncluded(input) {
|
||||
case .success(let isIncluded):
|
||||
return isIncluded ? downstream.receive(input) : .max(1)
|
||||
case .failure(let error):
|
||||
downstream.receive(completion: .failure(error))
|
||||
cancel()
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
guard !isFinished else { return }
|
||||
upstreamSubscription?.request(demand)
|
||||
}
|
||||
|
||||
override func cancel() {
|
||||
_isIncluded = nil
|
||||
upstreamSubscription?.cancel()
|
||||
upstreamSubscription = nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.Filter {
|
||||
|
||||
private final class Inner<Downstream: Subscriber>
|
||||
: _Filter<Upstream, Downstream>,
|
||||
Subscriber,
|
||||
CustomStringConvertible
|
||||
where Upstream.Output == Downstream.Input,
|
||||
Upstream.Failure == Downstream.Failure {
|
||||
|
||||
var description: String { return "Filter" }
|
||||
|
||||
func receive(completion: Subscribers.Completion<Failure>) {
|
||||
guard !isFinished else { return }
|
||||
downstream.receive(completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Publishers.TryFilter {
|
||||
|
||||
private final class Inner<Downstream: Subscriber>
|
||||
: _Filter<Upstream, Downstream>,
|
||||
Subscriber,
|
||||
CustomStringConvertible
|
||||
where Upstream.Output == Downstream.Input, Downstream.Failure == Error {
|
||||
|
||||
var description: String { return "TryFilter" }
|
||||
|
||||
func receive(completion: Subscribers.Completion<Failure>) {
|
||||
guard !isFinished else { return }
|
||||
downstream.receive(completion: completion.eraseError())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ final class AnyCancellableTests: XCTestCase {
|
||||
("testStoreInArbitraryCollection", testStoreInArbitraryCollection),
|
||||
("testStoreInSet", testStoreInSet),
|
||||
("testIndirectCancellation", testIndirectCancellation),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testClosureInitialized() {
|
||||
@@ -151,4 +152,17 @@ final class AnyCancellableTests: XCTestCase {
|
||||
cancellable1.cancel()
|
||||
XCTAssertEqual(subscription.history, [.cancelled])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ final class AnyPublisherTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testErasePublisher", testErasePublisher),
|
||||
("testDescription", testDescription),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = AnyPublisher<Int, TestingError>
|
||||
@@ -42,4 +43,17 @@ final class AnyPublisherTests: XCTestCase {
|
||||
XCTAssertEqual(erased.description, "AnyPublisher")
|
||||
XCTAssertEqual(erased.description, erased.playgroundDescription as? String)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ final class AnySubscriberTests: XCTestCase {
|
||||
("testErasingSubscriberSubscription", testErasingSubscriberSubscription),
|
||||
("testErasingSubject", testErasingSubject),
|
||||
("testErasingSubjectSubscription", testErasingSubjectSubscription),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testCombineIdentifier() {
|
||||
@@ -180,6 +181,19 @@ final class AnySubscriberTests: XCTestCase {
|
||||
XCTAssertEqual(subject.history, [.subscription("Subject"),
|
||||
.completion(.finished)])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13.0, *)
|
||||
|
||||
@@ -21,6 +21,7 @@ final class CombineIdentifierTests: PerformanceTestCase {
|
||||
("testDefaultInitialized", testDefaultInitialized),
|
||||
("testAnyObject", testAnyObject),
|
||||
("testDefaultInitializedPerformance", testDefaultInitializedPerformance),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testDefaultInitialized() {
|
||||
@@ -56,4 +57,17 @@ final class CombineIdentifierTests: PerformanceTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ final class CurrentValueSubjectTests: XCTestCase {
|
||||
("testSendSubscription", testSendSubscription),
|
||||
("testLifecycle", testLifecycle),
|
||||
("testSynchronization", testSynchronization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = CurrentValueSubject<Int, TestingError>
|
||||
@@ -506,4 +507,17 @@ final class CurrentValueSubjectTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(completions.value.count, 200)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// OperatorTestHelper.swift
|
||||
//
|
||||
//
|
||||
// Created by Joseph Spadafora on 7/6/19.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST
|
||||
import Combine
|
||||
#else
|
||||
import OpenCombine
|
||||
#endif
|
||||
|
||||
/// `OperatorTestHelper` is an abstraction that helps avoid a lot of boilerplate when
|
||||
/// testing an operator. It is initialized with a publisher type and creates a
|
||||
/// `CustomSubscription`, `CustomPublisherBase` and `TrackingSubscriberBase`.
|
||||
@available(macOS 10.15, iOS 13.0, *)
|
||||
class OperatorTestHelper<SourceValue: Equatable,
|
||||
SourcePublisher,
|
||||
Sut: Publisher>
|
||||
where Sut.Output: Equatable,
|
||||
SourcePublisher: CustomPublisherBase<SourceValue, TestingError>
|
||||
{
|
||||
typealias Value = Sut.Output
|
||||
typealias Failure = Sut.Failure
|
||||
|
||||
let subscription: CustomSubscription
|
||||
let publisher: SourcePublisher
|
||||
let tracking: TrackingSubscriberBase<Value, Failure>
|
||||
private(set) var sut: Sut
|
||||
|
||||
var downstreamSubscription: Subscription?
|
||||
|
||||
/// This initializes the `OperatorTestHelper`. In most cases,
|
||||
/// you can just pass a `publisherType` and closure
|
||||
/// for `createSut` to get all the setup that you'll need for a test.
|
||||
/// - Parameter publisherType: This should be filled in with the
|
||||
/// type of `CustomPublisherBase` that you would like the
|
||||
/// operator you are testing to be built from.
|
||||
/// - Parameter initialDemand: This is the demand that the
|
||||
/// created `TrackingSubscriber` should return upon receiving a subscription.
|
||||
/// - Parameter receiveValueDemand: This is the demand that the
|
||||
/// created `TrackingSubscriber should return upon receiving a value.
|
||||
/// - Parameter customSubscription: This parameter defaults to `CustomSubscription()`,
|
||||
/// but can be replaced with your own instance if you want to override
|
||||
/// any of the default `CustomSubscription` initializer closures.
|
||||
/// - Parameter createSut: This closure takes a new concrete instance
|
||||
/// of the `publisherType` as an input to the closure and creates an
|
||||
/// instance of the operator that you are trying to test.
|
||||
init(publisherType: SourcePublisher.Type,
|
||||
initialDemand: Subscribers.Demand,
|
||||
receiveValueDemand: Subscribers.Demand,
|
||||
customSubscription: CustomSubscription = CustomSubscription(),
|
||||
createSut: (SourcePublisher) -> Sut)
|
||||
{
|
||||
self.subscription = customSubscription
|
||||
let createdPublisher = publisherType.init(subscription: customSubscription)
|
||||
self.publisher = createdPublisher
|
||||
self.sut = createSut(createdPublisher)
|
||||
self.tracking = TrackingSubscriberBase<Value, Failure>(
|
||||
receiveSubscription: {
|
||||
$0.request(initialDemand)
|
||||
},
|
||||
receiveValue: { _ in receiveValueDemand }
|
||||
)
|
||||
tracking.onSubscribe = { self.downstreamSubscription = $0 }
|
||||
sut.subscribe(tracking)
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,12 @@ final class TrackingSubscriberBase<Value: Equatable, Failure: Error>
|
||||
private let _receiveCompletion: ((Subscribers.Completion<Failure>) -> Void)?
|
||||
private let _onDeinit: (() -> Void)?
|
||||
|
||||
var onSubscribe: ((Subscription) -> Void)?
|
||||
var onValue: ((Input) -> Void)?
|
||||
var onFinish: (() -> Void)?
|
||||
var onFailure: ((Failure) -> Void)?
|
||||
var onDeinit: (() -> Void)?
|
||||
|
||||
/// The history of subscriptions, inputs and completions of this subscriber
|
||||
private(set) var history: [Event] = []
|
||||
|
||||
@@ -144,16 +150,24 @@ final class TrackingSubscriberBase<Value: Equatable, Failure: Error>
|
||||
|
||||
func receive(subscription: Subscription) {
|
||||
history.append(.subscription(.init(subscription)))
|
||||
onSubscribe?(subscription)
|
||||
_receiveSubscription?(subscription)
|
||||
}
|
||||
|
||||
func receive(_ input: Value) -> Subscribers.Demand {
|
||||
history.append(.value(input))
|
||||
onValue?(input)
|
||||
return _receiveValue?(input) ?? .none
|
||||
}
|
||||
|
||||
func receive(completion: Subscribers.Completion<Failure>) {
|
||||
history.append(.completion(completion))
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
onFailure?(error)
|
||||
case .finished:
|
||||
onFinish?()
|
||||
}
|
||||
_receiveCompletion?(completion)
|
||||
}
|
||||
|
||||
@@ -162,6 +176,7 @@ final class TrackingSubscriberBase<Value: Equatable, Failure: Error>
|
||||
}
|
||||
|
||||
deinit {
|
||||
onDeinit?()
|
||||
_onDeinit?()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ final class ImmediateSchedulerTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testStride", testSchedulerTimeType),
|
||||
("testActions", testActions),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testSchedulerTimeType() throws {
|
||||
@@ -80,5 +81,35 @@ final class ImmediateSchedulerTests: XCTestCase {
|
||||
}
|
||||
|
||||
XCTAssertTrue(fired)
|
||||
fired = false
|
||||
|
||||
ImmediateScheduler.shared.schedule(after: ImmediateScheduler.shared.now) {
|
||||
fired = true
|
||||
}
|
||||
|
||||
XCTAssertTrue(fired)
|
||||
fired = false
|
||||
|
||||
let cancellable = ImmediateScheduler
|
||||
.shared
|
||||
.schedule(after: ImmediateScheduler.shared.now, interval: 10) {
|
||||
fired = true
|
||||
}
|
||||
|
||||
XCTAssertTrue(fired)
|
||||
XCTAssertEqual(String(describing: cancellable), "Empty")
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ final class PassthroughSubjectTests: XCTestCase {
|
||||
("testSendSubscription", testSendSubscription),
|
||||
("testLifecycle", testLifecycle),
|
||||
("testSynchronization", testSynchronization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = PassthroughSubject<Int, TestingError>
|
||||
@@ -440,4 +441,17 @@ final class PassthroughSubjectTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(completions.value.count, 200)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ final class PublisherTests: XCTestCase {
|
||||
("testSubscribeSubscriber", testSubscribeSubscriber),
|
||||
("testSubscribeSubject", testSubscribeSubject),
|
||||
("testSubjectSubscriber", testSubjectSubscriber),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testSubscribeSubscriber() {
|
||||
@@ -105,4 +106,17 @@ final class PublisherTests: XCTestCase {
|
||||
|
||||
XCTAssert(subjectDestroyed)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ final class CountTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testSendsCorrectCount", testSendsCorrectCount),
|
||||
("testCountWaitsUntilFinishedToSend", testCountWaitsUntilFinishedToSend),
|
||||
("testDemand", testDemand),
|
||||
("testAddingSubscriberRequestsUnlimitedDemand",
|
||||
testAddingSubscriberRequestsUnlimitedDemand),
|
||||
("testReceivesSubscriptionBeforeRequestingUpstream",
|
||||
testReceivesSubscriptionBeforeRequestingUpstream)
|
||||
testReceivesSubscriptionBeforeRequestingUpstream),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testSendsCorrectCount() {
|
||||
@@ -147,4 +149,17 @@ final class CountTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(receiveOrder, [receiveDownstream, upstreamRequest])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ final class DecodeTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testDecodingSuccess", testDecodingSuccess),
|
||||
("testDecodingFailure", testDecodingFailure),
|
||||
("testDemand", testDemand)
|
||||
("testDemand", testDemand),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
var jsonEncoder: TestEncoder = TestEncoder()
|
||||
@@ -92,6 +93,19 @@ final class DecodeTests: XCTestCase {
|
||||
XCTAssertEqual(publisher.send(10), .none)
|
||||
XCTAssertEqual(subscription.history, [.requested(.max(42)), .cancelled])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
let testValue = ["test": "TestDecodable"]
|
||||
|
||||
@@ -19,7 +19,8 @@ final class DeferredTests: XCTestCase {
|
||||
|
||||
static let allTests = [
|
||||
("testDeferredCreatedAfterSubscription",
|
||||
testDeferredCreatedAfterSubscription)
|
||||
testDeferredCreatedAfterSubscription),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testDeferredCreatedAfterSubscription() {
|
||||
@@ -51,4 +52,17 @@ final class DeferredTests: XCTestCase {
|
||||
XCTAssertEqual(tracking.history, [.subscription("CustomSubscription"),
|
||||
.subscription("CustomSubscription")])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ final class DropWhileTests: XCTestCase {
|
||||
("testDemand", testDemand),
|
||||
("testTryDropWhileCancelsUpstreamOnThrow",
|
||||
testTryDropWhileCancelsUpstreamOnThrow),
|
||||
("testDropWhileCompletion",
|
||||
testDropWhileCompletion),
|
||||
("testDropWhileCompletion", testDropWhileCompletion),
|
||||
("testCancelAlreadyCancelled", testCancelAlreadyCancelled),
|
||||
("testLifecycle", testLifecycle),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testDropWhile() {
|
||||
@@ -331,4 +333,17 @@ final class DropWhileTests: XCTestCase {
|
||||
try XCTUnwrap(subscription).cancel()
|
||||
XCTAssertEqual(deinitCounter, 0)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ final class EmptyTests: XCTestCase {
|
||||
("testEmpty", testEmpty),
|
||||
("testImmediatelyCancel", testImmediatelyCancel),
|
||||
("testEquatable", testEquatable),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testEmpty() {
|
||||
@@ -75,4 +76,17 @@ final class EmptyTests: XCTestCase {
|
||||
outputType: Int.self,
|
||||
failureType: Error.self))
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ final class EncodeTests: XCTestCase {
|
||||
("testEncodingFailure", testEncodingFailure),
|
||||
("testDemand", testDemand),
|
||||
("testEncodeSuccessHistory", testEncodeSuccessHistory),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private var encoder = TestEncoder()
|
||||
@@ -108,4 +109,17 @@ final class EncodeTests: XCTestCase {
|
||||
XCTAssertEqual(publisher.send(["test" : "TestDecodable"]), .max(2))
|
||||
XCTAssertEqual(subscription.history, [.requested(.max(37))])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ final class FailTests: XCTestCase {
|
||||
|
||||
static let allTests = [
|
||||
("testSubscription", testSubscription),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = Fail<Int, TestingError>
|
||||
@@ -30,4 +31,17 @@ final class FailTests: XCTestCase {
|
||||
XCTAssertEqual(tracking.history, [.subscription("Empty"),
|
||||
.completion(.failure(.oops))])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
//
|
||||
// FilterTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Joseph Spadafora on 6/25/19.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST
|
||||
import Combine
|
||||
#else
|
||||
import OpenCombine
|
||||
#endif
|
||||
|
||||
@available(macOS 10.15, iOS 13.0, *)
|
||||
final class FilterTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testFilterRemovesElements", testFilterRemovesElements),
|
||||
("testTryFilterWorks", testTryFilterWorks),
|
||||
("testTryFilterCompletesWithErrorWhenThrown",
|
||||
testTryFilterCompletesWithErrorWhenThrown),
|
||||
("testCanCompleteWithFinished", testCanCompleteWithFinished),
|
||||
("testFilterCanCompleteWithError", testFilterCanCompleteWithError),
|
||||
("testTryFilterCanCompleteWithError", testTryFilterCanCompleteWithError),
|
||||
("testFilterSubscriptionDemand", testFilterSubscriptionDemand),
|
||||
("testTryFilterSubscriptionDemand", testTryFilterSubscriptionDemand),
|
||||
("testFilterCancel", testFilterCancel),
|
||||
("testTryFilterCancel", testTryFilterCancel),
|
||||
("testCancelAlreadyCancelled", testCancelAlreadyCancelled),
|
||||
("testLifecycle", testLifecycle),
|
||||
("testFilterOperatorSpecializationForFilter",
|
||||
testFilterOperatorSpecializationForFilter),
|
||||
("testTryFilterOperatorSpecializationForFilter",
|
||||
testTryFilterOperatorSpecializationForFilter),
|
||||
("testFilterOperatorSpecializationForTryFilter",
|
||||
testFilterOperatorSpecializationForTryFilter),
|
||||
("testTryFilterOperatorSpecializationForTryFilter",
|
||||
testTryFilterOperatorSpecializationForTryFilter),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testFilterRemovesElements() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(2),
|
||||
receiveValueDemand: .none) {
|
||||
$0.filter { $0.isMultiple(of: 2) }
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...5 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("Filter"),
|
||||
.value(2),
|
||||
.value(4)])
|
||||
}
|
||||
|
||||
func testTryFilterWorks() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(2),
|
||||
receiveValueDemand: .none) {
|
||||
$0.tryFilter {
|
||||
try $0.isMultiple(of: 2) && nonthrowingReturn($0)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...5 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
try helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter"),
|
||||
.value(2),
|
||||
.value(4)])
|
||||
}
|
||||
|
||||
func testTryFilterCompletesWithErrorWhenThrown() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none) {
|
||||
$0.tryFilter {
|
||||
try failOnFive(value: $0)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...5 {
|
||||
_ = helper.publisher.send(i)
|
||||
}
|
||||
|
||||
helper.publisher.send(completion: .finished)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter"),
|
||||
.value(1),
|
||||
.value(2),
|
||||
.value(3),
|
||||
.value(4),
|
||||
.completion(.failure(TestingError.oops))
|
||||
])
|
||||
}
|
||||
|
||||
func testCanCompleteWithFinished() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none) {
|
||||
$0.filter { _ in true }
|
||||
}
|
||||
|
||||
// When
|
||||
XCTAssertEqual(helper.publisher.send(1), .none)
|
||||
helper.publisher.send(completion: .finished)
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("Filter"),
|
||||
.value(1),
|
||||
.completion(.finished)])
|
||||
}
|
||||
|
||||
func testFilterCanCompleteWithError() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none) {
|
||||
$0.filter { _ in true }
|
||||
}
|
||||
|
||||
// When
|
||||
XCTAssertEqual(helper.publisher.send(1), .none)
|
||||
helper.publisher.send(completion: .failure(.oops))
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("Filter"),
|
||||
.value(1),
|
||||
.completion(.failure(.oops))])
|
||||
}
|
||||
|
||||
func testTryFilterCanCompleteWithError() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(
|
||||
publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none,
|
||||
createSut: {
|
||||
$0.tryFilter { _ in true }
|
||||
}
|
||||
)
|
||||
|
||||
// When
|
||||
XCTAssertEqual(helper.publisher.send(1), .none)
|
||||
helper.publisher.send(completion: .failure(.oops))
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history,
|
||||
[.subscription("TryFilter"),
|
||||
.value(1),
|
||||
.completion(.failure(TestingError.oops))])
|
||||
}
|
||||
|
||||
func testFilterSubscriptionDemand() {
|
||||
let helper = OperatorTestHelper(
|
||||
publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(3),
|
||||
receiveValueDemand: .none,
|
||||
createSut: {
|
||||
$0.filter { $0.isMultiple(of: 2) }
|
||||
}
|
||||
)
|
||||
|
||||
XCTAssertEqual(helper.publisher.send(1), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(2), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(3), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(4), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(5), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(6), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(7), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(8), .max(0))
|
||||
|
||||
XCTAssertEqual(helper.subscription.history, [.requested(.max(3))])
|
||||
}
|
||||
|
||||
func testTryFilterSubscriptionDemand() {
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(3),
|
||||
receiveValueDemand: .none) {
|
||||
$0.tryFilter { $0.isMultiple(of: 2) }
|
||||
}
|
||||
|
||||
XCTAssertEqual(helper.publisher.send(1), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(2), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(3), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(4), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(5), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(6), .max(0))
|
||||
XCTAssertEqual(helper.publisher.send(7), .max(1))
|
||||
XCTAssertEqual(helper.publisher.send(8), .max(0))
|
||||
}
|
||||
|
||||
func testFilterCancel() throws {
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none,
|
||||
createSut: { $0.filter { $0.isMultiple(of: 2) } })
|
||||
|
||||
try XCTUnwrap(helper.downstreamSubscription).cancel()
|
||||
XCTAssertEqual(helper.publisher.send(2), .none)
|
||||
helper.publisher.send(completion: .finished)
|
||||
XCTAssertEqual(helper.publisher.send(4), .none)
|
||||
|
||||
XCTAssertEqual(helper.subscription.history, [.requested(.unlimited), .cancelled])
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("Filter")])
|
||||
}
|
||||
|
||||
func testTryFilterCancel() throws {
|
||||
let helper = OperatorTestHelper(
|
||||
publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none,
|
||||
createSut: {
|
||||
$0.tryFilter { try failOnFive(value: $0) && $0.isMultiple(of: 2) }
|
||||
}
|
||||
)
|
||||
|
||||
try XCTUnwrap(helper.downstreamSubscription).cancel()
|
||||
XCTAssertEqual(helper.publisher.send(2), .none)
|
||||
helper.publisher.send(completion: .finished)
|
||||
XCTAssertEqual(helper.publisher.send(4), .none)
|
||||
XCTAssertEqual(helper.publisher.send(5), .none)
|
||||
|
||||
XCTAssertEqual(helper.subscription.history, [.requested(.unlimited), .cancelled])
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter")])
|
||||
}
|
||||
|
||||
func testCancelAlreadyCancelled() throws {
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .unlimited,
|
||||
receiveValueDemand: .none,
|
||||
createSut: { $0.filter { $0.isMultiple(of: 2) } })
|
||||
|
||||
try XCTUnwrap(helper.downstreamSubscription).cancel()
|
||||
try XCTUnwrap(helper.downstreamSubscription).request(.unlimited)
|
||||
try XCTUnwrap(helper.downstreamSubscription).cancel()
|
||||
|
||||
XCTAssertEqual(helper.subscription.history, [.requested(.unlimited), .cancelled])
|
||||
}
|
||||
|
||||
func testLifecycle() throws {
|
||||
|
||||
var deinitCounter = 0
|
||||
|
||||
let onDeinit = { deinitCounter += 1 }
|
||||
|
||||
do {
|
||||
let passthrough = PassthroughSubject<Int, TestingError>()
|
||||
let filter = passthrough.filter { $0.isMultiple(of: 2) }
|
||||
let emptySubscriber = TrackingSubscriber(onDeinit: onDeinit)
|
||||
XCTAssertTrue(emptySubscriber.history.isEmpty)
|
||||
filter.subscribe(emptySubscriber)
|
||||
XCTAssertEqual(emptySubscriber.subscriptions.count, 1)
|
||||
passthrough.send(31)
|
||||
XCTAssertEqual(emptySubscriber.inputs.count, 0)
|
||||
passthrough.send(completion: .failure("failure"))
|
||||
XCTAssertEqual(emptySubscriber.completions.count, 1)
|
||||
}
|
||||
|
||||
XCTAssertEqual(deinitCounter, 0)
|
||||
|
||||
do {
|
||||
let passthrough = PassthroughSubject<Int, TestingError>()
|
||||
let filter = passthrough.filter { $0.isMultiple(of: 2) }
|
||||
let emptySubscriber = TrackingSubscriber(onDeinit: onDeinit)
|
||||
XCTAssertTrue(emptySubscriber.history.isEmpty)
|
||||
filter.subscribe(emptySubscriber)
|
||||
XCTAssertEqual(emptySubscriber.subscriptions.count, 1)
|
||||
XCTAssertEqual(emptySubscriber.inputs.count, 0)
|
||||
XCTAssertEqual(emptySubscriber.completions.count, 0)
|
||||
}
|
||||
|
||||
XCTAssertEqual(deinitCounter, 0)
|
||||
|
||||
var subscription: Subscription?
|
||||
|
||||
do {
|
||||
let passthrough = PassthroughSubject<Int, TestingError>()
|
||||
let filter = passthrough.filter { $0.isMultiple(of: 2) }
|
||||
let emptySubscriber = TrackingSubscriber(
|
||||
receiveSubscription: { subscription = $0; $0.request(.unlimited) },
|
||||
onDeinit: onDeinit
|
||||
)
|
||||
XCTAssertTrue(emptySubscriber.history.isEmpty)
|
||||
filter.subscribe(emptySubscriber)
|
||||
XCTAssertEqual(emptySubscriber.subscriptions.count, 1)
|
||||
passthrough.send(32)
|
||||
XCTAssertEqual(emptySubscriber.inputs.count, 1)
|
||||
XCTAssertEqual(emptySubscriber.completions.count, 0)
|
||||
XCTAssertNotNil(subscription)
|
||||
}
|
||||
|
||||
XCTAssertEqual(deinitCounter, 0)
|
||||
try XCTUnwrap(subscription).cancel()
|
||||
XCTAssertEqual(deinitCounter, 0)
|
||||
}
|
||||
|
||||
func testFilterOperatorSpecializationForFilter() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(1),
|
||||
receiveValueDemand: .none) {
|
||||
$0.filter {
|
||||
$0.isMultiple(of: 3)
|
||||
}.filter {
|
||||
$0.isMultiple(of: 5)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...20 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("Filter"), .value(15)])
|
||||
}
|
||||
|
||||
func testTryFilterOperatorSpecializationForFilter() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(1),
|
||||
receiveValueDemand: .none) {
|
||||
$0.filter {
|
||||
$0.isMultiple(of: 3)
|
||||
}.tryFilter {
|
||||
$0.isMultiple(of: 5)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...20 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
try helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter"), .value(15)])
|
||||
}
|
||||
|
||||
func testFilterOperatorSpecializationForTryFilter() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(1),
|
||||
receiveValueDemand: .none) {
|
||||
$0.tryFilter {
|
||||
$0.isMultiple(of: 3)
|
||||
}.filter {
|
||||
$0.isMultiple(of: 5)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...20 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
try helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter"), .value(15)])
|
||||
}
|
||||
|
||||
func testTryFilterOperatorSpecializationForTryFilter() {
|
||||
// Given
|
||||
let helper = OperatorTestHelper(publisherType: CustomPublisher.self,
|
||||
initialDemand: .max(3),
|
||||
receiveValueDemand: .none) {
|
||||
$0.tryFilter {
|
||||
$0.isMultiple(of: 3)
|
||||
}.tryFilter {
|
||||
$0.isMultiple(of: 5)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
for i in 1...20 {
|
||||
XCTAssertEqual(helper.publisher.send(i),
|
||||
try helper.sut.isIncluded(i) ? .none : .max(1))
|
||||
}
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(helper.tracking.history, [.subscription("TryFilter"),
|
||||
.value(15)])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private func nonthrowingReturn(_ value: Int) throws -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
private func failOnFive(value: Int) throws -> Bool {
|
||||
if value == 5 {
|
||||
throw TestingError.oops
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -65,6 +65,7 @@ final class JustTests: XCTestCase {
|
||||
("testPrefixWhileOperatorSpecialization", testPrefixWhileOperatorSpecialization),
|
||||
("testSetFailureTypeOperatorSpecialization",
|
||||
testSetFailureTypeOperatorSpecialization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = Just
|
||||
@@ -357,4 +358,17 @@ final class JustTests: XCTestCase {
|
||||
func testSetFailureTypeOperatorSpecialization() {
|
||||
XCTAssertEqual(try Sut(73).setFailureType(to: TestingError.self).result.get(), 73)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ final class MapErrorTests: XCTestCase {
|
||||
("testCancel", testCancel),
|
||||
("testCancelAlreadyCancelled", testCancelAlreadyCancelled),
|
||||
("testLifecycle", testLifecycle),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testEmpty() {
|
||||
@@ -251,6 +252,19 @@ final class MapErrorTests: XCTestCase {
|
||||
try XCTUnwrap(subscription).cancel()
|
||||
XCTAssertEqual(deinitCounter, 2)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private struct OtherError: Error {
|
||||
|
||||
@@ -36,7 +36,8 @@ final class MapTests: XCTestCase {
|
||||
("testMapOperatorSpecializationForTryMap",
|
||||
testMapOperatorSpecializationForTryMap),
|
||||
("testTryMapOperatorSpecializationForTryMap",
|
||||
testTryMapOperatorSpecializationForTryMap)
|
||||
testTryMapOperatorSpecializationForTryMap),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testEmpty() {
|
||||
@@ -458,4 +459,17 @@ final class MapTests: XCTestCase {
|
||||
.value(11),
|
||||
.completion(.failure(TestingError.oops))])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ final class MulticastTests: XCTestCase {
|
||||
("testMulticastDisconnect", testMulticastDisconnect),
|
||||
("testLateSubscriber", testLateSubscriber),
|
||||
("testSubscribeAfterCompletion", testSubscribeAfterCompletion),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testMulticast() throws {
|
||||
@@ -285,4 +286,17 @@ final class MulticastTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(lateSubscriber.history, [.subscription("Multicast")])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ final class OptionalPublisherTests: XCTestCase {
|
||||
testOutputInRangeOperatorSpecialization),
|
||||
("testPrefixOperatorSpecialization", testPrefixOperatorSpecialization),
|
||||
("testPrefixWhileOperatorSpecialization", testPrefixWhileOperatorSpecialization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST || !canImport(Combine)
|
||||
@@ -367,4 +368,17 @@ final class OptionalPublisherTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(count, 2)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ final class PrintTests: XCTestCase {
|
||||
("testPrintWithoutPrefix", testPrintWithoutPrefix),
|
||||
("testPrintWithPrefix", testPrintWithPrefix),
|
||||
("testSynchronization", testSynchronization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testPrintWithoutPrefix() {
|
||||
@@ -212,6 +213,19 @@ final class PrintTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(counter.value, 200)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private final class StringStream: TextOutputStream {
|
||||
|
||||
@@ -18,7 +18,8 @@ final class ReplaceNilTests: XCTestCase {
|
||||
static let allTests = [
|
||||
("testReplacesNilElement", testReplacesNilElement),
|
||||
("testExistingElementIsPreserved", testExistingElementIsPreserved),
|
||||
("testMultipleReplacements", testMultipleReplacements)
|
||||
("testMultipleReplacements", testMultipleReplacements),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testReplacesNilElement() {
|
||||
@@ -91,4 +92,17 @@ final class ReplaceNilTests: XCTestCase {
|
||||
.value(42),
|
||||
.completion(.finished)])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ final class ResultPublisherTests: XCTestCase {
|
||||
("testTryScanOperatorSpecialization", testTryScanOperatorSpecialization),
|
||||
("testSetFailureTypeOperatorSpecialization",
|
||||
testSetFailureTypeOperatorSpecialization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST || !canImport(Combine)
|
||||
@@ -451,4 +452,17 @@ final class ResultPublisherTests: XCTestCase {
|
||||
73
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ final class SequenceTests: XCTestCase {
|
||||
testAppendSequenceOperatorSpecialization),
|
||||
("testAppendPublisherOperatorSpecialization",
|
||||
testAppendPublisherOperatorSpecialization),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
#if OPENCOMBINE_COMPATIBILITY_TEST || !canImport(Combine)
|
||||
@@ -662,6 +663,19 @@ final class SequenceTests: XCTestCase {
|
||||
XCTAssertEqual(newCollection.history, [.initFromSequence,
|
||||
.appendSequence])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private final class Counter: Sequence, IteratorProtocol, CustomStringConvertible {
|
||||
|
||||
@@ -25,6 +25,7 @@ final class SetFailureTypeTests: XCTestCase {
|
||||
("testCompletion", testCompletion),
|
||||
("testCancel", testCancel),
|
||||
("testCancelAlreadyCancelled", testCancelAlreadyCancelled),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testEmpty() {
|
||||
@@ -169,4 +170,17 @@ final class SetFailureTypeTests: XCTestCase {
|
||||
.requested(.unlimited),
|
||||
.cancelled])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ final class AssignTests: XCTestCase {
|
||||
("testSubscription", testSubscription),
|
||||
("testReceiveValue", testReceiveValue),
|
||||
("testPublisherOperator", testPublisherOperator),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut<Root> = Subscribers.Assign<Root, Int>
|
||||
@@ -129,4 +130,17 @@ final class AssignTests: XCTestCase {
|
||||
publisher.send(100)
|
||||
XCTAssertEqual(object.value, 42)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ import Foundation
|
||||
final class CompletionTests: XCTestCase {
|
||||
|
||||
static let allTests = [
|
||||
("testEncodingDecoding", testEncodingDecoding)
|
||||
("testEncodingDecoding", testEncodingDecoding),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
typealias Sut = Subscribers.Completion<TestingError>
|
||||
@@ -67,4 +68,17 @@ final class CompletionTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ final class SinkTests: XCTestCase {
|
||||
("testSubscription", testSubscription),
|
||||
("testReceiveValue", testReceiveValue),
|
||||
("testPublisherOperator", testPublisherOperator),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
private typealias Sut = Subscribers.Sink<Int, Never>
|
||||
@@ -116,4 +117,17 @@ final class SinkTests: XCTestCase {
|
||||
publisher.send(100)
|
||||
XCTAssertEqual(value, 42)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ final class SubscribersDemandTests: XCTestCase {
|
||||
("testDescription", testDescription),
|
||||
("testEncodeDecodeJSON", testEncodeDecodeJSON),
|
||||
("testEncodeDecodePlist", testEncodeDecodePlist),
|
||||
("testTestSuiteIncludesAllTests", testTestSuiteIncludesAllTests),
|
||||
]
|
||||
|
||||
func testCrashesOnNegativeValue() {
|
||||
@@ -325,6 +326,19 @@ final class SubscribersDemandTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(decodedIllFormedTooBig.value.description, "unlimited")
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
func testTestSuiteIncludesAllTests() {
|
||||
// https://oleb.net/blog/2017/03/keeping-xctest-in-sync/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let thisClass = type(of: self)
|
||||
let allTestsCount = thisClass.allTests.count
|
||||
let darwinCount = thisClass.defaultTestSuite.testCaseCount
|
||||
XCTAssertEqual(allTestsCount,
|
||||
darwinCount,
|
||||
"\(darwinCount - allTestsCount) tests are missing from allTests")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.15, iOS 13.0, *)
|
||||
|
||||
@@ -12,28 +12,32 @@ public func allTests() -> [XCTestCaseEntry] {
|
||||
return [
|
||||
testCase(AnyCancellableTests.allTests),
|
||||
testCase(AnyPublisherTests.allTests),
|
||||
testCase(AnySubscriberTests.allTests),
|
||||
testCase(AssignTests.allTests),
|
||||
testCase(CombineIdentifierTests.allTests),
|
||||
testCase(CompletionTests.allTests),
|
||||
testCase(CountTests.allTests),
|
||||
testCase(CurrentValueSubjectTests.allTests),
|
||||
testCase(DecodeTests.allTests),
|
||||
testCase(DeferredTests.allTests),
|
||||
testCase(DropWhileTests.allTests),
|
||||
testCase(EmptyTests.allTests),
|
||||
testCase(EncodeTests.allTests),
|
||||
testCase(FailTests.allTests),
|
||||
testCase(FilterTests.allTests),
|
||||
testCase(ImmediateSchedulerTests.allTests),
|
||||
testCase(JustTests.allTests),
|
||||
testCase(MapErrorTests.allTests),
|
||||
testCase(MapTests.allTests),
|
||||
testCase(MulticastTests.allTests),
|
||||
testCase(ResultPublisherTests.allTests),
|
||||
testCase(OptionalPublisherTests.allTests),
|
||||
testCase(PassthroughSubjectTests.allTests),
|
||||
testCase(PrintTests.allTests),
|
||||
testCase(PublisherTests.allTests),
|
||||
testCase(ReplaceNilTests.allTests),
|
||||
testCase(SetFailureTypeTests.allTests),
|
||||
testCase(ResultPublisherTests.allTests),
|
||||
testCase(SequenceTests.allTests),
|
||||
testCase(SetFailureTypeTests.allTests),
|
||||
testCase(SinkTests.allTests),
|
||||
testCase(SubscribersDemandTests.allTests),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user