Merge branch 'feature/materialize_operator' of https://github.com/sergdort/RxSwift into sergdort-feature/materialize_operator

This commit is contained in:
Krunoslav Zaher 2017-03-28 15:23:27 +02:00
commit 4ebb4f844f
No known key found for this signature in database
GPG Key ID: 74BC718B68EA3842
11 changed files with 479 additions and 4 deletions

View File

@ -68,6 +68,7 @@ custom_categories:
- Deferred
- Delay
- DelaySubscription
- Dematerialize
- DistinctUntilChanged
- Do
- ElementAt
@ -78,6 +79,7 @@ custom_categories:
- GroupBy
- Just
- Map
- Materialize
- Merge
- Multicast
- Never

View File

@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
## Master
* Deprecates `bindTo` in favor of `bind(to:)`.
* Adds [`materialize()`](http://reactivex.io/documentation/operators/materialize-dematerialize.html) operator
## [3.3.1](https://github.com/ReactiveX/RxSwift/releases/tag/3.3.1) (Xcode 8 / Swift 3.0 compatible)

View File

@ -952,6 +952,14 @@
C8BF34D01C2E426800416CAE /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BF34CA1C2E426800416CAE /* Platform.Linux.swift */; };
C8BF34D11C2E426800416CAE /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BF34CA1C2E426800416CAE /* Platform.Linux.swift */; };
C8BF34D21C2E426800416CAE /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8BF34CA1C2E426800416CAE /* Platform.Linux.swift */; };
C8C0A4A11E886B1200B8215F /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A49F1E886B1200B8215F /* Dematerialize.swift */; };
C8C0A4A21E886B1200B8215F /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A49F1E886B1200B8215F /* Dematerialize.swift */; };
C8C0A4A31E886B1200B8215F /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A49F1E886B1200B8215F /* Dematerialize.swift */; };
C8C0A4A41E886B1200B8215F /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A49F1E886B1200B8215F /* Dematerialize.swift */; };
C8C0A4A51E886B1200B8215F /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A4A01E886B1200B8215F /* Materialize.swift */; };
C8C0A4A61E886B1200B8215F /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A4A01E886B1200B8215F /* Materialize.swift */; };
C8C0A4A71E886B1200B8215F /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A4A01E886B1200B8215F /* Materialize.swift */; };
C8C0A4A81E886B1200B8215F /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C0A4A01E886B1200B8215F /* Materialize.swift */; };
C8C217D51CB7100E0038A2E6 /* UITableView+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C217D41CB7100E0038A2E6 /* UITableView+RxTests.swift */; };
C8C217D71CB710200038A2E6 /* UICollectionView+RxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C217D61CB710200038A2E6 /* UICollectionView+RxTests.swift */; };
C8C3D9FE1B935EDF004D233E /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C3D9FD1B935EDF004D233E /* Zip+Collection.swift */; };
@ -1958,6 +1966,8 @@
C8BCD3F31C14B6D1005F1280 /* NSLayoutConstraint+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraint+Rx.swift"; sourceTree = "<group>"; };
C8BF34C91C2E426800416CAE /* Platform.Darwin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.Darwin.swift; sourceTree = "<group>"; };
C8BF34CA1C2E426800416CAE /* Platform.Linux.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.Linux.swift; sourceTree = "<group>"; };
C8C0A49F1E886B1200B8215F /* Dematerialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dematerialize.swift; sourceTree = "<group>"; };
C8C0A4A01E886B1200B8215F /* Materialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Materialize.swift; sourceTree = "<group>"; };
C8C217D41CB7100E0038A2E6 /* UITableView+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITableView+RxTests.swift"; sourceTree = "<group>"; };
C8C217D61CB710200038A2E6 /* UICollectionView+RxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UICollectionView+RxTests.swift"; sourceTree = "<group>"; };
C8C3D9FD1B935EDF004D233E /* Zip+Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Zip+Collection.swift"; sourceTree = "<group>"; };
@ -2273,10 +2283,11 @@
C8093C6A1B8A72BE0088E94D /* Implementations */ = {
isa = PBXGroup;
children = (
C85217E31E3374710015DD38 /* GroupBy.swift */,
CB883B491BE369AA000AC2EE /* AddRef.swift */,
C8093C6B1B8A72BE0088E94D /* Amb.swift */,
C8C3DA111B93A3EA004D233E /* AnonymousObservable.swift */,
C89814811E75B77B0035949C /* AsMaybe.swift */,
C89814861E75BE590035949C /* AsSingle.swift */,
C821DBA11BA4DCAB008F3809 /* Buffer.swift */,
C8093C6E1B8A72BE0088E94D /* Catch.swift */,
C8093C711B8A72BE0088E94D /* CombineLatest.swift */,
@ -2291,6 +2302,7 @@
C8093C761B8A72BE0088E94D /* Deferred.swift */,
C86B0A551D735CCC005D8A16 /* Delay.swift */,
C8093C771B8A72BE0088E94D /* DelaySubscription.swift */,
C8C0A49F1E886B1200B8215F /* Dematerialize.swift */,
C8093C781B8A72BE0088E94D /* DistinctUntilChanged.swift */,
C8093C791B8A72BE0088E94D /* Do.swift */,
C84CC53F1BDC3B3700E06A64 /* ElementAt.swift */,
@ -2298,8 +2310,10 @@
C8C3DA081B93941E004D233E /* Error.swift */,
C8093C7A1B8A72BE0088E94D /* Filter.swift */,
C84B38ED1BA433CD001B7D88 /* Generate.swift */,
C85217E31E3374710015DD38 /* GroupBy.swift */,
C8C3DA021B9390C4004D233E /* Just.swift */,
C8093C7C1B8A72BE0088E94D /* Map.swift */,
C8C0A4A01E886B1200B8215F /* Materialize.swift */,
C8093C7D1B8A72BE0088E94D /* Merge.swift */,
C8093C7E1B8A72BE0088E94D /* Multicast.swift */,
C8C3DA0B1B93959F004D233E /* Never.swift */,
@ -2325,6 +2339,7 @@
C8093C8A1B8A72BE0088E94D /* StartWith.swift */,
C8093C8B1B8A72BE0088E94D /* SubscribeOn.swift */,
C8093C8C1B8A72BE0088E94D /* Switch.swift */,
252FC1DE1E0DC64C00D28877 /* SwitchIfEmpty.swift */,
C8093C8D1B8A72BE0088E94D /* Take.swift */,
B1B7C3BC1BDD39DB0076934E /* TakeLast.swift */,
C8093C8E1B8A72BE0088E94D /* TakeUntil.swift */,
@ -2340,9 +2355,6 @@
C8093C921B8A72BE0088E94D /* Zip+arity.swift */,
C8093C931B8A72BE0088E94D /* Zip+arity.tt */,
C8C3D9FD1B935EDF004D233E /* Zip+Collection.swift */,
252FC1DE1E0DC64C00D28877 /* SwitchIfEmpty.swift */,
C89814811E75B77B0035949C /* AsMaybe.swift */,
C89814861E75BE590035949C /* AsSingle.swift */,
);
path = Implementations;
sourceTree = "<group>";
@ -4422,6 +4434,7 @@
C84CC5541BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */,
C8093D261B8A72BE0088E94D /* Multicast.swift in Sources */,
C8C3DA101B939767004D233E /* CurrentThreadScheduler.swift in Sources */,
C8C0A4A61E886B1200B8215F /* Materialize.swift in Sources */,
252FC1D01E0D250500D28877 /* DefaultIfEmpty.swift in Sources */,
C8093D861B8A72BE0088E94D /* Rx.swift in Sources */,
C80D342F1B9245A40014629D /* CombineLatest+Collection.swift in Sources */,
@ -4497,6 +4510,7 @@
C8093CEC1B8A72BE0088E94D /* SerialDisposable.swift in Sources */,
C8C3DA0D1B93959F004D233E /* Never.swift in Sources */,
C85217E51E3374710015DD38 /* GroupBy.swift in Sources */,
C8C0A4A21E886B1200B8215F /* Dematerialize.swift in Sources */,
C84CC5681BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */,
C8093CF61B8A72BE0088E94D /* Event.swift in Sources */,
C83D73C51C1DBAEE003DC470 /* ScheduledItem.swift in Sources */,
@ -4664,6 +4678,7 @@
C8C3DA0F1B939767004D233E /* CurrentThreadScheduler.swift in Sources */,
C8093D851B8A72BE0088E94D /* Rx.swift in Sources */,
C80D342E1B9245A40014629D /* CombineLatest+Collection.swift in Sources */,
C8C0A4A51E886B1200B8215F /* Materialize.swift in Sources */,
252FC1CF1E0D250500D28877 /* DefaultIfEmpty.swift in Sources */,
C84CC5401BDC3B3700E06A64 /* ElementAt.swift in Sources */,
C8093DA51B8A72BE0088E94D /* SubjectType.swift in Sources */,
@ -4739,6 +4754,7 @@
C8093CEB1B8A72BE0088E94D /* SerialDisposable.swift in Sources */,
C8C3DA0C1B93959F004D233E /* Never.swift in Sources */,
C85217E41E3374710015DD38 /* GroupBy.swift in Sources */,
C8C0A4A11E886B1200B8215F /* Dematerialize.swift in Sources */,
C84CC5671BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */,
C8093CF51B8A72BE0088E94D /* Event.swift in Sources */,
C83D73C41C1DBAEE003DC470 /* ScheduledItem.swift in Sources */,
@ -4834,6 +4850,7 @@
C84CC5561BDCF49300E06A64 /* SynchronizedOnType.swift in Sources */,
C8F0BFBA1BBBFB8B001B112F /* Multicast.swift in Sources */,
C8F0BFBB1BBBFB8B001B112F /* CurrentThreadScheduler.swift in Sources */,
C8C0A4A81E886B1200B8215F /* Materialize.swift in Sources */,
252FC1D21E0D250500D28877 /* DefaultIfEmpty.swift in Sources */,
C8F0BFBC1BBBFB8B001B112F /* Rx.swift in Sources */,
C8F0BFBD1BBBFB8B001B112F /* CombineLatest+Collection.swift in Sources */,
@ -4909,6 +4926,7 @@
C8F0BFF61BBBFB8B001B112F /* SerialDisposable.swift in Sources */,
C8F0BFF71BBBFB8B001B112F /* Never.swift in Sources */,
C85217E71E3374710015DD38 /* GroupBy.swift in Sources */,
C8C0A4A41E886B1200B8215F /* Dematerialize.swift in Sources */,
C84CC56A1BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */,
C8F0BFF91BBBFB8B001B112F /* Event.swift in Sources */,
C83D73C71C1DBAEE003DC470 /* ScheduledItem.swift in Sources */,
@ -5191,6 +5209,7 @@
D2752D631BC5551B0070C418 /* SkipUntil.swift in Sources */,
D2EBEB351BB9B6D2003A27DC /* ObserverBase.swift in Sources */,
D2EBEB0F1BB9B6C1003A27DC /* Generate.swift in Sources */,
C8C0A4A71E886B1200B8215F /* Materialize.swift in Sources */,
252FC1D11E0D250500D28877 /* DefaultIfEmpty.swift in Sources */,
D2EBEB1F1BB9B6C1003A27DC /* Skip.swift in Sources */,
D2EBEB321BB9B6CA003A27DC /* Observable+StandardSequenceOperators.swift in Sources */,
@ -5266,6 +5285,7 @@
D2EBEB171BB9B6C1003A27DC /* Producer.swift in Sources */,
D2EBEAF91BB9B6B2003A27DC /* SerialDisposable.swift in Sources */,
C85217E61E3374710015DD38 /* GroupBy.swift in Sources */,
C8C0A4A31E886B1200B8215F /* Dematerialize.swift in Sources */,
C84CC5691BDD08A500E06A64 /* SubscriptionDisposable.swift in Sources */,
D2EBEB0A1BB9B6C1003A27DC /* Do.swift in Sources */,
C83D73C61C1DBAEE003DC470 /* ScheduledItem.swift in Sources */,

View File

@ -88,3 +88,19 @@ extension Event {
}
}
}
/// A type that can be converted to `Event<Element>`.
public protocol EventConvertible {
/// Type of element in event
associatedtype ElementType
/// Event representation of this instance
var event: Event<ElementType> { get }
}
extension Event : EventConvertible {
/// Event representation of this instance
public var event: Event<Element> {
return self
}
}

