Skip to content

Commit

Permalink
Add DataGatherer
Browse files Browse the repository at this point in the history
Copied from commit 46ee0b0; needed for cherry-picking the test changes
from that commit.
  • Loading branch information
lawrence-forooghian committed Nov 6, 2023
1 parent c1913bc commit d528c10
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 d528c10

Please sign in to comment.