@@ -17,22 +17,44 @@ private import _TestingInternals
17
17
18
18
/// A type describing an exit test.
19
19
///
20
- /// Instances of this type describe an exit test defined by the test author and
21
- /// discovered or called at runtime.
22
- @_spi ( Experimental) @_spi ( ForToolsIntegrationOnly)
20
+ /// An instance of this type describes an exit test defined in a test target and
21
+ /// discovered or called at runtime. You do not create instances of this type.
22
+ ///
23
+ /// You don't usually need to interact with an instance of this type. To create
24
+ /// an exit test, use the ``expect(exitsWith:_:sourceLocation:performing:)``
25
+ /// or ``require(exitsWith:_:sourceLocation:performing:)`` macro.
26
+ @_spi ( Experimental)
23
27
public struct ExitTest : Sendable , ~ Copyable {
24
- /// The expected exit condition of the exit test .
28
+ /// This exit test's expected exit condition .
25
29
public var expectedExitCondition : ExitCondition
26
30
27
- /// The body closure of the exit test.
28
- fileprivate var body : @Sendable ( ) async throws -> Void = { }
29
-
30
- /// The source location of the exit test.
31
+ /// The source location of this exit test.
31
32
///
32
33
/// The source location is unique to each exit test and is consistent between
33
34
/// processes, so it can be used to uniquely identify an exit test at runtime.
34
35
public var sourceLocation : SourceLocation
35
36
37
+ /// The body closure of the exit test.
38
+ ///
39
+ /// Do not invoke this closure directly. Instead, invoke ``callAsFunction()``
40
+ /// to run the exit test. Running the exit test will always terminate the
41
+ /// current process.
42
+ fileprivate var body : @Sendable ( ) async throws -> Void
43
+
44
+ /// Initialize an exit test at runtime.
45
+ ///
46
+ /// - Warning: This initializer is used to implement the `#expect(exitsWith:)`
47
+ /// macro. Do not use it directly.
48
+ public init (
49
+ __expectedExitCondition expectedExitCondition: ExitCondition ,
50
+ sourceLocation: SourceLocation ,
51
+ body: @escaping @Sendable ( ) async throws -> Void = { }
52
+ ) {
53
+ self . expectedExitCondition = expectedExitCondition
54
+ self . sourceLocation = sourceLocation
55
+ self . body = body
56
+ }
57
+
36
58
/// Disable crash reporting, crash logging, or core dumps for the current
37
59
/// process.
38
60
private static func _disableCrashReporting( ) {
@@ -83,6 +105,7 @@ public struct ExitTest: Sendable, ~Copyable {
83
105
/// to terminate the process; if it does not, the testing library will
84
106
/// terminate the process in a way that causes the corresponding expectation
85
107
/// to fail.
108
+ @_spi ( ForToolsIntegrationOnly)
86
109
public consuming func callAsFunction( ) async -> Never {
87
110
Self . _disableCrashReporting ( )
88
111
@@ -102,44 +125,24 @@ public struct ExitTest: Sendable, ~Copyable {
102
125
103
126
// MARK: - Discovery
104
127
105
- /// A protocol describing a type that contains an exit test.
106
- ///
107
- /// - Warning: This protocol is used to implement the `#expect(exitsWith:)`
108
- /// macro. Do not use it directly.
109
- @_alwaysEmitConformanceMetadata
110
- @_spi ( Experimental)
111
- public protocol __ExitTestContainer {
112
- /// The expected exit condition of the exit test.
113
- static var __expectedExitCondition : ExitCondition { get }
114
-
115
- /// The source location of the exit test.
116
- static var __sourceLocation : SourceLocation { get }
117
-
118
- /// The body function of the exit test.
119
- static var __body : @Sendable ( ) async throws -> Void { get }
120
- }
121
-
122
128
extension ExitTest {
123
- /// A string that appears within all auto-generated types conforming to the
124
- /// `__ExitTestContainer` protocol.
125
- private static let _exitTestContainerTypeNameMagic = " __🟠$exit_test_body__ "
126
-
127
129
/// Find the exit test function at the given source location.
128
130
///
129
131
/// - Parameters:
130
132
/// - sourceLocation: The source location of the exit test to find.
131
133
///
132
134
/// - Returns: The specified exit test function, or `nil` if no such exit test
133
135
/// could be found.
136
+ @_spi ( ForToolsIntegrationOnly)
134
137
public static func find( at sourceLocation: SourceLocation ) -> Self ? {
135
138
var result : Self ?
136
139
137
- enumerateTypes ( withNamesContaining : _exitTestContainerTypeNameMagic ) { _, type , stop in
138
- if let type = type as? any __ExitTestContainer . Type , type . __sourceLocation == sourceLocation {
140
+ enumerateTestContent ( ofKind : . exitTest , as : ExitTest . self ) { _, exitTest , _ , stop in
141
+ if exitTest . sourceLocation == sourceLocation {
139
142
result = ExitTest (
140
- expectedExitCondition : type . __expectedExitCondition ,
141
- body : type . __body ,
142
- sourceLocation : type . __sourceLocation
143
+ __expectedExitCondition : exitTest . expectedExitCondition ,
144
+ sourceLocation : exitTest . sourceLocation ,
145
+ body : exitTest . body
143
146
)
144
147
stop = true
145
148
}
@@ -183,7 +186,7 @@ func callExitTest(
183
186
184
187
let actualExitCondition : ExitCondition
185
188
do {
186
- let exitTest = ExitTest ( expectedExitCondition : expectedExitCondition, sourceLocation: sourceLocation)
189
+ let exitTest = ExitTest ( __expectedExitCondition : expectedExitCondition, sourceLocation: sourceLocation)
187
190
actualExitCondition = try await configuration. exitTestHandler ( exitTest)
188
191
} catch {
189
192
// An error here would indicate a problem in the exit test handler such as a
@@ -295,7 +298,7 @@ extension ExitTest {
295
298
// External tools authors should set up their own back channel mechanisms
296
299
// and ensure they're installed before calling ExitTest.callAsFunction().
297
300
guard var result = find ( at: sourceLocation) else {
298
- return nil
301
+ fatalError ( " Could not find an exit test that should have been located at \( sourceLocation ) . " )
299
302
}
300
303
301
304
// We can't say guard let here because it counts as a consume.
0 commit comments