diff --git a/.gitignore b/.gitignore index 1f07c20f9..43ba54d5c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ xcuserdata *.xcscmblueprint .build/ Output/ +Tests/Functional/.lit_test_times.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e36355813..1b99588d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(XCTest Sources/XCTest/Private/SourceLocation.swift Sources/XCTest/Private/WaiterManager.swift Sources/XCTest/Private/IgnoredErrors.swift + Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift Sources/XCTest/Public/XCTestRun.swift Sources/XCTest/Public/XCTestMain.swift Sources/XCTest/Public/XCTestCase.swift diff --git a/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift b/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift new file mode 100644 index 000000000..83f43fe47 --- /dev/null +++ b/Sources/XCTest/Private/XCTestCase.TearDownBlocksState.swift @@ -0,0 +1,44 @@ +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +extension XCTestCase { + + /// A class which encapsulates teardown blocks which are registered via the `addTeardownBlock(_:)` method. + /// Supports async and sync throwing methods. + final class TeardownBlocksState { + + private var wasFinalized = false + private var blocks: [() throws -> Void] = [] + + // 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. + // + // 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) { + self.append { + try awaitUsingExpectation { try await block() } + } + } + + func append(_ block: @escaping () throws -> Void) { + XCTWaiter.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 { + 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/XCAbstractTest.swift b/Sources/XCTest/Public/XCAbstractTest.swift index c67c2b58a..b286ea058 100644 --- a/Sources/XCTest/Public/XCAbstractTest.swift +++ b/Sources/XCTest/Public/XCAbstractTest.swift @@ -52,6 +52,10 @@ open class XCTest { perform(testRun!) } + /// Async setup method called before the invocation of `setUpWithError` for each test method in the class. + @available(macOS 12.0, *) + open func setUp() async throws {} + /// Setup method called before the invocation of `setUp` and the test method /// for each test method in the class. open func setUpWithError() throws {} @@ -68,6 +72,11 @@ open class XCTest { /// for each test method in the class. open func tearDownWithError() throws {} + /// Async teardown method which is called after the invocation of `tearDownWithError` + /// for each test method in the class. + @available(macOS 12.0, *) + open func tearDown() async throws {} + // FIXME: This initializer is required due to a Swift compiler bug on Linux. // It should be removed once the bug is fixed. public init() {} diff --git a/Sources/XCTest/Public/XCTestCase.swift b/Sources/XCTest/Public/XCTestCase.swift index 947a35db7..4a6ff7609 100644 --- a/Sources/XCTest/Public/XCTestCase.swift +++ b/Sources/XCTest/Public/XCTestCase.swift @@ -195,23 +195,23 @@ open class XCTestCase: XCTest { /// class. open class func tearDown() {} - private var teardownBlocks: [() -> Void] = [] - private var teardownBlocksDequeued: Bool = false - private let teardownBlocksQueue: DispatchQueue = DispatchQueue(label: "org.swift.XCTest.XCTestCase.teardownBlocks") + private let teardownBlocksState = TeardownBlocksState() /// Registers a block of teardown code to be run after the current test /// method ends. open func addTeardownBlock(_ block: @escaping () -> Void) { - teardownBlocksQueue.sync { - precondition(!self.teardownBlocksDequeued, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued") - self.teardownBlocks.append(block) - } + teardownBlocksState.append(block) + } + + /// Registers a block of teardown code to be run after the current test + /// method ends. + @available(macOS 12.0, *) + public func addTeardownBlock(_ block: @Sendable @escaping () async throws -> Void) { + teardownBlocksState.appendAsync(block) } private func performSetUpSequence() { - do { - try setUpWithError() - } catch { + func handleErrorDuringSetUp(_ error: Error) { if error.xct_shouldRecordAsTestFailure { recordFailure(for: error) } @@ -225,10 +225,42 @@ open class XCTestCase: XCTest { } } + do { + if #available(macOS 12.0, *) { + try awaitUsingExpectation { + try await self.setUp() + } + } + } catch { + handleErrorDuringSetUp(error) + } + + do { + try setUpWithError() + } catch { + handleErrorDuringSetUp(error) + } + setUp() } private func performTearDownSequence() { + func handleErrorDuringTearDown(_ error: Error) { + if error.xct_shouldRecordAsTestFailure { + recordFailure(for: error) + } + } + + func runTeardownBlocks() { + for block in self.teardownBlocksState.finalize().reversed() { + do { + try block() + } catch { + handleErrorDuringTearDown(error) + } + } + } + runTeardownBlocks() tearDown() @@ -236,22 +268,17 @@ open class XCTestCase: XCTest { do { try tearDownWithError() } catch { - if error.xct_shouldRecordAsTestFailure { - recordFailure(for: error) - } - } - } - - private func runTeardownBlocks() { - let blocks = teardownBlocksQueue.sync { () -> [() -> Void] in - self.teardownBlocksDequeued = true - let blocks = self.teardownBlocks - self.teardownBlocks = [] - return blocks + handleErrorDuringTearDown(error) } - for block in blocks.reversed() { - block() + do { + if #available(macOS 12.0, *) { + try awaitUsingExpectation { + try await self.tearDown() + } + } + } catch { + handleErrorDuringTearDown(error) } } @@ -292,3 +319,59 @@ private func test(_ testFunc: @escaping (T) -> () throws -> Void) try testFunc(testCase)() } } + +@available(macOS 12.0, *) +public func asyncTest( + _ testClosureGenerator: @escaping (T) -> () async throws -> Void +) -> (T) -> () throws -> Void { + return { (testType: T) in + let testClosure = testClosureGenerator(testType) + return { + try awaitUsingExpectation(testClosure) + } + } +} + +@available(macOS 12.0, *) +func awaitUsingExpectation( + _ closure: @escaping () async throws -> Void +) throws -> Void { + let expectation = XCTestExpectation(description: "async test completion") + let thrownErrorWrapper = ThrownErrorWrapper() + + Task { + defer { expectation.fulfill() } + + do { + try await closure() + } catch { + thrownErrorWrapper.error = error + } + } + + _ = XCTWaiter.wait(for: [expectation], timeout: asyncTestTimeout) + + if let error = thrownErrorWrapper.error { + throw error + } +} + +private final class ThrownErrorWrapper: @unchecked Sendable { + + private var _error: Error? + + var error: Error? { + get { + XCTWaiter.subsystemQueue.sync { _error } + } + set { + XCTWaiter.subsystemQueue.sync { _error = newValue } + } + } +} + + +// This time interval is set to a very large value due to their being no real native timeout functionality within corelibs-xctest. +// With the introduction of async/await support, the framework now relies on XCTestExpectations internally to coordinate the addition async portions of setup and tear down. +// This time interval is the timeout corelibs-xctest uses with XCTestExpectations. +private let asyncTestTimeout: TimeInterval = 60 * 60 * 24 * 30 diff --git a/Tests/Functional/Asynchronous/Use/main.swift b/Tests/Functional/Asynchronous/Use/main.swift new file mode 100644 index 000000000..249a635f3 --- /dev/null +++ b/Tests/Functional/Asynchronous/Use/main.swift @@ -0,0 +1,181 @@ +// RUN: %{swiftc} %s -o %T/Use +// RUN: %T/Use > %t || true +// RUN: %{xctest_checker} %t %s +// REQUIRES: concurrency_runtime + +#if os(macOS) + import SwiftXCTest +#else + import XCTest +#endif + +actor TestActor { + + enum Errors: String, Error { + case example + } + + private(set) var counter: Int = 0 + + func increment() async { + counter += 1 + } + + func decrement() async { + counter -= 1 + } + + func alwaysThrows() async throws { + throw TestActor.Errors.example + } + + func neverThrows() async throws {} +} + +// CHECK: Test Suite 'All tests' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ +// CHECK: Test Suite '.*\.xctest' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + +// CHECK: Test Suite 'AsyncAwaitTests' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + +class AsyncAwaitTests: XCTestCase { + + lazy var subject = TestActor() + + static let allTests = { + return [ + ("test_explicitFailures_withinAsyncTests_areReported", asyncTest(test_explicitFailures_withinAsyncTests_areReported)), + ("test_asyncAnnotatedFunctionsCanPass", asyncTest(test_asyncAnnotatedFunctionsCanPass)), + ("test_actorsAreSupported", asyncTest(test_actorsAreSupported)), + ("test_asyncErrors_withinTestMethods_areReported", asyncTest(test_asyncErrors_withinTestMethods_areReported)), + ("test_asyncAwaitCalls_withinTeardownBlocks_areSupported", asyncTest(test_asyncAwaitCalls_withinTeardownBlocks_areSupported)), + ("test_asyncErrors_withinTeardownBlocks_areReported", asyncTest(test_asyncErrors_withinTeardownBlocks_areReported)), + ("test_somethingAsyncWithDelay", asyncTest(test_somethingAsyncWithDelay)), + ("test_syncWithinClassWithAsyncTestMethods", test_syncWithinClassWithAsyncTestMethods), + ] + }() + + override func setUp() async throws {} + + override func tearDown() async throws {} + + // CHECK: Test Case 'AsyncAwaitTests.test_explicitFailures_withinAsyncTests_areReported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: .*[/\\]Asynchronous[/\\]Use[/\\]main.swift:[[@LINE+3]]: error: AsyncAwaitTests.test_explicitFailures_withinAsyncTests_areReported : XCTAssertTrue failed - + // CHECK: Test Case 'AsyncAwaitTests.test_explicitFailures_withinAsyncTests_areReported' failed \(\d+\.\d+ seconds\) + func test_explicitFailures_withinAsyncTests_areReported() async throws { + XCTAssert(false) + } + + // CHECK: Test Case 'AsyncAwaitTests.test_asyncAnnotatedFunctionsCanPass' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: Test Case 'AsyncAwaitTests.test_asyncAnnotatedFunctionsCanPass' passed \(\d+\.\d+ seconds\) + func test_asyncAnnotatedFunctionsCanPass() async throws { + let value = await makeString() + XCTAssertNotEqual(value, "") + } + + // CHECK: Test Case 'AsyncAwaitTests.test_actorsAreSupported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: Test Case 'AsyncAwaitTests.test_actorsAreSupported' passed \(\d+\.\d+ seconds\) + func test_actorsAreSupported() async throws { + let initialCounterValue = await subject.counter + XCTAssertEqual(initialCounterValue, 0) + + await subject.increment() + await subject.increment() + + let secondCounterValue = await subject.counter + XCTAssertEqual(secondCounterValue, 2) + + await subject.decrement() + let thirdCounterValue = await subject.counter + XCTAssertEqual(thirdCounterValue, 1) + } + + // CHECK: Test Case 'AsyncAwaitTests.test_asyncErrors_withinTestMethods_areReported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: \:0: error: AsyncAwaitTests.test_asyncErrors_withinTestMethods_areReported : threw error "example" + // CHECK: Test Case 'AsyncAwaitTests.test_asyncErrors_withinTestMethods_areReported' failed \(\d+\.\d+ seconds\) + func test_asyncErrors_withinTestMethods_areReported() async throws { + try await subject.alwaysThrows() + } + + // CHECK: Test Case 'AsyncAwaitTests.test_asyncAwaitCalls_withinTeardownBlocks_areSupported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: In teardown block\n + // CHECK: \:0: error: AsyncAwaitTests.test_asyncAwaitCalls_withinTeardownBlocks_areSupported : threw error "example" + // CHECK: Test Case 'AsyncAwaitTests.test_asyncAwaitCalls_withinTeardownBlocks_areSupported' failed \(\d+\.\d+ seconds\) + func test_asyncAwaitCalls_withinTeardownBlocks_areSupported() async throws { + addTeardownBlock { + print("In teardown block") + try await self.subject.alwaysThrows() + } + } + + // CHECK: Test Case 'AsyncAwaitTests.test_asyncErrors_withinTeardownBlocks_areReported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+\ + // CHECK: :0: error: AsyncAwaitTests.test_asyncErrors_withinTeardownBlocks_areReported : threw error "example"\n + // CHECK: Test Case 'AsyncAwaitTests.test_asyncErrors_withinTeardownBlocks_areReported' failed \(\d+\.\d+ seconds\) + func test_asyncErrors_withinTeardownBlocks_areReported() throws { + let issueRecordedExpectation = XCTestExpectation(description: "Asynchronous error recorded in: \(#function)") + + addTeardownBlock { + // Use addTeardownBlock here because the `addTeardownBlock` below intentionally throws an error so we can't `wait` after that in the same scope + self.wait(for: [issueRecordedExpectation], timeout: 1) + } + + addTeardownBlock { + do { + try await self.subject.alwaysThrows() + } catch { + issueRecordedExpectation.fulfill() + throw error + } + } + } + + // CHECK: Test Case 'AsyncAwaitTests.test_somethingAsyncWithDelay' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: Test Case 'AsyncAwaitTests.test_somethingAsyncWithDelay' passed \(\d+\.\d+ seconds\) + func test_somethingAsyncWithDelay() async throws { + try await doSomethingWithDelay() + } + + // CHECK: Test Case 'AsyncAwaitTests.test_syncWithinClassWithAsyncTestMethods' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ + // CHECK: Test Case 'AsyncAwaitTests.test_syncWithinClassWithAsyncTestMethods' passed \(\d+\.\d+ seconds\) + func test_syncWithinClassWithAsyncTestMethods() /* intentionally non-async */ throws { + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") + } +} + +private extension AsyncAwaitTests { + + func makeString() async -> String { + """ + Some arbitrary text. + Nothing to see here, folx. + """ + } + + func doSomethingWithDelay() async throws { + func doSomethingWithDelay(completion: @escaping (Error?) -> Void) { + DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(10)) { + completion(nil) + } + } + + try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation) in + doSomethingWithDelay { error in + if let error = error { + continuation.resume(throwing: error) + } else { + continuation.resume() + } + } + } + } +} + +// CHECK: Test Suite 'AsyncAwaitTests' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ +// CHECK: \t Executed 8 tests, with 4 failures \(3 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds +// CHECK: Test Suite '.*\.xctest' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ +// CHECK: \t Executed 8 tests, with 4 failures \(3 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds + +XCTMain([testCase(AsyncAwaitTests.allTests)]) + +// CHECK: Test Suite 'All tests' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ +// CHECK: \t Executed 8 tests, with 4 failures \(3 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds + diff --git a/Tests/Functional/TestCaseLifecycle/main.swift b/Tests/Functional/TestCaseLifecycle/main.swift index 1a75526a7..a81c33c2c 100644 --- a/Tests/Functional/TestCaseLifecycle/main.swift +++ b/Tests/Functional/TestCaseLifecycle/main.swift @@ -25,17 +25,20 @@ class SetUpTearDownTestCase: XCTestCase { override class func setUp() { super.setUp() print("In class \(#function)") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } override func setUp() { super.setUp() print("In \(#function)") value = 42 + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } override func tearDown() { super.tearDown() print("In \(#function)") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } // CHECK: Test Case 'SetUpTearDownTestCase.test_hasValueFromSetUp' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ @@ -52,6 +55,7 @@ class SetUpTearDownTestCase: XCTestCase { override class func tearDown() { super.tearDown() print("In class \(#function)") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } } // CHECK: Test Suite 'SetUpTearDownTestCase' passed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ @@ -95,16 +99,21 @@ class TeardownBlocksTestCase: XCTestCase { ("test_withSeveralTeardownBlocks", test_withSeveralTeardownBlocks), ] }() + + override func setUp() { + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") + } override func tearDown() { print("In tearDown function") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } // CHECK: Test Case 'TeardownBlocksTestCase.test_withoutTeardownBlocks' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ // CHECK: In tearDown function // CHECK: Test Case 'TeardownBlocksTestCase.test_withoutTeardownBlocks' passed \(\d+\.\d+ seconds\) func test_withoutTeardownBlocks() { - // Intentionally blank + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } // CHECK: Test Case 'TeardownBlocksTestCase.test_withATeardownBlock' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+ @@ -114,6 +123,7 @@ class TeardownBlocksTestCase: XCTestCase { func test_withATeardownBlock() { addTeardownBlock { print("In teardown block A") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } } @@ -125,9 +135,11 @@ class TeardownBlocksTestCase: XCTestCase { func test_withSeveralTeardownBlocks() { addTeardownBlock { print("In teardown block B") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } addTeardownBlock { print("In teardown block C") + XCTAssert(Thread.isMainThread, "Expected to be ran on the main thread, but wasn't.") } } } diff --git a/Tests/Functional/lit.cfg b/Tests/Functional/lit.cfg index 07c8a8218..49a5bf3b2 100644 --- a/Tests/Functional/lit.cfg +++ b/Tests/Functional/lit.cfg @@ -7,16 +7,18 @@ # # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors - +from pkg_resources import parse_version import os import platform import tempfile import sys import lit import pipes +import re # Set up lit config. config.name = 'SwiftXCTestFunctionalTests' +config.os_info = (platform.system(), platform.mac_ver()[0]) config.test_format = lit.formats.ShTest(execute_external=False) config.suffixes = ['.swift'] @@ -139,3 +141,10 @@ config.substitutions.append(('%{xctest_checker}', '%%{python} %s' % xctest_check # Add Python to run xctest_checker.py tests as part of XCTest tests config.substitutions.append( ('%{python}', pipes.quote(sys.executable)) ) + +# Conditionally report the Swift 5.5 Concurrency runtime as available depending on the OS and version. +(run_os, run_vers) = config.os_info +os_is_not_macOS = run_os != 'Darwin' +macOS_version_is_recent_enough = parse_version(run_vers) >= parse_version('12.0') +if os_is_not_macOS or macOS_version_is_recent_enough: + config.available_features.add('concurrency_runtime') diff --git a/XCTest.xcodeproj/project.pbxproj b/XCTest.xcodeproj/project.pbxproj index 8edeb65fe..db4f11578 100644 --- a/XCTest.xcodeproj/project.pbxproj +++ b/XCTest.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 17B6C3ED210F53BE00A11ECC /* WaiterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B6C3EC210F53BE00A11ECC /* WaiterManager.swift */; }; 17B6C3EF210F990100A11ECC /* XCTWaiter+Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17B6C3EE210F990100A11ECC /* XCTWaiter+Validation.swift */; }; 17D5B680211216EF00D93239 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D5B67F211216EF00D93239 /* SourceLocation.swift */; }; + A53D646726EA8F0E00F48361 /* XCTestCase.TearDownBlocksState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D646626EA8F0E00F48361 /* XCTestCase.TearDownBlocksState.swift */; }; AE2FE0FB1CFE86DB003EF0D7 /* XCAbstractTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2FE0EA1CFE86DB003EF0D7 /* XCAbstractTest.swift */; }; AE2FE0FE1CFE86DB003EF0D7 /* XCTAssert.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2FE0ED1CFE86DB003EF0D7 /* XCTAssert.swift */; }; AE2FE0FF1CFE86DB003EF0D7 /* XCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2FE0EE1CFE86DB003EF0D7 /* XCTestCase.swift */; }; @@ -58,6 +59,7 @@ 17B6C3EE210F990100A11ECC /* XCTWaiter+Validation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTWaiter+Validation.swift"; sourceTree = ""; }; 17D5B67F211216EF00D93239 /* SourceLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceLocation.swift; sourceTree = ""; }; 5B5D86DB1BBC74AD00234F36 /* SwiftXCTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftXCTest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A53D646626EA8F0E00F48361 /* XCTestCase.TearDownBlocksState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.TearDownBlocksState.swift; sourceTree = ""; }; AE2FE0EA1CFE86DB003EF0D7 /* XCAbstractTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCAbstractTest.swift; sourceTree = ""; }; AE2FE0ED1CFE86DB003EF0D7 /* XCTAssert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTAssert.swift; sourceTree = ""; }; AE2FE0EE1CFE86DB003EF0D7 /* XCTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = ""; }; @@ -136,6 +138,7 @@ AE63767D1D01ED17002C0EA8 /* TestListing.swift */, AE2FE1111CFE86E6003EF0D7 /* WallClockTimeMetric.swift */, AE2FE1131CFE86E6003EF0D7 /* XCTestCaseSuite.swift */, + A53D646626EA8F0E00F48361 /* XCTestCase.TearDownBlocksState.swift */, AE2FE1141CFE86E6003EF0D7 /* XCTestInternalObservation.swift */, 17B6C3EC210F53BE00A11ECC /* WaiterManager.swift */, 17D5B67F211216EF00D93239 /* SourceLocation.swift */, @@ -355,6 +358,7 @@ AE2FE1081CFE86DB003EF0D7 /* XCTestRun.swift in Sources */, AE2FE10A1CFE86DB003EF0D7 /* XCTestSuiteRun.swift in Sources */, AE2FE1161CFE86E6003EF0D7 /* ObjectWrapper.swift in Sources */, + A53D646726EA8F0E00F48361 /* XCTestCase.TearDownBlocksState.swift in Sources */, 172FF8A72117B74D0059CBC5 /* XCTNSNotificationExpectation.swift in Sources */, AE2FE11A1CFE86E6003EF0D7 /* WallClockTimeMetric.swift in Sources */, AE2FE1191CFE86E6003EF0D7 /* TestFiltering.swift in Sources */, @@ -510,6 +514,7 @@ "OTHER_LDFLAGS[sdk=macosx*]" = ( "-framework", SwiftFoundation, + "-weak-lswift_Concurrency", ); PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; SKIP_INSTALL = YES; @@ -534,6 +539,7 @@ "OTHER_LDFLAGS[sdk=macosx*]" = ( "-framework", SwiftFoundation, + "-weak-lswift_Concurrency", ); PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; SKIP_INSTALL = YES;