@@ -56,6 +56,16 @@ public struct Runner: Sendable {
56
56
// MARK: - Running tests
57
57
58
58
extension Runner {
59
+ /// The current configuration _while_ running.
60
+ ///
61
+ /// This should be used from the functions in this extension which access the
62
+ /// current configuration. This is important since individual tests or suites
63
+ /// may have traits which customize the execution scope of their children,
64
+ /// including potentially modifying the current configuration.
65
+ private static var _configuration : Configuration {
66
+ . current ?? . init( )
67
+ }
68
+
59
69
/// Apply the custom scope for any test scope providers of the traits
60
70
/// associated with a specified test by calling their
61
71
/// ``TestScoping/provideScope(for:testCase:performing:)`` function.
@@ -70,7 +80,7 @@ extension Runner {
70
80
///
71
81
/// - Throws: Whatever is thrown by `body` or by any of the
72
82
/// ``TestScoping/provideScope(for:testCase:performing:)`` function calls.
73
- private func _applyScopingTraits(
83
+ private static func _applyScopingTraits(
74
84
for test: Test ,
75
85
testCase: Test . Case ? ,
76
86
_ body: @escaping @Sendable ( ) async throws -> Void
@@ -103,21 +113,13 @@ extension Runner {
103
113
///
104
114
/// - Parameters:
105
115
/// - sequence: The sequence to enumerate.
106
- /// - step: The plan step that controls parallelization. If `nil`, or if its
107
- /// ``Runner/Plan/Step/action`` property is not of case
108
- /// ``Runner/Plan/Action/run(options:)``, the
109
- /// ``Configuration/isParallelizationEnabled`` property of this runner's
110
- /// ``configuration`` property is used instead to determine if
111
- /// parallelization is enabled.
112
116
/// - body: The function to invoke.
113
117
///
114
118
/// - Throws: Whatever is thrown by `body`.
115
- private func _forEach< E> (
119
+ private static func _forEach< E> (
116
120
in sequence: some Sequence < E > ,
117
- for step: Plan . Step ? ,
118
121
_ body: @Sendable @escaping ( E) async throws -> Void
119
122
) async throws where E: Sendable {
120
- let isParallelizationEnabled = step? . action. isParallelizationEnabled ?? configuration. isParallelizationEnabled
121
123
try await withThrowingTaskGroup ( of: Void . self) { taskGroup in
122
124
for element in sequence {
123
125
// Each element gets its own subtask to run in.
@@ -126,7 +128,7 @@ extension Runner {
126
128
}
127
129
128
130
// If not parallelizing, wait after each task.
129
- if !isParallelizationEnabled {
131
+ if !_configuration . isParallelizationEnabled {
130
132
try await taskGroup. waitForAll ( )
131
133
}
132
134
}
@@ -137,12 +139,6 @@ extension Runner {
137
139
///
138
140
/// - Parameters:
139
141
/// - stepGraph: The subgraph whose root value, a step, is to be run.
140
- /// - depth: How deep into the step graph this call is. The first call has a
141
- /// depth of `0`.
142
- /// - lastAncestorStep: The last-known ancestral step, if any, of the step
143
- /// at the root of `stepGraph`. The options in this step (if its action is
144
- /// of case ``Runner/Plan/Action/run(options:)``) inform the execution of
145
- /// `stepGraph`.
146
142
///
147
143
/// - Throws: Whatever is thrown from the test body. Thrown errors are
148
144
/// normally reported as test failures.
@@ -157,7 +153,7 @@ extension Runner {
157
153
/// ## See Also
158
154
///
159
155
/// - ``Runner/run()``
160
- private func _runStep( atRootOf stepGraph: Graph < String , Plan . Step ? > , depth : Int , lastAncestorStep : Plan . Step ? ) async throws {
156
+ private static func _runStep( atRootOf stepGraph: Graph < String , Plan . Step ? > ) async throws {
161
157
// Exit early if the task has already been cancelled.
162
158
try Task . checkCancellation ( )
163
159
@@ -166,6 +162,8 @@ extension Runner {
166
162
// example, a skip event only sends `.testSkipped`.
167
163
let shouldSendTestEnded : Bool
168
164
165
+ let configuration = _configuration
166
+
169
167
// Determine what action to take for this step.
170
168
if let step = stepGraph. value {
171
169
Event . post ( . planStepStarted( step) , for: ( step. test, nil ) , configuration: configuration)
@@ -204,14 +202,14 @@ extension Runner {
204
202
}
205
203
206
204
// Run the children of this test (i.e. the tests in this suite.)
207
- try await _runChildren ( of: stepGraph, depth : depth , lastAncestorStep : lastAncestorStep )
205
+ try await _runChildren ( of: stepGraph)
208
206
}
209
207
}
210
208
}
211
209
} else {
212
210
// There is no test at this node in the graph, so just skip down to the
213
211
// child nodes.
214
- try await _runChildren ( of: stepGraph, depth : depth , lastAncestorStep : lastAncestorStep )
212
+ try await _runChildren ( of: stepGraph)
215
213
}
216
214
}
217
215
@@ -222,7 +220,7 @@ extension Runner {
222
220
///
223
221
/// - Returns: The source location of the root node of `stepGraph`, or of the
224
222
/// first descendant node thereof (sorted by source location.)
225
- private func _sourceLocation( of stepGraph: Graph < String , Plan . Step ? > ) -> SourceLocation ? {
223
+ private static func _sourceLocation( of stepGraph: Graph < String , Plan . Step ? > ) -> SourceLocation ? {
226
224
if let result = stepGraph. value? . test. sourceLocation {
227
225
return result
228
226
}
@@ -234,26 +232,13 @@ extension Runner {
234
232
/// Recursively run the tests that are children of a given plan step.
235
233
///
236
234
/// - Parameters:
237
- /// - stepGraph: The subgraph whose root value, a step, is to be run.
238
- /// - depth: How deep into the step graph this call is. The first call has a
239
- /// depth of `0`.
240
- /// - lastAncestorStep: The last-known ancestral step, if any, of the step
241
- /// at the root of `stepGraph`. The options in this step (if its action is
242
- /// of case ``Runner/Plan/Action/run(options:)``) inform the execution of
243
- /// `stepGraph`.
235
+ /// - stepGraph: The subgraph whose root value, a step, will be used to
236
+ /// find children to run.
244
237
///
245
238
/// - Throws: Whatever is thrown from the test body. Thrown errors are
246
239
/// normally reported as test failures.
247
- private func _runChildren( of stepGraph: Graph < String , Plan . Step ? > , depth: Int , lastAncestorStep: Plan . Step ? ) async throws {
248
- // Figure out the last-good step, either the one at the root of `stepGraph`
249
- // or, if it is nil, the one passed into this function. We need to track
250
- // this value in case we run into sparse sections of the graph so we don't
251
- // lose track of the recursive `isParallelizationEnabled` property in the
252
- // runnable steps' options.
253
- let stepOrAncestor = stepGraph. value ?? lastAncestorStep
254
-
255
- let isParallelizationEnabled = stepOrAncestor? . action. isParallelizationEnabled ?? configuration. isParallelizationEnabled
256
- let childGraphs = if isParallelizationEnabled {
240
+ private static func _runChildren( of stepGraph: Graph < String , Plan . Step ? > ) async throws {
241
+ let childGraphs = if _configuration. isParallelizationEnabled {
257
242
// Explicitly shuffle the steps to help detect accidental dependencies
258
243
// between tests due to their ordering.
259
244
Array ( stepGraph. children)
@@ -282,8 +267,8 @@ extension Runner {
282
267
}
283
268
284
269
// Run the child nodes.
285
- try await _forEach ( in: childGraphs, for : stepOrAncestor ) { _, childGraph in
286
- try await _runStep ( atRootOf: childGraph, depth : depth + 1 , lastAncestorStep : stepOrAncestor )
270
+ try await _forEach ( in: childGraphs) { _, childGraph in
271
+ try await _runStep ( atRootOf: childGraph)
287
272
}
288
273
}
289
274
@@ -298,13 +283,14 @@ extension Runner {
298
283
///
299
284
/// If parallelization is supported and enabled, the generated test cases will
300
285
/// be run in parallel using a task group.
301
- private func _runTestCases( _ testCases: some Sequence < Test . Case > , within step: Plan . Step ) async throws {
286
+ private static func _runTestCases( _ testCases: some Sequence < Test . Case > , within step: Plan . Step ) async throws {
302
287
// Apply the configuration's test case filter.
288
+ let testCaseFilter = _configuration. testCaseFilter
303
289
let testCases = testCases. lazy. filter { testCase in
304
- configuration . testCaseFilter ( testCase, step. test)
290
+ testCaseFilter ( testCase, step. test)
305
291
}
306
292
307
- try await _forEach ( in: testCases, for : step ) { testCase in
293
+ try await _forEach ( in: testCases) { testCase in
308
294
try await _runTestCase ( testCase, within: step)
309
295
}
310
296
}
@@ -320,10 +306,12 @@ extension Runner {
320
306
///
321
307
/// This function sets ``Test/Case/current``, then invokes the test case's
322
308
/// body closure.
323
- private func _runTestCase( _ testCase: Test . Case , within step: Plan . Step ) async throws {
309
+ private static func _runTestCase( _ testCase: Test . Case , within step: Plan . Step ) async throws {
324
310
// Exit early if the task has already been cancelled.
325
311
try Task . checkCancellation ( )
326
312
313
+ let configuration = _configuration
314
+
327
315
Event . post ( . testCaseStarted, for: ( step. test, testCase) , configuration: configuration)
328
316
defer {
329
317
Event . post ( . testCaseEnded, for: ( step. test, testCase) , configuration: configuration)
@@ -357,9 +345,6 @@ extension Runner {
357
345
///
358
346
/// - Parameters:
359
347
/// - runner: The runner to run.
360
- /// - configuration: The configuration to use for running. The value of this
361
- /// argument temporarily replaces the value of `runner`'s
362
- /// ``Runner/configuration`` property.
363
348
///
364
349
/// This function is `static` so that it cannot accidentally reference `self`
365
350
/// or `self.configuration` when it should use a modified copy of either.
@@ -399,7 +384,7 @@ extension Runner {
399
384
400
385
await withTaskGroup ( of: Void . self) { [ runner] taskGroup in
401
386
_ = taskGroup. addTaskUnlessCancelled {
402
- try ? await runner . _runStep ( atRootOf: runner. plan. stepGraph, depth : 0 , lastAncestorStep : nil )
387
+ try ? await _runStep ( atRootOf: runner. plan. stepGraph)
403
388
}
404
389
await taskGroup. waitForAll ( )
405
390
}
0 commit comments