2626@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
2727public func confirmPassesEventually(
2828 _ comment: Comment ? = nil ,
29+ maxPollingIterations: Int = 1000 ,
30+ pollingInterval: Duration = . milliseconds( 1 ) ,
2931 isolation: isolated ( any Actor ) ? = #isolation,
3032 sourceLocation: SourceLocation = #_sourceLocation,
3133 _ body: @escaping ( ) async throws -> Bool
3234) async {
3335 let poller = Poller (
3436 pollingBehavior: . passesOnce,
37+ pollingIterations: maxPollingIterations,
38+ pollingInterval: pollingInterval,
3539 comment: comment,
3640 sourceLocation: sourceLocation
3741 )
@@ -70,15 +74,20 @@ public struct PollingFailedError: Error {}
7074/// through other forms of `confirmation`.
7175@_spi ( Experimental)
7276@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
77+ @discardableResult
7378public func confirmPassesEventually< R> (
7479 _ comment: Comment ? = nil ,
80+ maxPollingIterations: Int = 1000 ,
81+ pollingInterval: Duration = . milliseconds( 1 ) ,
7582 isolation: isolated ( any Actor ) ? = #isolation,
7683 sourceLocation: SourceLocation = #_sourceLocation,
7784 _ body: @escaping ( ) async throws -> R ?
7885) async throws -> R where R: Sendable {
7986 let recorder = PollingRecorder < R > ( )
8087 let poller = Poller (
8188 pollingBehavior: . passesOnce,
89+ pollingIterations: maxPollingIterations,
90+ pollingInterval: pollingInterval,
8291 comment: comment,
8392 sourceLocation: sourceLocation
8493 )
@@ -113,12 +122,16 @@ public func confirmPassesEventually<R>(
113122@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
114123public func confirmAlwaysPasses(
115124 _ comment: Comment ? = nil ,
125+ maxPollingIterations: Int = 1000 ,
126+ pollingInterval: Duration = . milliseconds( 1 ) ,
116127 isolation: isolated ( any Actor ) ? = #isolation,
117128 sourceLocation: SourceLocation = #_sourceLocation,
118129 _ body: @escaping ( ) async throws -> Bool
119130) async {
120131 let poller = Poller (
121132 pollingBehavior: . passesAlways,
133+ pollingIterations: maxPollingIterations,
134+ pollingInterval: pollingInterval,
122135 comment: comment,
123136 sourceLocation: sourceLocation
124137 )
@@ -153,28 +166,26 @@ public func confirmAlwaysPasses(
153166@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
154167public func confirmAlwaysPasses< R> (
155168 _ comment: Comment ? = nil ,
169+ maxPollingIterations: Int = 1000 ,
170+ pollingInterval: Duration = . milliseconds( 1 ) ,
156171 isolation: isolated ( any Actor ) ? = #isolation,
157172 sourceLocation: SourceLocation = #_sourceLocation,
158173 _ body: @escaping ( ) async throws -> R ?
159- ) async throws -> R where R: Sendable {
160- let recorder = PollingRecorder < R > ( )
174+ ) async {
161175 let poller = Poller (
162176 pollingBehavior: . passesAlways,
177+ pollingIterations: maxPollingIterations,
178+ pollingInterval: pollingInterval,
163179 comment: comment,
164180 sourceLocation: sourceLocation
165181 )
166182 await poller. evaluate ( isolation: isolation) {
167183 do {
168- return try await recorder . record ( value : body ( ) )
184+ return try await body ( ) != nil
169185 } catch {
170186 return false
171187 }
172188 }
173-
174- if let value = await recorder. lastValue {
175- return value
176- }
177- throw PollingFailedError( )
178189}
179190
180191/// A type to record the last value returned by a closure returning an optional
@@ -289,6 +300,11 @@ private struct Poller {
289300 /// while the expression continues to pass)
290301 let pollingBehavior : PollingBehavior
291302
303+ // How many times to poll
304+ let pollingIterations : Int
305+ // Minimum waiting period between polling
306+ let pollingInterval : Duration
307+
292308 /// A comment from the test author associated with the polling
293309 let comment : Comment ?
294310
@@ -306,7 +322,6 @@ private struct Poller {
306322 _ body: @escaping ( ) async -> Bool
307323 ) async {
308324 let result = await poll (
309- runAmount: 1_000_000 ,
310325 expression: body
311326 )
312327 result. issue (
@@ -325,20 +340,22 @@ private struct Poller {
325340 /// - timeout: How long to poll for unitl the timeout triggers.
326341 /// - Returns: The result of this polling.
327342 private func poll(
328- runAmount: Int ,
329343 isolation: isolated ( any Actor ) ? = #isolation,
330344 expression: @escaping ( ) async -> Bool
331345 ) async -> PollResult {
332- for _ in 0 ..< runAmount {
333- if Task . isCancelled {
334- return . cancelled
335- }
346+ for _ in 0 ..< pollingIterations {
336347 if let result = await pollingBehavior. processFinishedExpression (
337348 expressionResult: expression ( )
338349 ) {
339350 return result
340351 }
341- await Task . yield ( )
352+ do {
353+ try await Task . sleep ( for: pollingInterval)
354+ } catch {
355+ // `Task.sleep` should only throw an error if it's cancelled
356+ // during the sleep period.
357+ return . cancelled
358+ }
342359 }
343360 return . ranToCompletion
344361 }
0 commit comments