From 81066514fed0211074284a4d60895d13b8ce0eb6 Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 27 Aug 2017 18:51:43 +0200 Subject: [PATCH] Renames `Publisher` to `Signal`. --- .jazzy.yml | 12 +- CHANGELOG.md | 2 +- Rx.xcodeproj/project.pbxproj | 158 +- RxCocoa/Deprecated.swift | 23 + RxCocoa/Traits/ControlEvent.swift | 2 +- RxCocoa/Traits/ControlProperty.swift | 2 +- .../Traits/Driver/Driver+Subscription.swift | 17 +- RxCocoa/Traits/Driver/Driver.swift | 48 +- .../ObservableConvertibleType+Driver.swift | 12 +- RxCocoa/Traits/Driver/Variable+Driver.swift | 2 +- RxCocoa/Traits/PublishRelay.swift | 19 +- RxCocoa/Traits/Publisher/Publisher.swift | 62 - .../SchedulerType+SharedSequence.swift | 61 + .../Variable+SharedSequence.swift | 22 - .../ObservableConvertibleType+Signal.swift | 60 + .../PublishRelay+Signal.swift} | 11 +- .../Traits/Signal/Signal+Subscription.swift | 80 + RxCocoa/Traits/Signal/Signal.swift | 47 + Sources/AllTestz/Driver+Extensions.swift | 1 - .../AllTestz/SharedSequence+Extensions.swift | 1 + .../SharedSequence+OperatorTest.swift | 1 + Sources/AllTestz/SharedSequence+Test.swift | 1 + Sources/AllTestz/SharingSchedulerTests.swift | 1 + Sources/AllTestz/Signal+Test.swift | 1 + Sources/AllTestz/main.swift | 138 +- .../ObservableConvertibleType+Signal.swift | 1 + .../RxCocoa/PublishRelay+SharedSequence.swift | 1 - Sources/RxCocoa/PublishRelay+Signal.swift | 1 + Sources/RxCocoa/Publisher.swift | 1 - .../SchedulerType+SharedSequence.swift | 1 + Sources/RxCocoa/Signal+Subscription.swift | 1 + Sources/RxCocoa/Signal.swift | 1 + Sources/RxCocoa/Variable+SharedSequence.swift | 1 - Tests/RxCocoaTests/Driver+Test.swift | 1289 ++--------------- Tests/RxCocoaTests/PublisherTests.swift | 97 -- ....swift => SharedSequence+Extensions.swift} | 2 +- .../SharedSequence+OperatorTest.swift | 1054 ++++++++++++++ Tests/RxCocoaTests/SharedSequence+Test.swift | 111 ++ Tests/RxCocoaTests/Signal+Test.swift | 326 +++++ .../RxSwiftTests/SharingSchedulerTests.swift | 84 ++ scripts/package-spm.swift | 5 +- 41 files changed, 2216 insertions(+), 1544 deletions(-) delete mode 100644 RxCocoa/Traits/Publisher/Publisher.swift create mode 100644 RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift delete mode 100644 RxCocoa/Traits/SharedSequence/Variable+SharedSequence.swift create mode 100644 RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift rename RxCocoa/Traits/{SharedSequence/PublishRelay+SharedSequence.swift => Signal/PublishRelay+Signal.swift} (51%) create mode 100644 RxCocoa/Traits/Signal/Signal+Subscription.swift create mode 100644 RxCocoa/Traits/Signal/Signal.swift delete mode 120000 Sources/AllTestz/Driver+Extensions.swift create mode 120000 Sources/AllTestz/SharedSequence+Extensions.swift create mode 120000 Sources/AllTestz/SharedSequence+OperatorTest.swift create mode 120000 Sources/AllTestz/SharedSequence+Test.swift create mode 120000 Sources/AllTestz/SharingSchedulerTests.swift create mode 120000 Sources/AllTestz/Signal+Test.swift create mode 120000 Sources/RxCocoa/ObservableConvertibleType+Signal.swift delete mode 120000 Sources/RxCocoa/PublishRelay+SharedSequence.swift create mode 120000 Sources/RxCocoa/PublishRelay+Signal.swift delete mode 120000 Sources/RxCocoa/Publisher.swift create mode 120000 Sources/RxCocoa/SchedulerType+SharedSequence.swift create mode 120000 Sources/RxCocoa/Signal+Subscription.swift create mode 120000 Sources/RxCocoa/Signal.swift delete mode 120000 Sources/RxCocoa/Variable+SharedSequence.swift delete mode 100644 Tests/RxCocoaTests/PublisherTests.swift rename Tests/RxCocoaTests/{Driver+Extensions.swift => SharedSequence+Extensions.swift} (90%) create mode 100644 Tests/RxCocoaTests/SharedSequence+OperatorTest.swift create mode 100644 Tests/RxCocoaTests/SharedSequence+Test.swift create mode 100644 Tests/RxCocoaTests/Signal+Test.swift create mode 100644 Tests/RxSwiftTests/SharingSchedulerTests.swift diff --git a/.jazzy.yml b/.jazzy.yml index 0ccc4edc..19e69396 100644 --- a/.jazzy.yml +++ b/.jazzy.yml @@ -288,14 +288,16 @@ custom_categories: - Driver - ObservableConvertibleType+Driver - Variable+Driver -- name: RxCocoa/Traits/Publisher - children: - - Publisher - name: RxCocoa/Traits/SharedSequence children: - ObservableConvertibleType+SharedSequence - - PublishRelay+SharedSequence + - SchedulerType+SharedSequence - SharedSequence+Operators+arity - SharedSequence+Operators - SharedSequence - - Variable+SharedSequence +- name: RxCocoa/Traits/Signal + children: + - ObservableConvertibleType+Signal + - PublishRelay+Signal + - Signal+Subscription + - Signal diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ee824d0..4ba4a9c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -126,7 +126,7 @@ All notable changes to this project will be documented in this file. ## [3.3.0](https://github.com/ReactiveX/RxSwift/releases/tag/3.3.0) (Xcode 8 / Swift 3.0 compatible) -* Adds `Single`, `Maybe`, `Completable` units inspired by RxJava (operators): +* Adds `Single`, `Maybe`, `Completable` traits inspired by RxJava (operators): * `create` * `deferred` * `just` diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index c46d1d6b..755e87b8 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -647,8 +647,6 @@ C835092F1C38706E0027C24C /* ControlPropertyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508DE1C38706D0027C24C /* ControlPropertyTests.swift */; }; C83509311C38706E0027C24C /* DelegateProxyTest+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E01C38706D0027C24C /* DelegateProxyTest+UIKit.swift */; }; C83509321C38706E0027C24C /* DelegateProxyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E11C38706D0027C24C /* DelegateProxyTest.swift */; }; - C83509331C38706E0027C24C /* Driver+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E21C38706D0027C24C /* Driver+Extensions.swift */; }; - C83509341C38706E0027C24C /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E31C38706D0027C24C /* Driver+Test.swift */; }; C83509351C38706E0027C24C /* KVOObservableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E41C38706D0027C24C /* KVOObservableTests.swift */; }; C83509361C38706E0027C24C /* NSLayoutConstraint+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E51C38706D0027C24C /* NSLayoutConstraint+RxTests.swift */; }; C83509371C38706E0027C24C /* NotificationCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E61C38706D0027C24C /* NotificationCenterTests.swift */; }; @@ -699,15 +697,11 @@ C83509BE1C3875100027C24C /* DelegateProxyTest+Cocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508DF1C38706D0027C24C /* DelegateProxyTest+Cocoa.swift */; }; C83509BF1C3875220027C24C /* DelegateProxyTest+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E01C38706D0027C24C /* DelegateProxyTest+UIKit.swift */; }; C83509C01C3875220027C24C /* DelegateProxyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E11C38706D0027C24C /* DelegateProxyTest.swift */; }; - C83509C11C3875220027C24C /* Driver+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E21C38706D0027C24C /* Driver+Extensions.swift */; }; - C83509C21C3875220027C24C /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E31C38706D0027C24C /* Driver+Test.swift */; }; C83509C31C3875220027C24C /* KVOObservableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E41C38706D0027C24C /* KVOObservableTests.swift */; }; C83509C41C3875220027C24C /* NSLayoutConstraint+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E51C38706D0027C24C /* NSLayoutConstraint+RxTests.swift */; }; C83509C51C3875220027C24C /* NotificationCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E61C38706D0027C24C /* NotificationCenterTests.swift */; }; C83509C61C3875220027C24C /* NSObject+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E71C38706D0027C24C /* NSObject+RxTests.swift */; }; C83509C81C3875230027C24C /* DelegateProxyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E11C38706D0027C24C /* DelegateProxyTest.swift */; }; - C83509C91C3875230027C24C /* Driver+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E21C38706D0027C24C /* Driver+Extensions.swift */; }; - C83509CA1C3875230027C24C /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E31C38706D0027C24C /* Driver+Test.swift */; }; C83509CB1C3875230027C24C /* KVOObservableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E41C38706D0027C24C /* KVOObservableTests.swift */; }; C83509CC1C3875230027C24C /* NSLayoutConstraint+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E51C38706D0027C24C /* NSLayoutConstraint+RxTests.swift */; }; C83509CD1C3875230027C24C /* NotificationCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83508E61C38706D0027C24C /* NotificationCenterTests.swift */; }; @@ -874,8 +868,14 @@ C85B016E1DB2ACAF006043C3 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85B01681DB2ACAF006043C3 /* Platform.Linux.swift */; }; C85B016F1DB2ACAF006043C3 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85B01681DB2ACAF006043C3 /* Platform.Linux.swift */; }; C85B01701DB2ACAF006043C3 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85B01681DB2ACAF006043C3 /* Platform.Linux.swift */; }; - C860EC951C42E25E00A664B3 /* SectionedViewDataSourceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D132521C42DA7F00B59FFF /* SectionedViewDataSourceMock.swift */; }; - C860EC961C42E26100A664B3 /* SectionedViewDataSourceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D132521C42DA7F00B59FFF /* SectionedViewDataSourceMock.swift */; }; + C85E6FBE1F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */; }; + C85E6FBF1F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */; }; + C85E6FC01F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */; }; + C85E6FC11F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */; }; + C85E6FC21F5305E300C5681E /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBB1F52FF4F00C5681E /* Signal.swift */; }; + C85E6FC31F5305E400C5681E /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBB1F52FF4F00C5681E /* Signal.swift */; }; + C85E6FC41F5305E400C5681E /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBB1F52FF4F00C5681E /* Signal.swift */; }; + C85E6FC51F5305E500C5681E /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C85E6FBB1F52FF4F00C5681E /* Signal.swift */; }; C86781701DB8129E00B2029A /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = C867816C1DB8129E00B2029A /* Bag.swift */; }; C86781711DB8129E00B2029A /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = C867816C1DB8129E00B2029A /* Bag.swift */; }; C86781721DB8129E00B2029A /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = C867816C1DB8129E00B2029A /* Bag.swift */; }; @@ -1036,10 +1036,6 @@ C89AB1F71DAAC3350065FBE6 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B91DAAC3350065FBE6 /* SharedSequence.swift */; }; C89AB1F81DAAC3350065FBE6 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B91DAAC3350065FBE6 /* SharedSequence.swift */; }; C89AB1F91DAAC3350065FBE6 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1B91DAAC3350065FBE6 /* SharedSequence.swift */; }; - C89AB1FA1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */; }; - C89AB1FB1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */; }; - C89AB1FC1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */; }; - C89AB1FD1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */; }; C89AB1FE1DAAC3350065FBE6 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BB1DAAC3350065FBE6 /* UIBindingObserver.swift */; }; C89AB1FF1DAAC3350065FBE6 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BB1DAAC3350065FBE6 /* UIBindingObserver.swift */; }; C89AB2001DAAC3350065FBE6 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AB1BB1DAAC3350065FBE6 /* UIBindingObserver.swift */; }; @@ -1188,6 +1184,21 @@ C8A9B6F41DAD752200C9B027 /* Observable+BindTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A9B6F31DAD752200C9B027 /* Observable+BindTests.swift */; }; C8A9B6F51DAD752200C9B027 /* Observable+BindTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A9B6F31DAD752200C9B027 /* Observable+BindTests.swift */; }; C8A9B6F61DAD752200C9B027 /* Observable+BindTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8A9B6F31DAD752200C9B027 /* Observable+BindTests.swift */; }; + C8B0F70D1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F70C1F530A1700548EBE /* SharingSchedulerTests.swift */; }; + C8B0F70E1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F70C1F530A1700548EBE /* SharingSchedulerTests.swift */; }; + C8B0F70F1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F70C1F530A1700548EBE /* SharingSchedulerTests.swift */; }; + C8B0F7151F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */; }; + C8B0F7161F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */; }; + C8B0F7171F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */; }; + C8B0F7181F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */; }; + C8B0F7191F530FE300548EBE /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7101F530CA700548EBE /* PublishRelay.swift */; }; + C8B0F71A1F530FE400548EBE /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7101F530CA700548EBE /* PublishRelay.swift */; }; + C8B0F71B1F530FE500548EBE /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7101F530CA700548EBE /* PublishRelay.swift */; }; + C8B0F71C1F530FE500548EBE /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7101F530CA700548EBE /* PublishRelay.swift */; }; + C8B0F7221F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */; }; + C8B0F7231F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */; }; + C8B0F7241F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */; }; + C8B0F7251F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */; }; C8B144FB1BD2D44500267DCE /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */; }; C8B144FC1BD2D44500267DCE /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */; }; C8B144FD1BD2D44500267DCE /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */; }; @@ -1251,6 +1262,27 @@ C8D132451C42D15E00B59FFF /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D132431C42D15E00B59FFF /* SectionedViewDataSourceType.swift */; }; C8D132461C42D15E00B59FFF /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D132431C42D15E00B59FFF /* SectionedViewDataSourceType.swift */; }; C8D132471C42D15E00B59FFF /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D132431C42D15E00B59FFF /* SectionedViewDataSourceType.swift */; }; + C8D970CE1F5324D90058F2FE /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */; }; + C8D970CF1F5324D90058F2FE /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */; }; + C8D970D01F5324D90058F2FE /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */; }; + C8D970D11F5324D90058F2FE /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */; }; + C8D970E31F532FD30058F2FE /* Signal+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DC1F532FD10058F2FE /* Signal+Test.swift */; }; + C8D970E41F532FD30058F2FE /* Signal+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DC1F532FD10058F2FE /* Signal+Test.swift */; }; + C8D970E51F532FD30058F2FE /* Signal+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DC1F532FD10058F2FE /* Signal+Test.swift */; }; + C8D970E61F532FD30058F2FE /* SharedSequence+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DD1F532FD10058F2FE /* SharedSequence+Test.swift */; }; + C8D970E71F532FD30058F2FE /* SharedSequence+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DD1F532FD10058F2FE /* SharedSequence+Test.swift */; }; + C8D970E81F532FD30058F2FE /* SharedSequence+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DD1F532FD10058F2FE /* SharedSequence+Test.swift */; }; + C8D970E91F532FD30058F2FE /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DE1F532FD20058F2FE /* Driver+Test.swift */; }; + C8D970EA1F532FD30058F2FE /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DE1F532FD20058F2FE /* Driver+Test.swift */; }; + C8D970EB1F532FD30058F2FE /* Driver+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970DE1F532FD20058F2FE /* Driver+Test.swift */; }; + C8D970EC1F532FD30058F2FE /* SectionedViewDataSourceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E01F532FD20058F2FE /* SectionedViewDataSourceMock.swift */; }; + C8D970ED1F532FD30058F2FE /* SectionedViewDataSourceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E01F532FD20058F2FE /* SectionedViewDataSourceMock.swift */; }; + C8D970EF1F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E11F532FD20058F2FE /* SharedSequence+Extensions.swift */; }; + C8D970F01F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E11F532FD20058F2FE /* SharedSequence+Extensions.swift */; }; + C8D970F11F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E11F532FD20058F2FE /* SharedSequence+Extensions.swift */; }; + C8D970F21F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E21F532FD30058F2FE /* SharedSequence+OperatorTest.swift */; }; + C8D970F31F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E21F532FD30058F2FE /* SharedSequence+OperatorTest.swift */; }; + C8D970F41F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D970E21F532FD30058F2FE /* SharedSequence+OperatorTest.swift */; }; C8E390631F379041004FC993 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E390621F379041004FC993 /* Enumerated.swift */; }; C8E390641F379041004FC993 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E390621F379041004FC993 /* Enumerated.swift */; }; C8E390651F379041004FC993 /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E390621F379041004FC993 /* Enumerated.swift */; }; @@ -1907,8 +1939,6 @@ C83508DF1C38706D0027C24C /* DelegateProxyTest+Cocoa.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DelegateProxyTest+Cocoa.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C83508E01C38706D0027C24C /* DelegateProxyTest+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "DelegateProxyTest+UIKit.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C83508E11C38706D0027C24C /* DelegateProxyTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelegateProxyTest.swift; sourceTree = ""; }; - C83508E21C38706D0027C24C /* Driver+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Driver+Extensions.swift"; sourceTree = ""; }; - C83508E31C38706D0027C24C /* Driver+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Driver+Test.swift"; sourceTree = ""; }; C83508E41C38706D0027C24C /* KVOObservableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVOObservableTests.swift; sourceTree = ""; }; C83508E51C38706D0027C24C /* NSLayoutConstraint+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraint+RxTests.swift"; sourceTree = ""; }; C83508E61C38706D0027C24C /* NotificationCenterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationCenterTests.swift; sourceTree = ""; }; @@ -1986,6 +2016,8 @@ C85B01721DB2ACF2006043C3 /* Platform.Darwin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Platform.Darwin.swift; sourceTree = ""; }; C85B01731DB2ACF2006043C3 /* Platform.Linux.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Platform.Linux.swift; sourceTree = ""; }; C85BA04B1C3878740075D68E /* PerformanceTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = PerformanceTests.app; path = Microoptimizations.app; sourceTree = BUILT_PRODUCTS_DIR; }; + C85E6FBB1F52FF4F00C5681E /* Signal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signal.swift; sourceTree = ""; }; + C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SchedulerType+SharedSequence.swift"; sourceTree = ""; }; C86781471DB8119900B2029A /* Bag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bag.swift; sourceTree = ""; }; C86781481DB8119900B2029A /* InfiniteSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteSequence.swift; sourceTree = ""; }; C86781491DB8119900B2029A /* PriorityQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriorityQueue.swift; sourceTree = ""; }; @@ -2062,7 +2094,6 @@ C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SharedSequence+Operators+arity.tt"; sourceTree = ""; }; C89AB1B81DAAC3350065FBE6 /* SharedSequence+Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SharedSequence+Operators.swift"; sourceTree = ""; }; C89AB1B91DAAC3350065FBE6 /* SharedSequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedSequence.swift; sourceTree = ""; }; - C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Variable+SharedSequence.swift"; sourceTree = ""; }; C89AB1BB1DAAC3350065FBE6 /* UIBindingObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBindingObserver.swift; sourceTree = ""; }; C89AB1BD1DAAC3350065FBE6 /* KVORepresentable+CoreGraphics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "KVORepresentable+CoreGraphics.swift"; sourceTree = ""; }; C89AB1BE1DAAC3350065FBE6 /* KVORepresentable+Swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "KVORepresentable+Swift.swift"; sourceTree = ""; }; @@ -2104,6 +2135,10 @@ C8A81C9F1E05E82C0008DEF4 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Extensions.swift"; sourceTree = ""; }; C8A81CA51E05EAF70008DEF4 /* UIBindingObserver+Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIBindingObserver+Tests.swift"; sourceTree = ""; }; C8A9B6F31DAD752200C9B027 /* Observable+BindTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+BindTests.swift"; sourceTree = ""; }; + C8B0F70C1F530A1700548EBE /* SharingSchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingSchedulerTests.swift; sourceTree = ""; }; + C8B0F7101F530CA700548EBE /* PublishRelay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublishRelay.swift; sourceTree = ""; }; + C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PublishRelay+Signal.swift"; sourceTree = ""; }; + C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObservableConvertibleType+Signal.swift"; sourceTree = ""; }; C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentMainScheduler.swift; sourceTree = ""; }; C8B290841C94D55600E923D0 /* RxTest+Controls.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RxTest+Controls.swift"; sourceTree = ""; }; C8B2908C1C94D6C500E923D0 /* UISearchBar+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UISearchBar+RxTests.swift"; sourceTree = ""; }; @@ -2130,8 +2165,14 @@ C8C4F1741DE9D80A00003FA7 /* NSSlider+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSSlider+RxTests.swift"; sourceTree = ""; }; C8C4F1761DE9D84900003FA7 /* NSButton+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSButton+RxTests.swift"; sourceTree = ""; }; C8D132431C42D15E00B59FFF /* SectionedViewDataSourceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedViewDataSourceType.swift; sourceTree = ""; }; - C8D132521C42DA7F00B59FFF /* SectionedViewDataSourceMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedViewDataSourceMock.swift; sourceTree = ""; }; C8D2C1501D4F3CD6006E2431 /* Rx.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Rx.playground; sourceTree = ""; }; + C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Signal+Subscription.swift"; sourceTree = ""; }; + C8D970DC1F532FD10058F2FE /* Signal+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Signal+Test.swift"; sourceTree = ""; }; + C8D970DD1F532FD10058F2FE /* SharedSequence+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SharedSequence+Test.swift"; sourceTree = ""; }; + C8D970DE1F532FD20058F2FE /* Driver+Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Driver+Test.swift"; sourceTree = ""; }; + C8D970E01F532FD20058F2FE /* SectionedViewDataSourceMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedViewDataSourceMock.swift; sourceTree = ""; }; + C8D970E11F532FD20058F2FE /* SharedSequence+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SharedSequence+Extensions.swift"; sourceTree = ""; }; + C8D970E21F532FD30058F2FE /* SharedSequence+OperatorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SharedSequence+OperatorTest.swift"; sourceTree = ""; }; C8E390621F379041004FC993 /* Enumerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enumerated.swift; sourceTree = ""; }; C8E390671F379386004FC993 /* Observable+EnumeratedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+EnumeratedTests.swift"; sourceTree = ""; }; C8E8BA551E2C181A00A4AC2C /* Benchmarks.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Benchmarks.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2622,8 +2663,13 @@ C83508D81C38706D0027C24C /* RxCocoaTests */ = { isa = PBXGroup; children = ( + C8D970DF1F532FD20058F2FE /* TestImplementations */, C8561B651DFE1169005E97F1 /* ExampleTests.swift */, - C8D132511C42DA7F00B59FFF /* TestImplementations */, + C8D970DC1F532FD10058F2FE /* Signal+Test.swift */, + C8D970DD1F532FD10058F2FE /* SharedSequence+Test.swift */, + C8D970E11F532FD20058F2FE /* SharedSequence+Extensions.swift */, + C8D970DE1F532FD20058F2FE /* Driver+Test.swift */, + C8D970E21F532FD30058F2FE /* SharedSequence+OperatorTest.swift */, C83508DC1C38706D0027C24C /* Control+RxTests.swift */, C83508DA1C38706D0027C24C /* Control+RxTests+Cocoa.swift */, C83508DB1C38706D0027C24C /* Control+RxTests+UIKit.swift */, @@ -2632,8 +2678,6 @@ C83508E11C38706D0027C24C /* DelegateProxyTest.swift */, C83508DF1C38706D0027C24C /* DelegateProxyTest+Cocoa.swift */, C83508E01C38706D0027C24C /* DelegateProxyTest+UIKit.swift */, - C83508E21C38706D0027C24C /* Driver+Extensions.swift */, - C83508E31C38706D0027C24C /* Driver+Test.swift */, C83508E41C38706D0027C24C /* KVOObservableTests.swift */, C8C4F1761DE9D84900003FA7 /* NSButton+RxTests.swift */, C834F6C51DB3950600C29244 /* NSControl+RxTests.swift */, @@ -2773,6 +2817,7 @@ C835091A1C38706D0027C24C /* SubjectConcurrencyTest.swift */, C835091B1C38706D0027C24C /* VariableTest.swift */, C835091C1C38706D0027C24C /* VirtualSchedulerTest.swift */, + C8B0F70C1F530A1700548EBE /* SharingSchedulerTests.swift */, ); path = RxSwiftTests; sourceTree = ""; @@ -2847,6 +2892,17 @@ path = Platform; sourceTree = ""; }; + C85E6FBA1F52FF4F00C5681E /* Signal */ = { + isa = PBXGroup; + children = ( + C85E6FBB1F52FF4F00C5681E /* Signal.swift */, + C8B0F7141F530F5900548EBE /* PublishRelay+Signal.swift */, + C8B0F7211F53135100548EBE /* ObservableConvertibleType+Signal.swift */, + C8D970CD1F5324D90058F2FE /* Signal+Subscription.swift */, + ); + path = Signal; + sourceTree = ""; + }; C86781461DB8119900B2029A /* DataStructures */ = { isa = PBXGroup; children = ( @@ -2996,6 +3052,8 @@ C89AB1AA1DAAC3350065FBE6 /* Traits */ = { isa = PBXGroup; children = ( + C85E6FBA1F52FF4F00C5681E /* Signal */, + C8B0F7101F530CA700548EBE /* PublishRelay.swift */, C89AB1AB1DAAC3350065FBE6 /* ControlEvent.swift */, C89AB1AC1DAAC3350065FBE6 /* ControlProperty.swift */, C89AB1AD1DAAC3350065FBE6 /* Driver */, @@ -3026,7 +3084,7 @@ C89AB1B71DAAC3350065FBE6 /* SharedSequence+Operators+arity.tt */, C89AB1B81DAAC3350065FBE6 /* SharedSequence+Operators.swift */, C89AB1B91DAAC3350065FBE6 /* SharedSequence.swift */, - C89AB1BA1DAAC3350065FBE6 /* Variable+SharedSequence.swift */, + C85E6FBD1F53025700C5681E /* SchedulerType+SharedSequence.swift */, ); path = SharedSequence; sourceTree = ""; @@ -3163,10 +3221,10 @@ path = Platform; sourceTree = ""; }; - C8D132511C42DA7F00B59FFF /* TestImplementations */ = { + C8D970DF1F532FD20058F2FE /* TestImplementations */ = { isa = PBXGroup; children = ( - C8D132521C42DA7F00B59FFF /* SectionedViewDataSourceMock.swift */, + C8D970E01F532FD20058F2FE /* SectionedViewDataSourceMock.swift */, ); path = TestImplementations; sourceTree = ""; @@ -4012,19 +4070,21 @@ C8093EFD1B8A732E0088E94D /* RxTarget.swift in Sources */, C88254361B8A752B00B02D69 /* UITextView+Rx.swift in Sources */, C88254171B8A752B00B02D69 /* RxTableViewReactiveArrayDataSource.swift in Sources */, + C8B0F71C1F530FE500548EBE /* PublishRelay.swift in Sources */, C882541E1B8A752B00B02D69 /* RxCollectionViewDataSourceProxy.swift in Sources */, + C85E6FBE1F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */, 84C225A31C33F00B008724EC /* RxTextStorageDelegateProxy.swift in Sources */, C89AB1DA1DAAC3350065FBE6 /* Driver.swift in Sources */, C88254231B8A752B00B02D69 /* RxTableViewDelegateProxy.swift in Sources */, C89AB2381DAAC3A60065FBE6 /* _RX.m in Sources */, 7F600F411C5D0C6E00535B1D /* UIRefreshControl+Rx.swift in Sources */, F31F35B01BB4FED800961002 /* UIStepper+Rx.swift in Sources */, + C8B0F7221F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */, C89AB1C61DAAC3350065FBE6 /* ControlEvent.swift in Sources */, C882542D1B8A752B00B02D69 /* UIImageView+Rx.swift in Sources */, A520FFFC1F0D291500573734 /* RxPickerViewDataSourceProxy.swift in Sources */, C882542A1B8A752B00B02D69 /* UIControl+Rx.swift in Sources */, C8D132441C42D15E00B59FFF /* SectionedViewDataSourceType.swift in Sources */, - C89AB1FA1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */, 84E4D3921C9AFD3400ADFDC9 /* UISearchController+Rx.swift in Sources */, C88254341B8A752B00B02D69 /* UITableView+Rx.swift in Sources */, C89AB1A61DAAC25A0065FBE6 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */, @@ -4036,6 +4096,7 @@ C88254201B8A752B00B02D69 /* RxScrollViewDelegateProxy.swift in Sources */, C89AB20A1DAAC3350065FBE6 /* KVORepresentable.swift in Sources */, C88F76811CE5341700D5A014 /* TextInput.swift in Sources */, + C8B0F7151F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */, C882542E1B8A752B00B02D69 /* UILabel+Rx.swift in Sources */, C89AB1CE1DAAC3350065FBE6 /* ControlEvent+Driver.swift in Sources */, C89AB1D61DAAC3350065FBE6 /* Driver+Subscription.swift in Sources */, @@ -4043,6 +4104,7 @@ 91BE429C1CBF7EC000F6B062 /* UIPageControl+Rx.swift in Sources */, C88254211B8A752B00B02D69 /* RxSearchBarDelegateProxy.swift in Sources */, A520FFF71F0D258E00573734 /* RxPickerViewDataSourceType.swift in Sources */, + C8D970CE1F5324D90058F2FE /* Signal+Subscription.swift in Sources */, 7EDBAEBC1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */, C839365F1C70E02200A9A09E /* UIApplication+Rx.swift in Sources */, 844BC8AC1CE4FA6300F5C7CB /* RxPickerViewDelegateProxy.swift in Sources */, @@ -4059,6 +4121,7 @@ C88254311B8A752B00B02D69 /* UISegmentedControl+Rx.swift in Sources */, AAE623761C82475700FC7801 /* UIProgressView+Rx.swift in Sources */, 271A97411CFC996B00D64125 /* UIViewController+Rx.swift in Sources */, + C85E6FC21F5305E300C5681E /* Signal.swift in Sources */, C89AB2481DAAC3A60065FBE6 /* _RXKVOObserver.m in Sources */, C88254281B8A752B00B02D69 /* UIButton+Rx.swift in Sources */, C89AB1CA1DAAC3350065FBE6 /* ControlProperty.swift in Sources */, @@ -4107,7 +4170,9 @@ buildActionMask = 2147483647; files = ( C89AB1C71DAAC3350065FBE6 /* ControlEvent.swift in Sources */, + C85E6FC31F5305E400C5681E /* Signal.swift in Sources */, C89AB1F71DAAC3350065FBE6 /* SharedSequence.swift in Sources */, + C8B0F7161F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */, C89AB21B1DAAC3350065FBE6 /* NSObject+Rx+RawRepresentable.swift in Sources */, C89AB1CF1DAAC3350065FBE6 /* ControlEvent+Driver.swift in Sources */, C81772991E7F408100EA679B /* Deprecated.swift in Sources */, @@ -4117,6 +4182,7 @@ A520FFF81F0D258E00573734 /* RxPickerViewDataSourceType.swift in Sources */, C89AB1E31DAAC3350065FBE6 /* Variable+Driver.swift in Sources */, C89AB1D31DAAC3350065FBE6 /* ControlProperty+Driver.swift in Sources */, + C85E6FBF1F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */, C8A81CA11E05E82C0008DEF4 /* DispatchQueue+Extensions.swift in Sources */, C88F76821CE5341700D5A014 /* TextInput.swift in Sources */, C89AB1DF1DAAC3350065FBE6 /* ObservableConvertibleType+Driver.swift in Sources */, @@ -4126,7 +4192,6 @@ C89AB1A71DAAC25A0065FBE6 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */, A520FFFD1F0D291500573734 /* RxPickerViewDataSourceProxy.swift in Sources */, C89AB2411DAAC3A60065FBE6 /* _RXDelegateProxy.m in Sources */, - C89AB1FB1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */, C867819C1DB823B500B2029A /* NSControl+Rx.swift in Sources */, C89AB2391DAAC3A60065FBE6 /* _RX.m in Sources */, C8093EFE1B8A732E0088E94D /* RxTarget.swift in Sources */, @@ -4134,10 +4199,12 @@ C86781B01DB823B500B2029A /* NSView+Rx.swift in Sources */, C89AB1741DAAC1680065FBE6 /* ControlTarget.swift in Sources */, C86781971DB823B500B2029A /* NSButton+Rx.swift in Sources */, + C8B0F7231F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */, C89AB2131DAAC3350065FBE6 /* NotificationCenter+Rx.swift in Sources */, C8BCD3F51C14B6D1005F1280 /* NSLayoutConstraint+Rx.swift in Sources */, C89AB2491DAAC3A60065FBE6 /* _RXKVOObserver.m in Sources */, C89AB1E71DAAC3350065FBE6 /* ObservableConvertibleType+SharedSequence.swift in Sources */, + C8D970CF1F5324D90058F2FE /* Signal+Subscription.swift in Sources */, C89AB2171DAAC3350065FBE6 /* NSObject+Rx+KVORepresentable.swift in Sources */, C89AB2071DAAC3350065FBE6 /* KVORepresentable+Swift.swift in Sources */, C89AB1DB1DAAC3350065FBE6 /* Driver.swift in Sources */, @@ -4146,6 +4213,7 @@ C89AB2031DAAC3350065FBE6 /* KVORepresentable+CoreGraphics.swift in Sources */, C8093EE21B8A732E0088E94D /* DelegateProxy.swift in Sources */, C89AB1F31DAAC3350065FBE6 /* SharedSequence+Operators.swift in Sources */, + C8B0F71A1F530FE400548EBE /* PublishRelay.swift in Sources */, C86781A61DB823B500B2029A /* NSSlider+Rx.swift in Sources */, C89AB2231DAAC3350065FBE6 /* URLSession+Rx.swift in Sources */, D29E231A1EF4B93E006E295D /* DelegateProxyFactory.swift in Sources */, @@ -4198,6 +4266,7 @@ C8845ADA1EDB607800B36836 /* Observable+ShareReplayScopeTests.swift in Sources */, C83509611C38706E0027C24C /* ObserverTests.swift in Sources */, C83509471C38706E0027C24C /* PrimitiveMockObserver.swift in Sources */, + C8D970EF1F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */, C8F03F4F1DBBAE9400AECC4C /* DispatchQueue+Extensions.swift in Sources */, C835094B1C38706E0027C24C /* Observable+Tests.swift in Sources */, C8C217D51CB7100E0038A2E6 /* UITableView+RxTests.swift in Sources */, @@ -4205,6 +4274,7 @@ 844BC8BB1CE5024500F5C7CB /* UIPickerView+RxTests.swift in Sources */, C896A68B1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift in Sources */, C820A9AA1EB505A800D431BC /* Observable+WithLatestFromTests.swift in Sources */, + C8D970E61F532FD30058F2FE /* SharedSequence+Test.swift in Sources */, C820A94E1EB4EC3C00D431BC /* Observable+ReduceTests.swift in Sources */, C820A97A1EB4FA0800D431BC /* Observable+RangeTests.swift in Sources */, C8B290891C94D64600E923D0 /* RxTest+Controls.swift in Sources */, @@ -4247,10 +4317,10 @@ C83509311C38706E0027C24C /* DelegateProxyTest+UIKit.swift in Sources */, C83509481C38706E0027C24C /* TestConnectableObservable.swift in Sources */, C8353CEC1DA19BC500BE3F5C /* XCTest+AllTests.swift in Sources */, + C8B0F70D1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */, D9080AD81EA06189002B433B /* UINavigationController+RxTests.swift in Sources */, C8353CE61DA19BC500BE3F5C /* Recorded+Timeless.swift in Sources */, C83509371C38706E0027C24C /* NotificationCenterTests.swift in Sources */, - C83509331C38706E0027C24C /* Driver+Extensions.swift in Sources */, C81B6AAD1DB2C15C0047CF86 /* Platform.Linux.swift in Sources */, C820A9E21EB50D6C00D431BC /* Observable+SampleTests.swift in Sources */, C8C4F1691DE9D48F00003FA7 /* UIActivityIndicatorView+RxTests.swift in Sources */, @@ -4287,6 +4357,7 @@ C820A9BA1EB5097700D431BC /* Observable+TakeTests.swift in Sources */, C835094C1C38706E0027C24C /* AssumptionsTest.swift in Sources */, C835092D1C38706E0027C24C /* Control+RxTests.swift in Sources */, + C8D970F21F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */, C834F6C21DB394E100C29244 /* Observable+BlockingTest.swift in Sources */, C8BAA78D1E34F8D400EEC727 /* RecursiveLockTest.swift in Sources */, C8E390681F379386004FC993 /* Observable+EnumeratedTests.swift in Sources */, @@ -4305,6 +4376,7 @@ C820A9A61EB5056C00D431BC /* Observable+SkipUntilTests.swift in Sources */, C890465A1DC5F7130041C7D8 /* Control+RxTests+UIKit.swift in Sources */, 88718D011CE5DE2600D88D60 /* UITabBar+RxTests.swift in Sources */, + C8D970EC1F532FD30058F2FE /* SectionedViewDataSourceMock.swift in Sources */, C822BACE1DB424EC00F98810 /* Reactive+Tests.swift in Sources */, C820A9BE1EB509B500D431BC /* Observable+TakeLastTests.swift in Sources */, C820A9AE1EB5073E00D431BC /* Observable+FilterTests.swift in Sources */, @@ -4318,7 +4390,6 @@ C835093D1C38706E0027C24C /* SentMessageTest.swift in Sources */, C83509401C38706E0027C24C /* EquatableArray.swift in Sources */, C820A9621EB4EFD300D431BC /* Observable+ObserveOnTests.swift in Sources */, - C83509341C38706E0027C24C /* Driver+Test.swift in Sources */, C820A9DA1EB50CAA00D431BC /* Observable+DoOnTests.swift in Sources */, C835092F1C38706E0027C24C /* ControlPropertyTests.swift in Sources */, C835093C1C38706E0027C24C /* RxObjCRuntimeState.swift in Sources */, @@ -4330,6 +4401,7 @@ C8C4F1671DE9D44600003FA7 /* UISegmentedControl+RxTests.swift in Sources */, C820A9661EB4F39500D431BC /* Observable+SubscribeOnTests.swift in Sources */, C820A9EE1EB50EA100D431BC /* Observable+ScanTests.swift in Sources */, + C8D970E91F532FD30058F2FE /* Driver+Test.swift in Sources */, C820A96A1EB4F64800D431BC /* Observable+JustTests.swift in Sources */, C820A98E1EB4FCC400D431BC /* Observable+SwitchTests.swift in Sources */, C81B6AAA1DB2C15C0047CF86 /* Platform.Darwin.swift in Sources */, @@ -4341,10 +4413,10 @@ C820A9B21EB507D300D431BC /* Observable+TakeWhileTests.swift in Sources */, C820A9FA1EB510D500D431BC /* Observable+MaterializeTests.swift in Sources */, C820A9EA1EB50E3400D431BC /* Observable+RetryWhenTests.swift in Sources */, - C860EC951C42E25E00A664B3 /* SectionedViewDataSourceMock.swift in Sources */, C83509431C38706E0027C24C /* MockDisposable.swift in Sources */, C8323A8E1E33FD5200CC0C7F /* Resources.swift in Sources */, C8C4F16D1DE9D4F400003FA7 /* UIDatePicker+RxTests.swift in Sources */, + C8D970E31F532FD30058F2FE /* Signal+Test.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4375,11 +4447,13 @@ C8C4F17D1DE9DF0200003FA7 /* UIGestureRecognizer+RxTests.swift in Sources */, C8C4F1811DE9DF0200003FA7 /* UIScrollView+RxTests.swift in Sources */, 54700CA11CE37E1900EF3A8F /* UINavigationItem+RxTests.swift.swift in Sources */, + C8D970E71F532FD30058F2FE /* SharedSequence+Test.swift in Sources */, C8350A191C38756A0027C24C /* VirtualSchedulerTest.swift in Sources */, C820A9E71EB50DB900D431BC /* Observable+TimerTests.swift in Sources */, C820A97F1EB4FA5A00D431BC /* Observable+RepeatTests.swift in Sources */, C8C4F1781DE9DF0200003FA7 /* UIActivityIndicatorView+RxTests.swift in Sources */, C83509BF1C3875220027C24C /* DelegateProxyTest+UIKit.swift in Sources */, + C8D970F31F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */, C820A94B1EB4E75E00D431BC /* Observable+AmbTests.swift in Sources */, C834F6C31DB394E100C29244 /* Observable+BlockingTest.swift in Sources */, C83509D41C38753C0027C24C /* RxObjCRuntimeState.swift in Sources */, @@ -4420,15 +4494,16 @@ ECBBA5A21DF8C0FF00DDDC2E /* UITabBarController+RxTests.swift in Sources */, C8353CED1DA19BC500BE3F5C /* XCTest+AllTests.swift in Sources */, C85218021E33FC160015DD38 /* RecursiveLock.swift in Sources */, + C8D970E41F532FD30058F2FE /* Signal+Test.swift in Sources */, C820A9771EB4F92100D431BC /* Observable+GenerateTests.swift in Sources */, C83509EB1C3875580027C24C /* MainThreadPrimitiveHotObservable.swift in Sources */, - C83509C21C3875220027C24C /* Driver+Test.swift in Sources */, C8F03F501DBBAE9400AECC4C /* DispatchQueue+Extensions.swift in Sources */, C820A9BF1EB509B500D431BC /* Observable+TakeLastTests.swift in Sources */, C820A9CB1EB50A7100D431BC /* Observable+ElementAtTests.swift in Sources */, C822BACB1DB4058000F98810 /* Event+Test.swift in Sources */, C8A53AE61F09292A00490535 /* Completable+AndThen.swift in Sources */, C820A99B1EB5001C00D431BC /* Observable+MergeTests.swift in Sources */, + C8D970F01F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */, C8353CE71DA19BC500BE3F5C /* Recorded+Timeless.swift in Sources */, C8350A161C38756A0027C24C /* QueueTests.swift in Sources */, C820A9DB1EB50CAA00D431BC /* Observable+DoOnTests.swift in Sources */, @@ -4458,7 +4533,6 @@ C820AA031EB5134000D431BC /* Observable+DelaySubscriptionTests.swift in Sources */, 7EDBAEC31C89BCB9006CBE67 /* UITabBarItem+RxTests.swift in Sources */, 914FCD681CCDB82E0058B304 /* UIPageControl+RxTest.swift in Sources */, - C83509C11C3875220027C24C /* Driver+Extensions.swift in Sources */, C8A81CA71E05EAF70008DEF4 /* UIBindingObserver+Tests.swift in Sources */, C83509DD1C38754C0027C24C /* EquatableArray.swift in Sources */, C83509F71C38755D0027C24C /* DisposableTest.swift in Sources */, @@ -4468,6 +4542,7 @@ C8E390691F379386004FC993 /* Observable+EnumeratedTests.swift in Sources */, C820A9A71EB5056C00D431BC /* Observable+SkipUntilTests.swift in Sources */, C83509DC1C38754C0027C24C /* ElementIndexPair.swift in Sources */, + C8B0F70E1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */, C8845ADB1EDB607800B36836 /* Observable+ShareReplayScopeTests.swift in Sources */, C8350A171C38756A0027C24C /* SubjectConcurrencyTest.swift in Sources */, C83509EA1C3875580027C24C /* BackgroundThreadPrimitiveHotObservable.swift in Sources */, @@ -4481,6 +4556,7 @@ C81B6AAE1DB2C15C0047CF86 /* Platform.Linux.swift in Sources */, C83509F21C38755D0027C24C /* Observable+Tests.swift in Sources */, C820A9E31EB50D6C00D431BC /* Observable+SampleTests.swift in Sources */, + C8D970EA1F532FD30058F2FE /* Driver+Test.swift in Sources */, 7FE849481C5D0D6B00845C0E /* UIRefreshControl+RxTests.swift in Sources */, C850F3D51E749F5C006C417C /* PrimitiveSequenceTest.swift in Sources */, C820A9FB1EB510D500D431BC /* Observable+MaterializeTests.swift in Sources */, @@ -4500,8 +4576,8 @@ C83509F41C38755D0027C24C /* BagTest.swift in Sources */, C8F27DC11CE68DA700D5FB4F /* UITextView+RxTests.swift in Sources */, C86B1E231D42BF5200130546 /* SchedulerTests.swift in Sources */, - C860EC961C42E26100A664B3 /* SectionedViewDataSourceMock.swift in Sources */, C820AA071EB5139C00D431BC /* Observable+BufferTests.swift in Sources */, + C8D970ED1F532FD30058F2FE /* SectionedViewDataSourceMock.swift in Sources */, C8350A0F1C3875630027C24C /* Observable+ZipTests+arity.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4527,6 +4603,7 @@ C8350A2B1C3875B60027C24C /* RxMutableBox.swift in Sources */, C83509B71C38750D0027C24C /* Control+RxTests.swift in Sources */, C8350A071C38755E0027C24C /* MainSchedulerTests.swift in Sources */, + C8D970F41F532FD30058F2FE /* SharedSequence+OperatorTest.swift in Sources */, C820A9F01EB50EA100D431BC /* Observable+ScanTests.swift in Sources */, C83509B81C38750D0027C24C /* ControlEventTests.swift in Sources */, C83509CB1C3875230027C24C /* KVOObservableTests.swift in Sources */, @@ -4539,6 +4616,7 @@ C83509E21C3875580027C24C /* BackgroundThreadPrimitiveHotObservable.swift in Sources */, C8350A0E1C3875630027C24C /* Observable+ZipTests+arity.swift in Sources */, C820AA001EB5110E00D431BC /* Observable+DematerializeTests.swift in Sources */, + C8D970F11F532FD30058F2FE /* SharedSequence+Extensions.swift in Sources */, C820A9941EB4FD1400D431BC /* Observable+SwitchIfEmptyTests.swift in Sources */, C83509CF1C3875260027C24C /* NSView+RxTests.swift in Sources */, C820A9501EB4EC3C00D431BC /* Observable+ReduceTests.swift in Sources */, @@ -4576,7 +4654,6 @@ C820AA081EB5139C00D431BC /* Observable+BufferTests.swift in Sources */, C820A9D01EB50AD400D431BC /* Observable+SingleTests.swift in Sources */, C820A9C81EB50A4200D431BC /* Observable+SkipWhileTests.swift in Sources */, - C83509C91C3875230027C24C /* Driver+Extensions.swift in Sources */, C820A9EC1EB50E3400D431BC /* Observable+RetryWhenTests.swift in Sources */, C8323A901E33FD5200CC0C7F /* Resources.swift in Sources */, C820A98C1EB4FBD600D431BC /* Observable+CatchTests.swift in Sources */, @@ -4590,8 +4667,8 @@ C83509D21C3875380027C24C /* RXObjCRuntime+Testing.m in Sources */, C8353CDE1DA19BA000BE3F5C /* MessageProcessingStage.swift in Sources */, C8F03F431DBB98DB00AECC4C /* Anomalies.swift in Sources */, + C8D970E81F532FD30058F2FE /* SharedSequence+Test.swift in Sources */, C83509CC1C3875230027C24C /* NSLayoutConstraint+RxTests.swift in Sources */, - C83509CA1C3875230027C24C /* Driver+Test.swift in Sources */, C896A68D1E6B7DC60073A3A8 /* Observable+CombineLatestTests.swift in Sources */, C820A9A41EB5011700D431BC /* Observable+TakeUntilTests.swift in Sources */, C8C4F1731DE9D7A300003FA7 /* NSTextField+RxTests.swift in Sources */, @@ -4626,13 +4703,16 @@ C820A9741EB4F84000D431BC /* Observable+OptionalTests.swift in Sources */, C820A9C41EB509FC00D431BC /* Observable+SkipTests.swift in Sources */, C820A9701EB4F7AC00D431BC /* Observable+SequenceTests.swift in Sources */, + C8B0F70F1F530A1700548EBE /* SharingSchedulerTests.swift in Sources */, C8350A211C38756B0027C24C /* SubjectConcurrencyTest.swift in Sources */, C8353CEE1DA19BC500BE3F5C /* XCTest+AllTests.swift in Sources */, + C8D970E51F532FD30058F2FE /* Signal+Test.swift in Sources */, C81B6AAF1DB2C15C0047CF86 /* Platform.Linux.swift in Sources */, C83509B51C3875050027C24C /* Control+RxTests+Cocoa.swift in Sources */, C8C4F1771DE9D84900003FA7 /* NSButton+RxTests.swift in Sources */, C820A9A81EB5056C00D431BC /* Observable+SkipUntilTests.swift in Sources */, C83509E61C3875580027C24C /* Observable.Extensions.swift in Sources */, + C8D970EB1F532FD30058F2FE /* Driver+Test.swift in Sources */, C83509DE1C38754F0027C24C /* Observable+Extensions.swift in Sources */, C83509DA1C38754C0027C24C /* ElementIndexPair.swift in Sources */, C89CFA0E1DAAB4670079D23B /* RxTest.swift in Sources */, @@ -5207,6 +5287,7 @@ C8F0C00B1BBBFBB9001B112F /* UITextView+Rx.swift in Sources */, C8F0C00C1BBBFBB9001B112F /* RxTableViewReactiveArrayDataSource.swift in Sources */, C8F0C00D1BBBFBB9001B112F /* RxCollectionViewDataSourceProxy.swift in Sources */, + C8B0F7251F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */, 84C225A51C33F00B008724EC /* RxTextStorageDelegateProxy.swift in Sources */, C8F0C0101BBBFBB9001B112F /* RxTableViewDelegateProxy.swift in Sources */, 7F600F3F1C5D0C6C00535B1D /* UIRefreshControl+Rx.swift in Sources */, @@ -5220,6 +5301,8 @@ C8F0C0161BBBFBB9001B112F /* UITableView+Rx.swift in Sources */, C89AB1D11DAAC3350065FBE6 /* ControlEvent+Driver.swift in Sources */, 84E4D3941C9AFD3600ADFDC9 /* UISearchController+Rx.swift in Sources */, + C85E6FC51F5305E500C5681E /* Signal.swift in Sources */, + C85E6FC11F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */, C89AB2211DAAC3350065FBE6 /* NSObject+Rx.swift in Sources */, C8F0C0171BBBFBB9001B112F /* RxCollectionViewReactiveArrayDataSource.swift in Sources */, 844BC8B61CE4FD7500F5C7CB /* UIPickerView+Rx.swift in Sources */, @@ -5248,12 +5331,15 @@ C8F0C0291BBBFBB9001B112F /* UIBarButtonItem+Rx.swift in Sources */, C8F0C02C1BBBFBB9001B112F /* UIDatePicker+Rx.swift in Sources */, C8F0C02D1BBBFBB9001B112F /* RxTableViewDataSourceProxy.swift in Sources */, + C8D970D11F5324D90058F2FE /* Signal+Subscription.swift in Sources */, 844BC8AE1CE4FA6600F5C7CB /* RxPickerViewDelegateProxy.swift in Sources */, C8BCD3F71C14B6D1005F1280 /* NSLayoutConstraint+Rx.swift in Sources */, C89AB1C91DAAC3350065FBE6 /* ControlEvent.swift in Sources */, C89AB1E91DAAC3350065FBE6 /* ObservableConvertibleType+SharedSequence.swift in Sources */, + C8B0F7191F530FE300548EBE /* PublishRelay.swift in Sources */, C8F0C0301BBBFBB9001B112F /* UIGestureRecognizer+Rx.swift in Sources */, C89AB2091DAAC3350065FBE6 /* KVORepresentable+Swift.swift in Sources */, + C8B0F7181F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */, C8F0C0311BBBFBB9001B112F /* DelegateProxy.swift in Sources */, C8F0C0331BBBFBB9001B112F /* UISwitch+Rx.swift in Sources */, C8F0C0351BBBFBB9001B112F /* UICollectionView+Rx.swift in Sources */, @@ -5284,7 +5370,6 @@ D29E231C1EF4B93F006E295D /* DelegateProxyFactory.swift in Sources */, 7EDBAEBF1C89B9B7006CBE67 /* UITabBarItem+Rx.swift in Sources */, C8F0C03D1BBBFBB9001B112F /* RxTableViewDataSourceType.swift in Sources */, - C89AB1FD1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5340,13 +5425,17 @@ C89AB1E81DAAC3350065FBE6 /* ObservableConvertibleType+SharedSequence.swift in Sources */, C89AB1A81DAAC25A0065FBE6 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */, D203C50C1BB9C53E00D02D00 /* UISearchBar+Rx.swift in Sources */, + C8B0F71B1F530FE500548EBE /* PublishRelay.swift in Sources */, + C8B0F7171F530F5A00548EBE /* PublishRelay+Signal.swift in Sources */, 846436E51C9AF65E0035B40D /* RxSearchControllerDelegateProxy.swift in Sources */, C89AB1751DAAC1680065FBE6 /* ControlTarget.swift in Sources */, D203C4FB1BB9C53700D02D00 /* RxCollectionViewDelegateProxy.swift in Sources */, D203C5031BB9C53E00D02D00 /* UIBarButtonItem+Rx.swift in Sources */, D29E231B1EF4B93E006E295D /* DelegateProxyFactory.swift in Sources */, C89AB1EC1DAAC3350065FBE6 /* SharedSequence+Operators+arity.swift in Sources */, + C85E6FC01F53025700C5681E /* SchedulerType+SharedSequence.swift in Sources */, D203C4FC1BB9C53700D02D00 /* RxScrollViewDelegateProxy.swift in Sources */, + C85E6FC41F5305E400C5681E /* Signal.swift in Sources */, C89AB1F81DAAC3350065FBE6 /* SharedSequence.swift in Sources */, C89AB2421DAAC3A60065FBE6 /* _RXDelegateProxy.m in Sources */, C89AB2291DAAC33F0065FBE6 /* RxCocoa.swift in Sources */, @@ -5365,6 +5454,7 @@ D203C5111BB9C53E00D02D00 /* UITableView+Rx.swift in Sources */, D203C5051BB9C53E00D02D00 /* UICollectionView+Rx.swift in Sources */, 9BA1CBFD1C0F84A10044B50A /* UIActivityIndicatorView+Rx.swift in Sources */, + C8B0F7241F53135100548EBE /* ObservableConvertibleType+Signal.swift in Sources */, ECBBA59F1DF8C0D400DDDC2E /* RxTabBarControllerDelegateProxy.swift in Sources */, 842A5A2D1C357F93003568D5 /* NSTextStorage+Rx.swift in Sources */, D203C5071BB9C53E00D02D00 /* UIDatePicker+Rx.swift in Sources */, @@ -5378,11 +5468,11 @@ AAE623771C82475700FC7801 /* UIProgressView+Rx.swift in Sources */, C89AB23A1DAAC3A60065FBE6 /* _RX.m in Sources */, D203C50A1BB9C53E00D02D00 /* UILabel+Rx.swift in Sources */, - C89AB1FC1DAAC3350065FBE6 /* Variable+SharedSequence.swift in Sources */, D203C4F51BB9C52900D02D00 /* ItemEvents.swift in Sources */, A520FFF91F0D258E00573734 /* RxPickerViewDataSourceType.swift in Sources */, C8BCD3F61C14B6D1005F1280 /* NSLayoutConstraint+Rx.swift in Sources */, D203C4FA1BB9C53700D02D00 /* RxCollectionViewDataSourceProxy.swift in Sources */, + C8D970D01F5324D90058F2FE /* Signal+Subscription.swift in Sources */, C89AB2141DAAC3350065FBE6 /* NotificationCenter+Rx.swift in Sources */, 91BE429D1CBF7EC000F6B062 /* UIPageControl+Rx.swift in Sources */, C89AB2521DAAC3A60065FBE6 /* _RXObjCRuntime.m in Sources */, diff --git a/RxCocoa/Deprecated.swift b/RxCocoa/Deprecated.swift index b4037bb3..b978786f 100644 --- a/RxCocoa/Deprecated.swift +++ b/RxCocoa/Deprecated.swift @@ -238,3 +238,26 @@ extension ObservableType { } } #endif + +/** + This method can be used in unit tests to ensure that driver is using mock schedulers instead of + main schedulers. + + **This shouldn't be used in normal release builds.** + */ +@available(*, deprecated, renamed: "SharingScheduler.mock(scheduler:action:)") +public func driveOnScheduler(_ scheduler: SchedulerType, action: () -> ()) { + SharingScheduler.mock(scheduler: scheduler, action: action) +} + +extension Variable { + /// Converts `Variable` to `SharedSequence` unit. + /// + /// - returns: Observable sequence. + @available(*, deprecated, renamed: "asDriver()") + public func asSharedSequence(strategy: SharingStrategy.Type = SharingStrategy.self) -> SharedSequence { + let source = self.asObservable() + .observeOn(SharingStrategy.scheduler) + return SharedSequence(source) + } +} diff --git a/RxCocoa/Traits/ControlEvent.swift b/RxCocoa/Traits/ControlEvent.swift index e8d3d7cc..ed539482 100644 --- a/RxCocoa/Traits/ControlEvent.swift +++ b/RxCocoa/Traits/ControlEvent.swift @@ -36,7 +36,7 @@ public protocol ControlEventType : ObservableType { **If they aren't, then using this trait communicates wrong properties and could potentially break someone's code.** **In case `events` observable sequence that is being passed into initializer doesn't satisfy all enumerated - properties, please don't use this unit.** + properties, please don't use this trait.** */ public struct ControlEvent : ControlEventType { public typealias E = PropertyType diff --git a/RxCocoa/Traits/ControlProperty.swift b/RxCocoa/Traits/ControlProperty.swift index cdac1ab9..2449e174 100644 --- a/RxCocoa/Traits/ControlProperty.swift +++ b/RxCocoa/Traits/ControlProperty.swift @@ -40,7 +40,7 @@ public protocol ControlPropertyType : ObservableType, ObserverType { **If they aren't, then using this trait communicates wrong properties and could potentially break someone's code.** **In case `values` observable sequence that is being passed into initializer doesn't satisfy all enumerated - properties, please don't use this unit.** + properties, please don't use this trait.** */ public struct ControlProperty : ControlPropertyType { public typealias E = PropertyType diff --git a/RxCocoa/Traits/Driver/Driver+Subscription.swift b/RxCocoa/Traits/Driver/Driver+Subscription.swift index 9957ce3b..8bcf818b 100644 --- a/RxCocoa/Traits/Driver/Driver+Subscription.swift +++ b/RxCocoa/Traits/Driver/Driver+Subscription.swift @@ -10,10 +10,9 @@ import RxSwift #endif -private let driverErrorMessage = "`drive*` family of methods can be only called from `MainThread`.\n" + +private let errorMessage = "`drive*` family of methods can be only called from `MainThread`.\n" + "This is required to ensure that the last replayed `Driver` element is delivered on `MainThread`.\n" -// This would ideally be Driver, but unfortunately Driver can't be extended in Swift 3.0 extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingStrategy { /** Creates new subscription and sends elements to observer. @@ -25,7 +24,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Disposable object that can be used to unsubscribe the observer from the subject. */ public func drive(_ observer: O) -> Disposable where O.E == E { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return self.asSharedSequence().asObservable().subscribe(observer) } @@ -39,7 +38,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Disposable object that can be used to unsubscribe the observer from the subject. */ public func drive(_ observer: O) -> Disposable where O.E == E? { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return self.asSharedSequence().asObservable().map { $0 as E? }.subscribe(observer) } @@ -51,7 +50,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Disposable object that can be used to unsubscribe the observer from the variable. */ public func drive(_ variable: Variable) -> Disposable { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return drive(onNext: { e in variable.value = e }) @@ -65,7 +64,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Disposable object that can be used to unsubscribe the observer from the variable. */ public func drive(_ variable: Variable) -> Disposable { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return drive(onNext: { e in variable.value = e }) @@ -79,7 +78,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Object representing subscription. */ public func drive(_ transformation: (Observable) -> R) -> R { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return transformation(self.asObservable()) } @@ -98,7 +97,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Object representing subscription. */ public func drive(_ with: (Observable) -> (R1) -> R2, curriedArgument: R1) -> R2 { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return with(self.asObservable())(curriedArgument) } @@ -116,7 +115,7 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt - returns: Subscription object used to unsubscribe from the observable sequence. */ public func drive(onNext: ((E) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable { - MainScheduler.ensureExecutingOnScheduler(errorMessage: driverErrorMessage) + MainScheduler.ensureExecutingOnScheduler(errorMessage: errorMessage) return self.asObservable().subscribe(onNext: onNext, onCompleted: onCompleted, onDisposed: onDisposed) } } diff --git a/RxCocoa/Traits/Driver/Driver.swift b/RxCocoa/Traits/Driver/Driver.swift index fa35c9d3..41780e00 100644 --- a/RxCocoa/Traits/Driver/Driver.swift +++ b/RxCocoa/Traits/Driver/Driver.swift @@ -16,12 +16,16 @@ - it never fails - it delivers events on `MainScheduler.instance` - - `shareReplayLatestWhileConnected()` behavior + - `share(replay: 1, scope: .whileConnected)` sharing strategy + + Additional explanation: - all observers share sequence computation resources - it's stateful, upon subscription (calling subscribe) last element is immediately replayed if it was produced - computation of elements is reference counted with respect to the number of observers - if there are no subscribers, it will release sequence computation resources + In case trait that models event bus is required, please check `Signal`. + `Driver` can be considered a builder pattern for observable sequences that drive the application. If observable sequence has produced at least one element, after new subscription is made last produced element will be @@ -37,9 +41,9 @@ public typealias Driver = SharedSequence public struct DriverSharingStrategy: SharingStrategyProtocol { - public static var scheduler: SchedulerType { return driverObserveOnScheduler() } + public static var scheduler: SchedulerType { return SharingScheduler.make() } public static func share(_ source: Observable) -> Observable { - return source.shareReplayLatestWhileConnected() + return source.share(replay: 1, scope: .whileConnected) } } @@ -50,41 +54,3 @@ extension SharedSequenceConvertibleType where SharingStrategy == DriverSharingSt } } -/** - This method can be used in unit tests to ensure that driver is using mock schedulers instead of - main schedulers. - - **This shouldn't be used in normal release builds.** -*/ -public func driveOnScheduler(_ scheduler: SchedulerType, action: () -> ()) { - let originalObserveOnScheduler = driverObserveOnScheduler - driverObserveOnScheduler = { return scheduler } - - action() - - // If you remove this line , compiler buggy optimizations will change behavior of this code - _forceCompilerToStopDoingInsaneOptimizationsThatBreakCode(scheduler) - // Scary, I know - - driverObserveOnScheduler = originalObserveOnScheduler -} - -#if os(Linux) - import Glibc -#else - import func Foundation.arc4random -#endif - -func _forceCompilerToStopDoingInsaneOptimizationsThatBreakCode(_ scheduler: SchedulerType) { - let a: Int32 = 1 -#if os(Linux) - let b = 314 + Int32(Glibc.random() & 1) -#else - let b = 314 + Int32(arc4random() & 1) -#endif - if a == b { - print(scheduler) - } -} - -fileprivate var driverObserveOnScheduler: () -> SchedulerType = { MainScheduler() } diff --git a/RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift b/RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift index f5e84d80..ba661025 100644 --- a/RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift +++ b/RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift @@ -12,10 +12,10 @@ import RxSwift extension ObservableConvertibleType { /** - Converts anything convertible to `Observable` to `Driver` unit. + Converts observable sequence to `Driver` trait. - parameter onErrorJustReturn: Element to return in case of error and after that complete the sequence. - - returns: Driving observable sequence. + - returns: Driver trait. */ public func asDriver(onErrorJustReturn: E) -> Driver { let source = self @@ -26,10 +26,10 @@ extension ObservableConvertibleType { } /** - Converts anything convertible to `Observable` to `Driver` unit. + Converts observable sequence to `Driver` trait. - parameter onErrorDriveWith: Driver that continues to drive the sequence in case of error. - - returns: Driving observable sequence. + - returns: Driver trait. */ public func asDriver(onErrorDriveWith: Driver) -> Driver { let source = self @@ -42,10 +42,10 @@ extension ObservableConvertibleType { } /** - Converts anything convertible to `Observable` to `Driver` unit. + Converts observable sequence to `Driver` trait. - parameter onErrorRecover: Calculates driver that continues to drive the sequence in case of error. - - returns: Driving observable sequence. + - returns: Driver trait. */ public func asDriver(onErrorRecover: @escaping (_ error: Swift.Error) -> Driver) -> Driver { let source = self diff --git a/RxCocoa/Traits/Driver/Variable+Driver.swift b/RxCocoa/Traits/Driver/Variable+Driver.swift index 7f200636..c4328144 100644 --- a/RxCocoa/Traits/Driver/Variable+Driver.swift +++ b/RxCocoa/Traits/Driver/Variable+Driver.swift @@ -11,7 +11,7 @@ #endif extension Variable { - /// Converts `Variable` to `Driver` unit. + /// Converts `Variable` to `Driver` trait. /// /// - returns: Driving observable sequence. public func asDriver() -> Driver { diff --git a/RxCocoa/Traits/PublishRelay.swift b/RxCocoa/Traits/PublishRelay.swift index b3eb6d70..630d1fe4 100644 --- a/RxCocoa/Traits/PublishRelay.swift +++ b/RxCocoa/Traits/PublishRelay.swift @@ -13,17 +13,15 @@ import Dispatch /// PublishRelay is a wrapper for `PublishSubject`. /// -/// Unlike `PublishSubject` it can't terminate with error, and when publisher is deallocated +/// Unlike `PublishSubject` it can't terminate with error. /// it will complete it's observable sequence (`asObservable`). -public final class PublishRelay { - +public final class PublishRelay: ObservableType { public typealias E = Element - public typealias SharingStrategy = PublishSharingStrategy - + private let _subject: PublishSubject // Accepts `event` and emits it to subscribers - public func accept(_ event: E) { + public func accept(_ event: Element) { _subject.onNext(event) } @@ -31,9 +29,14 @@ public final class PublishRelay { public init() { _subject = PublishSubject() } + + /// Subscribes observer + public func subscribe(_ observer: O) -> Disposable where O.E == E { + return _subject.subscribe(observer) + } /// - returns: Canonical interface for push style sequence - public func asObservable() -> Observable { - return _subject.observeOn(SharingStrategy.scheduler) + public func asObservable() -> Observable { + return _subject.asObservable() } } diff --git a/RxCocoa/Traits/Publisher/Publisher.swift b/RxCocoa/Traits/Publisher/Publisher.swift deleted file mode 100644 index e2085b7c..00000000 --- a/RxCocoa/Traits/Publisher/Publisher.swift +++ /dev/null @@ -1,62 +0,0 @@ -// -// Publisher.swift -// RxCocoa -// -// Created by Krunoslav Zaher on 9/26/16. -// Copyright © 2016 Krunoslav Zaher. All rights reserved. -// - -#if !RX_NO_MODULE - import RxSwift -#endif - -/** - Unit that represents observable sequence with following properties: - - - it never fails - - it delivers events on `MainScheduler.instance` - - all observers share sequence computation resources - - computation of elements is reference counted with respect to the number of observers - - if there are no subscribers, it will release sequence computation resources - - `Publisher` can be considered a builder pattern for observable sequences that model imperative events part of the application. - - To find out more about units and how to use them, please visit `Documentation/Units.md`. - */ -public typealias Publisher = SharedSequence - -public struct PublishSharingStrategy : SharingStrategyProtocol { - public static var scheduler: SchedulerType { return publisherObserveOnScheduler } - - public static func share(_ source: Observable) -> Observable { - return source.share() - } -} - -extension SharedSequenceConvertibleType where SharingStrategy == PublishSharingStrategy { - /// Adds `asPublisher` to `SharingSequence` with `PublishSharingStrategy`. - public func asPublisher() -> Publisher { - return asSharedSequence() - } -} - -/** - This method can be used in unit tests to ensure that publisher is using mock schedulers instead of - main schedulers. - - **This shouldn't be used in normal release builds.** - */ -public func publishOnScheduler(_ scheduler: SchedulerType, action: () -> ()) { - let originalObserveOnScheduler = publisherObserveOnScheduler - publisherObserveOnScheduler = scheduler - - action() - - // If you remove this line , compiler buggy optimizations will change behavior of this code - _forceCompilerToStopDoingInsaneOptimizationsThatBreakCode(publisherObserveOnScheduler) - // Scary, I know - - publisherObserveOnScheduler = originalObserveOnScheduler -} - -fileprivate var publisherObserveOnScheduler: SchedulerType = MainScheduler.instance diff --git a/RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift b/RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift new file mode 100644 index 00000000..b55911c5 --- /dev/null +++ b/RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift @@ -0,0 +1,61 @@ +// +// SchedulerType+SharedSequence.swift +// RxCocoa +// +// Created by Krunoslav Zaher on 8/27/17. +// Copyright © 2017 Krunoslav Zaher. All rights reserved. +// + +import RxSwift + +public enum SharingScheduler { + /// Default scheduler used in SharedSequence based traits. + public private(set) static var make: () -> SchedulerType = { MainScheduler() } + + /** + This method can be used in unit tests to ensure that built in shared sequences are using mock schedulers instead + of main schedulers. + + **This shouldn't be used in normal release builds.** + */ + static public func mock(scheduler: SchedulerType, action: () -> ()) { + return mock(makeScheduler: { scheduler }, action: action) + } + + /** + This method can be used in unit tests to ensure that built in shared sequences are using mock schedulers instead + of main schedulers. + + **This shouldn't be used in normal release builds.** + */ + static public func mock(makeScheduler: @escaping () -> SchedulerType, action: () -> ()) { + let originalMake = make + make = makeScheduler + + action() + + // If you remove this line , compiler buggy optimizations will change behavior of this code + _forceCompilerToStopDoingInsaneOptimizationsThatBreakCode(makeScheduler) + // Scary, I know + + make = originalMake + } +} + +#if os(Linux) + import Glibc +#else + import func Foundation.arc4random +#endif + +func _forceCompilerToStopDoingInsaneOptimizationsThatBreakCode(_ scheduler: () -> SchedulerType) { + let a: Int32 = 1 +#if os(Linux) + let b = 314 + Int32(Glibc.random() & 1) +#else + let b = 314 + Int32(arc4random() & 1) +#endif + if a == b { + print(scheduler()) + } +} diff --git a/RxCocoa/Traits/SharedSequence/Variable+SharedSequence.swift b/RxCocoa/Traits/SharedSequence/Variable+SharedSequence.swift deleted file mode 100644 index 3bf580d7..00000000 --- a/RxCocoa/Traits/SharedSequence/Variable+SharedSequence.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Variable+SharedSequence.swift -// RxCocoa -// -// Created by Krunoslav Zaher on 12/28/15. -// Copyright © 2015 Krunoslav Zaher. All rights reserved. -// - -#if !RX_NO_MODULE - import RxSwift -#endif - -extension Variable { - /// Converts `Variable` to `SharedSequence` unit. - /// - /// - returns: Observable sequence. - public func asSharedSequence(strategy: SharingStrategy.Type = SharingStrategy.self) -> SharedSequence { - let source = self.asObservable() - .observeOn(SharingStrategy.scheduler) - return SharedSequence(source) - } -} diff --git a/RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift b/RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift new file mode 100644 index 00000000..0e0823e1 --- /dev/null +++ b/RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift @@ -0,0 +1,60 @@ +// +// ObservableConvertibleType+Signal.swift +// RxCocoa +// +// Created by Krunoslav Zaher on 9/19/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +#if !RX_NO_MODULE + import RxSwift +#endif + +extension ObservableConvertibleType { + /** + Converts observable sequence to `Signal` trait. + + - parameter onErrorJustReturn: Element to return in case of error and after that complete the sequence. + - returns: Signal trait. + */ + public func asSignal(onErrorJustReturn: E) -> Signal { + let source = self + .asObservable() + .observeOn(SignalSharingStrategy.scheduler) + .catchErrorJustReturn(onErrorJustReturn) + return Signal(source) + } + + /** + Converts observable sequence to `Driver` trait. + + - parameter onErrorDriveWith: Driver that continues to drive the sequence in case of error. + - returns: Signal trait. + */ + public func asSignal(onErrorSignalWith: Signal) -> Signal { + let source = self + .asObservable() + .observeOn(SignalSharingStrategy.scheduler) + .catchError { _ in + onErrorSignalWith.asObservable() + } + return Signal(source) + } + + /** + Converts observable sequence to `Driver` trait. + + - parameter onErrorRecover: Calculates driver that continues to drive the sequence in case of error. + - returns: Signal trait. + */ + public func asSignal(onErrorRecover: @escaping (_ error: Swift.Error) -> Signal) -> Signal { + let source = self + .asObservable() + .observeOn(SignalSharingStrategy.scheduler) + .catchError { error in + onErrorRecover(error).asObservable() + } + return Signal(source) + } +} + diff --git a/RxCocoa/Traits/SharedSequence/PublishRelay+SharedSequence.swift b/RxCocoa/Traits/Signal/PublishRelay+Signal.swift similarity index 51% rename from RxCocoa/Traits/SharedSequence/PublishRelay+SharedSequence.swift rename to RxCocoa/Traits/Signal/PublishRelay+Signal.swift index fb11776c..a6e73dfd 100644 --- a/RxCocoa/Traits/SharedSequence/PublishRelay+SharedSequence.swift +++ b/RxCocoa/Traits/Signal/PublishRelay+Signal.swift @@ -1,5 +1,5 @@ // -// PublishRelay+SharedSequence.swift +// PublishRelay+Signal.swift // RxCocoa // // Created by Krunoslav Zaher on 12/28/15. @@ -10,14 +10,13 @@ import RxSwift #endif -extension PublishRelay : SharedSequenceConvertibleType { - - /// Converts `PublishRelay` to `SharedSequence`. +extension PublishRelay { + /// Converts `PublishRelay` to `Signal`. /// /// - returns: Observable sequence. - public func asSharedSequence() -> SharedSequence { + public func asSignal() -> Signal { let source = self.asObservable() - .observeOn(SharingStrategy.scheduler) + .observeOn(SignalSharingStrategy.scheduler) return SharedSequence(source) } } diff --git a/RxCocoa/Traits/Signal/Signal+Subscription.swift b/RxCocoa/Traits/Signal/Signal+Subscription.swift new file mode 100644 index 00000000..4946fb31 --- /dev/null +++ b/RxCocoa/Traits/Signal/Signal+Subscription.swift @@ -0,0 +1,80 @@ +// +// Signal+Subscription.swift +// RxCocoa +// +// Created by Krunoslav Zaher on 9/19/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +#if !RX_NO_MODULE + import RxSwift +#endif + +extension SharedSequenceConvertibleType where SharingStrategy == SignalSharingStrategy { + /** + Creates new subscription and sends elements to observer. + + In this form it's equivalent to `subscribe` method, but it communicates intent better. + + - parameter to: Observer that receives events. + - returns: Disposable object that can be used to unsubscribe the observer from the subject. + */ + public func emit(to observer: O) -> Disposable where O.E == E { + return self.asSharedSequence().asObservable().subscribe(observer) + } + + /** + Creates new subscription and sends elements to observer. + + In this form it's equivalent to `subscribe` method, but it communicates intent better. + + - parameter to: Observer that receives events. + - returns: Disposable object that can be used to unsubscribe the observer from the subject. + */ + public func emit(to observer: O) -> Disposable where O.E == E? { + return self.asSharedSequence().asObservable().map { $0 as E? }.subscribe(observer) + } + + /** + Creates new subscription and sends elements to variable. + + - parameter relay: Target relay for sequence elements. + - returns: Disposable object that can be used to unsubscribe the observer from the variable. + */ + public func emit(to relay: PublishRelay) -> Disposable { + return emit(onNext: { e in + relay.accept(e) + }) + } + + /** + Creates new subscription and sends elements to variable. + + - parameter to: Target relay for sequence elements. + - returns: Disposable object that can be used to unsubscribe the observer from the variable. + */ + public func emit(to relay: PublishRelay) -> Disposable { + return emit(onNext: { e in + relay.accept(e) + }) + } + + /** + Subscribes an element handler, a completion handler and disposed handler to an observable sequence. + + Error callback is not exposed because `Signal` can't error out. + + - parameter onNext: Action to invoke for each element in the observable sequence. + - parameter onCompleted: Action to invoke upon graceful termination of the observable sequence. + gracefully completed, errored, or if the generation is canceled by disposing subscription) + - parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has + gracefully completed, errored, or if the generation is canceled by disposing subscription) + - returns: Subscription object used to unsubscribe from the observable sequence. + */ + public func emit(onNext: ((E) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable { + return self.asObservable().subscribe(onNext: onNext, onCompleted: onCompleted, onDisposed: onDisposed) + } +} + + + diff --git a/RxCocoa/Traits/Signal/Signal.swift b/RxCocoa/Traits/Signal/Signal.swift new file mode 100644 index 00000000..0f15d3a4 --- /dev/null +++ b/RxCocoa/Traits/Signal/Signal.swift @@ -0,0 +1,47 @@ +// +// Signal.swift +// RxCocoa +// +// Created by Krunoslav Zaher on 9/26/16. +// Copyright © 2016 Krunoslav Zaher. All rights reserved. +// + +#if !RX_NO_MODULE + import RxSwift +#endif + +/** + Trait that represents observable sequence with following properties: + + - it never fails + - it delivers events on `MainScheduler.instance` + - `share(scope: .whileConnected)` sharing strategy + + Additional explanation: + - all observers share sequence computation resources + - there is no replaying of sequence elements on new observer subscription + - computation of elements is reference counted with respect to the number of observers + - if there are no subscribers, it will release sequence computation resources + + In case trait that models state propagation is required, please check `Driver`. + + `Signal` can be considered a builder pattern for observable sequences that model imperative events part of the application. + + To find out more about units and how to use them, please visit `Documentation/Traits.md`. + */ +public typealias Signal = SharedSequence + +public struct SignalSharingStrategy : SharingStrategyProtocol { + public static var scheduler: SchedulerType { return SharingScheduler.make() } + + public static func share(_ source: Observable) -> Observable { + return source.share(scope: .whileConnected) + } +} + +extension SharedSequenceConvertibleType where SharingStrategy == SignalSharingStrategy { + /// Adds `asPublisher` to `SharingSequence` with `PublishSharingStrategy`. + public func asSignal() -> Signal { + return asSharedSequence() + } +} diff --git a/Sources/AllTestz/Driver+Extensions.swift b/Sources/AllTestz/Driver+Extensions.swift deleted file mode 120000 index ee8427b3..00000000 --- a/Sources/AllTestz/Driver+Extensions.swift +++ /dev/null @@ -1 +0,0 @@ -../../Tests/RxCocoaTests/Driver+Extensions.swift \ No newline at end of file diff --git a/Sources/AllTestz/SharedSequence+Extensions.swift b/Sources/AllTestz/SharedSequence+Extensions.swift new file mode 120000 index 00000000..0af09d2e --- /dev/null +++ b/Sources/AllTestz/SharedSequence+Extensions.swift @@ -0,0 +1 @@ +../../Tests/RxCocoaTests/SharedSequence+Extensions.swift \ No newline at end of file diff --git a/Sources/AllTestz/SharedSequence+OperatorTest.swift b/Sources/AllTestz/SharedSequence+OperatorTest.swift new file mode 120000 index 00000000..6aca487c --- /dev/null +++ b/Sources/AllTestz/SharedSequence+OperatorTest.swift @@ -0,0 +1 @@ +../../Tests/RxCocoaTests/SharedSequence+OperatorTest.swift \ No newline at end of file diff --git a/Sources/AllTestz/SharedSequence+Test.swift b/Sources/AllTestz/SharedSequence+Test.swift new file mode 120000 index 00000000..29f2d718 --- /dev/null +++ b/Sources/AllTestz/SharedSequence+Test.swift @@ -0,0 +1 @@ +../../Tests/RxCocoaTests/SharedSequence+Test.swift \ No newline at end of file diff --git a/Sources/AllTestz/SharingSchedulerTests.swift b/Sources/AllTestz/SharingSchedulerTests.swift new file mode 120000 index 00000000..636a5b8b --- /dev/null +++ b/Sources/AllTestz/SharingSchedulerTests.swift @@ -0,0 +1 @@ +../../Tests/RxSwiftTests/SharingSchedulerTests.swift \ No newline at end of file diff --git a/Sources/AllTestz/Signal+Test.swift b/Sources/AllTestz/Signal+Test.swift new file mode 120000 index 00000000..22659d36 --- /dev/null +++ b/Sources/AllTestz/Signal+Test.swift @@ -0,0 +1 @@ +../../Tests/RxCocoaTests/Signal+Test.swift \ No newline at end of file diff --git a/Sources/AllTestz/main.swift b/Sources/AllTestz/main.swift index d180de46..fd2ddc03 100644 --- a/Sources/AllTestz/main.swift +++ b/Sources/AllTestz/main.swift @@ -530,6 +530,19 @@ final class QueueTest_ : QueueTest, RxTestCase { ] } } +final class SharingSchedulerTest_ : SharingSchedulerTest, RxTestCase { + #if os(macOS) + required override init() { + super.init() + } + #endif + + static var allTests: [(String, (SharingSchedulerTest_) -> () -> ())] { return [ + ("testSharingSchedulerMockMake", SharingSchedulerTest.testSharingSchedulerMockMake), + ("testSharingSchedulerMockInstance", SharingSchedulerTest.testSharingSchedulerMockInstance), + ] } +} + final class ObservableSequenceTest_ : ObservableSequenceTest, RxTestCase { #if os(macOS) required override init() { @@ -563,53 +576,15 @@ final class DriverTest_ : DriverTest, RxTestCase { ("testAsDriver_onErrorJustReturn", DriverTest.testAsDriver_onErrorJustReturn), ("testAsDriver_onErrorDriveWith", DriverTest.testAsDriver_onErrorDriveWith), ("testAsDriver_onErrorRecover", DriverTest.testAsDriver_onErrorRecover), - ("testAsDriver_deferred", DriverTest.testAsDriver_deferred), - ("testAsDriver_map", DriverTest.testAsDriver_map), - ("testAsDriver_filter", DriverTest.testAsDriver_filter), - ("testAsDriver_switchLatest", DriverTest.testAsDriver_switchLatest), - ("testAsDriver_flatMapLatest", DriverTest.testAsDriver_flatMapLatest), - ("testAsDriver_flatMapFirst", DriverTest.testAsDriver_flatMapFirst), - ("testAsDriver_doOn", DriverTest.testAsDriver_doOn), - ("testAsDriver_doOnNext", DriverTest.testAsDriver_doOnNext), - ("testAsDriver_doOnCompleted", DriverTest.testAsDriver_doOnCompleted), - ("testAsDriver_distinctUntilChanged1", DriverTest.testAsDriver_distinctUntilChanged1), - ("testAsDriver_distinctUntilChanged2", DriverTest.testAsDriver_distinctUntilChanged2), - ("testAsDriver_distinctUntilChanged3", DriverTest.testAsDriver_distinctUntilChanged3), - ("testAsDriver_distinctUntilChanged4", DriverTest.testAsDriver_distinctUntilChanged4), - ("testAsDriver_flatMap", DriverTest.testAsDriver_flatMap), - ("testAsDriver_mergeSync", DriverTest.testAsDriver_mergeSync), - ("testAsDriver_merge", DriverTest.testAsDriver_merge), - ("testAsDriver_merge2", DriverTest.testAsDriver_merge2), - ("testAsDriver_debug", DriverTest.testAsDriver_debug), - ("testAsDriver_debounce", DriverTest.testAsDriver_debounce), - ("testAsDriver_throttle", DriverTest.testAsDriver_throttle), - ("testAsDriver_throttle2", DriverTest.testAsDriver_throttle2), - ("testAsDriver_scan", DriverTest.testAsDriver_scan), - ("testAsDriver_concat_sequenceType", DriverTest.testAsDriver_concat_sequenceType), - ("testAsDriver_concat", DriverTest.testAsDriver_concat), - ("testAsDriver_combineLatest_array", DriverTest.testAsDriver_combineLatest_array), - ("testAsDriver_combineLatest", DriverTest.testAsDriver_combineLatest), - ("testAsDriver_zip_array", DriverTest.testAsDriver_zip_array), - ("testAsDriver_zip", DriverTest.testAsDriver_zip), - ("testAsDriver_withLatestFrom", DriverTest.testAsDriver_withLatestFrom), - ("testAsDriver_withLatestFromDefaultOverload", DriverTest.testAsDriver_withLatestFromDefaultOverload), - ("testAsDriver_skip", DriverTest.testAsDriver_skip), - ("testAsDriver_startWith", DriverTest.testAsDriver_startWith), - ("testAsDriver_delay", DriverTest.testAsDriver_delay), - ("testAsDriver_interval", DriverTest.testAsDriver_interval), - ("testAsDriver_timer", DriverTest.testAsDriver_timer), + ("testDrivingOrderOfSynchronousSubscriptions1", DriverTest.testDrivingOrderOfSynchronousSubscriptions1), + ("testDrivingOrderOfSynchronousSubscriptions2", DriverTest.testDrivingOrderOfSynchronousSubscriptions2), ("testDriveObserver", DriverTest.testDriveObserver), ("testDriveOptionalObserver", DriverTest.testDriveOptionalObserver), ("testDriveNoAmbiguity", DriverTest.testDriveNoAmbiguity), - ("testdriveVariable", DriverTest.testdriveVariable), - ("testDriveOptionalVariable", DriverTest.testDriveOptionalVariable), + ("testDriveVariable", DriverTest.testDriveVariable), + ("testDriveOptionalVariable1", DriverTest.testDriveOptionalVariable1), + ("testDriveOptionalVariable2", DriverTest.testDriveOptionalVariable2), ("testDriveVariableNoAmbiguity", DriverTest.testDriveVariableNoAmbiguity), - ("testDriverFromOptional", DriverTest.testDriverFromOptional), - ("testDriverFromOptionalWhenNil", DriverTest.testDriverFromOptionalWhenNil), - ("testDriverFromSequence", DriverTest.testDriverFromSequence), - ("testDriverFromArray", DriverTest.testDriverFromArray), - ("testDrivingOrderOfSynchronousSubscriptions1", DriverTest.testDrivingOrderOfSynchronousSubscriptions1), - ("testDrivingOrderOfSynchronousSubscriptions2", DriverTest.testDrivingOrderOfSynchronousSubscriptions2), ] } } @@ -689,6 +664,56 @@ final class ObservableWindowTest_ : ObservableWindowTest, RxTestCase { ] } } +final class SharedSequenceOperatorTests_ : SharedSequenceOperatorTests, RxTestCase { + #if os(macOS) + required override init() { + super.init() + } + #endif + + static var allTests: [(String, (SharedSequenceOperatorTests_) -> () -> ())] { return [ + ("testAsDriver_deferred", SharedSequenceOperatorTests.testAsDriver_deferred), + ("testAsDriver_map", SharedSequenceOperatorTests.testAsDriver_map), + ("testAsDriver_filter", SharedSequenceOperatorTests.testAsDriver_filter), + ("testAsDriver_switchLatest", SharedSequenceOperatorTests.testAsDriver_switchLatest), + ("testAsDriver_flatMapLatest", SharedSequenceOperatorTests.testAsDriver_flatMapLatest), + ("testAsDriver_flatMapFirst", SharedSequenceOperatorTests.testAsDriver_flatMapFirst), + ("testAsDriver_doOn", SharedSequenceOperatorTests.testAsDriver_doOn), + ("testAsDriver_doOnNext", SharedSequenceOperatorTests.testAsDriver_doOnNext), + ("testAsDriver_doOnCompleted", SharedSequenceOperatorTests.testAsDriver_doOnCompleted), + ("testAsDriver_distinctUntilChanged1", SharedSequenceOperatorTests.testAsDriver_distinctUntilChanged1), + ("testAsDriver_distinctUntilChanged2", SharedSequenceOperatorTests.testAsDriver_distinctUntilChanged2), + ("testAsDriver_distinctUntilChanged3", SharedSequenceOperatorTests.testAsDriver_distinctUntilChanged3), + ("testAsDriver_distinctUntilChanged4", SharedSequenceOperatorTests.testAsDriver_distinctUntilChanged4), + ("testAsDriver_flatMap", SharedSequenceOperatorTests.testAsDriver_flatMap), + ("testAsDriver_mergeSync", SharedSequenceOperatorTests.testAsDriver_mergeSync), + ("testAsDriver_merge", SharedSequenceOperatorTests.testAsDriver_merge), + ("testAsDriver_merge2", SharedSequenceOperatorTests.testAsDriver_merge2), + ("testAsDriver_debug", SharedSequenceOperatorTests.testAsDriver_debug), + ("testAsDriver_debounce", SharedSequenceOperatorTests.testAsDriver_debounce), + ("testAsDriver_throttle", SharedSequenceOperatorTests.testAsDriver_throttle), + ("testAsDriver_throttle2", SharedSequenceOperatorTests.testAsDriver_throttle2), + ("testAsDriver_scan", SharedSequenceOperatorTests.testAsDriver_scan), + ("testAsDriver_concat_sequenceType", SharedSequenceOperatorTests.testAsDriver_concat_sequenceType), + ("testAsDriver_concat", SharedSequenceOperatorTests.testAsDriver_concat), + ("testAsDriver_combineLatest_array", SharedSequenceOperatorTests.testAsDriver_combineLatest_array), + ("testAsDriver_combineLatest", SharedSequenceOperatorTests.testAsDriver_combineLatest), + ("testAsDriver_zip_array", SharedSequenceOperatorTests.testAsDriver_zip_array), + ("testAsDriver_zip", SharedSequenceOperatorTests.testAsDriver_zip), + ("testAsDriver_withLatestFrom", SharedSequenceOperatorTests.testAsDriver_withLatestFrom), + ("testAsDriver_withLatestFromDefaultOverload", SharedSequenceOperatorTests.testAsDriver_withLatestFromDefaultOverload), + ("testAsDriver_skip", SharedSequenceOperatorTests.testAsDriver_skip), + ("testAsDriver_startWith", SharedSequenceOperatorTests.testAsDriver_startWith), + ("testAsDriver_delay", SharedSequenceOperatorTests.testAsDriver_delay), + ("testAsDriver_interval", SharedSequenceOperatorTests.testAsDriver_interval), + ("testAsDriver_timer", SharedSequenceOperatorTests.testAsDriver_timer), + ("testDriverFromOptional", SharedSequenceOperatorTests.testDriverFromOptional), + ("testDriverFromOptionalWhenNil", SharedSequenceOperatorTests.testDriverFromOptionalWhenNil), + ("testDriverFromSequence", SharedSequenceOperatorTests.testDriverFromSequence), + ("testDriverFromArray", SharedSequenceOperatorTests.testDriverFromArray), + ] } +} + final class ObservableZipTest_ : ObservableZipTest, RxTestCase { #if os(macOS) required override init() { @@ -1789,6 +1814,30 @@ final class ObservableReduceTest_ : ObservableReduceTest, RxTestCase { ("test_ReduceWithSeedAndResult_SelectorThrows", ObservableReduceTest.test_ReduceWithSeedAndResult_SelectorThrows), ] } } + +final class SignalTests_ : SignalTests, RxTestCase { + #if os(macOS) + required override init() { + super.init() + } + #endif + + static var allTests: [(String, (SignalTests_) -> () -> ())] { return [ + ("testSignalSharing_WhenErroring", SignalTests.testSignalSharing_WhenErroring), + ("testSignalSharing_WhenCompleted", SignalTests.testSignalSharing_WhenCompleted), + ("testPublishRelayAsSignal", SignalTests.testPublishRelayAsSignal), + ("testAsSignal_onErrorJustReturn", SignalTests.testAsSignal_onErrorJustReturn), + ("testAsSignal_onErrorDriveWith", SignalTests.testAsSignal_onErrorDriveWith), + ("testAsSignal_onErrorRecover", SignalTests.testAsSignal_onErrorRecover), + ("testEmitObserver", SignalTests.testEmitObserver), + ("testEmitOptionalObserver", SignalTests.testEmitOptionalObserver), + ("testEmitNoAmbiguity", SignalTests.testEmitNoAmbiguity), + ("testSignalRelay", SignalTests.testSignalRelay), + ("testSignalOptionalRelay1", SignalTests.testSignalOptionalRelay1), + ("testSignalOptionalRelay2", SignalTests.testSignalOptionalRelay2), + ("testDriveVariableNoAmbiguity", SignalTests.testDriveVariableNoAmbiguity), + ] } +} #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) func testCase(_ tests: [(String, (T) -> () -> ())]) -> () -> () { @@ -1838,12 +1887,14 @@ func XCTMain(_ tests: [() -> ()]) { testCase(RecursiveLockTests_.allTests), testCase(ObservableEnumeratedTest_.allTests), testCase(QueueTest_.allTests), + testCase(SharingSchedulerTest_.allTests), testCase(ObservableSequenceTest_.allTests), testCase(DriverTest_.allTests), testCase(ObservableMapTest_.allTests), testCase(CurrentThreadSchedulerTest_.allTests), testCase(ObservableSubscribeOnTest_.allTests), testCase(ObservableWindowTest_.allTests), + testCase(SharedSequenceOperatorTests_.allTests), testCase(ObservableZipTest_.allTests), testCase(ObservableSkipUntilTest_.allTests), testCase(ObservableDefaultIfEmptyTest_.allTests), @@ -1892,5 +1943,6 @@ func XCTMain(_ tests: [() -> ()]) { testCase(ObservableTakeUntilTest_.allTests), testCase(ObservableMergeTest_.allTests), testCase(ObservableReduceTest_.allTests), + testCase(SignalTests_.allTests), ]) //} diff --git a/Sources/RxCocoa/ObservableConvertibleType+Signal.swift b/Sources/RxCocoa/ObservableConvertibleType+Signal.swift new file mode 120000 index 00000000..a8584777 --- /dev/null +++ b/Sources/RxCocoa/ObservableConvertibleType+Signal.swift @@ -0,0 +1 @@ +../../RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift \ No newline at end of file diff --git a/Sources/RxCocoa/PublishRelay+SharedSequence.swift b/Sources/RxCocoa/PublishRelay+SharedSequence.swift deleted file mode 120000 index a63a4be0..00000000 --- a/Sources/RxCocoa/PublishRelay+SharedSequence.swift +++ /dev/null @@ -1 +0,0 @@ -../../RxCocoa/Traits/SharedSequence/PublishRelay+SharedSequence.swift \ No newline at end of file diff --git a/Sources/RxCocoa/PublishRelay+Signal.swift b/Sources/RxCocoa/PublishRelay+Signal.swift new file mode 120000 index 00000000..cd6f009b --- /dev/null +++ b/Sources/RxCocoa/PublishRelay+Signal.swift @@ -0,0 +1 @@ +../../RxCocoa/Traits/Signal/PublishRelay+Signal.swift \ No newline at end of file diff --git a/Sources/RxCocoa/Publisher.swift b/Sources/RxCocoa/Publisher.swift deleted file mode 120000 index dd189e70..00000000 --- a/Sources/RxCocoa/Publisher.swift +++ /dev/null @@ -1 +0,0 @@ -../../RxCocoa/Traits/Publisher/Publisher.swift \ No newline at end of file diff --git a/Sources/RxCocoa/SchedulerType+SharedSequence.swift b/Sources/RxCocoa/SchedulerType+SharedSequence.swift new file mode 120000 index 00000000..793ca114 --- /dev/null +++ b/Sources/RxCocoa/SchedulerType+SharedSequence.swift @@ -0,0 +1 @@ +../../RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift \ No newline at end of file diff --git a/Sources/RxCocoa/Signal+Subscription.swift b/Sources/RxCocoa/Signal+Subscription.swift new file mode 120000 index 00000000..6ff3d47f --- /dev/null +++ b/Sources/RxCocoa/Signal+Subscription.swift @@ -0,0 +1 @@ +../../RxCocoa/Traits/Signal/Signal+Subscription.swift \ No newline at end of file diff --git a/Sources/RxCocoa/Signal.swift b/Sources/RxCocoa/Signal.swift new file mode 120000 index 00000000..33fa6f34 --- /dev/null +++ b/Sources/RxCocoa/Signal.swift @@ -0,0 +1 @@ +../../RxCocoa/Traits/Signal/Signal.swift \ No newline at end of file diff --git a/Sources/RxCocoa/Variable+SharedSequence.swift b/Sources/RxCocoa/Variable+SharedSequence.swift deleted file mode 120000 index e49f8510..00000000 --- a/Sources/RxCocoa/Variable+SharedSequence.swift +++ /dev/null @@ -1 +0,0 @@ -../../RxCocoa/Traits/SharedSequence/Variable+SharedSequence.swift \ No newline at end of file diff --git a/Tests/RxCocoaTests/Driver+Test.swift b/Tests/RxCocoaTests/Driver+Test.swift index 98c60fc8..0a9daf06 100644 --- a/Tests/RxCocoaTests/Driver+Test.swift +++ b/Tests/RxCocoaTests/Driver+Test.swift @@ -12,93 +12,7 @@ import RxCocoa import XCTest import RxTest -class DriverTest : RxTest { - var backgroundScheduler = SerialDispatchQueueScheduler(qos: .default) - - override func tearDown() { - super.tearDown() - } -} - -// test helpers that make sure that resulting driver operator honors definition -// * only one subscription is made and shared - shareReplay(1) -// * subscription is made on main thread - subscribeOn(ConcurrentMainScheduler.instance) -// * events are observed on main thread - observeOn(MainScheduler.instance) -// * it can't error out - it needs to have catch somewhere -extension DriverTest { - - func subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(_ driver: Driver, subscribedOnBackground: () -> ()) -> [R] { - var firstElements = [R]() - var secondElements = [R]() - - let subscribeFinished = self.expectation(description: "subscribeFinished") - - var expectation1: XCTestExpectation! - var expectation2: XCTestExpectation! - - _ = backgroundScheduler.schedule(()) { _ in - var subscribing1 = true - _ = driver.asObservable().subscribe { e in - if !subscribing1 { - XCTAssertTrue(DispatchQueue.isMain) - } - switch e { - case .next(let element): - firstElements.append(element) - case .error(let error): - XCTFail("Error passed \(error)") - case .completed: - expectation1.fulfill() - } - } - subscribing1 = false - - var subscribing = true - _ = driver.asDriver().asObservable().subscribe { e in - if !subscribing { - XCTAssertTrue(DispatchQueue.isMain) - } - switch e { - case .next(let element): - secondElements.append(element) - case .error(let error): - XCTFail("Error passed \(error)") - case .completed: - expectation2.fulfill() - } - } - - subscribing = false - - // Subscription should be made on main scheduler - // so this will make sure execution is continued after - // subscription because of serial nature of main scheduler. - _ = MainScheduler.instance.schedule(()) { _ in - subscribeFinished.fulfill() - return Disposables.create() - } - - return Disposables.create() - } - - waitForExpectations(timeout: 1.0) { error in - XCTAssertTrue(error == nil) - } - - expectation1 = self.expectation(description: "finished1") - expectation2 = self.expectation(description: "finished2") - - subscribedOnBackground() - - waitForExpectations(timeout: 1.0) { error in - XCTAssertTrue(error == nil) - } - - XCTAssertTrue(firstElements == secondElements) - - return firstElements - } -} +class DriverTest : SharedSequenceTest { } // MARK: properties extension DriverTest { @@ -189,7 +103,7 @@ extension DriverTest { next(20, 1), next(30, 2), next(40, 3), - error(50, testError) + completed(50) ]) let driver = coldObservable.asDriver(onErrorJustReturn: -1) @@ -232,7 +146,6 @@ extension DriverTest { next(225, 1), next(230, 2), next(240, 3), - next(250, -1), completed(250) ]) @@ -252,11 +165,11 @@ extension DriverTest { extension DriverTest { func testVariableAsDriver() { var hotObservable: Variable? = Variable(1) - let driver = Driver.zip(hotObservable!.asDriver(), Driver.of(0, 0)) { (optInt, int) in + let xs = Driver.zip(hotObservable!.asDriver(), Driver.of(0, 0)) { (optInt, int) in return optInt } - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { hotObservable?.value = 1 hotObservable?.value = 2 hotObservable = nil @@ -267,9 +180,9 @@ extension DriverTest { func testAsDriver_onErrorJustReturn() { let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1) + let xs = hotObservable.asDriver(onErrorJustReturn: -1) - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) hotObservable.on(.next(1)) @@ -284,9 +197,9 @@ extension DriverTest { func testAsDriver_onErrorDriveWith() { let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorDriveWith: Driver.just(-1)) + let xs = hotObservable.asDriver(onErrorDriveWith: Driver.just(-1)) - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) hotObservable.on(.next(1)) @@ -301,11 +214,11 @@ extension DriverTest { func testAsDriver_onErrorRecover() { let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver { e in + let xs = hotObservable.asDriver { e in return Driver.empty() } - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) hotObservable.on(.next(1)) @@ -319,1110 +232,6 @@ extension DriverTest { } } -// MARK: deferred -extension DriverTest { - func testAsDriver_deferred() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = Driver.deferred { hotObservable.asDriver(onErrorJustReturn: -1) } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } -} - -// MARK: map -extension DriverTest { - func testAsDriver_map() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Int in - XCTAssertTrue(DispatchQueue.isMain) - return n + 1 - } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2, 3, 0]) - } -} - -// MARK: filter -extension DriverTest { - func testAsDriver_filter() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).filter { n in - XCTAssertTrue(DispatchQueue.isMain) - return n % 2 == 0 - } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2]) - } -} - - -// MARK: switch latest -extension DriverTest { - func testAsDriver_switchLatest() { - let hotObservable = BackgroundThreadPrimitiveHotObservable>() - let hotObservable1 = MainThreadPrimitiveHotObservable() - let hotObservable2 = MainThreadPrimitiveHotObservable() - - let driver = hotObservable.asDriver(onErrorJustReturn: hotObservable1.asDriver(onErrorJustReturn: -1)).switchLatest() - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(hotObservable1.asDriver(onErrorJustReturn: -2))) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - hotObservable1.on(.error(testError)) - - hotObservable.on(.next(hotObservable2.asDriver(onErrorJustReturn: -3))) - - hotObservable2.on(.next(10)) - hotObservable2.on(.next(11)) - hotObservable2.on(.error(testError)) - - hotObservable.on(.error(testError)) - - hotObservable1.on(.completed) - hotObservable.on(.completed) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [ - 1, 2, -2, - 10, 11, -3, - -1 - ]) - } -} - -// MARK: flatMapLatest -extension DriverTest { - func testAsDriver_flatMapLatest() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let hotObservable1 = MainThreadPrimitiveHotObservable() - let hotObservable2 = MainThreadPrimitiveHotObservable() - let errorHotObservable = MainThreadPrimitiveHotObservable() - - let drivers: [Driver] = [ - hotObservable1.asDriver(onErrorJustReturn: -2), - hotObservable2.asDriver(onErrorJustReturn: -3), - errorHotObservable.asDriver(onErrorJustReturn: -4), - ] - - let driver = hotObservable.asDriver(onErrorJustReturn: 2).flatMapLatest { drivers[$0] } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(0)) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - hotObservable1.on(.error(testError)) - - hotObservable.on(.next(1)) - - hotObservable2.on(.next(10)) - hotObservable2.on(.next(11)) - hotObservable2.on(.error(testError)) - - hotObservable.on(.error(testError)) - - errorHotObservable.on(.completed) - hotObservable.on(.completed) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [ - 1, 2, -2, - 10, 11, -3 - ]) - } -} - -// MARK: flatMapFirst -extension DriverTest { - func testAsDriver_flatMapFirst() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let hotObservable1 = MainThreadPrimitiveHotObservable() - let hotObservable2 = MainThreadPrimitiveHotObservable() - let errorHotObservable = MainThreadPrimitiveHotObservable() - - let drivers: [Driver] = [ - hotObservable1.asDriver(onErrorJustReturn: -2), - hotObservable2.asDriver(onErrorJustReturn: -3), - errorHotObservable.asDriver(onErrorJustReturn: -4), - ] - - let driver = hotObservable.asDriver(onErrorJustReturn: 2).flatMapFirst { drivers[$0] } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(0)) - hotObservable.on(.next(1)) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - hotObservable1.on(.error(testError)) - - hotObservable2.on(.next(10)) - hotObservable2.on(.next(11)) - hotObservable2.on(.error(testError)) - - hotObservable.on(.error(testError)) - - errorHotObservable.on(.completed) - hotObservable.on(.completed) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [ - 1, 2, -2, - ]) - } -} - -// MARK: doOn -extension DriverTest { - func testAsDriver_doOn() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - var events = [Event]() - - var calledSubscribe = false - var calledSubscribed = false - var calledDispose = false - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onNext: { e in - XCTAssertTrue(DispatchQueue.isMain) - - events.append(.next(e)) - }, onCompleted: { - XCTAssertTrue(DispatchQueue.isMain) - events.append(.completed) - }, onSubscribe: { - XCTAssertTrue(!DispatchQueue.isMain) - calledSubscribe = true - }, onSubscribed: { - XCTAssertTrue(!DispatchQueue.isMain) - calledSubscribed = true - }, onDispose: { - XCTAssertTrue(DispatchQueue.isMain) - calledDispose = true - }) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - let expectedEvents = [.next(1), .next(2), .next(-1), .completed] as [Event] - XCTAssertEqual(events, expectedEvents) - XCTAssertEqual(calledSubscribe, true) - XCTAssertEqual(calledSubscribed, true) - XCTAssertEqual(calledDispose, true) - } - - - func testAsDriver_doOnNext() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - var events = [Int]() - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onNext: { e in - XCTAssertTrue(DispatchQueue.isMain) - events.append(e) - }) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - let expectedEvents = [1, 2, -1] - XCTAssertEqual(events, expectedEvents) - } - - func testAsDriver_doOnCompleted() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - var completed = false - let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onCompleted: { - XCTAssertTrue(DispatchQueue.isMain) - completed = true - }) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - XCTAssertEqual(completed, true) - } -} - -// MARK: distinct until change -extension DriverTest { - func testAsDriver_distinctUntilChanged1() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged() - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } - - func testAsDriver_distinctUntilChanged2() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 }) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } - - func testAsDriver_distinctUntilChanged3() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 == $1 }) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } - - - func testAsDriver_distinctUntilChanged4() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 }) { $0 == $1 } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } - -} - -// MARK: flat map -extension DriverTest { - func testAsDriver_flatMap() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).flatMap { (n: Int) -> Driver in - XCTAssertTrue(DispatchQueue.isMain) - return Driver.just(n + 1) - } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2, 3, 0]) - } - -} - -// MARK: merge - -extension DriverTest { - func testAsDriver_mergeSync() { - let factories: [(Driver) -> Driver] = - [ - { source in Driver.merge(source) }, - { source in Driver.merge([source]) }, - { source in Driver.merge(AnyCollection([source])) }, - ] - - for factory in factories { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = factory(hotObservable.asDriver(onErrorJustReturn: -1)) - - let results = self.subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } - } -} - -// MARK: merge -extension DriverTest { - func testAsDriver_merge() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Driver in - XCTAssertTrue(DispatchQueue.isMain) - return Driver.just(n + 1) - }.merge() - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2, 3, 0]) - } - - func testAsDriver_merge2() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Driver in - XCTAssertTrue(DispatchQueue.isMain) - return Driver.just(n + 1) - }.merge(maxConcurrent: 1) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2, 3, 0]) - } -} - -// MARK: debug -extension DriverTest { - func testAsDriver_debug() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).debug("a", trimOutput: false) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, -1]) - } -} - -// MARK: debounce -extension DriverTest { - func testAsDriver_debounce() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).debounce(0.0) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [-1]) - } - - func testAsDriver_throttle() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).throttle(0.5) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, -1]) - } - - func testAsDriver_throttle2() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).throttle(0.5, latest: false) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1]) - } - -} - -// MARK: scan -extension DriverTest { - func testAsDriver_scan() { - let hotObservable = BackgroundThreadPrimitiveHotObservable() - let driver = hotObservable.asDriver(onErrorJustReturn: -1).scan(0) { (a: Int, n: Int) -> Int in - XCTAssertTrue(DispatchQueue.isMain) - return a + n - } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) - - hotObservable.on(.next(1)) - hotObservable.on(.next(2)) - hotObservable.on(.error(testError)) - - XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 3, 2]) - } - -} - -// MARK: concat -extension DriverTest { - func testAsDriver_concat_sequenceType() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = MainThreadPrimitiveHotObservable() - - let driver = Driver.concat(AnySequence([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)])) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - hotObservable1.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable2.on(.next(4)) - hotObservable2.on(.next(5)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1, 4, 5, -2]) - } - - func testAsDriver_concat() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = MainThreadPrimitiveHotObservable() - - let driver = Driver.concat([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - hotObservable1.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable2.on(.next(4)) - hotObservable2.on(.next(5)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1, 4, 5, -2]) - } -} - -// MARK: combine latest -extension DriverTest { - func testAsDriver_combineLatest_array() { - let factories: [([Driver]) -> Driver] = - [ - { e0 in - Driver.combineLatest(e0) { a in a.reduce(0, +) } - }, - { e0 in - Driver.combineLatest(e0).map { a in a.reduce(0, +) } - }, - ] - - for factory in factories { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = factory([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [5, 6, 7, 4, -3]) - } - } - - func testAsDriver_combineLatest() { - let factories: [(Driver, Driver) -> Driver] = - [ - { e0, e1 in - Driver.combineLatest(e0, e1, resultSelector: +) - }, - { e0, e1 in - Driver.combineLatest(e0, e1).map(+) - }, - ] - for factory in factories { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = factory(hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [5, 6, 7, 4, -3]) - } - } -} - -// MARK: zip -extension DriverTest { - func testAsDriver_zip_array() { - let factories: [([Driver]) -> Driver] = - [ - { e0 in - Driver.zip(e0) { a in a.reduce(0, +) } - }, - { e0 in - Driver.zip(e0).map { a in a.reduce(0, +) } - }, - ] - - for factory in factories { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = factory([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [5, 7, -3]) - } - } - - func testAsDriver_zip() { - let factories: [(Driver, Driver) -> Driver] = - [ - { e0, e1 in - Driver.zip(e0, e1, resultSelector: +) - }, - { e0, e1 in - Driver.zip(e0, e1).map(+) - }, - ] - for factory in factories { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = factory(hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [5, 7, -3]) - } - } -} - -// MARK: withLatestFrom -extension DriverTest { - func testAsDriver_withLatestFrom() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable1.asDriver(onErrorJustReturn: -1).withLatestFrom(hotObservable2.asDriver(onErrorJustReturn: -2)) { f, s in "\(f)\(s)" } - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, ["24", "-15"]) - } - - func testAsDriver_withLatestFromDefaultOverload() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - let hotObservable2 = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable1.asDriver(onErrorJustReturn: -1).withLatestFrom(hotObservable2.asDriver(onErrorJustReturn: -2)) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable2.on(.next(4)) - - hotObservable1.on(.next(2)) - hotObservable2.on(.next(5)) - - hotObservable1.on(.error(testError)) - hotObservable2.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [4, 5]) - - } -} - -// MARK: skip -extension DriverTest { - func testAsDriver_skip() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable1.asDriver(onErrorJustReturn: -1).skip(1) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - - hotObservable1.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [2, -1]) - } -} - -// MARK: startWith -extension DriverTest { - func testAsDriver_startWith() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable1.asDriver(onErrorJustReturn: -1).startWith(0) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - - hotObservable1.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [0, 1, 2, -1]) - } -} - -// MARK: delay -extension DriverTest { - func testAsDriver_delay() { - let hotObservable1 = BackgroundThreadPrimitiveHotObservable() - - let driver = hotObservable1.asDriver(onErrorJustReturn: -1).delay(0.1) - - let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { - XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) - - hotObservable1.on(.next(1)) - hotObservable1.on(.next(2)) - - hotObservable1.on(.error(testError)) - - XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) - } - - XCTAssertEqual(results, [1, 2, -1]) - } -} - -//MARK: interval -extension DriverTest { - func testAsDriver_interval() { - let testScheduler = TestScheduler(initialClock: 0) - - let firstObserver = testScheduler.createObserver(Int.self) - let secondObserver = testScheduler.createObserver(Int.self) - - var disposable1: Disposable! - var disposable2: Disposable! - - driveOnScheduler(testScheduler) { - let interval = Driver.interval(100) - - testScheduler.scheduleAt(20) { - disposable1 = interval.asObservable().subscribe(firstObserver) - } - - testScheduler.scheduleAt(170) { - disposable2 = interval.asObservable().subscribe(secondObserver) - } - - testScheduler.scheduleAt(230) { - disposable1.dispose() - disposable2.dispose() - } - - testScheduler.start() - } - - XCTAssertEqual(firstObserver.events, [ - next(120, 0), - next(220, 1) - ]) - XCTAssertEqual(secondObserver.events, [ - next(170, 0), - next(220, 1) - ]) - } -} - -//MARK: timer -extension DriverTest { - func testAsDriver_timer() { - let testScheduler = TestScheduler(initialClock: 0) - - let firstObserver = testScheduler.createObserver(Int.self) - let secondObserver = testScheduler.createObserver(Int.self) - - var disposable1: Disposable! - var disposable2: Disposable! - - driveOnScheduler(testScheduler) { - let interval = Driver.timer(100, period: 105) - - testScheduler.scheduleAt(20) { - disposable1 = interval.asObservable().subscribe(firstObserver) - } - - testScheduler.scheduleAt(170) { - disposable2 = interval.asObservable().subscribe(secondObserver) - } - - testScheduler.scheduleAt(230) { - disposable1.dispose() - disposable2.dispose() - } - - testScheduler.start() - } - - XCTAssertEqual(firstObserver.events, [ - next(120, 0), - next(225, 1) - ]) - XCTAssertEqual(secondObserver.events, [ - next(170, 0), - next(225, 1) - ]) - } -} - -// MARK: drive observer -extension DriverTest { - func testDriveObserver() { - var events: [Recorded>] = [] - - let observer: AnyObserver = AnyObserver { event in - events.append(Recorded(time: 0, value: event)) - } - - _ = Driver.just(1).drive(observer) - } - - func testDriveOptionalObserver() { - var events: [Recorded>] = [] - - let observer: AnyObserver = AnyObserver { event in - events.append(Recorded(time: 0, value: event)) - } - - _ = (Driver.just(1) as Driver).drive(observer) - - XCTAssertEqual(events[0].value.element!, 1) - } - - func testDriveNoAmbiguity() { - var events: [Recorded>] = [] - - let observer: AnyObserver = AnyObserver { event in - events.append(Recorded(time: 0, value: event)) - } - - _ = Driver.just(1).drive(observer) - - XCTAssertEqual(events[0].value.element!, 1) - } -} - -// MARK: drive variable - -extension DriverTest { - func testdriveVariable() { - let variable = Variable(0) - - _ = Driver.just(1).drive(variable) - - XCTAssertEqual(variable.value, 1) - } - - func testDriveOptionalVariable() { - let variable = Variable(0) - - _ = (Driver.just(1) as Driver).drive(variable) - - XCTAssertEqual(variable.value, 1) - } - - func testDriveVariableNoAmbiguity() { - let variable = Variable(0) - - _ = Driver.just(1).drive(variable) - - XCTAssertEqual(variable.value, 1) - } -} - -// MARK: from optional - -extension DriverTest { - func testDriverFromOptional() { - let scheduler = TestScheduler(initialClock: 0) - - driveOnScheduler(scheduler) { - let res = scheduler.start { Driver.from(optional: 1 as Int?).asObservable() } - XCTAssertEqual(res.events, [ - next(201, 1), - completed(202) - ]) - } - } - - func testDriverFromOptionalWhenNil() { - let scheduler = TestScheduler(initialClock: 0) - - driveOnScheduler(scheduler) { - let res = scheduler.start { Driver.from(optional: nil as Int?).asObservable() } - XCTAssertEqual(res.events, [ - completed(201) - ]) - } - } -} - - -// MARK: from sequence - -extension DriverTest { - func testDriverFromSequence() { - let scheduler = TestScheduler(initialClock: 0) - - driveOnScheduler(scheduler) { - let res = scheduler.start { Driver.from(AnySequence([10])).asObservable() } - XCTAssertEqual(res.events, [ - next(201, 10), - completed(202) - ]) - } - } - - func testDriverFromArray() { - let scheduler = TestScheduler(initialClock: 0) - - driveOnScheduler(scheduler) { - let res = scheduler.start { Driver.from([20]).asObservable() } - XCTAssertEqual(res.events, [ - next(201, 20), - completed(202) - ]) - } - } -} - // MARK: correct order of sync subscriptions extension DriverTest { @@ -1491,3 +300,81 @@ extension DriverTest { XCTAssertEqual(latestValue, 2) } } + + +// MARK: drive observer +extension DriverTest { + func testDriveObserver() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + _ = (Driver.just(1) as Driver).drive(observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } + + func testDriveOptionalObserver() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + _ = (Driver.just(1) as Driver).drive(observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } + + func testDriveNoAmbiguity() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + // shouldn't cause compile time error + _ = Driver.just(1).drive(observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } +} + +// MARK: drive variable + +extension DriverTest { + func testDriveVariable() { + let variable = Variable(0) + + _ = (Driver.just(1) as Driver).drive(variable) + + XCTAssertEqual(variable.value, 1) + } + + func testDriveOptionalVariable1() { + let variable = Variable(0) + + _ = (Driver.just(1) as Driver).drive(variable) + + XCTAssertEqual(variable.value, 1) + } + + func testDriveOptionalVariable2() { + let variable = Variable(0) + + _ = (Driver.just(1) as Driver).drive(variable) + + XCTAssertEqual(variable.value, 1) + } + + func testDriveVariableNoAmbiguity() { + let variable = Variable(0) + + // shouldn't cause compile time error + _ = Driver.just(1).drive(variable) + + XCTAssertEqual(variable.value, 1) + } +} diff --git a/Tests/RxCocoaTests/PublisherTests.swift b/Tests/RxCocoaTests/PublisherTests.swift deleted file mode 100644 index 3c407cae..00000000 --- a/Tests/RxCocoaTests/PublisherTests.swift +++ /dev/null @@ -1,97 +0,0 @@ -// -// PublisherTests.swift -// Tests -// -// Created by Krunoslav Zaher on 2/26/17. -// Copyright © 2017 Krunoslav Zaher. All rights reserved. -// - -import Dispatch -import RxSwift -import RxCocoa -import XCTest -import RxTest - -class PublishRelayTest: RxTest {} - -extension PublishRelayTest { - func testPublishRelaySharing() { - let scheduler = TestScheduler(initialClock: 0) - - let observer1 = scheduler.createObserver(Int.self) - let observer2 = scheduler.createObserver(Int.self) - let observer3 = scheduler.createObserver(Int.self) - var disposable1: Disposable! - var disposable2: Disposable! - var disposable3: Disposable! - - let publisher = PublishRelay() - scheduler.scheduleAt(100) { publisher.accept(0) } - scheduler.scheduleAt(210) { publisher.accept(1) } - scheduler.scheduleAt(225) { publisher.accept(2) } - scheduler.scheduleAt(245) { publisher.accept(3) } - scheduler.scheduleAt(265) { publisher.accept(4) } - - scheduler.scheduleAt(200) { - disposable1 = publisher.asObservable().subscribe(observer1) - } - - scheduler.scheduleAt(220) { - disposable2 = publisher.asObservable().subscribe(observer2) - } - - scheduler.scheduleAt(235) { - disposable1.dispose() - } - - scheduler.scheduleAt(260) { - disposable2.dispose() - } - - // resubscription - - scheduler.scheduleAt(260) { - disposable3 = publisher.asObservable().subscribe(observer3) - } - - scheduler.scheduleAt(285) { - disposable3.dispose() - } - - scheduler.start() - - XCTAssertEqual(observer1.events, [ - next(210, 1), - next(225, 2) - ]) - - XCTAssertEqual(observer2.events, [ - next(225, 2), - next(245, 3) - ]) - - XCTAssertEqual(observer3.events, [ - next(265, 4) - ]) - } -} - -extension PublishRelayTest { - func testPublisherAlwaysObservingOnMainThread() { - - let relay = PublishRelay() - let mainThreadExpectation = expectation(description: "PublishRelay emits items on main thread") - - let d = relay.asObservable().subscribe(onNext: { - XCTAssertTrue(DispatchQueue.isMain) - mainThreadExpectation.fulfill() - }) - - doOnBackgroundQueue { - relay.accept(()) - } - - waitForExpectations(timeout: 0.5, handler: nil) - d.dispose() - } -} diff --git a/Tests/RxCocoaTests/Driver+Extensions.swift b/Tests/RxCocoaTests/SharedSequence+Extensions.swift similarity index 90% rename from Tests/RxCocoaTests/Driver+Extensions.swift rename to Tests/RxCocoaTests/SharedSequence+Extensions.swift index 0b985948..73df43d2 100644 --- a/Tests/RxCocoaTests/Driver+Extensions.swift +++ b/Tests/RxCocoaTests/SharedSequence+Extensions.swift @@ -1,5 +1,5 @@ // -// Driver+Extensions.swift +// SharedSequence+Extensions.swift // Tests // // Created by Krunoslav Zaher on 12/25/15. diff --git a/Tests/RxCocoaTests/SharedSequence+OperatorTest.swift b/Tests/RxCocoaTests/SharedSequence+OperatorTest.swift new file mode 100644 index 00000000..ff0acd93 --- /dev/null +++ b/Tests/RxCocoaTests/SharedSequence+OperatorTest.swift @@ -0,0 +1,1054 @@ +// +// SharedSequence+OperatorTest.swift +// Tests +// +// Created by Krunoslav Zaher on 10/14/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Dispatch +import RxSwift +import RxCocoa +import XCTest +import RxTest + +class SharedSequenceOperatorTests : SharedSequenceTest { } + +// MARK: deferred +extension SharedSequenceOperatorTests { + func testAsDriver_deferred() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = Driver.deferred { hotObservable.asDriver(onErrorJustReturn: -1) } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } +} + +// MARK: map +extension SharedSequenceOperatorTests { + func testAsDriver_map() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Int in + XCTAssertTrue(DispatchQueue.isMain) + return n + 1 + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2, 3, 0]) + } +} + +// MARK: filter +extension SharedSequenceOperatorTests { + func testAsDriver_filter() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).filter { n in + XCTAssertTrue(DispatchQueue.isMain) + return n % 2 == 0 + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2]) + } +} + + +// MARK: switch latest +extension SharedSequenceOperatorTests { + func testAsDriver_switchLatest() { + let hotObservable = BackgroundThreadPrimitiveHotObservable>() + let hotObservable1 = MainThreadPrimitiveHotObservable() + let hotObservable2 = MainThreadPrimitiveHotObservable() + + let driver = hotObservable.asDriver(onErrorJustReturn: hotObservable1.asDriver(onErrorJustReturn: -1)).switchLatest() + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(hotObservable1.asDriver(onErrorJustReturn: -2))) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + hotObservable1.on(.error(testError)) + + hotObservable.on(.next(hotObservable2.asDriver(onErrorJustReturn: -3))) + + hotObservable2.on(.next(10)) + hotObservable2.on(.next(11)) + hotObservable2.on(.error(testError)) + + hotObservable.on(.error(testError)) + + hotObservable1.on(.completed) + hotObservable.on(.completed) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [ + 1, 2, -2, + 10, 11, -3, + -1 + ]) + } +} + +// MARK: flatMapLatest +extension SharedSequenceOperatorTests { + func testAsDriver_flatMapLatest() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let hotObservable1 = MainThreadPrimitiveHotObservable() + let hotObservable2 = MainThreadPrimitiveHotObservable() + let errorHotObservable = MainThreadPrimitiveHotObservable() + + let drivers: [Driver] = [ + hotObservable1.asDriver(onErrorJustReturn: -2), + hotObservable2.asDriver(onErrorJustReturn: -3), + errorHotObservable.asDriver(onErrorJustReturn: -4), + ] + + let driver = hotObservable.asDriver(onErrorJustReturn: 2).flatMapLatest { drivers[$0] } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(0)) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + hotObservable1.on(.error(testError)) + + hotObservable.on(.next(1)) + + hotObservable2.on(.next(10)) + hotObservable2.on(.next(11)) + hotObservable2.on(.error(testError)) + + hotObservable.on(.error(testError)) + + errorHotObservable.on(.completed) + hotObservable.on(.completed) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [ + 1, 2, -2, + 10, 11, -3 + ]) + } +} + +// MARK: flatMapFirst +extension SharedSequenceOperatorTests { + func testAsDriver_flatMapFirst() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let hotObservable1 = MainThreadPrimitiveHotObservable() + let hotObservable2 = MainThreadPrimitiveHotObservable() + let errorHotObservable = MainThreadPrimitiveHotObservable() + + let drivers: [Driver] = [ + hotObservable1.asDriver(onErrorJustReturn: -2), + hotObservable2.asDriver(onErrorJustReturn: -3), + errorHotObservable.asDriver(onErrorJustReturn: -4), + ] + + let driver = hotObservable.asDriver(onErrorJustReturn: 2).flatMapFirst { drivers[$0] } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(0)) + hotObservable.on(.next(1)) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + hotObservable1.on(.error(testError)) + + hotObservable2.on(.next(10)) + hotObservable2.on(.next(11)) + hotObservable2.on(.error(testError)) + + hotObservable.on(.error(testError)) + + errorHotObservable.on(.completed) + hotObservable.on(.completed) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [ + 1, 2, -2, + ]) + } +} + +// MARK: doOn +extension SharedSequenceOperatorTests { + func testAsDriver_doOn() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + var events = [Event]() + + var calledSubscribe = false + var calledSubscribed = false + var calledDispose = false + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onNext: { e in + XCTAssertTrue(DispatchQueue.isMain) + + events.append(.next(e)) + }, onCompleted: { + XCTAssertTrue(DispatchQueue.isMain) + events.append(.completed) + }, onSubscribe: { + XCTAssertTrue(!DispatchQueue.isMain) + calledSubscribe = true + }, onSubscribed: { + XCTAssertTrue(!DispatchQueue.isMain) + calledSubscribed = true + }, onDispose: { + XCTAssertTrue(DispatchQueue.isMain) + calledDispose = true + }) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + let expectedEvents = [.next(1), .next(2), .next(-1), .completed] as [Event] + XCTAssertEqual(events, expectedEvents) + XCTAssertEqual(calledSubscribe, true) + XCTAssertEqual(calledSubscribed, true) + XCTAssertEqual(calledDispose, true) + } + + + func testAsDriver_doOnNext() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + var events = [Int]() + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onNext: { e in + XCTAssertTrue(DispatchQueue.isMain) + events.append(e) + }) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + let expectedEvents = [1, 2, -1] + XCTAssertEqual(events, expectedEvents) + } + + func testAsDriver_doOnCompleted() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + var completed = false + let driver = hotObservable.asDriver(onErrorJustReturn: -1).do(onCompleted: { + XCTAssertTrue(DispatchQueue.isMain) + completed = true + }) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + XCTAssertEqual(completed, true) + } +} + +// MARK: distinct until change +extension SharedSequenceOperatorTests { + func testAsDriver_distinctUntilChanged1() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged() + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + + func testAsDriver_distinctUntilChanged2() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 }) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + + func testAsDriver_distinctUntilChanged3() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 == $1 }) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + + + func testAsDriver_distinctUntilChanged4() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable.asDriver(onErrorJustReturn: -1).distinctUntilChanged({ $0 }) { $0 == $1 } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + +} + +// MARK: flat map +extension SharedSequenceOperatorTests { + func testAsDriver_flatMap() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).flatMap { (n: Int) -> Driver in + XCTAssertTrue(DispatchQueue.isMain) + return Driver.just(n + 1) + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2, 3, 0]) + } + +} + +// MARK: merge + +extension SharedSequenceOperatorTests { + func testAsDriver_mergeSync() { + let factories: [(Driver) -> Driver] = + [ + { source in Driver.merge(source) }, + { source in Driver.merge([source]) }, + { source in Driver.merge(AnyCollection([source])) }, + ] + + for factory in factories { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = factory(hotObservable.asDriver(onErrorJustReturn: -1)) + + let results = self.subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + } +} + +// MARK: merge +extension SharedSequenceOperatorTests { + func testAsDriver_merge() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Driver in + XCTAssertTrue(DispatchQueue.isMain) + return Driver.just(n + 1) + }.merge() + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2, 3, 0]) + } + + func testAsDriver_merge2() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).map { (n: Int) -> Driver in + XCTAssertTrue(DispatchQueue.isMain) + return Driver.just(n + 1) + }.merge(maxConcurrent: 1) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2, 3, 0]) + } +} + +// MARK: debug +extension SharedSequenceOperatorTests { + func testAsDriver_debug() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).debug("a", trimOutput: false) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, -1]) + } +} + +// MARK: debounce +extension SharedSequenceOperatorTests { + func testAsDriver_debounce() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).debounce(0.0) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [-1]) + } + + func testAsDriver_throttle() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).throttle(0.5) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, -1]) + } + + func testAsDriver_throttle2() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).throttle(0.5, latest: false) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1]) + } + +} + +// MARK: scan +extension SharedSequenceOperatorTests { + func testAsDriver_scan() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let driver = hotObservable.asDriver(onErrorJustReturn: -1).scan(0) { (a: Int, n: Int) -> Int in + XCTAssertTrue(DispatchQueue.isMain) + return a + n + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 3, 2]) + } + +} + +// MARK: concat +extension SharedSequenceOperatorTests { + func testAsDriver_concat_sequenceType() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = MainThreadPrimitiveHotObservable() + + let driver = Driver.concat(AnySequence([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)])) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + hotObservable1.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable2.on(.next(4)) + hotObservable2.on(.next(5)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1, 4, 5, -2]) + } + + func testAsDriver_concat() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = MainThreadPrimitiveHotObservable() + + let driver = Driver.concat([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + hotObservable1.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable2.on(.next(4)) + hotObservable2.on(.next(5)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1, 4, 5, -2]) + } +} + +// MARK: combine latest +extension SharedSequenceOperatorTests { + func testAsDriver_combineLatest_array() { + let factories: [([Driver]) -> Driver] = + [ + { e0 in + Driver.combineLatest(e0) { a in a.reduce(0, +) } + }, + { e0 in + Driver.combineLatest(e0).map { a in a.reduce(0, +) } + }, + ] + + for factory in factories { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = factory([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [5, 6, 7, 4, -3]) + } + } + + func testAsDriver_combineLatest() { + let factories: [(Driver, Driver) -> Driver] = + [ + { e0, e1 in + Driver.combineLatest(e0, e1, resultSelector: +) + }, + { e0, e1 in + Driver.combineLatest(e0, e1).map(+) + }, + ] + for factory in factories { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = factory(hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [5, 6, 7, 4, -3]) + } + } +} + +// MARK: zip +extension SharedSequenceOperatorTests { + func testAsDriver_zip_array() { + let factories: [([Driver]) -> Driver] = + [ + { e0 in + Driver.zip(e0) { a in a.reduce(0, +) } + }, + { e0 in + Driver.zip(e0).map { a in a.reduce(0, +) } + }, + ] + + for factory in factories { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = factory([hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)]) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [5, 7, -3]) + } + } + + func testAsDriver_zip() { + let factories: [(Driver, Driver) -> Driver] = + [ + { e0, e1 in + Driver.zip(e0, e1, resultSelector: +) + }, + { e0, e1 in + Driver.zip(e0, e1).map(+) + }, + ] + for factory in factories { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = factory(hotObservable1.asDriver(onErrorJustReturn: -1), hotObservable2.asDriver(onErrorJustReturn: -2)) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [5, 7, -3]) + } + } +} + +// MARK: withLatestFrom +extension SharedSequenceOperatorTests { + func testAsDriver_withLatestFrom() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable1.asDriver(onErrorJustReturn: -1).withLatestFrom(hotObservable2.asDriver(onErrorJustReturn: -2)) { f, s in "\(f)\(s)" } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, ["24", "-15"]) + } + + func testAsDriver_withLatestFromDefaultOverload() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + let hotObservable2 = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable1.asDriver(onErrorJustReturn: -1).withLatestFrom(hotObservable2.asDriver(onErrorJustReturn: -2)) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable2.on(.next(4)) + + hotObservable1.on(.next(2)) + hotObservable2.on(.next(5)) + + hotObservable1.on(.error(testError)) + hotObservable2.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + XCTAssertTrue(hotObservable2.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [4, 5]) + + } +} + +// MARK: skip +extension SharedSequenceOperatorTests { + func testAsDriver_skip() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable1.asDriver(onErrorJustReturn: -1).skip(1) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + + hotObservable1.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [2, -1]) + } +} + +// MARK: startWith +extension SharedSequenceOperatorTests { + func testAsDriver_startWith() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable1.asDriver(onErrorJustReturn: -1).startWith(0) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + + hotObservable1.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [0, 1, 2, -1]) + } +} + +// MARK: delay +extension SharedSequenceOperatorTests { + func testAsDriver_delay() { + let hotObservable1 = BackgroundThreadPrimitiveHotObservable() + + let driver = hotObservable1.asDriver(onErrorJustReturn: -1).delay(0.1) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) { + XCTAssertTrue(hotObservable1.subscriptions == [SubscribedToHotObservable]) + + hotObservable1.on(.next(1)) + hotObservable1.on(.next(2)) + + hotObservable1.on(.error(testError)) + + XCTAssertTrue(hotObservable1.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } +} + +//MARK: interval +extension SharedSequenceOperatorTests { + func testAsDriver_interval() { + let testScheduler = TestScheduler(initialClock: 0) + + let firstObserver = testScheduler.createObserver(Int.self) + let secondObserver = testScheduler.createObserver(Int.self) + + var disposable1: Disposable! + var disposable2: Disposable! + + SharingScheduler.mock(scheduler: testScheduler) { + let interval = Driver.interval(100) + + testScheduler.scheduleAt(20) { + disposable1 = interval.asObservable().subscribe(firstObserver) + } + + testScheduler.scheduleAt(170) { + disposable2 = interval.asObservable().subscribe(secondObserver) + } + + testScheduler.scheduleAt(230) { + disposable1.dispose() + disposable2.dispose() + } + + testScheduler.start() + } + + XCTAssertEqual(firstObserver.events, [ + next(120, 0), + next(220, 1) + ]) + XCTAssertEqual(secondObserver.events, [ + next(170, 0), + next(220, 1) + ]) + } +} + +//MARK: timer +extension SharedSequenceOperatorTests { + func testAsDriver_timer() { + let testScheduler = TestScheduler(initialClock: 0) + + let firstObserver = testScheduler.createObserver(Int.self) + let secondObserver = testScheduler.createObserver(Int.self) + + var disposable1: Disposable! + var disposable2: Disposable! + + SharingScheduler.mock(scheduler: testScheduler) { + let interval = Driver.timer(100, period: 105) + + testScheduler.scheduleAt(20) { + disposable1 = interval.asObservable().subscribe(firstObserver) + } + + testScheduler.scheduleAt(170) { + disposable2 = interval.asObservable().subscribe(secondObserver) + } + + testScheduler.scheduleAt(230) { + disposable1.dispose() + disposable2.dispose() + } + + testScheduler.start() + } + + XCTAssertEqual(firstObserver.events, [ + next(120, 0), + next(225, 1) + ]) + XCTAssertEqual(secondObserver.events, [ + next(170, 0), + next(225, 1) + ]) + } +} + +// MARK: from optional + +extension SharedSequenceOperatorTests { + func testDriverFromOptional() { + let scheduler = TestScheduler(initialClock: 0) + + SharingScheduler.mock(scheduler: scheduler) { + let res = scheduler.start { Driver.from(optional: 1 as Int?).asObservable() } + XCTAssertEqual(res.events, [ + next(201, 1), + completed(202) + ]) + } + } + + func testDriverFromOptionalWhenNil() { + let scheduler = TestScheduler(initialClock: 0) + + SharingScheduler.mock(scheduler: scheduler) { + let res = scheduler.start { Driver.from(optional: nil as Int?).asObservable() } + XCTAssertEqual(res.events, [ + completed(201) + ]) + } + } +} + + +// MARK: from sequence + +extension SharedSequenceOperatorTests { + func testDriverFromSequence() { + let scheduler = TestScheduler(initialClock: 0) + + SharingScheduler.mock(scheduler: scheduler) { + let res = scheduler.start { Driver.from(AnySequence([10])).asObservable() } + XCTAssertEqual(res.events, [ + next(201, 10), + completed(202) + ]) + } + } + + func testDriverFromArray() { + let scheduler = TestScheduler(initialClock: 0) + + SharingScheduler.mock(scheduler: scheduler) { + let res = scheduler.start { Driver.from([20]).asObservable() } + XCTAssertEqual(res.events, [ + next(201, 20), + completed(202) + ]) + } + } +} diff --git a/Tests/RxCocoaTests/SharedSequence+Test.swift b/Tests/RxCocoaTests/SharedSequence+Test.swift new file mode 100644 index 00000000..7d337b9a --- /dev/null +++ b/Tests/RxCocoaTests/SharedSequence+Test.swift @@ -0,0 +1,111 @@ +// +// SharedSequence+Test.swift +// Tests +// +// Created by Krunoslav Zaher on 8/27/17. +// Copyright © 2017 Krunoslav Zaher. All rights reserved. +// + +import Dispatch +import RxSwift +import RxCocoa +import XCTest +import RxTest + +class SharedSequenceTest : RxTest { + var backgroundScheduler = SerialDispatchQueueScheduler(qos: .default) + + override func tearDown() { + super.tearDown() + } +} + +// test helpers that make sure that resulting driver operator honors definition +// * only one subscription is made and shared - shareReplay(1) +// * subscription is made on main thread - subscribeOn(ConcurrentMainScheduler.instance) +// * events are observed on main thread - observeOn(MainScheduler.instance) +// * it can't error out - it needs to have catch somewhere +extension SharedSequenceTest { + + func subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(_ xs: SharedSequence, expectationFulfilled: @escaping (R) -> Bool = { _ in false }, subscribedOnBackground: () -> ()) -> [R] { + var firstElements = [R]() + var secondElements = [R]() + + let subscribeFinished = self.expectation(description: "subscribeFinished") + + var expectation1: XCTestExpectation! + var expectation2: XCTestExpectation! + + _ = backgroundScheduler.schedule(()) { _ in + var subscribing1 = true + let firstSubscriptionFuture = SingleAssignmentDisposable() + let firstSubscription = xs.asObservable().subscribe { e in + if !subscribing1 { + XCTAssertTrue(DispatchQueue.isMain) + } + switch e { + case .next(let element): + firstElements.append(element) + if expectationFulfilled(element) { + expectation1.fulfill() + firstSubscriptionFuture.dispose() + } + case .error(let error): + XCTFail("Error passed \(error)") + case .completed: + expectation1.fulfill() + } + } + firstSubscriptionFuture.setDisposable(firstSubscription) + subscribing1 = false + + var subscribing = true + let secondSubscriptionFuture = SingleAssignmentDisposable() + let secondSubscription = xs.asObservable().subscribe { e in + if !subscribing { + XCTAssertTrue(DispatchQueue.isMain) + } + switch e { + case .next(let element): + secondElements.append(element) + if expectationFulfilled(element) { + expectation2.fulfill() + secondSubscriptionFuture.dispose() + } + case .error(let error): + XCTFail("Error passed \(error)") + case .completed: + expectation2.fulfill() + } + } + secondSubscriptionFuture.setDisposable(secondSubscription) + + subscribing = false + + // Subscription should be made on main scheduler + // so this will make sure execution is continued after + // subscription because of serial nature of main scheduler. + _ = MainScheduler.instance.schedule(()) { _ in + subscribeFinished.fulfill() + return Disposables.create() + } + + return Disposables.create() + } + + waitForExpectations(timeout: 1.0) { error in + XCTAssertTrue(error == nil) + } + + expectation1 = self.expectation(description: "finished1") + expectation2 = self.expectation(description: "finished2") + + subscribedOnBackground() + + waitForExpectations(timeout: 1.0) { error in + XCTAssertTrue(error == nil) + } + + return firstElements + } +} diff --git a/Tests/RxCocoaTests/Signal+Test.swift b/Tests/RxCocoaTests/Signal+Test.swift new file mode 100644 index 00000000..2ab229e3 --- /dev/null +++ b/Tests/RxCocoaTests/Signal+Test.swift @@ -0,0 +1,326 @@ +// +// Signal+Test.swift +// Tests +// +// Created by Krunoslav Zaher on 2/26/17. +// Copyright © 2017 Krunoslav Zaher. All rights reserved. +// + +import Dispatch +import RxSwift +import RxCocoa +import XCTest +import RxTest + +class SignalTests: SharedSequenceTest { } + +extension SignalTests { + func testSignalSharing_WhenErroring() { + let scheduler = TestScheduler(initialClock: 0) + + let observer1 = scheduler.createObserver(Int.self) + let observer2 = scheduler.createObserver(Int.self) + let observer3 = scheduler.createObserver(Int.self) + var disposable1: Disposable! + var disposable2: Disposable! + var disposable3: Disposable! + + let coldObservable = scheduler.createColdObservable([ + next(10, 0), + next(20, 1), + next(30, 2), + next(40, 3), + error(50, testError) + ]) + let signal = coldObservable.asSignal(onErrorJustReturn: -1) + + scheduler.scheduleAt(200) { + disposable1 = signal.asObservable().subscribe(observer1) + } + + scheduler.scheduleAt(225) { + disposable2 = signal.asObservable().subscribe(observer2) + } + + scheduler.scheduleAt(235) { + disposable1.dispose() + } + + scheduler.scheduleAt(260) { + disposable2.dispose() + } + + // resubscription + + scheduler.scheduleAt(260) { + disposable3 = signal.asObservable().subscribe(observer3) + } + + scheduler.scheduleAt(285) { + disposable3.dispose() + } + + scheduler.start() + + XCTAssertEqual(observer1.events, [ + next(210, 0), + next(220, 1), + next(230, 2) + ]) + + XCTAssertEqual(observer2.events, [ + next(230, 2), + next(240, 3), + next(250, -1), + completed(250) + ]) + + XCTAssertEqual(observer3.events, [ + next(270, 0), + next(280, 1), + ]) + + XCTAssertEqual(coldObservable.subscriptions, [ + Subscription(200, 250), + Subscription(260, 285), + ]) + } + + func testSignalSharing_WhenCompleted() { + let scheduler = TestScheduler(initialClock: 0) + + let observer1 = scheduler.createObserver(Int.self) + let observer2 = scheduler.createObserver(Int.self) + let observer3 = scheduler.createObserver(Int.self) + var disposable1: Disposable! + var disposable2: Disposable! + var disposable3: Disposable! + + let coldObservable = scheduler.createColdObservable([ + next(10, 0), + next(20, 1), + next(30, 2), + next(40, 3), + completed(50) + ]) + let signal = coldObservable.asSignal(onErrorJustReturn: -1) + + + scheduler.scheduleAt(200) { + disposable1 = signal.asObservable().subscribe(observer1) + } + + scheduler.scheduleAt(225) { + disposable2 = signal.asObservable().subscribe(observer2) + } + + scheduler.scheduleAt(235) { + disposable1.dispose() + } + + scheduler.scheduleAt(260) { + disposable2.dispose() + } + + // resubscription + + scheduler.scheduleAt(260) { + disposable3 = signal.asObservable().subscribe(observer3) + } + + scheduler.scheduleAt(285) { + disposable3.dispose() + } + + scheduler.start() + + XCTAssertEqual(observer1.events, [ + next(210, 0), + next(220, 1), + next(230, 2) + ]) + + XCTAssertEqual(observer2.events, [ + next(230, 2), + next(240, 3), + completed(250) + ]) + + XCTAssertEqual(observer3.events, [ + next(270, 0), + next(280, 1), + ]) + + XCTAssertEqual(coldObservable.subscriptions, [ + Subscription(200, 250), + Subscription(260, 285), + ]) + } +} + +// MARK: conversions +extension SignalTests { + func testPublishRelayAsSignal() { + let hotObservable: PublishRelay = PublishRelay() + let xs = Signal.zip(hotObservable.asSignal(), Signal.of(0, 0)) { x, _ in + return x + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs, expectationFulfilled: { $0 == 2 }) { + hotObservable.accept(1) + hotObservable.accept(2) + } + + XCTAssertEqual(results, [1, 2]) + } + + func testAsSignal_onErrorJustReturn() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let xs = hotObservable.asSignal(onErrorJustReturn: -1) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + + func testAsSignal_onErrorDriveWith() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let xs = hotObservable.asSignal(onErrorSignalWith: Signal.just(-1)) + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2, -1]) + } + + func testAsSignal_onErrorRecover() { + let hotObservable = BackgroundThreadPrimitiveHotObservable() + let xs = hotObservable.asSignal { e in + return Signal.empty() + } + + let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(xs) { + XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable]) + + hotObservable.on(.next(1)) + hotObservable.on(.next(2)) + hotObservable.on(.error(testError)) + + XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable]) + } + + XCTAssertEqual(results, [1, 2]) + } +} + +// MARK: emit observer +extension SignalTests { + func testEmitObserver() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + _ = Signal.just(1).emit(to: observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } + + func testEmitOptionalObserver() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + _ = (Signal.just(1) as Signal).emit(to: observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } + + func testEmitNoAmbiguity() { + var events: [Recorded>] = [] + + let observer: AnyObserver = AnyObserver { event in + events.append(Recorded(time: 0, value: event)) + } + + // shouldn't cause compile time error + _ = Signal.just(1).emit(to: observer) + + XCTAssertEqual(events.first?.value.element.flatMap { $0 }, 1) + } +} + +// MARK: emit variable + +extension SignalTests { + func testSignalRelay() { + let relay = PublishRelay() + + var latest: Int? = nil + _ = relay.subscribe(onNext: { latestElement in + latest = latestElement + }) + + _ = (Signal.just(1) as Signal).emit(to: relay) + + XCTAssertEqual(latest, 1) + } + + func testSignalOptionalRelay1() { + let relay = PublishRelay() + + var latest: Int? = nil + _ = relay.subscribe(onNext: { latestElement in + latest = latestElement + }) + + _ = (Signal.just(1) as Signal).emit(to: relay) + + XCTAssertEqual(latest, 1) + } + + func testSignalOptionalRelay2() { + let relay = PublishRelay() + + var latest: Int? = nil + _ = relay.subscribe(onNext: { latestElement in + latest = latestElement + }) + + _ = (Signal.just(1) as Signal).emit(to: relay) + + XCTAssertEqual(latest, 1) + } + + func testDriveVariableNoAmbiguity() { + let relay = PublishRelay() + + var latest: Int? = nil + _ = relay.subscribe(onNext: { latestElement in + latest = latestElement + }) + + // shouldn't cause compile time error + _ = Signal.just(1).emit(to: relay) + + XCTAssertEqual(latest, 1) + } +} diff --git a/Tests/RxSwiftTests/SharingSchedulerTests.swift b/Tests/RxSwiftTests/SharingSchedulerTests.swift new file mode 100644 index 00000000..041825fa --- /dev/null +++ b/Tests/RxSwiftTests/SharingSchedulerTests.swift @@ -0,0 +1,84 @@ +// +// SharingSchedulerTests.swift +// Tests +// +// Created by Krunoslav Zaher on 8/27/17. +// Copyright © 2017 Krunoslav Zaher. All rights reserved. +// + +import RxSwift +import RxCocoa +import XCTest +#if os(Linux) + import Glibc +#endif + +import struct Foundation.Date + +class SharingSchedulerTest : RxTest { + +} + +extension SharingSchedulerTest { + func testSharingSchedulerMockMake() { + XCTAssertTrue(SharingScheduler.make() is MainScheduler) + + SharingScheduler.mock(makeScheduler: { Scheduler1() }) { + XCTAssertTrue(SharingScheduler.make() is Scheduler1) + SharingScheduler.mock(makeScheduler: { Scheduler2() }) { + XCTAssertTrue(SharingScheduler.make() is Scheduler2) + } + XCTAssertTrue(SharingScheduler.make() is Scheduler1) + } + } + + func testSharingSchedulerMockInstance() { + XCTAssertTrue(SharingScheduler.make() is MainScheduler) + + let scheduler1 = Scheduler1() + SharingScheduler.mock(scheduler: scheduler1) { + XCTAssertTrue(SharingScheduler.make() is Scheduler1 && SharingScheduler.make() as! Scheduler1 === scheduler1) + let scheduler2 = Scheduler2() + SharingScheduler.mock(scheduler: scheduler2) { + XCTAssertTrue(SharingScheduler.make() is Scheduler2 && SharingScheduler.make() as! Scheduler2 === scheduler2) + } + XCTAssertTrue(SharingScheduler.make() is Scheduler1) + } + } +} + +class Scheduler1: SchedulerType { + var now : RxTime { + fatalError() + } + + func schedule(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable { + fatalError() + } + + func scheduleRelative(_ state: StateType, dueTime: RxTimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable { + fatalError() + } + + func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable { + fatalError() + } +} + +class Scheduler2: SchedulerType { + var now : RxTime { + fatalError() + } + + func schedule(_ state: StateType, action: @escaping (StateType) -> Disposable) -> Disposable { + fatalError() + } + + func scheduleRelative(_ state: StateType, dueTime: RxTimeInterval, action: @escaping (StateType) -> Disposable) -> Disposable { + fatalError() + } + + func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable { + fatalError() + } +} diff --git a/scripts/package-spm.swift b/scripts/package-spm.swift index 760698fb..521a0364 100755 --- a/scripts/package-spm.swift +++ b/scripts/package-spm.swift @@ -307,7 +307,10 @@ try packageRelativePath([ "Tests/XCTest+AllTests.swift", "Platform", "Tests/RxCocoaTests/Driver+Test.swift", - "Tests/RxCocoaTests/Driver+Extensions.swift", + "Tests/RxCocoaTests/Signal+Test.swift", + "Tests/RxCocoaTests/SharedSequence+Extensions.swift", + "Tests/RxCocoaTests/SharedSequence+Test.swift", + "Tests/RxCocoaTests/SharedSequence+OperatorTest.swift", "Tests/RxCocoaTests/NotificationCenterTests.swift", ], targetDirName: "AllTestz",