From 277b836eea0d5f55dd88292caed1362b2e101e9f Mon Sep 17 00:00:00 2001 From: mosamer Date: Wed, 22 Nov 2017 11:25:05 +0100 Subject: [PATCH 1/5] improve input tests Test that work factory is called with received inputs instead of testing that they are received on `inputs` subject --- Tests/ActionTests/ActionTests.swift | 55 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Tests/ActionTests/ActionTests.swift b/Tests/ActionTests/ActionTests.swift index ac251dfd..e5dd116e 100644 --- a/Tests/ActionTests/ActionTests.swift +++ b/Tests/ActionTests/ActionTests.swift @@ -16,19 +16,21 @@ class ActionTests: QuickSpec { } describe("completable action") { + var inputs: TestableObserver! var action: CompletableAction! beforeEach { - let work: Completable = Observable.empty().asCompletable() - action = CompletableAction {_ in work } + inputs = scheduler.createObserver(String.self) + action = CompletableAction { input -> Completable in + inputs.onNext(input) + return Observable.empty().asCompletable() + } scheduler.scheduleAt(10) { action.inputs.onNext("a") } scheduler.scheduleAt(20) { action.inputs.onNext("b") } } afterEach { action = nil } - it("inputs subject receives generated inputs") { - let inputs = scheduler.createObserver(String.self) - action.inputs.bind(to: inputs).disposed(by: disposeBag) + it("receives generated inputs") { scheduler.start() XCTAssertEqual(inputs.events, [ next(10, "a"), @@ -61,12 +63,14 @@ class ActionTests: QuickSpec { executionObservables = scheduler.createObserver(Observable.self) underlyingError = scheduler.createObserver(Error.self) } - - func bindAction(action: Action) { - action.inputs - .bind(to: inputs) - .disposed(by: disposeBag) - + + func buildAction(enabledIf: Observable = Observable.just(true), + factory: @escaping (String) -> Observable) -> Action { + let action = Action(enabledIf: enabledIf) { + inputs.onNext($0) + return factory($0) + } + action.elements .bind(to: elements) .disposed(by: disposeBag) @@ -92,17 +96,18 @@ class ActionTests: QuickSpec { .disposed(by: disposeBag) // Dummy subscription for multiple subcription tests - action.inputs.subscribe().disposed(by: disposeBag) action.elements.subscribe().disposed(by: disposeBag) action.errors.subscribe().disposed(by: disposeBag) action.isEnabled.subscribe().disposed(by: disposeBag) action.isExecuting.subscribe().disposed(by: disposeBag) action.executionObservables.subscribe().disposed(by: disposeBag) + + return action } describe("single element action") { sharedExamples("send elements to elements observable") { - it("inputs subject receives generated inputs") { + it("work factory receives inputs") { XCTAssertEqual(inputs.events, [ next(10, "a"), next(20, "b"), @@ -148,8 +153,7 @@ class ActionTests: QuickSpec { var action: Action! beforeEach { - action = Action { Observable.just($0) } - bindAction(action: action) + action = buildAction { Observable.just($0) } } context("trigger via inputs subject") { @@ -175,7 +179,7 @@ class ActionTests: QuickSpec { describe("multiple element action") { sharedExamples("send array elements to elements observable") { - it("inputs subject receives generated inputs") { + it("work factory receives inputs") { XCTAssertEqual(inputs.events, [ next(10, "a"), next(20, "b"), @@ -225,7 +229,7 @@ class ActionTests: QuickSpec { var action: Action! beforeEach { - action = Action { input in + action = buildAction { input in // "a" -> ["a", "b", "c"] let baseValue = UnicodeScalar(input)!.value let strings = (baseValue..<(baseValue + 3)) @@ -234,8 +238,6 @@ class ActionTests: QuickSpec { return Observable.from(strings) } - - bindAction(action: action) } context("trigger via inputs subject") { @@ -261,7 +263,7 @@ class ActionTests: QuickSpec { describe("error action") { sharedExamples("send errors to errors observable") { - it("inputs subject receives generated inputs") { + it("work factory receives inputs") { XCTAssertEqual(inputs.events, [ next(10, "a"), next(20, "b"), @@ -318,8 +320,7 @@ class ActionTests: QuickSpec { var action: Action! beforeEach { - action = Action { _ in Observable.error(TestError) } - bindAction(action: action) + action = buildAction { _ in Observable.error(TestError) } } context("trigger via inputs subject") { @@ -345,11 +346,8 @@ class ActionTests: QuickSpec { describe("disabled action") { sharedExamples("send notEnabled errors to errors observable") { - it("inputs subject receives generated inputs") { - XCTAssertEqual(inputs.events, [ - next(10, "a"), - next(20, "b"), - ]) + it("work factory receives nothing") { + XCTAssertEqual(inputs.events, []) } it("elements observable receives nothing") { @@ -387,8 +385,7 @@ class ActionTests: QuickSpec { var action: Action! beforeEach { - action = Action(enabledIf: Observable.just(false)) { Observable.just($0) } - bindAction(action: action) + action = buildAction(enabledIf: Observable.just(false)) { Observable.just($0) } } context("trigger via inputs subject") { From ee18fc00c7ffb553c2f38629f399576b459a465e Mon Sep 17 00:00:00 2001 From: mosamer Date: Wed, 22 Nov 2017 12:42:02 +0100 Subject: [PATCH 2/5] add test cases for input receiving terminating events --- Tests/ActionTests/ActionTests.swift | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Tests/ActionTests/ActionTests.swift b/Tests/ActionTests/ActionTests.swift index e5dd116e..26ff11dd 100644 --- a/Tests/ActionTests/ActionTests.swift +++ b/Tests/ActionTests/ActionTests.swift @@ -44,6 +44,72 @@ class ActionTests: QuickSpec { XCTAssertEqual(elements.events.count, 0) } } + + describe("Input subject behavior") { + var action: Action! + var inputs: TestableObserver! + var executions: TestableObserver>! + beforeEach { + inputs = scheduler.createObserver(String.self) + action = Action { + inputs.onNext($0) + return Observable.just($0) + } + executions = scheduler.createObserver(Observable.self) + action.executionObservables.bind(to: executions).disposed(by: disposeBag) + } + afterEach { + action = nil + inputs = nil + executions = nil + } + + it("execute on .next") { + scheduler.scheduleAt(10) { action.inputs.onNext("a") } + scheduler.start() + XCTAssertEqual(inputs.events, [next(10, "a")]) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 1) + } + it("ignore .error events") { + scheduler.scheduleAt(10) { action.inputs.onError(TestError) } + scheduler.start() + XCTAssertEqual(inputs.events, []) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 0) + } + it("ignore .completed events") { + scheduler.scheduleAt(10) { action.inputs.onCompleted() } + scheduler.start() + XCTAssertEqual(inputs.events, []) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 0) + } + it("accept multiple .next events") { + scheduler.scheduleAt(10) { action.inputs.onNext("a") } + scheduler.scheduleAt(20) { action.inputs.onNext("b") } + scheduler.start() + XCTAssertEqual(inputs.events, [ + next(10, "a"), + next(20, "b"), + ]) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 2) + XCTAssertEqual(executions.events.filter { $0.value.isStopEvent }.count, 0) + } + it("not terminate after .error event") { + scheduler.scheduleAt(10) { action.inputs.onError(TestError) } + scheduler.scheduleAt(20) { action.inputs.onNext("b") } + scheduler.start() + XCTAssertEqual(inputs.events, [next(20, "b")]) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 1) + XCTAssertEqual(executions.events.filter { $0.value.isStopEvent }.count, 0) + } + it("not terminate after .completed event") { + scheduler.scheduleAt(10) { action.inputs.onCompleted() } + scheduler.scheduleAt(20) { action.inputs.onNext("b") } + scheduler.start() + XCTAssertEqual(inputs.events, [next(20, "b")]) + XCTAssertEqual(executions.events.filter { !$0.value.isStopEvent }.count, 1) + XCTAssertEqual(executions.events.filter { $0.value.isStopEvent }.count, 0) + } + } describe("action properties") { var inputs: TestableObserver! From db7694ac21e9e7a504f03e33213398c85310f4e3 Mon Sep 17 00:00:00 2001 From: mosamer Date: Wed, 22 Nov 2017 12:44:31 +0100 Subject: [PATCH 3/5] change `inputs` type to `AnyObserver` --- Sources/Action/Action.swift | 13 +++++++------ Tests/ActionTests/ActionTests.swift | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Sources/Action/Action.swift b/Sources/Action/Action.swift index d966ca88..0b91f338 100644 --- a/Sources/Action/Action.swift +++ b/Sources/Action/Action.swift @@ -22,11 +22,9 @@ When this excuted via execute() or inputs subject, it passes its parameter to th public final class Action { public typealias WorkFactory = (Input) -> Observable - /// Inputs that triggers execution of action. - /// This subject also includes inputs as aguments of execute(). - /// All inputs are always appear in this subject even if the action is not enabled. - /// Thus, inputs count equals elements count + errors count. - public let inputs = InputSubject() + + /// Bindable sink for inputs that triggers execution of action. + public let inputs: AnyObserver /// Errors aggrevated from invocations of execute(). /// Delivered on whatever scheduler they were sent from. @@ -70,7 +68,10 @@ public final class Action { let errorsSubject = PublishSubject() errors = errorsSubject.asObservable() - executionObservables = inputs + let inputsSubject = InputSubject() + inputs = inputsSubject.asObserver() + + executionObservables = inputsSubject .withLatestFrom(isEnabled) { input, enabled in (input, enabled) } .flatMap { input, enabled -> Observable> in if enabled { diff --git a/Tests/ActionTests/ActionTests.swift b/Tests/ActionTests/ActionTests.swift index 26ff11dd..548a1564 100644 --- a/Tests/ActionTests/ActionTests.swift +++ b/Tests/ActionTests/ActionTests.swift @@ -45,7 +45,7 @@ class ActionTests: QuickSpec { } } - describe("Input subject behavior") { + describe("Input observer behavior") { var action: Action! var inputs: TestableObserver! var executions: TestableObserver>! From bc909c91b34869f20ae265ab77dc1fb5100521ab Mon Sep 17 00:00:00 2001 From: mosamer Date: Wed, 22 Nov 2017 12:48:15 +0100 Subject: [PATCH 4/5] drop `InputSubject` --- Action.xcodeproj/project.pbxproj | 15 ---- Sources/Action/Action.swift | 7 +- Sources/Action/InputSubject.swift | 93 ------------------------ Tests/InputSubjectTests.swift | 113 ------------------------------ 4 files changed, 5 insertions(+), 223 deletions(-) delete mode 100644 Sources/Action/InputSubject.swift delete mode 100644 Tests/InputSubjectTests.swift diff --git a/Action.xcodeproj/project.pbxproj b/Action.xcodeproj/project.pbxproj index ac5c74b4..c887e6ff 100644 --- a/Action.xcodeproj/project.pbxproj +++ b/Action.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ 3D730DEB1F674044008534D3 /* Button+Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D730DE81F673FD9008534D3 /* Button+Action.swift */; }; 3DD965C01F5DC0E400C180FE /* Action.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FCDDA821EAC3295006EB95B /* Action.framework */; }; 3DD965C61F5DC2E100C180FE /* ActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0569F01DE288EB007E1D0D /* ActionTests.swift */; }; - 3DD965C81F5DC2E700C180FE /* InputSubjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C91ED6A41700BB327A /* InputSubjectTests.swift */; }; 3DD965DE1F5DF8C500C180FE /* BindToTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD965DD1F5DF86B00C180FE /* BindToTests.swift */; }; 3DD965DF1F5DF8C900C180FE /* NSButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DD965DA1F5DF79800C180FE /* NSButtonTests.swift */; }; 5ED520241E1EA199007621B9 /* BindToTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED520231E1EA199007621B9 /* BindToTests.swift */; }; @@ -72,10 +71,6 @@ C41E08EF2237D2700039D213 /* Action+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DE00042229758700FB50AB /* Action+Extensions.swift */; }; C41E08F02237D2740039D213 /* Action+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DE00042229758700FB50AB /* Action+Extensions.swift */; }; C4DE00052229758700FB50AB /* Action+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DE00042229758700FB50AB /* Action+Extensions.swift */; }; - CA2861C81ED6979400BB327A /* InputSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C71ED6979400BB327A /* InputSubject.swift */; }; - CA2861CA1ED6A41700BB327A /* InputSubjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C91ED6A41700BB327A /* InputSubjectTests.swift */; }; - CA2861CB1ED6B08300BB327A /* InputSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C71ED6979400BB327A /* InputSubject.swift */; }; - CA2861CC1ED6B08400BB327A /* InputSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C71ED6979400BB327A /* InputSubject.swift */; }; FA3F973C1EDAF46F00A84787 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0569E21DE28587007E1D0D /* Action.swift */; }; FA3F973D1EDAF46F00A84787 /* Action+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0569E01DE28587007E1D0D /* Action+Internal.swift */; }; FA3F973E1EDAF46F00A84787 /* InputSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2861C71ED6979400BB327A /* InputSubject.swift */; }; @@ -168,8 +163,6 @@ C4E0264220D11A3B00C8164C /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = ""; }; C4E0264320D11CDD00C8164C /* circle.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = circle.yml; sourceTree = ""; }; C4E0264420D1244900C8164C /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = ""; }; - CA2861C71ED6979400BB327A /* InputSubject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputSubject.swift; sourceTree = ""; }; - CA2861C91ED6A41700BB327A /* InputSubjectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputSubjectTests.swift; sourceTree = ""; }; FC9C4166215A99BE00541C4B /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/iOS/RxCocoa.framework; sourceTree = ""; }; FC9C4167215A99BE00541C4B /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -295,7 +288,6 @@ 7F0569E21DE28587007E1D0D /* Action.swift */, C4DE00042229758700FB50AB /* Action+Extensions.swift */, 7F0569E01DE28587007E1D0D /* Action+Internal.swift */, - CA2861C71ED6979400BB327A /* InputSubject.swift */, 3D730DE11F673BCB008534D3 /* CommonUI */, 7F0569E41DE28587007E1D0D /* UIKitExtensions */, 7F0569EF1DE28598007E1D0D /* Supporting Files */, @@ -352,7 +344,6 @@ 3DD965DC1F5DF84800C180FE /* macOS-Tests */, 3DD965DB1F5DF83700C180FE /* iOS-Tests */, 7F0569F01DE288EB007E1D0D /* ActionTests.swift */, - CA2861C91ED6A41700BB327A /* InputSubjectTests.swift */, 7F0569F41DE288EB007E1D0D /* Info.plist */, ); path = Tests; @@ -723,7 +714,6 @@ C41E08EE2237D26D0039D213 /* Action+Extensions.swift in Sources */, 3D730DEA1F674043008534D3 /* Button+Action.swift in Sources */, 1FCDDA671EAC31EF006EB95B /* UIBarButtonItem+Action.swift in Sources */, - CA2861CB1ED6B08300BB327A /* InputSubject.swift in Sources */, 3D730DE41F673C64008534D3 /* Control+Action.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -732,7 +722,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - CA2861CC1ED6B08400BB327A /* InputSubject.swift in Sources */, C41E08EF2237D2700039D213 /* Action+Extensions.swift in Sources */, 3D730DE51F673C65008534D3 /* Control+Action.swift in Sources */, 1FCDDA8A1EAC329E006EB95B /* Action.swift in Sources */, @@ -747,7 +736,6 @@ files = ( FA3F973C1EDAF46F00A84787 /* Action.swift in Sources */, FA3F973D1EDAF46F00A84787 /* Action+Internal.swift in Sources */, - FA3F973E1EDAF46F00A84787 /* InputSubject.swift in Sources */, C41E08F02237D2740039D213 /* Action+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -759,7 +747,6 @@ 3DD965DE1F5DF8C500C180FE /* BindToTests.swift in Sources */, 3DD965C61F5DC2E100C180FE /* ActionTests.swift in Sources */, 3DD965DF1F5DF8C900C180FE /* NSButtonTests.swift in Sources */, - 3DD965C81F5DC2E700C180FE /* InputSubjectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -773,7 +760,6 @@ 7F0569F51DE288EB007E1D0D /* ActionTests.swift in Sources */, 7B4BFE6320C290BF00D72FB0 /* RefreshControlTests.swift in Sources */, 7F0569F81DE288EB007E1D0D /* ButtonTests.swift in Sources */, - CA2861CA1ED6A41700BB327A /* InputSubjectTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -796,7 +782,6 @@ 7F0569ED1DE28587007E1D0D /* UIBarButtonItem+Action.swift in Sources */, C4DE00052229758700FB50AB /* Action+Extensions.swift in Sources */, 3D730DE91F673FD9008534D3 /* Button+Action.swift in Sources */, - CA2861C81ED6979400BB327A /* InputSubject.swift in Sources */, 3D730DE31F673BE4008534D3 /* Control+Action.swift in Sources */, 7F0569EA1DE28587007E1D0D /* Action.swift in Sources */, ); diff --git a/Sources/Action/Action.swift b/Sources/Action/Action.swift index 0b91f338..5793644d 100644 --- a/Sources/Action/Action.swift +++ b/Sources/Action/Action.swift @@ -68,8 +68,11 @@ public final class Action { let errorsSubject = PublishSubject() errors = errorsSubject.asObservable() - let inputsSubject = InputSubject() - inputs = inputsSubject.asObserver() + let inputsSubject = PublishSubject() + inputs = AnyObserver { event in + guard case .next(let value) = event else { return } + inputsSubject.onNext(value) + } executionObservables = inputsSubject .withLatestFrom(isEnabled) { input, enabled in (input, enabled) } diff --git a/Sources/Action/InputSubject.swift b/Sources/Action/InputSubject.swift deleted file mode 100644 index e4fcb211..00000000 --- a/Sources/Action/InputSubject.swift +++ /dev/null @@ -1,93 +0,0 @@ -import Foundation -import RxSwift - -/// A special subject for Action.inputs. It only emits `.next` event. -public class InputSubject: ObservableType, Cancelable, SubjectType, ObserverType { - - public typealias E = Element - typealias Key = UInt - - /// Indicates whether the subject has any observers - public var hasObservers: Bool { - _lock.lock() - let count = _observers.count > 0 - _lock.unlock() - return count - } - - // state - private let _lock = NSRecursiveLock() - private var _nextKey: Key = 0 - private var _observers: [Key: (Event) -> Void] = [:] - private var _isDisposed = false - - /// Indicates whether the subject has been isDisposed. - public var isDisposed: Bool { - _lock.lock() - let isDisposed = _isDisposed - _lock.unlock() - return isDisposed - } - - /// Creates a subject. - public init() { - #if TRACE_RESOURCES - _ = Resources.incrementTotal() - #endif - } - - /// Notifies all subscribed observers abount only `.next` event. - /// - /// - parameter event: Event to send to the observers. - public func on(_ event: Event) { - _lock.lock() - switch event { - case .next where !_isDisposed: - _observers.values.forEach { $0(event) } - default: - break - } - _lock.unlock() - } - - /** - Subscribes an observer to the subject. - - - parameter observer: Observer to subscribe to the subject. - - returns: Disposable object that can be used to unsubscribe the observer from the subject. - */ - public func subscribe(_ observer: O) -> Disposable where O.E == Element { - _lock.lock() - - if _isDisposed { - observer.on(.error(RxError.disposed(object: self))) - return Disposables.create() - } - - let key = _nextKey - _nextKey += 1 - _observers[key] = observer.on - _lock.unlock() - - return Disposables.create { [weak self] in - self?._lock.lock() - self?._observers.removeValue(forKey: key) - self?._lock.unlock() - } - } - - /// Unsubscribe all observers and release resources. - public func dispose() { - _lock.lock() - _isDisposed = true - _observers.removeAll() - _lock.unlock() - } - - #if TRACE_RESOURCES - deinit { - _ = Resources.decrementTotal() - } - #endif - -} diff --git a/Tests/InputSubjectTests.swift b/Tests/InputSubjectTests.swift deleted file mode 100644 index 69cd1b11..00000000 --- a/Tests/InputSubjectTests.swift +++ /dev/null @@ -1,113 +0,0 @@ -import Quick -import Nimble -import RxSwift -import RxTest -import Action - -class InputSubjectTests: QuickSpec { - override func spec() { - var scheduler: TestScheduler! - var disposeBag: DisposeBag! - - beforeEach { - scheduler = TestScheduler(initialClock: 0) - disposeBag = DisposeBag() - } - - describe("Disposable observable") { - it("observables can be dispose") { - let subject = InputSubject() - let disposable1 = subject.subscribe() - let disposable2 = subject.subscribe() - expect(subject.hasObservers).to(beTrue()) - disposable2.dispose() - expect(subject.hasObservers).to(beTrue()) - disposable1.dispose() - expect(subject.hasObservers).to(beFalse()) - } - - it("dispose all observables") { - let subject = InputSubject() - _ = subject.subscribe() - _ = subject.subscribe() - expect(subject.hasObservers).to(beTrue()) - subject.dispose() - expect(subject.hasObservers).to(beFalse()) - expect(subject.isDisposed).to(beTrue()) - } - } - - describe("emit events") { - it("emit .next events") { - let subject = InputSubject() - let observer = scheduler.createObserver(Int.self) - subject.asObservable() - .bind(to: observer) - .disposed(by: disposeBag) - scheduler.scheduleAt(10) { subject.onNext(1) } - scheduler.scheduleAt(20) { subject.onNext(2) } - scheduler.scheduleAt(30) { subject.onNext(3) } - scheduler.start() - - XCTAssertEqual(observer.events, [ - next(10, 1), - next(20, 2), - next(30, 3) - ]) - } - - it("ignore .error events") { - let subject = InputSubject() - let observer = scheduler.createObserver(Int.self) - subject.asObservable() - .bind(to: observer) - .disposed(by: disposeBag) - scheduler.scheduleAt(10) { subject.onNext(1) } - scheduler.scheduleAt(20) { subject.onError(TestError) } - scheduler.scheduleAt(30) { subject.onNext(3) } - scheduler.start() - - XCTAssertEqual(observer.events, [ - next(10, 1), - next(30, 3) - ]) - } - - it("ignore .completed events") { - let subject = InputSubject() - let observer = scheduler.createObserver(Int.self) - subject.asObservable() - .bind(to: observer) - .disposed(by: disposeBag) - scheduler.scheduleAt(10) { subject.onNext(1) } - scheduler.scheduleAt(20) { subject.onCompleted() } - scheduler.scheduleAt(30) { subject.onNext(3) } - scheduler.start() - - XCTAssertEqual(observer.events, [ - next(10, 1), - next(30, 3) - ]) - } - - it("event does not fire on disposed subject") { - let subject = InputSubject() - let observer = scheduler.createObserver(Int.self) - subject.asObservable() - .bind(to: observer) - .disposed(by: disposeBag) - scheduler.scheduleAt(10) { subject.onNext(1) } - scheduler.scheduleAt(20) { subject.onNext(2) } - scheduler.scheduleAt(30) { subject.dispose() } - scheduler.scheduleAt(40) { subject.onNext(4) } - scheduler.start() - - XCTAssertEqual(observer.events, [ - next(10, 1), - next(20, 2), - ]) - } - } - - } -} From 9a32e059bdc412628a9ebefbb1e74b9e377d4851 Mon Sep 17 00:00:00 2001 From: Mostafa Amer Date: Mon, 22 Apr 2019 11:38:53 +0200 Subject: [PATCH 5/5] Update changelog --- Changelog.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 8d614261..3559e5a6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,11 +15,13 @@ Current master - `enabled` ~> `isEnabled` - `executing` ~> `isExecuting` - Deprecate renamed properties +- Change `inputs` type to `AnyObserver` + ======= 3.11.0 ------- -- Introduction of `underlyingError` observable which returns a `Swift.Error` element type. -- Updated specs that were breaking in `Circle CI` pipeline +- Introduction of `underlyingError` observable which returns a `Swift.Error` element type. +- Updated specs that were breaking in `Circle CI` pipeline 3.10.2 -------