Skip to content

Commit

Permalink
Add DataGatherer from 46ee0b0
Browse files Browse the repository at this point in the history
  • Loading branch information
lawrence-forooghian committed Nov 6, 2023
1 parent f7399db commit 563d808
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Ably.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
21881E7A283BD08300CFD9E2 /* GCDTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A22171266F526600C87C42 /* GCDTests.swift */; };
21881E7B283BD0DF00CFD9E2 /* StringifiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520C4DD2680A1E3000012B2 /* StringifiableTests.swift */; };
21881E7C283BD0E100CFD9E2 /* StringifiableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520C4DD2680A1E3000012B2 /* StringifiableTests.swift */; };
21D3CC572AF964AC00B3F2BD /* DataGatherer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D3CC562AF964AC00B3F2BD /* DataGatherer.swift */; };
21D3CC582AF964AC00B3F2BD /* DataGatherer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D3CC562AF964AC00B3F2BD /* DataGatherer.swift */; };
21D3CC592AF964AC00B3F2BD /* DataGatherer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D3CC562AF964AC00B3F2BD /* DataGatherer.swift */; };
560579D924AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; };
560579DA24AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; };
560579DB24AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */; };
Expand Down Expand Up @@ -1002,6 +1005,7 @@
217D181E25421FED00DFF07E /* ARTSRSecurityPolicy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTSRSecurityPolicy.m; sourceTree = "<group>"; };
217D181F25421FED00DFF07E /* ARTSRWebSocket.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTSRWebSocket.m; sourceTree = "<group>"; };
217D182025421FED00DFF07E /* ARTSRSecurityPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARTSRSecurityPolicy.h; sourceTree = "<group>"; };
21D3CC562AF964AC00B3F2BD /* DataGatherer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataGatherer.swift; sourceTree = "<group>"; };
560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARTDefaultTests.swift; sourceTree = "<group>"; };
56190953238C3D3200A862A6 /* CryptoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTest.m; sourceTree = "<group>"; };
841134772722205400CFA837 /* ARTArchiveTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTArchiveTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1499,6 +1503,7 @@
21BF060A2758477E00AE4C43 /* Test Utilities */ = {
isa = PBXGroup;
children = (
21D3CC562AF964AC00B3F2BD /* DataGatherer.swift */,
D7093CA8219EFA8A00723F17 /* MockDeviceStorage.swift */,
D780846C1C68B3E50083009D /* NSObject+TestSuite.h */,
D780846D1C68B3E50083009D /* NSObject+TestSuite.m */,
Expand Down Expand Up @@ -2653,6 +2658,7 @@
D777EEE820650ADF002EBA03 /* PushChannelTests.swift in Sources */,
D746AE2D1BBB625E003ECEF8 /* RestClientChannelsTests.swift in Sources */,
EBAB9A6F1C69702800AF036B /* ReadmeExamplesTests.swift in Sources */,
21D3CC572AF964AC00B3F2BD /* DataGatherer.swift in Sources */,
56190954238C3D3200A862A6 /* CryptoTest.m in Sources */,
D7C1B8771BBEA81A0087B55F /* AuthTests.swift in Sources */,
D7EBE5A31BE8391E0086E675 /* RealtimeClientConnectionTests.swift in Sources */,
Expand Down Expand Up @@ -2783,6 +2789,7 @@
D7093C1C219E466400723F17 /* ReadmeExamplesTests.swift in Sources */,
21881E7B283BD0DF00CFD9E2 /* StringifiableTests.swift in Sources */,
D7093C27219E466E00723F17 /* RealtimeClientChannelsTests.swift in Sources */,
21D3CC582AF964AC00B3F2BD /* DataGatherer.swift in Sources */,
848ED97426E50D0F0087E800 /* ObjcppTest.mm in Sources */,
D7093C28219E466E00723F17 /* RealtimeClientPresenceTests.swift in Sources */,
D7093C24219E466E00723F17 /* RealtimeClientTests.swift in Sources */,
Expand Down Expand Up @@ -2817,6 +2824,7 @@
D7093C71219EE25800723F17 /* NSObject+TestSuite.m in Sources */,
D7093C70219EE25400723F17 /* TestUtilities.swift in Sources */,
84569FA826B46F5100457CF5 /* ClientOptionsTests.swift in Sources */,
21D3CC592AF964AC00B3F2BD /* DataGatherer.swift in Sources */,
D7093C80219EE26400723F17 /* StatsTests.swift in Sources */,
D7093C77219EE26400723F17 /* RestClientChannelTests.swift in Sources */,
D520C4E32680A1FC000012B2 /* StringifiableTests.swift in Sources */,
Expand Down
75 changes: 75 additions & 0 deletions Spec/Test Utilities/DataGatherer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Foundation
import XCTest

/**
A `DataGatherer` instance initiates a user-specified data-gathering activity, and provides a method for waiting until the activity submits some data.

The `DataGatherer` instance only cares about the _first_ data that is submitted to it, and will ignore any subsequently-submitted data. When the gathered data has value semantics, this can simplify the implementation of tests, since they do not need to be so careful about making sure to stop their data-gathering process at the right time.
*/
class DataGatherer<T> {
private let expectation: XCTestExpectation

// The value that the initializer’s `gather` block passed to its `submit` argument.
private var value: T?
// Synchronises access to `value`.
private let semaphore = DispatchSemaphore(value: 1)

/**
Initiates the data-gathering process specified by `gather`.

- Parameters:
- description: A human-readable description of the data-gathering process.
- gather: A function which implements the data-gathering process. It should call the `submit` callback with the gathered data when ready. Subsequent calls to `submit` will have no effect. `submit` can be safely called from any thread.
*/
init(description: String, gather: (_ submit: @escaping (T) -> Void) -> Void) {
expectation = XCTestExpectation(description: description)
gather(complete(withValue:))
}

enum Error: Swift.Error {
case unexpectedResult(XCTWaiter.Result)
}

/**
Waits for the initializer’s `gather` function to submit data and then returns the submitted data. If data has already been submitted then it is returned immediately. This method can be safely called from any thread.
*/
func waitForData(timeout: TimeInterval) throws -> T {
semaphore.wait()
if let value {
semaphore.signal()
return value
}
semaphore.signal()

let waiter = XCTWaiter()
let result = waiter.wait(for: [expectation], timeout: timeout)

switch result {
case .completed:
let value: T
semaphore.wait()
value = self.value!
semaphore.signal()
return value
default:
throw Error.unexpectedResult(result)
}
}

/**
Waits for the initializer’s `gather` function to submit data and then returns the submitted data. If data has already been submitted then it is returned immediately. This method can be safely called from any thread.
*/
func waitForData(timeout: DispatchTimeInterval) throws -> T {
return try waitForData(timeout: timeout.toTimeInterval())
}

private func complete(withValue value: T) {
semaphore.wait()
if self.value == nil {
self.value = value
}
semaphore.signal()

expectation.fulfill()
}
}

0 comments on commit 563d808

Please sign in to comment.