diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index e4b3869a..97f9e98b 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -394,6 +394,10 @@ C8B145011BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; C8B145021BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; C8B145031BD2D80100267DCE /* ImmediateScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */; }; + C8BCD3C71C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; + C8BCD3C81C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; + C8BCD3C91C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; + C8BCD3CA1C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */; }; C8C3D9FE1B935EDF004D233E /* Zip+CollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */; }; C8C3D9FF1B935EDF004D233E /* Zip+CollectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */; }; C8C3DA031B9390C4004D233E /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3DA021B9390C4004D233E /* Just.swift */; }; @@ -1081,6 +1085,7 @@ C8A56AD71AD7424700B4673B /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C8B144FA1BD2D44500267DCE /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentMainScheduler.swift; sourceTree = ""; }; C8B144FF1BD2D80100267DCE /* ImmediateScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImmediateScheduler.swift; sourceTree = ""; }; + C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareReplay1WhileConnected.swift; sourceTree = ""; }; C8C3D9FD1B935EDF004D233E /* Zip+CollectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Zip+CollectionType.swift"; sourceTree = ""; }; C8C3DA021B9390C4004D233E /* Just.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Just.swift; sourceTree = ""; }; C8C3DA051B9393AC004D233E /* Empty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Empty.swift; sourceTree = ""; }; @@ -1341,6 +1346,7 @@ C8093C871B8A72BE0088E94D /* Scan.swift */, C83100631BF7D51600AAE3CD /* Sequence.swift */, C89CDB351BCB0DD7002063D9 /* ShareReplay1.swift */, + C8BCD3C61C1468D4005F1280 /* ShareReplay1WhileConnected.swift */, CB30D9E81BF0E3500084C1C0 /* SingleAsync.swift */, C8093C881B8A72BE0088E94D /* Sink.swift */, C8093C891B8A72BE0088E94D /* Skip.swift */, @@ -2294,6 +2300,7 @@ C8093D4A1B8A72BE0088E94D /* Throttle.swift in Sources */, C8B145011BD2D80100267DCE /* ImmediateScheduler.swift in Sources */, C8093D061B8A72BE0088E94D /* Catch.swift in Sources */, + C8BCD3C81C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */, C8F6A0FA1BEE33C1007DF367 /* InvocableScheduledItem.swift in Sources */, C8093D0C1B8A72BE0088E94D /* CombineLatest.swift in Sources */, D2FC15B31BCB95E5007361FF /* SkipWhile.swift in Sources */, @@ -2433,6 +2440,7 @@ C8093D491B8A72BE0088E94D /* Throttle.swift in Sources */, C8B145001BD2D80100267DCE /* ImmediateScheduler.swift in Sources */, C8093D051B8A72BE0088E94D /* Catch.swift in Sources */, + C8BCD3C71C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */, C8F6A0F91BEE33C1007DF367 /* InvocableScheduledItem.swift in Sources */, C8093D0B1B8A72BE0088E94D /* CombineLatest.swift in Sources */, D22B6D261BC8504A00BCE0AB /* SkipWhile.swift in Sources */, @@ -2572,6 +2580,7 @@ C8F0BFAA1BBBFB8B001B112F /* Throttle.swift in Sources */, C8B145031BD2D80100267DCE /* ImmediateScheduler.swift in Sources */, C8F0BFAC1BBBFB8B001B112F /* Catch.swift in Sources */, + C8BCD3CA1C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */, C8F6A0FC1BEE33C1007DF367 /* InvocableScheduledItem.swift in Sources */, C8F0BFAD1BBBFB8B001B112F /* CombineLatest.swift in Sources */, D2FC15B51BCB95E8007361FF /* SkipWhile.swift in Sources */, @@ -2874,6 +2883,7 @@ D2EBEB2D1BB9B6CA003A27DC /* Observable+Concurrency.swift in Sources */, D2EBEB381BB9B6D8003A27DC /* ConcurrentDispatchQueueScheduler.swift in Sources */, C8B145021BD2D80100267DCE /* ImmediateScheduler.swift in Sources */, + C8BCD3C91C1468D4005F1280 /* ShareReplay1WhileConnected.swift in Sources */, C8F6A0FB1BEE33C1007DF367 /* InvocableScheduledItem.swift in Sources */, D2EBEB131BB9B6C1003A27DC /* Multicast.swift in Sources */, D2EBEB111BB9B6C1003A27DC /* Map.swift in Sources */, diff --git a/RxTests/RxSwiftTests/TestImplementations/Recorded.swift b/RxTests/RxSwiftTests/TestImplementations/Recorded.swift index a3d9a74b..89ef8aaa 100644 --- a/RxTests/RxSwiftTests/TestImplementations/Recorded.swift +++ b/RxTests/RxSwiftTests/TestImplementations/Recorded.swift @@ -43,6 +43,4 @@ extension Recorded { func == (lhs: Recorded, rhs: Recorded) -> Bool { return lhs.time == rhs.time && lhs.event == rhs.event -} - - +} \ No newline at end of file diff --git a/RxTests/RxSwiftTests/TestImplementations/Schedulers/TestScheduler.swift b/RxTests/RxSwiftTests/TestImplementations/Schedulers/TestScheduler.swift index 86b56302..463a954f 100644 --- a/RxTests/RxSwiftTests/TestImplementations/Schedulers/TestScheduler.swift +++ b/RxTests/RxSwiftTests/TestImplementations/Schedulers/TestScheduler.swift @@ -9,18 +9,6 @@ import Foundation import RxSwift -func createHotObservable(scheduler: TestScheduler, events: [Recorded]) -> HotObservable { - return HotObservable(testScheduler: scheduler, recordedEvents: events) -} - -func createColdObservable(scheduler: TestScheduler, events: [Recorded]) -> ColdObservable { - return ColdObservable(testScheduler: scheduler, recordedEvents: events) -} - -func createObserver(scheduler: TestScheduler) -> MockObserver { - return MockObserver(scheduler: scheduler) -} - class TestScheduler : VirtualTimeSchedulerBase { override init(initialClock: Time) { @@ -34,8 +22,8 @@ class TestScheduler : VirtualTimeSchedulerBase { func createColdObservable(events: [Recorded]) -> ColdObservable { return ColdObservable(testScheduler: self as AnyObject as! TestScheduler, recordedEvents: events) } - - func createObserver() -> MockObserver { + + func createObserver(type: E.Type) -> MockObserver { return MockObserver(scheduler: self as AnyObject as! TestScheduler) } @@ -49,7 +37,7 @@ class TestScheduler : VirtualTimeSchedulerBase { func start(created: Time, subscribed: Time, disposed: Time, create: () -> Observable) -> MockObserver { var source : Observable? = nil var subscription : Disposable? = nil - let observer: MockObserver = createObserver() + let observer: MockObserver = createObserver(Element) let state : Void = () diff --git a/RxTests/RxSwiftTests/Tests/BehaviorSubjectTest.swift b/RxTests/RxSwiftTests/Tests/BehaviorSubjectTest.swift index e9b6020e..630b20d0 100644 --- a/RxTests/RxSwiftTests/Tests/BehaviorSubjectTest.swift +++ b/RxTests/RxSwiftTests/Tests/BehaviorSubjectTest.swift @@ -33,13 +33,13 @@ class BehaviorSubjectTest : RxTest { var subject: BehaviorSubject! = nil var subscription: Disposable! = nil - let results1: MockObserver = scheduler.createObserver() + let results1 = scheduler.createObserver(Int) var subscription1: Disposable! = nil - let results2: MockObserver = scheduler.createObserver() + let results2 = scheduler.createObserver(Int) var subscription2: Disposable! = nil - let results3: MockObserver = scheduler.createObserver() + let results3 = scheduler.createObserver(Int) var subscription3: Disposable! = nil scheduler.scheduleAt(100) { subject = BehaviorSubject(value: 100) } @@ -97,13 +97,13 @@ class BehaviorSubjectTest : RxTest { var subject: BehaviorSubject! = nil var subscription: Disposable! = nil - let results1: MockObserver = scheduler.createObserver() + let results1 = scheduler.createObserver(Int) var subscription1: Disposable! = nil - let results2: MockObserver = scheduler.createObserver() + let results2 = scheduler.createObserver(Int) var subscription2: Disposable! = nil - let results3: MockObserver = scheduler.createObserver() + let results3 = scheduler.createObserver(Int) var subscription3: Disposable! = nil scheduler.scheduleAt(100) { subject = BehaviorSubject(value: 100) } @@ -160,13 +160,13 @@ class BehaviorSubjectTest : RxTest { var subject: BehaviorSubject! = nil var subscription: Disposable! = nil - let results1: MockObserver = scheduler.createObserver() + let results1 = scheduler.createObserver(Int) var subscription1: Disposable! = nil - let results2: MockObserver = scheduler.createObserver() + let results2 = scheduler.createObserver(Int) var subscription2: Disposable! = nil - let results3: MockObserver = scheduler.createObserver() + let results3 = scheduler.createObserver(Int) var subscription3: Disposable! = nil scheduler.scheduleAt(100) { subject = BehaviorSubject(value: 100) } @@ -216,13 +216,13 @@ class BehaviorSubjectTest : RxTest { var subject: BehaviorSubject! = nil var subscription: Disposable! = nil - let results1: MockObserver = scheduler.createObserver() + let results1 = scheduler.createObserver(Int) var subscription1: Disposable! = nil - let results2: MockObserver = scheduler.createObserver() + let results2 = scheduler.createObserver(Int) var subscription2: Disposable! = nil - let results3: MockObserver = scheduler.createObserver() + let results3 = scheduler.createObserver(Int) var subscription3: Disposable! = nil scheduler.scheduleAt(100) { subject = BehaviorSubject(value: 100) } diff --git a/RxTests/RxSwiftTests/Tests/Driver+Test.swift b/RxTests/RxSwiftTests/Tests/Driver+Test.swift index 3c5fe358..15c07db7 100644 --- a/RxTests/RxSwiftTests/Tests/Driver+Test.swift +++ b/RxTests/RxSwiftTests/Tests/Driver+Test.swift @@ -89,6 +89,154 @@ extension DriverTest { } } +// MARK: properties +extension DriverTest { + func testDriverSharing_WhenErroring() { + let scheduler = TestScheduler(initialClock: 0) + + let observer1 = scheduler.createObserver(Int) + let observer2 = scheduler.createObserver(Int) + let observer3 = scheduler.createObserver(Int) + 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 driver = coldObservable.asDriver(onErrorJustReturn: -1) + + scheduler.scheduleAt(200) { + disposable1 = driver.asObservable().subscribe(observer1) + } + + scheduler.scheduleAt(225) { + disposable2 = driver.asObservable().subscribe(observer2) + } + + scheduler.scheduleAt(235) { + disposable1.dispose() + } + + scheduler.scheduleAt(260) { + disposable2.dispose() + } + + // resubscription + + scheduler.scheduleAt(260) { + disposable3 = driver.asObservable().subscribe(observer3) + } + + scheduler.scheduleAt(285) { + disposable3.dispose() + } + + scheduler.start() + + XCTAssertEqual(observer1.messages, [ + next(210, 0), + next(220, 1), + next(230, 2) + ]) + + XCTAssertEqual(observer2.messages, [ + next(225, 1), + next(230, 2), + next(240, 3), + next(250, -1), + completed(250) + ]) + + XCTAssertEqual(observer3.messages, [ + next(270, 0), + next(280, 1), + ]) + + XCTAssertEqual(coldObservable.subscriptions, [ + Subscription(200, 250), + Subscription(260, 285), + ]) + } + + func testDriverSharing_WhenCompleted() { + let scheduler = TestScheduler(initialClock: 0) + + let observer1 = scheduler.createObserver(Int) + let observer2 = scheduler.createObserver(Int) + let observer3 = scheduler.createObserver(Int) + 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 driver = coldObservable.asDriver(onErrorJustReturn: -1) + + + scheduler.scheduleAt(200) { + disposable1 = driver.asObservable().subscribe(observer1) + } + + scheduler.scheduleAt(225) { + disposable2 = driver.asObservable().subscribe(observer2) + } + + scheduler.scheduleAt(235) { + disposable1.dispose() + } + + scheduler.scheduleAt(260) { + disposable2.dispose() + } + + // resubscription + + scheduler.scheduleAt(260) { + disposable3 = driver.asObservable().subscribe(observer3) + } + + scheduler.scheduleAt(285) { + disposable3.dispose() + } + + scheduler.start() + + XCTAssertEqual(observer1.messages, [ + next(210, 0), + next(220, 1), + next(230, 2) + ]) + + XCTAssertEqual(observer2.messages, [ + next(225, 1), + next(230, 2), + next(240, 3), + next(250, -1), + completed(250) + ]) + + XCTAssertEqual(observer3.messages, [ + next(270, 0), + next(280, 1), + ]) + + XCTAssertEqual(coldObservable.subscriptions, [ + Subscription(200, 250), + Subscription(260, 285), + ]) + } +} + // MARK: conversions extension DriverTest { func testAsDriver_onErrorJustReturn() { diff --git a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift index a7209a8b..609628c5 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+BindingTest.swift @@ -210,22 +210,22 @@ extension ObservableBindingTest { let res = xs.publish().refCount() var d1: Disposable! - let o1: MockObserver = scheduler.createObserver() + let o1 = scheduler.createObserver(Int) scheduler.scheduleAt(215) { d1 = res.subscribe(o1) } scheduler.scheduleAt(235) { d1.dispose() } var d2: Disposable! - let o2: MockObserver = scheduler.createObserver() + let o2 = scheduler.createObserver(Int) scheduler.scheduleAt(225) { d2 = res.subscribe(o2) } scheduler.scheduleAt(275) { d2.dispose() } var d3: Disposable! - let o3: MockObserver = scheduler.createObserver() + let o3 = scheduler.createObserver(Int) scheduler.scheduleAt(255) { d3 = res.subscribe(o3) } scheduler.scheduleAt(265) { d3.dispose() } var d4: Disposable! - let o4: MockObserver = scheduler.createObserver() + let o4 = scheduler.createObserver(Int) scheduler.scheduleAt(285) { d4 = res.subscribe(o4) } scheduler.scheduleAt(320) { d4.dispose() } @@ -285,7 +285,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(3) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -339,7 +339,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(3) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -391,7 +391,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(3) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -443,7 +443,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(3) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -496,7 +496,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(1) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -548,7 +548,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(1) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -598,7 +598,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(1) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -648,7 +648,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replay(1) } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -699,7 +699,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replayAll() } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -758,7 +758,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replayAll() } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -811,7 +811,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replayAll() } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -864,7 +864,7 @@ extension ObservableBindingTest { var ys: ConnectableObservable>! = nil var subscription: Disposable! = nil var connection: Disposable! = nil - let res: MockObserver = scheduler.createObserver() + let res = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = xs.replayAll() } scheduler.scheduleAt(450, action: { subscription = ys.subscribe(res) }) @@ -984,8 +984,8 @@ extension ObservableBindingTest { var subscription1: Disposable! = nil var subscription2: Disposable! = nil - let res1: MockObserver = scheduler.createObserver() - let res2: MockObserver = scheduler.createObserver() + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = transform(xs.asObservable()) } @@ -1053,8 +1053,8 @@ extension ObservableBindingTest { var subscription1: Disposable! = nil var subscription2: Disposable! = nil - let res1: MockObserver = scheduler.createObserver() - let res2: MockObserver = scheduler.createObserver() + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = transform(xs.asObservable()) } @@ -1119,8 +1119,8 @@ extension ObservableBindingTest { var subscription1: Disposable! = nil var subscription2: Disposable! = nil - let res1: MockObserver = scheduler.createObserver() - let res2: MockObserver = scheduler.createObserver() + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = transform(xs.asObservable()) } @@ -1179,8 +1179,8 @@ extension ObservableBindingTest { var subscription1: Disposable! = nil var subscription2: Disposable! = nil - let res1: MockObserver = scheduler.createObserver() - let res2: MockObserver = scheduler.createObserver() + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) scheduler.scheduleAt(Defaults.created) { ys = transform(xs.asObservable()) } @@ -1213,4 +1213,245 @@ extension ObservableBindingTest { XCTAssertTrue(xs.subscriptions.count == 1 || xs.subscriptions[1] == Subscription(440, 440)) } } +} + +// shareReplay(1) +extension ObservableBindingTest { + func testShareReplayLatestWhileConnected_DeadlockImmediatelly() { + var nEvents = 0 + + let observable = sequenceOf(0, 1, 2).shareReplayLatestWhileConnected() + _ = observable.subscribeNext { n in + nEvents++ + } + + XCTAssertEqual(nEvents, 3) + } + + func testShareReplayLatestWhileConnected_DeadlockEmpty() { + var nEvents = 0 + + let observable = empty(Int).shareReplayLatestWhileConnected() + _ = observable.subscribeCompleted { n in + nEvents++ + } + + XCTAssertEqual(nEvents, 1) + } + + func testShareReplayLatestWhileConnected_DeadlockError() { + var nEvents = 0 + + let observable = failWith(testError, Int.self).shareReplayLatestWhileConnected() + _ = observable.subscribeError { _ in + nEvents++ + } + + XCTAssertEqual(nEvents, 1) + } + + func testShareReplayLatestWhileConnected_DeadlockErrorAfterN() { + var nEvents = 0 + + let observable = [sequenceOf(0, 1, 2), failWith(testError)].concat().shareReplayLatestWhileConnected() + _ = observable.subscribeError { n in + nEvents++ + } + + XCTAssertEqual(nEvents, 1) + } + + func testShareReplayLatestWhileConnected_Basic() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(110, 7), + next(220, 3), + next(280, 4), + next(290, 1), + next(340, 8), + next(360, 5), + next(370, 6), + next(390, 7), + next(410, 13), + next(430, 2), + next(450, 9), + next(520, 11), + next(560, 20), + error(600, testError) + ]) + + var ys: Observable! = nil + + var subscription1: Disposable! = nil + var subscription2: Disposable! = nil + + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) + + scheduler.scheduleAt(Defaults.created) { ys = xs.shareReplayLatestWhileConnected() } + + scheduler.scheduleAt(335) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(400) { subscription1.dispose() } + + scheduler.scheduleAt(355) { subscription2 = ys.subscribe(res2) } + scheduler.scheduleAt(415) { subscription2.dispose() } + + scheduler.scheduleAt(440) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(455) { subscription1.dispose() } + + scheduler.start(); + + XCTAssertEqual(res1.messages, [ + // 1rt batch + next(340, 8), + next(360, 5), + next(370, 6), + next(390, 7), + + // 2nd batch + next(450, 9) + ]) + + XCTAssertEqual(res2.messages, [ + next(355, 8), + next(360, 5), + next(370, 6), + next(390, 7), + next(410, 13) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(335, 415), + Subscription(440, 455) + ]) + } + + func testShareReplayLatestWhileConnected_Error() { + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(110, 7), + next(220, 3), + next(280, 4), + next(290, 1), + next(340, 8), + next(360, 5), + error(365, testError), + next(370, 6), + next(390, 7), + next(410, 13), + next(430, 2), + next(450, 9), + next(520, 11), + next(560, 20), + ]) + + var ys: Observable! = nil + + var subscription1: Disposable! = nil + var subscription2: Disposable! = nil + + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) + + scheduler.scheduleAt(Defaults.created) { ys = xs.shareReplayLatestWhileConnected() } + + scheduler.scheduleAt(335) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(400) { subscription1.dispose() } + + scheduler.scheduleAt(355) { subscription2 = ys.subscribe(res2) } + scheduler.scheduleAt(415) { subscription2.dispose() } + + scheduler.scheduleAt(440) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(455) { subscription1.dispose() } + + scheduler.start(); + + XCTAssertEqual(res1.messages, [ + // 1rt batch + next(340, 8), + next(360, 5), + error(365, testError), + + // 2nd batch + next(450, 9), + ]) + + XCTAssertEqual(res2.messages, [ + next(355, 8), + next(360, 5), + error(365, testError), + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(335, 365), + Subscription(440, 455) + ]) + } + + func testShareReplayLatestWhileConnected_Completed() { + _testIdenticalBehaviorOfShareReplayOptimizedAndComposed { transform in + let scheduler = TestScheduler(initialClock: 0) + + let xs = scheduler.createHotObservable([ + next(110, 7), + next(220, 3), + next(280, 4), + next(290, 1), + next(340, 8), + next(360, 5), + completed(365), + next(370, 6), + next(390, 7), + next(410, 13), + next(430, 2), + next(450, 9), + next(520, 11), + next(560, 20), + ]) + + var ys: Observable! = nil + + var subscription1: Disposable! = nil + var subscription2: Disposable! = nil + + let res1 = scheduler.createObserver(Int) + let res2 = scheduler.createObserver(Int) + + scheduler.scheduleAt(Defaults.created) { ys = xs.shareReplayLatestWhileConnected() } + + scheduler.scheduleAt(335) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(400) { subscription1.dispose() } + + scheduler.scheduleAt(355) { subscription2 = ys.subscribe(res2) } + scheduler.scheduleAt(415) { subscription2.dispose() } + + scheduler.scheduleAt(440) { subscription1 = ys.subscribe(res1) } + scheduler.scheduleAt(455) { subscription1.dispose() } + + scheduler.start(); + + XCTAssertEqual(res1.messages, [ + // 1rt batch + next(340, 8), + next(360, 5), + completed(365), + + // 2nd batch + next(450, 9), + ]) + + XCTAssertEqual(res2.messages, [ + next(355, 8), + next(360, 5), + completed(365) + ]) + + XCTAssertEqual(xs.subscriptions, [ + Subscription(335, 365), + Subscription(440, 455) + ]) + } + } } \ No newline at end of file diff --git a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift index 31fd2ee6..7d773353 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift @@ -58,7 +58,7 @@ extension ObservableCreationTests { let d = SingleAssignmentDisposable() - let res = createObserver(scheduler) as MockObserver + let res = scheduler.createObserver(Int) scheduler.scheduleAt(100) { d.disposable = just(42, scheduler: scheduler).subscribe { e in