Skip to content

Commit 9b64c4a

Browse files
author
pranav shenoy
committed
Using RunLoopSource in XCTestCase.waitForExpectations(withTimeout:file:line:handler:)
1 parent 1764c54 commit 9b64c4a

File tree

1 file changed

+7
-25
lines changed

1 file changed

+7
-25
lines changed

Sources/XCTest/Public/Asynchronous/XCTWaiter.swift

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
// XCTWaiter.swift
1111
//
1212

13-
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
1413
import CoreFoundation
15-
#endif
1614

1715
/// Events are reported to the waiter's delegate via these methods. XCTestCase conforms to this
1816
/// protocol and will automatically report timeouts and other unexpected events as test failures.
@@ -119,7 +117,7 @@ open class XCTWaiter {
119117
internal var waitSourceLocation: SourceLocation?
120118
private weak var manager: WaiterManager<XCTWaiter>?
121119
private var runLoop: RunLoop?
122-
120+
private var runLoopSource: RunLoop._Source?
123121
private weak var _delegate: XCTWaiterDelegate?
124122
private let delegateQueue = DispatchQueue(label: "org.swift.XCTest.XCTWaiter.delegate")
125123

@@ -210,7 +208,8 @@ open class XCTWaiter {
210208
queue_configureExpectations(expectations)
211209
state = .waiting(state: waitingState)
212210
self.runLoop = runLoop
213-
211+
self.runLoopSource = RunLoop._Source()
212+
self.runLoop?._add(self.runLoopSource!, forMode: .default)
214213
queue_validateExpectationFulfillment(dueToTimeout: false)
215214
}
216215

@@ -219,14 +218,7 @@ open class XCTWaiter {
219218
self.manager = manager
220219

221220
// 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)
230222

231223
manager.stopManaging(self)
232224
self.manager = nil
@@ -358,22 +350,12 @@ open class XCTWaiter {
358350

359351
private extension XCTWaiter {
360352
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))
368354
}
369355

370356
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()
377359
}
378360
}
379361

0 commit comments

Comments
 (0)