import Dispatch import XCTest class ValueObservationRecorderTests: FailureTestCase { // MARK: - NextOne func testNextOneSuccess() throws { do { let recorder = ValueObservationRecorder() recorder.onChange("foo") try XCTAssertEqual(recorder.next().get(), "foo") recorder.onChange("bar") try XCTAssertEqual(recorder.next().get(), "bar") } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onChange("bar") try XCTAssertEqual(recorder.next().get(), "foo") try XCTAssertEqual(recorder.next().get(), "bar") } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onChange("bar") try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "foo") try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "bar") } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "foo") try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "bar") } } func testNextOneError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try recorder.next().get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try wait(for: recorder.next(), timeout: 0.1) XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) try XCTAssertEqual(recorder.next().get(), "foo") do { _ = try recorder.next().get() XCTFail("Expected error") } catch is CustomError { } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } _ = try wait(for: recorder.next(), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "foo") do { _ = try wait(for: recorder.next(), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } } func testNextOneTimeout() throws { try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() _ = try wait(for: recorder.next(), timeout: 0.1) XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } try XCTAssertEqual(wait(for: recorder.next(), timeout: 0.5), "foo") do { _ = try wait(for: recorder.next(), timeout: 0.5) XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } } } func testNextOneNotEnoughElement() throws { do { let recorder = ValueObservationRecorder() _ = try recorder.next().get() XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") try XCTAssertEqual(recorder.next().get(), "foo") do { _ = try recorder.next().get() XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } } // MARK: - NextOne Inverted func testNextOneInvertedSuccess() throws { do { let recorder = ValueObservationRecorder() try recorder.next().inverted.get() } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") _ = try recorder.next().get() try recorder.next().inverted.get() } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } _ = try wait(for: recorder.next(), timeout: 0.5) try wait(for: recorder.next().inverted, timeout: 0.5) } } func testNextOneInvertedError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) try recorder.next().inverted.get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) _ = try recorder.next().get() do { try recorder.next().inverted.get() XCTFail("Expected error") } catch is CustomError { } } } func testNextOneInvertedTimeout() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } try assertFailure("Fulfilled inverted expectation") { try wait(for: recorder.next().inverted, timeout: 0.5) } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } _ = try wait(for: recorder.next(), timeout: 0.5) try assertFailure("Fulfilled inverted expectation") { try wait(for: recorder.next().inverted, timeout: 0.5) } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } try assertFailure("Fulfilled inverted expectation") { do { try wait(for: recorder.next().inverted, timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } _ = try wait(for: recorder.next(), timeout: 0.5) try assertFailure("Fulfilled inverted expectation") { do { try wait(for: recorder.next().inverted, timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } } } // MARK: - Next func testNextSuccess() throws { do { let recorder = ValueObservationRecorder() try XCTAssertEqual(recorder.next(0).get(), []) recorder.onChange("foo") try XCTAssertEqual(recorder.next(1).get(), ["foo"]) recorder.onChange("bar") recorder.onChange("baz") try XCTAssertEqual(recorder.next(2).get(), ["bar", "baz"]) } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onChange("bar") try XCTAssertEqual(recorder.next(1).get(), ["foo"]) recorder.onChange("baz") try XCTAssertEqual(recorder.next(2).get(), ["bar", "baz"]) } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } try XCTAssertEqual(wait(for: recorder.next(2), timeout: 0.5), ["foo", "bar"]) } } func testNextError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try recorder.next(2).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) _ = try recorder.next(2).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } _ = try wait(for: recorder.next(2), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } _ = try wait(for: recorder.next(2), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } func testNextTimeout() throws { try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() _ = try wait(for: recorder.next(2), timeout: 0.1) XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() recorder.onChange("foo") _ = try wait(for: recorder.next(2), timeout: 0.1) XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } _ = try wait(for: recorder.next(2), timeout: 0.5) XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } } func testNextNotEnoughElement() throws { do { let recorder = ValueObservationRecorder() _ = try recorder.next(2).get() XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") _ = try recorder.next(2).get() XCTFail("Expected error") } catch ValueRecordingError.notEnoughValues { } } // MARK: - Prefix(maxLength) func testPrefixMaxLengthSuccess() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() try XCTAssertEqual(recorder.prefix(0).get(), []) recorder.onChange("foo") try XCTAssertEqual(recorder.prefix(0).get(), []) try XCTAssertEqual(recorder.prefix(1).get(), ["foo"]) recorder.onChange("bar") recorder.onChange("baz") try XCTAssertEqual(recorder.prefix(0).get(), []) try XCTAssertEqual(recorder.prefix(1).get(), ["foo"]) try XCTAssertEqual(recorder.prefix(2).get(), ["foo", "bar"]) try XCTAssertEqual(recorder.prefix(3).get(), ["foo", "bar", "baz"]) } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) try XCTAssertEqual(recorder.prefix(0).get(), []) } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) try XCTAssertEqual(recorder.prefix(1).get(), ["foo"]) } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } try XCTAssertEqual(wait(for: recorder.prefix(2), timeout: 0.5), ["foo", "bar"]) } } func testPrefixMaxLengthError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try recorder.prefix(2).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) _ = try recorder.prefix(2).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } _ = try wait(for: recorder.prefix(2), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } _ = try wait(for: recorder.prefix(2), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } func testPrefixMaxLengthTimeout() throws { try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() let values = try wait(for: recorder.prefix(2), timeout: 0.1) XCTAssertEqual(values, []) } try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() recorder.onChange("foo") let values = try wait(for: recorder.prefix(2), timeout: 0.1) XCTAssertEqual(values, ["foo"]) } try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } let values = try wait(for: recorder.prefix(2), timeout: 0.5) XCTAssertEqual(values, ["foo"]) } } // MARK: - Prefix(maxLength) Inverted func testPrefixMaxLengthInvertedSuccess() throws { do { let recorder = ValueObservationRecorder() try XCTAssertEqual(recorder.prefix(1).inverted.get(), []) } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") try XCTAssertEqual(recorder.prefix(2).inverted.get(), ["foo"]) } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } try XCTAssertEqual(wait(for: recorder.prefix(2).inverted, timeout: 0.5), ["foo"]) } } func testPrefixMaxLengthInvertedError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try recorder.prefix(1).inverted.get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) _ = try recorder.prefix(2).inverted.get() XCTFail("Expected error") } catch is CustomError { } } func testPrefixMaxLengthInvertedTimeout() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } try assertFailure("Fulfilled inverted expectation") { _ = try wait(for: recorder.prefix(1).inverted, timeout: 0.5) } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } try assertFailure("Fulfilled inverted expectation") { _ = try wait(for: recorder.prefix(2).inverted, timeout: 0.5) } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } try assertFailure("Fulfilled inverted expectation") { do { _ = try wait(for: recorder.prefix(1).inverted, timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } try assertFailure("Fulfilled inverted expectation") { do { _ = try wait(for: recorder.prefix(2).inverted, timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } } } // MARK: - Prefix(maxLength) func testPrefixUntilSuccess() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") try XCTAssertEqual(recorder.prefix(until: { $0 == "foo" }).get(), ["foo"]) recorder.onChange("bar") recorder.onChange("baz") try XCTAssertEqual(recorder.prefix(until: { $0 == "foo" }).get(), ["foo"]) try XCTAssertEqual(recorder.prefix(until: { $0 == "bar" }).get(), ["foo", "bar"]) try XCTAssertEqual(recorder.prefix(until: { $0 == "baz" }).get(), ["foo", "bar", "baz"]) } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) try XCTAssertEqual(recorder.prefix(until: { $0 == "foo" }).get(), ["foo"]) } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("bar") } } try XCTAssertEqual(wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.5), ["foo", "bar"]) } } func testPrefixUntilError() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) _ = try recorder.prefix(until: { $0 == "bar" }).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") recorder.onError(CustomError()) _ = try recorder.prefix(until: { $0 == "bar" }).get() XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } _ = try wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onError(CustomError()) } } _ = try wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.5) XCTFail("Expected error") } catch is CustomError { } } func testPrefixUntilTimeout() throws { try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() let values = try wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.1) XCTAssertEqual(values, []) } try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() recorder.onChange("foo") let values = try wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.1) XCTAssertEqual(values, ["foo"]) } try assertFailure("Asynchronous wait failed") { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } let values = try wait(for: recorder.prefix(until: { $0 == "bar" }), timeout: 0.5) XCTAssertEqual(values, ["foo"]) } } // MARK: - Failure func testFailureSuccess() throws { struct CustomError: Error { } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) let (elements, error) = try recorder.failure().get() XCTAssertEqual(elements, []) XCTAssert(error is CustomError) } do { let recorder = ValueObservationRecorder() recorder.onError(CustomError()) let (elements, error) = try wait(for: recorder.failure(), timeout: 0.1) XCTAssertEqual(elements, []) XCTAssert(error is CustomError) } } func testFailureTimeout() throws { try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() _ = try wait(for: recorder.failure(), timeout: 0.1) XCTFail("Expected error") } catch ValueRecordingError.notFailed { } } try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() recorder.onChange("foo") _ = try wait(for: recorder.failure(), timeout: 0.1) XCTFail("Expected error") } catch ValueRecordingError.notFailed { } } try assertFailure("Asynchronous wait failed") { do { let recorder = ValueObservationRecorder() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { recorder.onChange("foo") } _ = try wait(for: recorder.failure(), timeout: 0.5) XCTFail("Expected error") } catch ValueRecordingError.notFailed { } } } func testFailureNotFailed() throws { do { let recorder = ValueObservationRecorder() _ = try recorder.failure().get() XCTFail("Expected error") } catch ValueRecordingError.notFailed { } do { let recorder = ValueObservationRecorder() recorder.onChange("foo") _ = try recorder.failure().get() XCTFail("Expected error") } catch ValueRecordingError.notFailed { } } // MARK: - assertValueObservationRecordingMatch func testAssertValueObservationRecordingMatch() { do { let expected = [3] XCTAssertTrue(valueObservationRecordingMatch(recorded: [3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2, 3], expected: expected)) } do { let expected = [2, 3] XCTAssertTrue(valueObservationRecordingMatch(recorded: [3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 2, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 2, 3, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [3, 2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [1, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [1, 2, 3], expected: expected)) } do { let expected = [3, 3] XCTAssertTrue(valueObservationRecordingMatch(recorded: [3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2, 2, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [1, 2, 3], expected: expected)) } do { let expected = [1, 2, 2, 3] XCTAssertTrue(valueObservationRecordingMatch(recorded: [3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 1, 3, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 2, 3], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [3, 2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2, 1, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [0, 3], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [0, 1, 2, 3], expected: expected)) } do { let expected = [1, 2, 1] XCTAssertTrue(valueObservationRecordingMatch(recorded: [1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 1, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 1, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 2, 1], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [1, 2], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [0, 1], expected: expected)) } do { let expected = [1, 2, 3, 2, 1] XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 3, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 3, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 3, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 1], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3, 1], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [3, 1, 2, 1], expected: expected)) } do { let expected = [1, 2, 1, 3, 1, 4] XCTAssertTrue(valueObservationRecordingMatch(recorded: [4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 3, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 2, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 1, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [1, 3, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [3, 1, 1, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 1, 3, 4], expected: expected)) XCTAssertTrue(valueObservationRecordingMatch(recorded: [2, 3, 1, 4], expected: expected)) XCTAssertFalse(valueObservationRecordingMatch(recorded: [3, 2, 4], expected: expected)) } } }