View File

@ -0,0 +1,39 @@
//
// Dematerialize.swift
// RxSwift
//
// Created by Jamie Pinkham on 3/13/17.
// Copyright © 2017 Krunoslav Zaher. All rights reserved.
//
fileprivate final class DematerializeSink<Element: EventConvertible, O: ObserverType>: Sink<O>, ObserverType where O.E == Element.ElementType {
fileprivate func on(_ event: Event<Element>) {
switch event {
case .next(let element):
forwardOn(element.event)
if element.event.isStopEvent {
dispose()
}
case .completed:
forwardOn(.completed)
dispose()
case .error(let error):
forwardOn(.error(error))
dispose()
}
}
}
final class Dematerialize<Element: EventConvertible>: Producer<Element.ElementType> {
private let _source: Observable<Element>
init(source: Observable<Element>) {
_source = source
}
override func run<O : ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element.ElementType {
let sink = DematerializeSink<Element, O>(observer: observer, cancel: cancel)
let subscription = _source.subscribe(sink)
return (sink: sink, subscription: subscription)
}
}

View File

@ -0,0 +1,33 @@
//
// Materialize.swift
// RxSwift
//
// Created by sergdort on 08/03/2017.
// Copyright © 2017 Krunoslav Zaher. All rights reserved.
//
fileprivate final class MaterializeSink<Element, O: ObserverType>: Sink<O>, ObserverType where O.E == Event<Element> {
func on(_ event: Event<Element>) {
forwardOn(.next(event))
if event.isStopEvent {
forwardOn(.completed)
dispose()
}
}
}
final class Materialize<Element>: Producer<Event<Element>> {
private let _source: Observable<Element>
init(source: Observable<Element>) {
_source = source
}
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == E {
let sink = MaterializeSink(observer: observer, cancel: cancel)
let subscription = _source.subscribe(sink)
return (sink: sink, subscription: subscription)
}
}

