diff --git a/CMakeLists.txt b/CMakeLists.txt index a386ef08..14ecd0fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,15 @@ project(XCTest LANGUAGES Swift) option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(USE_FOUNDATION_FRAMEWORK "Use Foundation.framework on Darwin" NO) -if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) +set(DISABLE_XCTWAITER_default NO) + +if(CMAKE_SYSTEM_PROCESSOR STREQUAL wasm32) + set(DISABLE_XCTWAITER_default ON) +endif() + +option(DISABLE_XCTWAITER "Disable XCTWaiter" "${DISABLE_XCTWAITER_default}") + +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin AND NOT DISABLE_XCTWAITER) find_package(dispatch CONFIG REQUIRED) find_package(Foundation CONFIG REQUIRED) endif() @@ -49,6 +57,12 @@ add_library(XCTest Sources/XCTest/Public/Asynchronous/XCTWaiter.swift Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift) + +if(DISABLE_XCTWAITER) + target_compile_definitions(XCTest PRIVATE + DISABLE_XCTWAITER) +endif() + if(USE_FOUNDATION_FRAMEWORK) target_compile_definitions(XCTest PRIVATE USE_FOUNDATION_FRAMEWORK) diff --git a/Sources/XCTest/Private/WaiterManager.swift b/Sources/XCTest/Private/WaiterManager.swift index f705165f..2366e0ed 100644 --- a/Sources/XCTest/Private/WaiterManager.swift +++ b/Sources/XCTest/Private/WaiterManager.swift @@ -9,6 +9,7 @@ // // WaiterManager.swift // +#if !DISABLE_XCTWAITER internal protocol ManageableWaiter: AnyObject, Equatable { var isFinished: Bool { get } @@ -143,3 +144,5 @@ internal final class WaiterManager : NSObject { } } + +#endif diff --git a/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift b/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift index 83f43fe4..db45f88a 100644 --- a/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift +++ b/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift @@ -12,8 +12,14 @@ extension XCTestCase { /// Supports async and sync throwing methods. final class TeardownBlocksState { + #if DISABLE_XCTWAITER + typealias TeardownBlock = @Sendable @MainActor () async throws -> Void + #else + typealias TeardownBlock = () throws -> Void + #endif + private var wasFinalized = false - private var blocks: [() throws -> Void] = [] + private var blocks: [TeardownBlock] = [] // We don't want to overload append(_:) below because of how Swift will implicitly promote sync closures to async closures, // which can unexpectedly change their semantics in difficult to track down ways. @@ -21,20 +27,27 @@ extension XCTestCase { // Because of this, we chose the unusual decision to forgo overloading (which is a super sweet language feature <3) to prevent this issue from surprising any contributors to corelibs-xctest @available(macOS 12.0, *) func appendAsync(_ block: @Sendable @escaping () async throws -> Void) { + #if DISABLE_XCTWAITER + XCTestCase.subsystemQueue.sync { + precondition(wasFinalized == false, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued") + blocks.append(block) + } + #else self.append { try awaitUsingExpectation { try await block() } } + #endif } func append(_ block: @escaping () throws -> Void) { - XCTWaiter.subsystemQueue.sync { + XCTestCase.subsystemQueue.sync { precondition(wasFinalized == false, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued") blocks.append(block) } } - func finalize() -> [() throws -> Void] { - XCTWaiter.subsystemQueue.sync { + func finalize() -> [TeardownBlock] { + XCTestCase.subsystemQueue.sync { precondition(wasFinalized == false, "API violation -- attempting to run teardown blocks after they've already run") wasFinalized = true return blocks diff --git a/Sources/XCTest/Public/Asynchronous/XCTNSNotificationExpectation.swift b/Sources/XCTest/Public/Asynchronous/XCTNSNotificationExpectation.swift index dc867804..7d66e64d 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTNSNotificationExpectation.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTNSNotificationExpectation.swift @@ -10,6 +10,8 @@ // XCTNSNotificationExpectation.swift // +#if !DISABLE_XCTWAITER + /// Expectation subclass for waiting on a condition defined by a Foundation Notification instance. open class XCTNSNotificationExpectation: XCTestExpectation { @@ -114,3 +116,5 @@ open class XCTNSNotificationExpectation: XCTestExpectation { /// - SeeAlso: `XCTNSNotificationExpectation.handler` @available(*, deprecated, renamed: "XCTNSNotificationExpectation.Handler") public typealias XCNotificationExpectationHandler = XCTNSNotificationExpectation.Handler + +#endif diff --git a/Sources/XCTest/Public/Asynchronous/XCTNSPredicateExpectation.swift b/Sources/XCTest/Public/Asynchronous/XCTNSPredicateExpectation.swift index b41bca14..70fa2b96 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTNSPredicateExpectation.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTNSPredicateExpectation.swift @@ -10,6 +10,8 @@ // XCTNSPredicateExpectation.swift // +#if !DISABLE_XCTWAITER + /// Expectation subclass for waiting on a condition defined by an NSPredicate and an optional object. open class XCTNSPredicateExpectation: XCTestExpectation { @@ -133,3 +135,4 @@ open class XCTNSPredicateExpectation: XCTestExpectation { /// - SeeAlso: `XCTNSPredicateExpectation.handler` @available(*, deprecated, renamed: "XCTNSPredicateExpectation.Handler") public typealias XCPredicateExpectationHandler = XCTNSPredicateExpectation.Handler +#endif diff --git a/Sources/XCTest/Public/Asynchronous/XCTWaiter+Validation.swift b/Sources/XCTest/Public/Asynchronous/XCTWaiter+Validation.swift index 5ff4643c..c9dd621e 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTWaiter+Validation.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTWaiter+Validation.swift @@ -9,6 +9,7 @@ // // XCTWaiter+Validation.swift // +#if !DISABLE_XCTWAITER protocol XCTWaiterValidatableExpectation: Equatable { var isFulfilled: Bool { get } @@ -87,3 +88,5 @@ extension XCTWaiter { return .incomplete } } + +#endif diff --git a/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift b/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift index f19b344f..ac114578 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift @@ -9,6 +9,7 @@ // // XCTWaiter.swift // +#if !DISABLE_XCTWAITER #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import CoreFoundation @@ -479,3 +480,5 @@ extension XCTWaiter: ManageableWaiter { } } } + +#endif diff --git a/Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift b/Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift index b9935ff7..34d43e94 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift @@ -11,6 +11,8 @@ // Methods on XCTestCase for testing asynchronous operations // +#if !DISABLE_XCTWAITER + public extension XCTestCase { /// Creates a point of synchronization in the flow of a test. Only one @@ -265,3 +267,4 @@ internal extension XCTestCase { expected: false) } } +#endif diff --git a/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift b/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift index 16564dd9..829ba798 100644 --- a/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift +++ b/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift @@ -9,6 +9,7 @@ // // XCTestExpectation.swift // +#if !DISABLE_XCTWAITER /// Expectations represent specific conditions in asynchronous testing. open class XCTestExpectation: @unchecked Sendable { @@ -320,3 +321,5 @@ extension XCTestExpectation: CustomStringConvertible { return expectationDescription } } + +#endif diff --git a/Sources/XCTest/Public/XCAbstractTest.swift b/Sources/XCTest/Public/XCAbstractTest.swift index cf37cba0..f1f06b3b 100644 --- a/Sources/XCTest/Public/XCAbstractTest.swift +++ b/Sources/XCTest/Public/XCAbstractTest.swift @@ -36,20 +36,43 @@ open class XCTest { /// testRunClass. If the test has not yet been run, this will be nil. open private(set) var testRun: XCTestRun? = nil + #if DISABLE_XCTWAITER + internal var performTask: Task? + + internal func _performAsync(_ run: XCTestRun) async { + fatalError("Must be overridden by subclasses.") + } + internal func _runAsync() async { + guard let testRunType = testRunClass as? XCTestRun.Type else { + fatalError("XCTest.testRunClass must be a kind of XCTestRun.") + } + testRun = testRunType.init(test: self) + await _performAsync(testRun!) + } + #endif + /// The method through which tests are executed. Must be overridden by /// subclasses. + #if DISABLE_XCTWAITER + @available(*, unavailable) + #endif open func perform(_ run: XCTestRun) { fatalError("Must be overridden by subclasses.") } /// Creates an instance of the `testRunClass` and passes it as a parameter /// to `perform()`. + #if DISABLE_XCTWAITER + @available(*, unavailable) + #endif open func run() { + #if !DISABLE_XCTWAITER guard let testRunType = testRunClass as? XCTestRun.Type else { fatalError("XCTest.testRunClass must be a kind of XCTestRun.") } testRun = testRunType.init(test: self) perform(testRun!) + #endif } /// Async setup method called before the invocation of `setUpWithError` for each test method in the class. diff --git a/Sources/XCTest/Public/XCTestCase.swift b/Sources/XCTest/Public/XCTestCase.swift index 4d734cd8..2d899b91 100644 --- a/Sources/XCTest/Public/XCTestCase.swift +++ b/Sources/XCTest/Public/XCTestCase.swift @@ -36,6 +36,12 @@ open class XCTestCase: XCTest { private var skip: XCTSkip? +#if DISABLE_XCTWAITER + /// A task that ends when the test closure has actually finished running. + /// This is used to ensure that all async work has completed. + fileprivate var testClosureTask: Task? +#endif + /// The name of the test case, consisting of its class name and the method /// name it will run. open override var name: String { @@ -48,6 +54,25 @@ open class XCTestCase: XCTest { return 1 } + #if DISABLE_XCTWAITER && os(WASI) + /// Single-threaded queue without any actual queueing + struct SubsystemQueue { + init(label: String) {} + + func sync(_ body: () -> T) -> T { + body() + } + func async(_ body: @escaping () -> Void) { + body() + } + } + #else + typealias SubsystemQueue = DispatchQueue + #endif + + internal static let subsystemQueue = SubsystemQueue(label: "org.swift.XCTestCase") + + #if !DISABLE_XCTWAITER @MainActor internal var currentWaiter: XCTWaiter? @@ -81,6 +106,7 @@ open class XCTestCase: XCTest { } } } + #endif /// An internal object implementing performance measurements. internal var _performanceMeter: PerformanceMeter? @@ -89,6 +115,20 @@ open class XCTestCase: XCTest { return XCTestCaseRun.self } + #if DISABLE_XCTWAITER + override func _performAsync(_ run: XCTestRun) async { + guard let testRun = run as? XCTestCaseRun else { + fatalError("Wrong XCTestRun class.") + } + + XCTCurrentTestCase = self + testRun.start() + await _invokeTestAsync() + + testRun.stop() + XCTCurrentTestCase = nil + } + #else open override func perform(_ run: XCTestRun) { guard let testRun = run as? XCTestCaseRun else { fatalError("Wrong XCTestRun class.") @@ -104,6 +144,7 @@ open class XCTestCase: XCTest { testRun.stop() XCTCurrentTestCase = nil } + #endif /// The designated initializer for SwiftXCTest's XCTestCase. /// - Note: Like the designated initializer for Apple XCTest's XCTestCase, @@ -114,9 +155,46 @@ open class XCTestCase: XCTest { self.testClosure = testClosure } + #if DISABLE_XCTWAITER + @MainActor internal func _invokeTestAsync() async { + await performSetUpSequence() + + do { + if skip == nil { + try testClosure(self) + } + if let task = testClosureTask { + _ = try await task.value + } + } catch { + if error.xct_shouldRecordAsTestFailure { + recordFailure(for: error) + } + + if error.xct_shouldRecordAsTestSkip { + if let skip = error as? XCTSkip { + self.skip = skip + } else { + self.skip = XCTSkip(error: error, message: nil, sourceLocation: nil) + } + } + } + + if let skip = skip { + testRun?.recordSkip(description: skip.summary, sourceLocation: skip.sourceLocation) + } + + await performTearDownSequence() + } + #endif + /// Invoking a test performs its setUp, invocation, and tearDown. In /// general this should not be called directly. + #if DISABLE_XCTWAITER + @available(*, unavailable) + #endif open func invokeTest() { + #if !DISABLE_XCTWAITER performSetUpSequence() do { @@ -142,6 +220,7 @@ open class XCTestCase: XCTest { } performTearDownSequence() + #endif } /// Records a failure in the execution of the test and is used by all test @@ -211,31 +290,21 @@ open class XCTestCase: XCTest { teardownBlocksState.appendAsync(block) } - private func performSetUpSequence() { - func handleErrorDuringSetUp(_ error: Error) { - if error.xct_shouldRecordAsTestFailure { - recordFailure(for: error) - } - - if error.xct_shouldSkipTestInvocation { - if let skip = error as? XCTSkip { - self.skip = skip - } else { - self.skip = XCTSkip(error: error, message: nil, sourceLocation: nil) - } - } + private func handleErrorDuringSetUp(_ error: Error) { + if error.xct_shouldRecordAsTestFailure { + recordFailure(for: error) } - do { - if #available(macOS 12.0, *) { - try awaitUsingExpectation { - try await self.setUp() - } + if error.xct_shouldSkipTestInvocation { + if let skip = error as? XCTSkip { + self.skip = skip + } else { + self.skip = XCTSkip(error: error, message: nil, sourceLocation: nil) } - } catch { - handleErrorDuringSetUp(error) } + } + private func performPostSetup() { do { try setUpWithError() } catch { @@ -245,32 +314,82 @@ open class XCTestCase: XCTest { setUp() } - private func performTearDownSequence() { - func handleErrorDuringTearDown(_ error: Error) { - if error.xct_shouldRecordAsTestFailure { - recordFailure(for: error) + private func handleErrorDuringTearDown(_ error: Error) { + if error.xct_shouldRecordAsTestFailure { + recordFailure(for: error) + } + } + + private func performSyncTearDown() { + tearDown() + + do { + try tearDownWithError() + } catch { + handleErrorDuringTearDown(error) + } + } + + #if DISABLE_XCTWAITER + @MainActor private func runTeardownBlocks() async { + for block in self.teardownBlocksState.finalize().reversed() { + do { + try await block() + } catch { + handleErrorDuringTearDown(error) } } + } - func runTeardownBlocks() { - for block in self.teardownBlocksState.finalize().reversed() { - do { - try block() - } catch { - handleErrorDuringTearDown(error) - } + @MainActor private func performSetUpSequence() async { + do { + if #available(macOS 12.0, *) { + try await self.setUp() } + } catch { + handleErrorDuringSetUp(error) } - runTeardownBlocks() + performPostSetup() + } - tearDown() + @MainActor private func performTearDownSequence() async { + await runTeardownBlocks() + performSyncTearDown() do { - try tearDownWithError() + try await self.tearDown() } catch { handleErrorDuringTearDown(error) } + } + #else + private func runTeardownBlocks() { + for block in self.teardownBlocksState.finalize().reversed() { + do { + try block() + } catch { + handleErrorDuringTearDown(error) + } + } + } + + private func performSetUpSequence() { + do { + if #available(macOS 12.0, *) { + try awaitUsingExpectation { + try await self.setUp() + } + } + } catch { + handleErrorDuringSetUp(error) + } + performPostSetup() + } + + private func performTearDownSequence() { + runTeardownBlocks() + performSyncTearDown() do { if #available(macOS 12.0, *) { @@ -282,6 +401,7 @@ open class XCTestCase: XCTest { handleErrorDuringTearDown(error) } } + #endif open var continueAfterFailure: Bool { get { @@ -325,14 +445,27 @@ private func test(_ testFunc: @escaping (T) -> () throws -> Void) public func asyncTest( _ testClosureGenerator: @escaping (T) -> () async throws -> Void ) -> (T) -> () throws -> Void { +#if DISABLE_XCTWAITER + return { (testType: T) in + let testClosure = testClosureGenerator(testType) + return { + assert(testType.testClosureTask == nil, "Async test case \(testType) cannot be run more than once") + testType.testClosureTask = Task { + try await testClosure() + } + } + } +#else return { (testType: T) in let testClosure = testClosureGenerator(testType) return { try awaitUsingExpectation(testClosure) } } +#endif } +#if !DISABLE_XCTWAITER @available(macOS 12.0, *) func awaitUsingExpectation( _ closure: @escaping () async throws -> Void @@ -356,6 +489,7 @@ func awaitUsingExpectation( throw error } } +#endif private final class ThrownErrorWrapper: @unchecked Sendable { @@ -363,10 +497,10 @@ private final class ThrownErrorWrapper: @unchecked Sendable { var error: Error? { get { - XCTWaiter.subsystemQueue.sync { _error } + XCTestCase.subsystemQueue.sync { _error } } set { - XCTWaiter.subsystemQueue.sync { _error = newValue } + XCTestCase.subsystemQueue.sync { _error = newValue } } } } diff --git a/Sources/XCTest/Public/XCTestMain.swift b/Sources/XCTest/Public/XCTestMain.swift index 33572e72..1bbd6538 100644 --- a/Sources/XCTest/Public/XCTestMain.swift +++ b/Sources/XCTest/Public/XCTestMain.swift @@ -69,12 +69,70 @@ /// - Returns: The exit code to use when the process terminates. `EXIT_SUCCESS` /// indicates success, while any other value (including `EXIT_FAILURE`) /// indicates failure. +#if DISABLE_XCTWAITER +@_disfavoredOverload +public func XCTMain( + _ testCases: [XCTestCaseEntry], + arguments: [String] = CommandLine.arguments, + observers: [XCTestObservation]? = nil +) async -> CInt { + // Async-version of XCTMain() + switch XCTMainMisc(testCases, arguments: arguments, observers: observers) { + case .exitCode(let code): + return code + case .testSuite(let rootTestSuite, let testBundle, let observers): + // Add a test observer that prints test progress to stdout. + let observationCenter = XCTestObservationCenter.shared + for observer in observers { + observationCenter.addTestObserver(observer) + } + + observationCenter.testBundleWillStart(testBundle) + await rootTestSuite._runAsync() + observationCenter.testBundleDidFinish(testBundle) + + return rootTestSuite.testRun!.totalFailureCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE + } +} +#else @_disfavoredOverload public func XCTMain( _ testCases: [XCTestCaseEntry], arguments: [String] = CommandLine.arguments, observers: [XCTestObservation]? = nil ) -> CInt { + // Sync-version of XCTMain() + switch XCTMainMisc(testCases, arguments: arguments, observers: observers) { + case .exitCode(let code): + return code + case .testSuite(let rootTestSuite, let testBundle, let observers): + // Add a test observer that prints test progress to stdout. + let observationCenter = XCTestObservationCenter.shared + for observer in observers { + observationCenter.addTestObserver(observer) + } + + observationCenter.testBundleWillStart(testBundle) + rootTestSuite.run() + observationCenter.testBundleDidFinish(testBundle) + + return rootTestSuite.testRun!.totalFailureCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE + } +} +#endif + +internal enum TestSuiteOrExitCode { + case testSuite(rootTestSuite: XCTestSuite, testBundle: Bundle, observers: [XCTestObservation]) + case exitCode(CInt) +} + +/// Returns a test suite to be run or an exit code for the specified test cases and +/// command-line arguments. +internal func XCTMainMisc( + _ testCases: [XCTestCaseEntry], + arguments: [String] = CommandLine.arguments, + observers: [XCTestObservation]? +) -> TestSuiteOrExitCode { let observers = observers ?? [PrintObserver()] let testBundle = Bundle.main @@ -103,10 +161,10 @@ public func XCTMain( switch executionMode { case .list(type: .humanReadable): TestListing(testSuite: rootTestSuite).printTestList() - return EXIT_SUCCESS + return .exitCode(EXIT_SUCCESS) case .list(type: .json): TestListing(testSuite: rootTestSuite).printTestJSON() - return EXIT_SUCCESS + return .exitCode(EXIT_SUCCESS) case let .help(invalidOption): if let invalid = invalidOption { let errMsg = "Error: Invalid option \"\(invalid)\"\n" @@ -137,22 +195,32 @@ public func XCTMain( > \(exeName) \(sampleTests) """) - return invalidOption == nil ? EXIT_SUCCESS : EXIT_FAILURE + return .exitCode(invalidOption == nil ? EXIT_SUCCESS : EXIT_FAILURE) case .run(selectedTestNames: _): - // Add a test observer that prints test progress to stdout. - let observationCenter = XCTestObservationCenter.shared - for observer in observers { - observationCenter.addTestObserver(observer) - } + return .testSuite(rootTestSuite: rootTestSuite, testBundle: testBundle, observers: observers) + } +} - observationCenter.testBundleWillStart(testBundle) - rootTestSuite.run() - observationCenter.testBundleDidFinish(testBundle) +#if DISABLE_XCTWAITER +// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.") +public func XCTMain(_ testCases: [XCTestCaseEntry]) async -> Never { + exit(await XCTMain(testCases, arguments: CommandLine.arguments, observers: nil) as CInt) +} - return rootTestSuite.testRun!.totalFailureCount == 0 ? EXIT_SUCCESS : EXIT_FAILURE - } +// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.") +public func XCTMain(_ testCases: [XCTestCaseEntry], arguments: [String]) async -> Never { + exit(await XCTMain(testCases, arguments: arguments, observers: nil) as CInt) } +// @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.") +public func XCTMain( + _ testCases: [XCTestCaseEntry], + arguments: [String], + observers: [XCTestObservation] +) async -> Never { + exit(await XCTMain(testCases, arguments: arguments, observers: observers) as CInt) +} +#else // @available(*, deprecated, message: "Call the overload of XCTMain() that returns an exit code instead.") public func XCTMain(_ testCases: [XCTestCaseEntry]) -> Never { exit(XCTMain(testCases, arguments: CommandLine.arguments, observers: nil) as CInt) @@ -171,3 +239,4 @@ public func XCTMain( ) -> Never { exit(XCTMain(testCases, arguments: arguments, observers: observers) as CInt) } +#endif diff --git a/Sources/XCTest/Public/XCTestSuite.swift b/Sources/XCTest/Public/XCTestSuite.swift index 177dd1cb..7ee39b65 100644 --- a/Sources/XCTest/Public/XCTestSuite.swift +++ b/Sources/XCTest/Public/XCTestSuite.swift @@ -38,6 +38,27 @@ open class XCTestSuite: XCTest { return XCTestSuiteRun.self } + #if DISABLE_XCTWAITER + override func _performAsync(_ run: XCTestRun) async { + guard let testRun = run as? XCTestSuiteRun else { + fatalError("Wrong XCTestRun class.") + } + + run.start() + func syncSetUp() { setUp() } + syncSetUp() + for test in tests { + await test._runAsync() + if let childPerformTask = test.performTask { + _ = await childPerformTask.value + } + testRun.addTestRun(test.testRun!) + } + func syncTearDown() { tearDown() } + syncTearDown() + run.stop() + } + #else open override func perform(_ run: XCTestRun) { guard let testRun = run as? XCTestSuiteRun else { fatalError("Wrong XCTestRun class.") @@ -52,6 +73,7 @@ open class XCTestSuite: XCTest { tearDown() run.stop() } + #endif public init(name: String) { _name = name diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 3c9dbc5f..cabd5d11 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -36,6 +36,8 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "i686" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") set("${result_var_name}" "i686" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "wasm32") + set("${result_var_name}" "wasm32" PARENT_SCOPE) else() message(FATAL_ERROR "Unrecognized architecture on host system: ${CMAKE_SYSTEM_PROCESSOR}") endif()