8
8
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9
9
//
10
10
11
- private import _TestingInternals
12
-
13
- /// A protocol describing a type that contains tests.
14
- ///
15
- /// - Warning: This protocol is used to implement the `@Test` macro. Do not use
16
- /// it directly.
17
- @_alwaysEmitConformanceMetadata
18
- public protocol __TestContainer {
19
- /// The set of tests contained by this type.
20
- static var __tests : [ Test ] { get async }
21
- }
11
+ internal import _TestingInternals
22
12
23
13
extension Test {
24
- /// A string that appears within all auto-generated types conforming to the
25
- /// `__TestContainer` protocol.
26
- private static let _testContainerTypeNameMagic = " __🟠$test_container__ "
27
-
28
14
/// All available ``Test`` instances in the process, according to the runtime.
29
15
///
30
16
/// The order of values in this sequence is unspecified.
@@ -47,16 +33,14 @@ extension Test {
47
33
/// contain duplicates; callers should use ``all`` instead.
48
34
private static var _all : some Sequence < Self > {
49
35
get async {
50
- await withTaskGroup ( of: [ Self ] . self) { taskGroup in
51
- enumerateTypes ( withNamesContaining: _testContainerTypeNameMagic) { _, type, _ in
52
- if let type = type as? any __TestContainer . Type {
53
- taskGroup. addTask {
54
- await type. __tests
55
- }
36
+ await withTaskGroup ( of: Self . self) { taskGroup in
37
+ enumerateTestContent( ofKind: . testDeclaration, as: ( @Sendable ( ) async -> Test) . self ) { _, generator, _, _ in
38
+ taskGroup. addTask {
39
+ await generator ( )
56
40
}
57
41
}
58
42
59
- return await taskGroup. reduce ( into: [ ] , += )
43
+ return await taskGroup. reduce ( into: [ ] ) { $0 . append ( $1 ) }
60
44
}
61
45
}
62
46
}
@@ -111,35 +95,71 @@ extension Test {
111
95
112
96
// MARK: -
113
97
114
- /// The type of callback called by ``enumerateTypes(withNamesContaining:_:)``.
98
+ /// The type of callback called by `_enumerateTestContent(_:)`.
99
+ ///
100
+ /// - Parameters:
101
+ /// - record: A pointer to a structure containing information about the
102
+ /// enumerated test content.
103
+ /// - stop: A pointer to a boolean variable indicating whether test content
104
+ /// enumeration should stop after the function returns. Set `*stop` to
105
+ /// `true` to stop test content enumeration.
106
+ private typealias _TestContentEnumerator = ( _ record: UnsafePointer < SWTTestContentRecord > , _ stop: UnsafeMutablePointer < Bool > ) -> Void
107
+
108
+ /// Enumerate all test content known to Swift and found in the current process.
109
+ ///
110
+ /// - Parameters:
111
+ /// - body: A function to invoke, once per raw test content record.
112
+ ///
113
+ /// This function enumerates all raw test content records discovered at runtime.
114
+ /// Callers should prefer ``enumerateTestContent(ofKind:as:_:)`` instead.
115
+ private func _enumerateTestContent( _ body: _TestContentEnumerator ) {
116
+ withoutActuallyEscaping ( body) { body in
117
+ withUnsafePointer ( to: body) { context in
118
+ swt_enumerateTestContent ( . init( mutating: context) ) { record, stop, context in
119
+ let body = context!. load ( as: _TestContentEnumerator. self)
120
+ body ( record, stop)
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ /// The type of callback called by ``enumerateTestContent(ofKind:as:_:)``.
115
127
///
116
128
/// - Parameters:
117
129
/// - imageAddress: A pointer to the start of the image. This value is _not_
118
130
/// equal to the value returned from `dlopen()`. On platforms that do not
119
- /// support dynamic loading (and so do not have loadable images), this
120
- /// argument is unspecified.
121
- /// - type: A Swift type.
131
+ /// support dynamic loading (and so do not have loadable images), the value
132
+ /// of this argument is unspecified.
133
+ /// - content: The enumerated test content.
134
+ /// - flags: Flags associated with `content`. The value of this argument is
135
+ /// dependent on the type of test content being enumerated.
122
136
/// - stop: An `inout` boolean variable indicating whether type enumeration
123
137
/// should stop after the function returns. Set `stop` to `true` to stop
124
138
/// type enumeration.
125
- typealias TypeEnumerator = ( _ imageAddress: UnsafeRawPointer ? , _ type : Any . Type , _ stop: inout Bool ) -> Void
139
+ typealias TestContentEnumerator < T > = ( _ imageAddress: UnsafeRawPointer ? , _ content : borrowing T , _ flags : UInt64 , _ stop: inout Bool ) -> Void where T : ~ Copyable
126
140
127
- /// Enumerate all types known to Swift found in the current process whose names
128
- /// contain a given substring.
141
+ /// Enumerate all test content known to Swift and found in the current process.
129
142
///
130
143
/// - Parameters:
131
- /// - nameSubstring: A string which the names of matching classes all contain.
132
- /// - body: A function to invoke, once per matching type.
133
- func enumerateTypes( withNamesContaining nameSubstring: String , _ typeEnumerator: TypeEnumerator ) {
134
- withoutActuallyEscaping ( typeEnumerator) { typeEnumerator in
135
- withUnsafePointer ( to: typeEnumerator) { context in
136
- swt_enumerateTypes ( withNamesContaining: nameSubstring, . init( mutating: context) ) { imageAddress, type, stop, context in
137
- let typeEnumerator = context!. load ( as: TypeEnumerator . self)
138
- let type = unsafeBitCast ( type, to: Any . Type. self)
139
- var stop2 = false
140
- typeEnumerator ( imageAddress, type, & stop2)
141
- stop. pointee = stop2
144
+ /// - kind: The kind of test content to look for.
145
+ /// - type: The Swift type of test content to look for.
146
+ /// - body: A function to invoke, once per matching test content record.
147
+ func enumerateTestContent< T> ( ofKind kind: SWTTestContentKind , as type: T . Type , _ body: TestContentEnumerator < T > ) where T: ~ Copyable {
148
+ _enumerateTestContent { record, stop in
149
+ if record. pointee. kind != kind {
150
+ return
151
+ }
152
+ withUnsafeTemporaryAllocation ( of: type, capacity: 1 ) { buffer in
153
+ // Load the content from the record via its accessor function.
154
+ guard record. pointee. accessor ( buffer. baseAddress!) else {
155
+ return
142
156
}
157
+ defer {
158
+ buffer. deinitialize ( )
159
+ }
160
+
161
+ // Call the callback.
162
+ body ( record. pointee. imageAddress, buffer. baseAddress!. pointee, record. pointee. flags, & stop. pointee)
143
163
}
144
164
}
145
165
}
0 commit comments