Skip to content

Commit 331ca10

Browse files
Sean OlszewskiSean Olszewski
authored andcommitted
Address PR comments
* Move all the new XCTestCase files into a directory so they're more easily discovered and maintained * Actor -> Class to preserve existing clients * Remove erroneous thrown error from new async test to resolve a test failure
1 parent d568eb3 commit 331ca10

File tree

8 files changed

+87
-46
lines changed

8 files changed

+87
-46
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See http://swift.org/LICENSE.txt for license information
7+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8+
//
9+
//
10+
// XCTestCase.ClosureType.swift
11+
// Extension on XCTestCase which encapsulates ClosureType
12+
//
13+
14+
/// XCTestCase.TeardownBlocksState
15+
/// A class which encapsulates teardown blocks which are registered via the `addTearDownBlock(_block:)` method.
16+
/// Supports async and sync throwing methods
17+
18+
extension XCTestCase {
19+
class TeardownBlocksState {
20+
21+
enum BlockType {
22+
case sync(() throws -> Void)
23+
case async(() async throws -> Void)
24+
}
25+
26+
private var wasFinalized = false
27+
private var blocks: [BlockType] = []
28+
29+
func append(_ block: @escaping () throws -> Void) {
30+
precondition(wasFinalized == false, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued")
31+
self.blocks.append(.sync(block))
32+
}
33+
34+
func append(_ block: @escaping () async throws -> Void) {
35+
precondition(wasFinalized == false, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued")
36+
self.blocks.append(.async(block))
37+
}
38+
39+
func finalize() -> [BlockType] {
40+
precondition(wasFinalized == false, "API violation -- attempting to run teardown blocks after they've already run")
41+
wasFinalized = true
42+
return self.blocks
43+
}
44+
}
45+
}

Sources/XCTest/Public/XCTestCase.swift renamed to Sources/XCTest/Public/XCTestCase/XCTestCase.swift

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ open class XCTestCase: XCTest {
5555
/// The set of expectations made upon this test case.
5656
private var _allExpectations = [XCTestExpectation]()
5757

58-
private var setupEncounteredError = true
58+
private let teardownBlocks = TeardownBlocksState()
59+
60+
// This time interval is set to a very large value due to their being no real native timeout functionality within corelibs-xctest.
61+
// 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.
62+
// This time interval is the timeout corelibs-xctest uses with XCTestExpectations.
5963
private static let asyncTestTimeout: TimeInterval = 60 * 60 * 24 * 30
6064

6165
internal var expectations: [XCTestExpectation] {
@@ -127,13 +131,11 @@ open class XCTestCase: XCTest {
127131
/// Invoking a test performs its setUp, invocation, and tearDown. In
128132
/// general this should not be called directly.
129133
open func invokeTest() {
134+
performSetup()
130135
if skip == nil {
131-
performSetup()
132-
if !setupEncounteredError {
133-
performTest()
134-
}
135-
performTeardown()
136+
performTest()
136137
}
138+
performTeardown()
137139

138140
if let skip = skip {
139141
testRun?.recordSkip(description: skip.summary, sourceLocation: skip.sourceLocation)
@@ -162,7 +164,6 @@ open class XCTestCase: XCTest {
162164
try await setUp()
163165
} catch {
164166
recordError(error)
165-
self.setupEncounteredError = true
166167
}
167168
}
168169
_ = XCTWaiter.wait(for: [asyncSetUpExpectation], timeout: Self.asyncTestTimeout)
@@ -171,7 +172,6 @@ open class XCTestCase: XCTest {
171172
try setUpWithError()
172173
} catch {
173174
recordError(error)
174-
self.setupEncounteredError = true
175175
}
176176

177177
setUp()
@@ -200,10 +200,15 @@ open class XCTestCase: XCTest {
200200
}
201201

202202
func performTeardown() {
203-
@Sendable func runTeardownBlocks(errorHandler: (Error) -> Void) async {
204-
for block in await teardownBlocks.finalize().reversed() {
203+
@Sendable func runTeardownBlocks(errorHandler: @escaping (Error) -> Void) async {
204+
for block in teardownBlocks.finalize().reversed() {
205205
do {
206-
try await block()
206+
switch block {
207+
case .sync(let teardownBlock):
208+
try teardownBlock()
209+
case .async(let teardownBlock):
210+
try await teardownBlock()
211+
}
207212
} catch {
208213
errorHandler(error)
209214
}
@@ -290,37 +295,19 @@ open class XCTestCase: XCTest {
290295
/// class.
291296
open class func tearDown() {}
292297

293-
private actor TeardownBlocksState {
294-
295-
private var wasFinalized = false
296-
private var blocks: [() async throws -> Void] = []
297-
298-
func append(_ block: @escaping () async throws -> Void) {
299-
precondition(wasFinalized == false, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued")
300-
self.blocks.append(block)
301-
}
302-
303-
func finalize() -> [() async throws -> Void] {
304-
precondition(wasFinalized == false, "API violation -- attempting to run teardown blocks after they've already run")
305-
wasFinalized = true
306-
return self.blocks
307-
}
308-
}
309-
310-
private let teardownBlocks = TeardownBlocksState()
311-
312-
/// Registers a block of teardown code to be run after the current test
298+
/// Registers a block of teardown code to be sychronously ran after the current test
313299
/// method ends.
314300
open func addTeardownBlock(_ block: @escaping () -> Void) {
315-
Task {
316-
await teardownBlocks.append(block)
301+
XCTWaiter.subsystemQueue.sync {
302+
teardownBlocks.append(block)
317303
}
318304
}
319305

320-
// TODO: Doc comment
306+
/// Registers a block of teardown code to be asychronously ran after the current test
307+
/// method ends. The thread this block is executed on is decided by the Swift runtime.
321308
open func addTeardownBlock(_ block: @escaping () async throws -> Void) {
322-
Task {
323-
await teardownBlocks.append(block)
309+
XCTWaiter.subsystemQueue.sync {
310+
teardownBlocks.append(block)
324311
}
325312
}
326313

Tests/Functional/Asynchronous/Use/main.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,9 @@ class AsyncAwaitTests: XCTestCase {
5353
]
5454
}()
5555

56-
override func setUp() async throws {
57-
}
56+
override func setUp() async throws {}
5857

59-
override func tearDown() async throws {
60-
throw TestActor.Errors.example
61-
}
58+
override func tearDown() async throws {}
6259

6360
// CHECK: Test Case 'AsyncAwaitTests.test_explicitFailures_withinAsyncTests_areReported' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
6461
// CHECK: .*[/\\]Asynchronous[/\\]Use[/\\]main.swift:[[@LINE+3]]: error: AsyncAwaitTests.test_explicitFailures_withinAsyncTests_areReported : XCTAssertTrue failed -

XCTest.xcodeproj/project.pbxproj

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
17D5B680211216EF00D93239 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D5B67F211216EF00D93239 /* SourceLocation.swift */; };
1616
A516286D26C1D8C80015BA86 /* Factory_Methods.swift in Sources */ = {isa = PBXBuildFile; fileRef = A516286C26C1D8C80015BA86 /* Factory_Methods.swift */; };
1717
A52317E926CC227F002DDA48 /* XCTestCase.Entry.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52317E826CC227F002DDA48 /* XCTestCase.Entry.swift */; };
18+
A52317EB26CC52CA002DDA48 /* XCTestCase.TearDownBlocksState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52317EA26CC52C9002DDA48 /* XCTestCase.TearDownBlocksState.swift */; };
1819
A5C3F89626BC9A96004A70C8 /* XCTestCase.ClosureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C3F89526BC9A96004A70C8 /* XCTestCase.ClosureType.swift */; };
1920
AE2FE0FB1CFE86DB003EF0D7 /* XCAbstractTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2FE0EA1CFE86DB003EF0D7 /* XCAbstractTest.swift */; };
2021
AE2FE0FE1CFE86DB003EF0D7 /* XCTAssert.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2FE0ED1CFE86DB003EF0D7 /* XCTAssert.swift */; };
@@ -63,6 +64,7 @@
6364
5B5D86DB1BBC74AD00234F36 /* SwiftXCTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftXCTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6465
A516286C26C1D8C80015BA86 /* Factory_Methods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Factory_Methods.swift; sourceTree = "<group>"; };
6566
A52317E826CC227F002DDA48 /* XCTestCase.Entry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.Entry.swift; sourceTree = "<group>"; };
67+
A52317EA26CC52C9002DDA48 /* XCTestCase.TearDownBlocksState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.TearDownBlocksState.swift; sourceTree = "<group>"; };
6668
A5C3F89526BC9A96004A70C8 /* XCTestCase.ClosureType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.ClosureType.swift; sourceTree = "<group>"; };
6769
AE2FE0EA1CFE86DB003EF0D7 /* XCAbstractTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCAbstractTest.swift; sourceTree = "<group>"; };
6870
AE2FE0ED1CFE86DB003EF0D7 /* XCTAssert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTAssert.swift; sourceTree = "<group>"; };
@@ -130,6 +132,19 @@
130132
name = Products;
131133
sourceTree = "<group>";
132134
};
135+
A52317EC26CC53D3002DDA48 /* XCTestCase */ = {
136+
isa = PBXGroup;
137+
children = (
138+
A516286C26C1D8C80015BA86 /* Factory_Methods.swift */,
139+
AE2FE0EE1CFE86DB003EF0D7 /* XCTestCase.swift */,
140+
A52317E826CC227F002DDA48 /* XCTestCase.Entry.swift */,
141+
A52317EA26CC52C9002DDA48 /* XCTestCase.TearDownBlocksState.swift */,
142+
A5C3F89526BC9A96004A70C8 /* XCTestCase.ClosureType.swift */,
143+
AE2FE0F01CFE86DB003EF0D7 /* XCTestCase+Performance.swift */,
144+
);
145+
path = XCTestCase;
146+
sourceTree = "<group>";
147+
};
133148
AE2FE0E81CFE86A5003EF0D7 /* Private */ = {
134149
isa = PBXGroup;
135150
children = (
@@ -156,9 +171,7 @@
156171
AE2FE0EA1CFE86DB003EF0D7 /* XCAbstractTest.swift */,
157172
AE2FE0ED1CFE86DB003EF0D7 /* XCTAssert.swift */,
158173
1748FE3623AFD2D80014DB87 /* XCTSkip.swift */,
159-
AE2FE0EE1CFE86DB003EF0D7 /* XCTestCase.swift */,
160-
A5C3F89526BC9A96004A70C8 /* XCTestCase.ClosureType.swift */,
161-
AE2FE0F01CFE86DB003EF0D7 /* XCTestCase+Performance.swift */,
174+
A52317EC26CC53D3002DDA48 /* XCTestCase */,
162175
AE2FE0F11CFE86DB003EF0D7 /* XCTestCaseRun.swift */,
163176
AE2FE0F21CFE86DB003EF0D7 /* XCTestErrors.swift */,
164177
AE2FE0F41CFE86DB003EF0D7 /* XCTestMain.swift */,
@@ -167,8 +180,6 @@
167180
AE2FE0F71CFE86DB003EF0D7 /* XCTestRun.swift */,
168181
AE2FE0F81CFE86DB003EF0D7 /* XCTestSuite.swift */,
169182
AE2FE0F91CFE86DB003EF0D7 /* XCTestSuiteRun.swift */,
170-
A516286C26C1D8C80015BA86 /* Factory_Methods.swift */,
171-
A52317E826CC227F002DDA48 /* XCTestCase.Entry.swift */,
172183
);
173184
path = Public;
174185
sourceTree = "<group>";
@@ -347,6 +358,7 @@
347358
AE2FE1011CFE86DB003EF0D7 /* XCTestCase+Performance.swift in Sources */,
348359
DA9D441B1D920A3500108768 /* XCTestCase+Asynchronous.swift in Sources */,
349360
AE2FE1181CFE86E6003EF0D7 /* PrintObserver.swift in Sources */,
361+
A52317EB26CC52CA002DDA48 /* XCTestCase.TearDownBlocksState.swift in Sources */,
350362
17B6C3EB210D5A3900A11ECC /* XCTWaiter.swift in Sources */,
351363
17B6C3EF210F990100A11ECC /* XCTWaiter+Validation.swift in Sources */,
352364
AE2FE1021CFE86DB003EF0D7 /* XCTestCaseRun.swift in Sources */,

0 commit comments

Comments
 (0)