1010
1111@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
1212internal let defaultPollingConfiguration = (
13- maxPollingIterations : 1000 ,
13+ pollingDuration : Duration . seconds ( 1 ) ,
1414 pollingInterval: Duration . milliseconds ( 1 )
1515)
1616
@@ -23,12 +23,14 @@ public struct PollingFailedError: Error, Equatable {}
2323/// - Parameters:
2424/// - comment: An optional comment to apply to any issues generated by this
2525/// function.
26- /// - maxPollingIterations: The maximum amount of times to attempt polling.
26+ /// - pollingDuration: The expected length of time to continue polling for.
27+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
28+ /// on highly-loaded systems with a lot of tests running.
2729/// If nil, this uses whatever value is specified under the last
2830/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
2931/// suite.
3032/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
31- /// polling will be attempted 1000 times before recording an issue.
33+ /// polling will be attempted for about 1 second before recording an issue.
3234/// `maxPollingIterations` must be greater than 0.
3335/// - pollingInterval: The minimum amount of time to wait between polling
3436/// attempts.
@@ -50,18 +52,18 @@ public struct PollingFailedError: Error, Equatable {}
5052@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
5153public func confirmPassesEventually(
5254 _ comment: Comment ? = nil ,
53- maxPollingIterations : Int ? = nil ,
55+ pollingDuration : Duration ? = nil ,
5456 pollingInterval: Duration ? = nil ,
5557 isolation: isolated ( any Actor ) ? = #isolation,
5658 sourceLocation: SourceLocation = #_sourceLocation,
5759 _ body: @escaping ( ) async throws -> Bool
5860) async {
5961 let poller = Poller (
6062 pollingBehavior: . passesOnce,
61- pollingIterations : getValueFromPollingTrait (
62- providedValue: maxPollingIterations ,
63- default: defaultPollingConfiguration. maxPollingIterations ,
64- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
63+ pollingDuration : getValueFromPollingTrait (
64+ providedValue: pollingDuration ,
65+ default: defaultPollingConfiguration. pollingDuration ,
66+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
6567 ) ,
6668 pollingInterval: getValueFromPollingTrait (
6769 providedValue: pollingInterval,
@@ -85,12 +87,14 @@ public func confirmPassesEventually(
8587/// - Parameters:
8688/// - comment: An optional comment to apply to any issues generated by this
8789/// function.
88- /// - maxPollingIterations: The maximum amount of times to attempt polling.
90+ /// - pollingDuration: The expected length of time to continue polling for.
91+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
92+ /// on highly-loaded systems with a lot of tests running.
8993/// If nil, this uses whatever value is specified under the last
9094/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
9195/// suite.
9296/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
93- /// polling will be attempted 1000 times before recording an issue.
97+ /// polling will be attempted for about 1 second before recording an issue.
9498/// `maxPollingIterations` must be greater than 0.
9599/// - pollingInterval: The minimum amount of time to wait between polling
96100/// attempts.
@@ -115,18 +119,18 @@ public func confirmPassesEventually(
115119@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
116120public func requirePassesEventually(
117121 _ comment: Comment ? = nil ,
118- maxPollingIterations : Int ? = nil ,
122+ pollingDuration : Duration ? = nil ,
119123 pollingInterval: Duration ? = nil ,
120124 isolation: isolated ( any Actor ) ? = #isolation,
121125 sourceLocation: SourceLocation = #_sourceLocation,
122126 _ body: @escaping ( ) async throws -> Bool
123127) async throws {
124128 let poller = Poller (
125129 pollingBehavior: . passesOnce,
126- pollingIterations : getValueFromPollingTrait (
127- providedValue: maxPollingIterations ,
128- default: defaultPollingConfiguration. maxPollingIterations ,
129- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
130+ pollingDuration : getValueFromPollingTrait (
131+ providedValue: pollingDuration ,
132+ default: defaultPollingConfiguration. pollingDuration ,
133+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
130134 ) ,
131135 pollingInterval: getValueFromPollingTrait (
132136 providedValue: pollingInterval,
@@ -153,12 +157,14 @@ public func requirePassesEventually(
153157/// - Parameters:
154158/// - comment: An optional comment to apply to any issues generated by this
155159/// function.
156- /// - maxPollingIterations: The maximum amount of times to attempt polling.
160+ /// - pollingDuration: The expected length of time to continue polling for.
161+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
162+ /// on highly-loaded systems with a lot of tests running.
157163/// If nil, this uses whatever value is specified under the last
158164/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
159165/// suite.
160166/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
161- /// polling will be attempted 1000 times before recording an issue.
167+ /// polling will be attempted for about 1 second before recording an issue.
162168/// `maxPollingIterations` must be greater than 0.
163169/// - pollingInterval: The minimum amount of time to wait between polling
164170/// attempts.
@@ -186,18 +192,18 @@ public func requirePassesEventually(
186192@discardableResult
187193public func confirmPassesEventually< R> (
188194 _ comment: Comment ? = nil ,
189- maxPollingIterations : Int ? = nil ,
195+ pollingDuration : Duration ? = nil ,
190196 pollingInterval: Duration ? = nil ,
191197 isolation: isolated ( any Actor ) ? = #isolation,
192198 sourceLocation: SourceLocation = #_sourceLocation,
193199 _ body: @escaping ( ) async throws -> sending R?
194200) async throws -> R {
195201 let poller = Poller (
196202 pollingBehavior: . passesOnce,
197- pollingIterations : getValueFromPollingTrait (
198- providedValue: maxPollingIterations ,
199- default: defaultPollingConfiguration. maxPollingIterations ,
200- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
203+ pollingDuration : getValueFromPollingTrait (
204+ providedValue: pollingDuration ,
205+ default: defaultPollingConfiguration. pollingDuration ,
206+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
201207 ) ,
202208 pollingInterval: getValueFromPollingTrait (
203209 providedValue: pollingInterval,
@@ -226,11 +232,13 @@ public func confirmPassesEventually<R>(
226232/// - Parameters:
227233/// - comment: An optional comment to apply to any issues generated by this
228234/// function.
229- /// - maxPollingIterations: The maximum amount of times to attempt polling.
235+ /// - pollingDuration: The expected length of time to continue polling for.
236+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
237+ /// on highly-loaded systems with a lot of tests running.
230238/// If nil, this uses whatever value is specified under the last
231239/// ``ConfirmAlwaysPassesConfigurationTrait`` added to the test or suite.
232240/// If no ``ConfirmAlwaysPassesConfigurationTrait`` has been added, then
233- /// polling will be attempted 1000 times before recording an issue.
241+ /// polling will be attempted for about 1 second before recording an issue.
234242/// `maxPollingIterations` must be greater than 0.
235243/// - pollingInterval: The minimum amount of time to wait between polling
236244/// attempts.
@@ -251,18 +259,18 @@ public func confirmPassesEventually<R>(
251259@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
252260public func confirmAlwaysPasses(
253261 _ comment: Comment ? = nil ,
254- maxPollingIterations : Int ? = nil ,
262+ pollingDuration : Duration ? = nil ,
255263 pollingInterval: Duration ? = nil ,
256264 isolation: isolated ( any Actor ) ? = #isolation,
257265 sourceLocation: SourceLocation = #_sourceLocation,
258266 _ body: @escaping ( ) async throws -> Bool
259267) async {
260268 let poller = Poller (
261269 pollingBehavior: . passesAlways,
262- pollingIterations : getValueFromPollingTrait (
263- providedValue: maxPollingIterations ,
264- default: defaultPollingConfiguration. maxPollingIterations ,
265- \ConfirmAlwaysPassesConfigurationTrait . maxPollingIterations
270+ pollingDuration : getValueFromPollingTrait (
271+ providedValue: pollingDuration ,
272+ default: defaultPollingConfiguration. pollingDuration ,
273+ \ConfirmAlwaysPassesConfigurationTrait . pollingDuration
266274 ) ,
267275 pollingInterval: getValueFromPollingTrait (
268276 providedValue: pollingInterval,
@@ -286,11 +294,13 @@ public func confirmAlwaysPasses(
286294/// - Parameters:
287295/// - comment: An optional comment to apply to any issues generated by this
288296/// function.
289- /// - maxPollingIterations: The maximum amount of times to attempt polling.
297+ /// - pollingDuration: The expected length of time to continue polling for.
298+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
299+ /// on highly-loaded systems with a lot of tests running.
290300/// If nil, this uses whatever value is specified under the last
291301/// ``ConfirmAlwaysPassesConfigurationTrait`` added to the test or suite.
292302/// If no ``ConfirmAlwaysPassesConfigurationTrait`` has been added, then
293- /// polling will be attempted 1000 times before recording an issue.
303+ /// polling will be attempted for about 1 second before recording an issue.
294304/// `maxPollingIterations` must be greater than 0.
295305/// - pollingInterval: The minimum amount of time to wait between polling
296306/// attempts.
@@ -314,18 +324,18 @@ public func confirmAlwaysPasses(
314324@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
315325public func requireAlwaysPasses(
316326 _ comment: Comment ? = nil ,
317- maxPollingIterations : Int ? = nil ,
327+ pollingDuration : Duration ? = nil ,
318328 pollingInterval: Duration ? = nil ,
319329 isolation: isolated ( any Actor ) ? = #isolation,
320330 sourceLocation: SourceLocation = #_sourceLocation,
321331 _ body: @escaping ( ) async throws -> Bool
322332) async throws {
323333 let poller = Poller (
324334 pollingBehavior: . passesAlways,
325- pollingIterations : getValueFromPollingTrait (
326- providedValue: maxPollingIterations ,
327- default: defaultPollingConfiguration. maxPollingIterations ,
328- \ConfirmAlwaysPassesConfigurationTrait . maxPollingIterations
335+ pollingDuration : getValueFromPollingTrait (
336+ providedValue: pollingDuration ,
337+ default: defaultPollingConfiguration. pollingDuration ,
338+ \ConfirmAlwaysPassesConfigurationTrait . pollingDuration
329339 ) ,
330340 pollingInterval: getValueFromPollingTrait (
331341 providedValue: pollingInterval,
@@ -466,8 +476,8 @@ private struct Poller {
466476 /// while the expression continues to pass)
467477 let pollingBehavior : PollingBehavior
468478
469- // How many times to poll
470- let pollingIterations : Int
479+ // Approximately how long to poll for
480+ let pollingDuration : Duration
471481 // Minimum waiting period between polling
472482 let pollingInterval : Duration
473483
@@ -526,9 +536,16 @@ private struct Poller {
526536 isolation: isolated ( any Actor ) ? ,
527537 _ body: @escaping ( ) async -> sending R?
528538 ) async -> R ? {
529- precondition ( pollingIterations > 0 )
539+ precondition ( pollingDuration > Duration . zero )
530540 precondition ( pollingInterval > Duration . zero)
541+ precondition ( pollingDuration > pollingInterval)
542+ let durationSeconds = Double ( pollingDuration. components. seconds) + Double( pollingDuration. components. attoseconds) * 1e-18
543+ let intervalSeconds = Double ( pollingInterval. components. seconds) + Double( pollingInterval. components. attoseconds) * 1e-18
544+
545+ let pollingIterations = max ( Int ( durationSeconds / intervalSeconds) , 1 )
546+
531547 let ( result, value) = await poll (
548+ pollingIterations: pollingIterations,
532549 expression: body
533550 )
534551 if let issue = result. issue (
@@ -552,12 +569,14 @@ private struct Poller {
552569 /// `.passesOnce`
553570 ///
554571 /// - Parameters:
572+ /// - pollingIterations: The maximum amount of times to continue polling.
555573 /// - expression: An expression to continuously evaluate
556574 /// - behavior: The polling behavior to use
557575 /// - timeout: How long to poll for unitl the timeout triggers.
558576 /// - Returns: The result of this polling and the most recent value if the
559577 /// result is .finished, otherwise nil.
560578 private func poll< R> (
579+ pollingIterations: Int ,
561580 isolation: isolated ( any Actor ) ? = #isolation,
562581 expression: @escaping ( ) async -> sending R?
563582 ) async -> ( PollResult , R ? ) {
0 commit comments