diff --git a/RxTest/Event+Equatable.swift b/RxTest/Event+Equatable.swift index 05b403bef..0156a78eb 100644 --- a/RxTest/Event+Equatable.swift +++ b/RxTest/Event+Equatable.swift @@ -47,6 +47,25 @@ internal func equals(lhs: Event, rhs: Event, rhs: Event) -> Bool { + switch (lhs, rhs) { + case (.completed, .completed): return true + case let (.error(e1), .error(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 + case (.next, .next): return true + default: return false + } +} + internal func equals(lhs: SingleEvent, rhs: SingleEvent) -> Bool { switch (lhs, rhs) { case let (.failure(e1), .failure(e2)): @@ -84,6 +103,25 @@ internal func equals(lhs: MaybeEvent, rhs: MaybeEve } } +internal func equals(lhs: MaybeEvent, rhs: MaybeEvent) -> Bool { + switch (lhs, rhs) { + case (.completed, .completed): return true + case let (.error(e1), .error(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 + case (.success, .success): return true + default: return false + } +} + /// Compares two `CompletableEvent` events. /// /// In case `Error` events are being compared, they are equal in case their `NSError` representations are equal (domain and code) @@ -114,8 +152,20 @@ extension Event: Equatable where Element: Equatable { } } +public extension Event where Element == Void { + static func == (lhs: Event, rhs: Event) -> Bool { + equals(lhs: lhs, rhs: rhs) + } +} + extension MaybeEvent: Equatable where Element: Equatable { public static func == (lhs: MaybeEvent, rhs: MaybeEvent) -> Bool { equals(lhs: lhs, rhs: rhs) } } + +public extension MaybeEvent where Element == Void { + static func == (lhs: MaybeEvent, rhs: MaybeEvent) -> Bool { + equals(lhs: lhs, rhs: rhs) + } +} diff --git a/RxTest/Recorded+Event.swift b/RxTest/Recorded+Event.swift index fda6de9da..6dff9da8c 100644 --- a/RxTest/Recorded+Event.swift +++ b/RxTest/Recorded+Event.swift @@ -20,6 +20,15 @@ extension Recorded { public static func next(_ time: TestTime, _ element: T) -> Recorded> where Value == Event { Recorded(time: time, value: .next(element)) } + + /** + Factory method for a `.next` event recorded at a given time. + - parameter time: Recorded virtual time the `.next` event occurs. + - returns: Recorded event in time. + */ + public static func next(_ time: TestTime) -> Recorded where Value == Event { + return Recorded(time: time, value: .next(())) + } /** Factory method for an `.completed` event recorded at a given time. diff --git a/RxTest/Recorded.swift b/RxTest/Recorded.swift index 6a9983e73..1aca9debf 100644 --- a/RxTest/Recorded.swift +++ b/RxTest/Recorded.swift @@ -37,3 +37,15 @@ extension Recorded: Equatable where Value: Equatable { lhs.time == rhs.time && lhs.value == rhs.value } } + +public extension Recorded where Value == Event { + static func == (lhs: Recorded, rhs: Recorded) -> Bool { + lhs.time == rhs.time && lhs.value == rhs.value + } +} + +public extension Recorded where Value == MaybeEvent { + static func == (lhs: Recorded, rhs: Recorded) -> Bool { + lhs.time == rhs.time && lhs.value == rhs.value + } +} diff --git a/RxTest/XCTest+Rx.swift b/RxTest/XCTest+Rx.swift index 5401aa899..ad3d89e87 100644 --- a/RxTest/XCTest+Rx.swift +++ b/RxTest/XCTest+Rx.swift @@ -37,6 +37,34 @@ public func XCTAssertEqual(_ lhs: [Event], _ rhs: [ printSequenceDifferences(lhs, rhs, ==) } +/** +Asserts two lists of events are equal. + +Event is considered equal if: +* `Next` events are equal if they have equal corresponding elements. +* `Error` events are equal if errors have same domain and code for `NSError` representation and have equal descriptions. +* `Completed` events are always equal. + +- parameter lhs: first set of events. +- parameter rhs: second set of events. +- parameter file: The path to the file in which it appears. +- parameter line: The line number on which it appears. +*/ +public func XCTAssertEqual(_ lhs: [Event], _ rhs: [Event], file: StaticString = #file, line: UInt = #line) { + let leftEquatable = lhs.map { AnyEquatable(target: $0, comparer: ==) } + let rightEquatable = rhs.map { AnyEquatable(target: $0, comparer: ==) } + #if os(Linux) + XCTAssertEqual(leftEquatable, rightEquatable) + #else + XCTAssertEqual(leftEquatable, rightEquatable, file: file, line: line) + #endif + if leftEquatable == rightEquatable { + return + } + + printSequenceDifferences(lhs, rhs, ==) +} + /** Asserts two lists of events are equal. @@ -65,6 +93,34 @@ public func XCTAssertEqual(_ lhs: [SingleEvent], _ printSequenceDifferences(lhs.map { try? $0.get() }, rhs.map { try? $0.get() }, ==) } +/** + Asserts two lists of events are equal. + + Event is considered equal if: + * `Next` events are equal if they have equal corresponding elements. + * `Error` events are equal if errors have same domain and code for `NSError` representation and have equal descriptions. + * `Completed` events are always equal. + + - parameter lhs: first set of events. + - parameter rhs: second set of events. + - parameter file: The path to the file in which it appears. + - parameter line: The line number on which it appears. + */ +public func XCTAssertEqual(_ lhs: [SingleEvent], _ rhs: [SingleEvent], file: StaticString = #file, line: UInt = #line) { + let leftEquatable = lhs.map { AnyEquatable(target: try? $0.get(), comparer: compareVoidOptionals) } + let rightEquatable = rhs.map { AnyEquatable(target: try? $0.get(), comparer: compareVoidOptionals) } + #if os(Linux) + XCTAssertEqual(leftEquatable, rightEquatable) + #else + XCTAssertEqual(leftEquatable, rightEquatable, file: file, line: line) + #endif + if leftEquatable == rightEquatable { + return + } + + printSequenceDifferences(lhs.map { try? $0.get() }, rhs.map { try? $0.get() }, ==) +} + /** Asserts two lists of events are equal. @@ -93,6 +149,34 @@ public func XCTAssertEqual(_ lhs: [MaybeEvent], _ r printSequenceDifferences(lhs, rhs, ==) } +/** + Asserts two lists of events are equal. + + Event is considered equal if: + * `Next` events are equal if they have equal corresponding elements. + * `Error` events are equal if errors have same domain and code for `NSError` representation and have equal descriptions. + * `Completed` events are always equal. + + - parameter lhs: first set of events. + - parameter rhs: second set of events. + - parameter file: The path to the file in which it appears. + - parameter line: The line number on which it appears. + */ +public func XCTAssertEqual(_ lhs: [MaybeEvent], _ rhs: [MaybeEvent], file: StaticString = #file, line: UInt = #line) { + let leftEquatable = lhs.map { AnyEquatable(target: $0, comparer: ==) } + let rightEquatable = rhs.map { AnyEquatable(target: $0, comparer: ==) } + #if os(Linux) + XCTAssertEqual(leftEquatable, rightEquatable) + #else + XCTAssertEqual(leftEquatable, rightEquatable, file: file, line: line) + #endif + if leftEquatable == rightEquatable { + return + } + + printSequenceDifferences(lhs, rhs, ==) +} + /** Asserts two lists of events are equal. @@ -183,6 +267,37 @@ public func XCTAssertEqual(_ lhs: [Recorded> printSequenceDifferences(lhs, rhs, ==) } +/** + Asserts two lists of Recorded events with optional elements are equal. + + Recorded events are equal if times are equal and recorded events are equal. + + Event is considered equal if: + * `Next` events are equal if they have equal corresponding elements. + * `Error` events are equal if errors have same domain and code for `NSError` representation and have equal descriptions. + * `Completed` events are always equal. + + - parameter lhs: first set of events. + - parameter rhs: second set of events. + - parameter file: The path to the file in which it appears. + - parameter line: The line number on which it appears. + */ +public func XCTAssertEqual(_ lhs: [Recorded>], _ rhs: [Recorded>], file: StaticString = #file, line: UInt = #line) { + let leftEquatable = lhs.map { AnyEquatable(target: $0, comparer: ==) } + let rightEquatable = rhs.map { AnyEquatable(target: $0, comparer: ==) } + #if os(Linux) + XCTAssertEqual(leftEquatable, rightEquatable) + #else + XCTAssertEqual(leftEquatable, rightEquatable, file: file, line: line) + #endif + + if leftEquatable == rightEquatable { + return + } + + printSequenceDifferences(lhs, rhs, ==) +} + /** Assert a list of Recorded events has emitted the provided elements. This method does not take event times into consideration. @@ -243,4 +358,15 @@ func printSequenceDifferences(_ lhs: [Element], _ rhs: [Element], _ equ print("rhs[\(index + shortest)]:\n \(element)") } } + +private func compareVoidOptionals(_ lhs: Optional, _ rhs: Optional) -> Bool { + switch (lhs, rhs) { + case (.none, .none), + (.some, .some): + return true + case (.none, .some), + (.some, .none): + return false + } +} #endif