10
10
// XCTWaiter.swift
11
11
//
12
12
13
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
14
13
import CoreFoundation
15
- #endif
16
14
17
15
/// Events are reported to the waiter's delegate via these methods. XCTestCase conforms to this
18
16
/// protocol and will automatically report timeouts and other unexpected events as test failures.
@@ -119,7 +117,7 @@ open class XCTWaiter {
119
117
internal var waitSourceLocation : SourceLocation ?
120
118
private weak var manager : WaiterManager < XCTWaiter > ?
121
119
private var runLoop : RunLoop ?
122
-
120
+ private var runLoopSource : RunLoop . _Source ?
123
121
private weak var _delegate : XCTWaiterDelegate ?
124
122
private let delegateQueue = DispatchQueue ( label: " org.swift.XCTest.XCTWaiter.delegate " )
125
123
@@ -210,7 +208,8 @@ open class XCTWaiter {
210
208
queue_configureExpectations ( expectations)
211
209
state = . waiting( state: waitingState)
212
210
self . runLoop = runLoop
213
-
211
+ self . runLoopSource = RunLoop . _Source ( )
212
+ self . runLoop? . _add ( self . runLoopSource!, forMode: . default)
214
213
queue_validateExpectationFulfillment ( dueToTimeout: false )
215
214
}
216
215
@@ -219,14 +218,7 @@ open class XCTWaiter {
219
218
self . manager = manager
220
219
221
220
// Begin the core wait loop.
222
- let timeoutTimestamp = Date . timeIntervalSinceReferenceDate + timeout
223
- while !isFinished {
224
- let remaining = timeoutTimestamp - Date. timeIntervalSinceReferenceDate
225
- if remaining <= 0 {
226
- break
227
- }
228
- primitiveWait ( using: runLoop, duration: remaining)
229
- }
221
+ primitiveWait ( using: runLoop, duration: timeout)
230
222
231
223
manager. stopManaging ( self )
232
224
self . manager = nil
@@ -358,22 +350,12 @@ open class XCTWaiter {
358
350
359
351
private extension XCTWaiter {
360
352
func primitiveWait( using runLoop: RunLoop , duration timeout: TimeInterval ) {
361
- // The contract for `primitiveWait(for:)` explicitly allows waiting for a shorter period than requested
362
- // by the `timeout` argument. Only run for a short time in case `cancelPrimitiveWait()` was called and
363
- // issued `CFRunLoopStop` just before we reach this point.
364
- let timeIntervalToRun = min ( 0.1 , timeout)
365
-
366
- // RunLoop.run(mode:before:) should have @discardableResult <rdar://problem/45371901>
367
- _ = runLoop. run ( mode: . default, before: Date ( timeIntervalSinceNow: timeIntervalToRun) )
353
+ runLoop. run ( until: . init( timeIntervalSinceNow: timeout) )
368
354
}
369
355
370
356
func cancelPrimitiveWait( ) {
371
- guard let runLoop = runLoop else { return }
372
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
373
- CFRunLoopStop ( runLoop. getCFRunLoop ( ) )
374
- #else
375
- runLoop. _stop ( )
376
- #endif
357
+ dispatchPrecondition ( condition: . onQueue( XCTWaiter . subsystemQueue) )
358
+ runLoopSource? . invalidate ( )
377
359
}
378
360
}
379
361
0 commit comments