View File

@ -229,3 +229,28 @@ extension ObservableType {
}
}
}
// MARK: materialize
extension ObservableType {
/**
Convert any Observable into an Observable of its events.
- seealso: [materialize operator on reactivex.io](http://reactivex.io/documentation/operators/materialize-dematerialize.html)
- returns: An observable sequence that wraps events in an Event<E>. The returned Observable never errors, but it does complete after observing all of the events of the underlying Observable.
*/
public func materialize() -> Observable<Event<E>> {
return Materialize(source: self.asObservable())
}
}
extension ObservableType where E: EventConvertible {
/**
Convert any previously materialized Observable into it's original form.
- seealso: [materialize operator on reactivex.io](http://reactivex.io/documentation/operators/materialize-dematerialize.html)
- returns: The dematerialized observable sequence.
*/
public func dematerialize() -> Observable<E.ElementType> {
return Dematerialize(source: self.asObservable())
}
}

View File

@ -416,6 +416,18 @@ final class ObservableSingleTest_ : ObservableSingleTest, RxTestCase {
("testDefaultIfEmpty_Source_Errors", ObservableSingleTest.testDefaultIfEmpty_Source_Errors),
("testDefaultIfEmpty_Source_Emits", ObservableSingleTest.testDefaultIfEmpty_Source_Emits),
("testDefaultIfEmpty_Never", ObservableSingleTest.testDefaultIfEmpty_Never),
("testMaterializeNever", ObservableSingleTest.testMaterializeNever),
("testMaterializeEmpty", ObservableSingleTest.testMaterializeEmpty),
("testMaterializeEmits", ObservableSingleTest.testMaterializeEmits),
("testMaterializeThrow", ObservableSingleTest.testMaterializeThrow),
("testDematerialize_Range1", ObservableSingleTest.testDematerialize_Range1),
("testDematerialize_Range2", ObservableSingleTest.testDematerialize_Range2),
("testDematerialize_Error", ObservableSingleTest.testDematerialize_Error),
("testDematerialize_Error2", ObservableSingleTest.testDematerialize_Error2),
("testMaterialize_Dematerialize_Never", ObservableSingleTest.testMaterialize_Dematerialize_Never),
("testMaterialize_Dematerialize_Empty", ObservableSingleTest.testMaterialize_Dematerialize_Empty),
("testMaterialize_Dematerialize_Return", ObservableSingleTest.testMaterialize_Dematerialize_Return),
("testMaterialize_Dematerialize_Throw", ObservableSingleTest.testMaterialize_Dematerialize_Throw),
("testGroupBy_TwoGroup", ObservableSingleTest.testGroupBy_TwoGroup),
("testGroupBy_OuterComplete", ObservableSingleTest.testGroupBy_OuterComplete),
("testGroupBy_OuterError", ObservableSingleTest.testGroupBy_OuterError),

View File

@ -0,0 +1 @@
../../RxSwift/Observables/Implementations/Dematerialize.swift

View File

@ -0,0 +1 @@
../../RxSwift/Observables/Implementations/Materialize.swift

View File

@ -1829,3 +1829,328 @@ extension ObservableSingleTest {
#endif
}
// materialize
extension ObservableSingleTest {
func testMaterializeNever() {
let scheduler = TestScheduler(initialClock: 0)
let res = scheduler.start {
return Observable<Int>.never().materialize()
}
XCTAssertEqual(res.events, [], materializedRecoredEventsComparison)
}
func testMaterializeEmpty() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
completed(201, Int.self),
completed(202, Int.self),
])
let res = scheduler.start {
return xs.materialize()
}
let expectedEvents = [
next(201, Event<Int>.completed),
completed(201)
]
XCTAssertEqual(xs.subscriptions, [Subscription(200, 201)])
XCTAssertEqual(res.events, expectedEvents, materializedRecoredEventsComparison)
}
func testMaterializeEmits() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, 1),
next(210, 2),
completed(250),
completed(251),
])
let res = scheduler.start {
return xs.materialize()
}
let expectedEvents = [
next(210, Event.next(2)),
next(250, Event.completed),
completed(250)
]
XCTAssertEqual(xs.subscriptions, [Subscription(200, 250)])
XCTAssertEqual(res.events, expectedEvents, materializedRecoredEventsComparison)
}
func testMaterializeThrow() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, 1),
error(250, testError),
error(251, testError),
])
let res = scheduler.start {
return xs.materialize()
}
let expectedEvents = [
next(250, Event<Int>.error(testError)),
completed(250)
]
XCTAssertEqual(xs.subscriptions, [Subscription(200, 250)])
XCTAssertEqual(res.events, expectedEvents, materializedRecoredEventsComparison)
}
#if TRACE_RESOURCES
func testMaterializeReleasesResourcesOnComplete1() {
_ = Observable<Int>.just(1).materialize().subscribe()
}
func testMaterializeReleasesResourcesOnComplete2() {
_ = Observable<Int>.empty().materialize().subscribe()
}
func testMaterializeReleasesResourcesOnError() {
_ = Observable<Int>.error(testError).materialize().subscribe()
}
#endif
}
//dematerialize
extension ObservableSingleTest {
func testDematerialize_Range1() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, Event.next(41)),
next(210, Event.next(42)),
next(220, Event.next(43)),
completed(250),
completed(251),
])
let res = scheduler.start {
xs.dematerialize()
}
XCTAssertEqual(res.events, [
next(210, 42),
next(220, 43),
completed(250)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 250)
])
}
func testDematerialize_Range2() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, Event.next(41)),
next(210, Event.next(42)),
next(220, Event.next(43)),
next(230, Event.completed),
next(231, Event.completed),
])
let res = scheduler.start {
xs.dematerialize()
}
XCTAssertEqual(res.events, [
next(210, 42),
next(220, 43),
completed(230)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 230)
])
}
func testDematerialize_Error() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, Event.next(41)),
next(210, Event.next(42)),
next(220, Event.next(43)),
error(230, TestError.dummyError),
error(231, TestError.dummyError),
])
let res = scheduler.start {
xs.dematerialize()
}
XCTAssertEqual(res.events, [
next(210, 42),
next(220, 43),
error(230, TestError.dummyError)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 230)
])
}
func testDematerialize_Error2() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, Event.next(41)),
next(210, Event.next(42)),
next(220, Event.next(43)),
next(230, Event.error(TestError.dummyError)),
next(231, Event.error(TestError.dummyError))
])
let res = scheduler.start {
xs.dematerialize()
}
XCTAssertEqual(res.events, [
next(210, 42),
next(220, 43),
error(230, TestError.dummyError)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 230)
])
}
func testMaterialize_Dematerialize_Never() {
let scheduler = TestScheduler(initialClock: 0)
let xs = Observable<Int>.never()
let res = scheduler.start {
xs.materialize().dematerialize()
}
XCTAssertEqual(res.events, [])
}
func testMaterialize_Dematerialize_Empty() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, 1),
completed(250)
])
let res = scheduler.start {
xs.materialize().dematerialize()
}
XCTAssertEqual(res.events, [
completed(250)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 250)
])
}
func testMaterialize_Dematerialize_Return() {
let scheduler = TestScheduler(initialClock: 0)
let xs = scheduler.createHotObservable([
next(150, 1),
next(210, 2),
completed(250)
])
let res = scheduler.start {
xs.materialize().dematerialize()
}
XCTAssertEqual(res.events, [
next(210, 2),
completed(250)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 250)
])
}
func testMaterialize_Dematerialize_Throw() {
let scheduler = TestScheduler(initialClock: 0)
let dummyError = TestError.dummyError
let xs = scheduler.createHotObservable([
next(150, 1),
error(250, dummyError)
])
let res = scheduler.start {
xs.materialize().dematerialize()
}
XCTAssertEqual(res.events, [
error(250, dummyError)
])
XCTAssertEqual(xs.subscriptions, [
Subscription(200, 250)
])
}
#if TRACE_RESOURCES
func testDematerializeReleasesResourcesOnComplete1() {
_ = Observable.just(Event.next(1)).dematerialize().subscribe()
}
func testDematerializeReleasesResourcesOnComplete2() {
_ = Observable<Event<Int>>.empty().dematerialize().subscribe()
}
func testDematerializeReleasesResourcesOnError() {
_ = Observable<Event<Int>>.error(testError).dematerialize().subscribe()
}
#endif
}
fileprivate func materializedRecoredEventsComparison<T: Equatable>(lhs: [Recorded<Event<Event<T>>>], rhs: [Recorded<Event<Event<T>>>]) -> Bool {
guard lhs.count == rhs.count else {
return false
}
for (lhsElement, rhsElement) in zip(lhs, rhs) {
guard lhsElement == rhsElement else {
return false
}
}
return true
}
fileprivate func == <T: Equatable>(lhs: Recorded<Event<Event<T>>>, rhs: Recorded<Event<Event<T>>>) -> Bool {
return lhs.time == rhs.time && lhs.value == rhs.value
}
fileprivate func == <T: Equatable>(lhs: Event<Event<T>>, rhs: Event<Event<T>>) -> Bool {
switch (lhs, rhs) {
case (.next(let lhsEvent), .next(let rhsEvent)):
return lhsEvent == rhsEvent
case (.completed, .completed): return true
case (.error(let e1), .error(let e2)):
#if os(Linux)
return "\(e1)" == "\(e2)"
#else
let error1 = e1 as NSError
let error2 = e2 as NSError
return error1.domain == error2.domain
&& error1.code == error2.code
&& "\(e1)" == "\(e2)"
#endif
default:
return false
}
}