Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XCTestCase.fulfillment(…) missing on Linux #436

Closed
tonyarnold opened this issue Apr 1, 2023 · 8 comments · Fixed by #453
Closed

XCTestCase.fulfillment(…) missing on Linux #436

tonyarnold opened this issue Apr 1, 2023 · 8 comments · Fixed by #453
Assignees

Comments

@tonyarnold
Copy link

Hi folks,

It looks like the fulfillment(…) methods on XCTestCase and XCTWaiter are both missing on Linux.

It would be helpful to have API parity here, as Xcode 14.3 complains if I use the older wait(…) methods:

Instance method 'wait' is unavailable from asynchronous contexts; Use await fulfillment(of:timeout:enforceOrder:) instead; this is an error in Swift 6

Here are the missing methods:

extension XCTestCase {

    /// Waits on a group of expectations for up to the specified timeout,
    /// optionally enforcing their order of fulfillment.
    ///
    /// - Parameters:
    ///     - expectations: An array of expectations that must be fulfilled.
    ///     - seconds: The number of seconds within which all expectations must
    ///         be fulfilled. The default timeout allows the test to run until
    ///         it reaches its execution time allowance.
    ///     - enforceOrderOfFulfillment: If `true`, the expectations specified
    ///         by the `expectations` parameter must be satisfied in the order
    ///         they appear in the array.
    ///
    /// Expectations can only appear in the list once. This function may return
    /// early based on fulfillment of the provided expectations.
    ///
    /// - Note: If you do not specify a timeout when calling this function, it
    ///     is recommended that you enable test timeouts to prevent a runaway
    ///     expectation from hanging the test.
    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
    @nonobjc public func fulfillment(of expectations: [XCTestExpectation], timeout seconds: TimeInterval = .infinity, enforceOrder enforceOrderOfFulfillment: Bool = false) async
}

extension XCTWaiter {

    /// Waits on a group of expectations for up to the specified timeout,
    /// optionally enforcing their order of fulfillment.
    ///
    /// - Parameters:
    ///     - expectations: An array of expectations that must be fulfilled.
    ///     - seconds: The number of seconds within which all expectations must
    ///         be fulfilled. The default timeout allows the test to run until
    ///         it reaches its execution time allowance.
    ///     - enforceOrderOfFulfillment: If `true`, the expectations specified
    ///         by the `expectations` parameter must be satisfied in the order
    ///         they appear in the array.
    ///
    /// - Returns: A value describing the outcome of waiting for `expectations`.
    ///
    /// Expectations can only appear in the list once. This function may return
    /// early based on fulfillment of the provided expectations.
    ///
    /// - Note: If you do not specify a timeout when calling this function, it
    ///     is recommended that you enable test timeouts to prevent a runaway
    ///     expectation from hanging the test.
    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
    @discardableResult
    @nonobjc public func fulfillment(of expectations: [XCTestExpectation], timeout seconds: TimeInterval = .infinity, enforceOrder enforceOrderOfFulfillment: Bool = false) async -> XCTWaiter.Result

    /// Creates a waiter that waits on a group of expectations for up to the
    /// specified timeout, optionally enforcing their order of fulfillment.
    ///
    /// - Parameters:
    ///     - expectations: An array of expectations that must be fulfilled.
    ///     - seconds: The number of seconds within which all expectations must
    ///         be fulfilled. The default timeout allows the test to run until
    ///         it reaches its execution time allowance.
    ///     - enforceOrderOfFulfillment: If `true`, the expectations specified
    ///         by the `expectations` parameter must be satisfied in the order
    ///         they appear in the array.
    ///
    /// - Returns: A value describing the outcome of waiting for `expectations`.
    ///
    /// Expectations can only appear in the list once. This function may return
    /// early based on fulfillment of the provided expectations.
    ///
    /// The waiter is discarded when the wait completes.
    ///
    /// - Note: If you do not specify a timeout when calling this function, it
    ///     is recommended that you enable test timeouts to prevent a runaway
    ///     expectation from hanging the test.
    @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
    @nonobjc public class func fulfillment(of expectations: [XCTestExpectation], timeout seconds: TimeInterval = .infinity, enforceOrder enforceOrderOfFulfillment: Bool = false) async -> XCTWaiter.Result
}
@tmaly1980
Copy link

I've also checked Xcode 14.2/iOS 16.2 on an M1 and Intel MacBook Pro, and it keeps saying "Cannot find 'fulfillment' in scope" . Any clue why?

@tonyarnold
Copy link
Author

@tmaly1980 this seems like a question better asked on StackOverflow than on a specific issue on GitHub, as it's like to be your project configuration at fault (check your minimum deployment targets).

@tonyarnold
Copy link
Author

Thanks, @grynspan ❤️

@grynspan
Copy link
Contributor

Always happy to help!

@award999
Copy link

@grynspan saw this was merged into main, what are the chances of it making into 5.9? Kind of needed to do asynchronous testing on Linux

@grynspan
Copy link
Contributor

@briancroom is looking into it.

grynspan added a commit that referenced this issue Jun 28, 2023
XCTestCase.fulfillment(…) missing on Linux #436
@joshuawright11
Copy link

joshuawright11 commented Sep 2, 2023

If anyone stumbles upon this before Swift 5.10/whatever release this becomes available, here is the extension I use for support on Linux (based on @grynspan's PR).

When this is officially released, you should just be able to remove the extension.

#if os(Linux)
import XCTest

extension XCTestCase {
    /// Wait on an array of expectations for up to the specified timeout, and optionally specify whether they
    /// must be fulfilled in the given order. May return early based on fulfillment of the waited on expectations.
    ///
    /// - Parameter expectations: The expectations to wait on.
    /// - Parameter timeout: The maximum total time duration to wait on all expectations.
    /// - Parameter enforceOrder: Specifies whether the expectations must be fulfilled in the order
    ///   they are specified in the `expectations` Array. Default is false.
    /// - Parameter file: The file name to use in the error message if
    ///   expectations are not fulfilled before the given timeout. Default is the file
    ///   containing the call to this method. It is rare to provide this
    ///   parameter when calling this method.
    /// - Parameter line: The line number to use in the error message if the
    ///   expectations are not fulfilled before the given timeout. Default is the line
    ///   number of the call to this method in the calling file. It is rare to
    ///   provide this parameter when calling this method.
    ///
    /// - SeeAlso: XCTWaiter
    func fulfillment(of expectations: [XCTestExpectation], timeout: TimeInterval, enforceOrder: Bool = false) async {
        return await withCheckedContinuation { continuation in
            // This function operates by blocking a background thread instead of one owned by libdispatch or by the
            // Swift runtime (as used by Swift concurrency.) To ensure we use a thread owned by neither subsystem, use
            // Foundation's Thread.detachNewThread(_:).
            Thread.detachNewThread { [self] in
                wait(for: expectations, timeout: timeout, enforceOrder: enforceOrder)
                continuation.resume()
            }
        }
    }
}
#endif

dirtyhenry added a commit to dirtyhenry/swift-blocks that referenced this issue Sep 4, 2023
@grynspan
Copy link
Contributor

grynspan commented Sep 5, 2023

For anyone watching at home: if you're developing for a Darwin-based platform (macOS, iOS, etc.) using the version of XCTest that ships with Xcode 14.3 or later, this API is already available and you don't need the category.

LosFarmosCTL added a commit to LosFarmosCTL/swift-twitch-client that referenced this issue Jan 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants