@@ -78,7 +78,12 @@ extension Runner {
78
78
/// This enumeration conforms to `CaseIterable`, so callers can iterate over
79
79
/// all stages by looping over `Stage.allCases`. `Stage.allCases.first` and
80
80
/// `Stage.allCases.last` are respectively the first and last stages to run.
81
- enum Stage : Sendable , CaseIterable {
81
+ ///
82
+ /// The names of cases are meant to describe what happens during them (so as
83
+ /// to aid debugging.) Most code that uses test run stages doesn't need to
84
+ /// care about them in isolation, but rather looks at `Stage.allCases`,
85
+ /// ranges of stages, etc.
86
+ enum Stage : Sendable , Comparable , CaseIterable {
82
87
/// Tests that might run in parallel (globally or locally) are being run.
83
88
case parallelizationAllowed
84
89
@@ -102,48 +107,8 @@ extension Runner {
102
107
/// The action to perform with ``test``.
103
108
public var action : Action
104
109
105
- /// The stage at which this step should be performed.
106
- var stage : Stage = . default
107
-
108
- /// Whether or not this step may perform work over multiple stages of a
109
- /// test run.
110
- var isMultistaged : Bool {
111
- test. isSuite
112
- }
113
-
114
- /// Whether or not this step performs its first work in the given test
115
- /// run stage.
116
- ///
117
- /// - Parameters:
118
- /// - stage: The stage of interest.
119
- ///
120
- /// - Returns: Whether or not `stage` is the first stage in which this
121
- /// step performs some work.
122
- func starts( in stage: Stage ) -> Bool {
123
- let firstStage = if isMultistaged {
124
- Stage . allCases. first
125
- } else {
126
- self . stage
127
- }
128
- return stage == firstStage
129
- }
130
-
131
- /// Whether or not this step performs its final work in the given test
132
- /// run stage.
133
- ///
134
- /// - Parameters:
135
- /// - stage: The stage of interest.
136
- ///
137
- /// - Returns: Whether or not `stage` is the last stage in which this
138
- /// step performs some work.
139
- func ends( in stage: Stage ) -> Bool {
140
- let lastStage = if isMultistaged {
141
- Stage . allCases. last
142
- } else {
143
- self . stage
144
- }
145
- return stage == lastStage
146
- }
110
+ /// The stages at which this step operates.
111
+ var stages : ClosedRange < Stage > = . default ... . default
147
112
}
148
113
149
114
/// The graph of the steps in the runner plan.
@@ -254,6 +219,23 @@ extension Runner.Plan {
254
219
synthesizeSuites ( in: & graph, sourceLocation: & sourceLocation)
255
220
}
256
221
222
+ /// Recursively widen the range of test run stages each (yet-to-be-created)
223
+ /// step in the specified graph will operate in.
224
+ ///
225
+ /// - Parameters:
226
+ /// - graph: The graph in which test run stage ranges should be computed.
227
+ private static func _recursivelyComputeStageRanges( in graph: inout Graph < String , ClosedRange < Stage > > ) {
228
+ var minStage = graph. value. lowerBound
229
+ var maxStage = graph. value. upperBound
230
+ for (key, var childGraph) in graph. children {
231
+ _recursivelyComputeStageRanges ( in: & childGraph)
232
+ graph. children [ key] = childGraph
233
+ minStage = min ( minStage, childGraph. value. lowerBound)
234
+ maxStage = max ( maxStage, childGraph. value. upperBound)
235
+ }
236
+ graph. value = minStage ... maxStage
237
+ }
238
+
257
239
/// Construct a graph of runner plan steps for the specified tests.
258
240
///
259
241
/// - Parameters:
@@ -379,25 +361,27 @@ extension Runner.Plan {
379
361
( action, recursivelyApply: action. isRecursive)
380
362
}
381
363
382
- // Figure out what stage each test should operate in.
383
- let stageGraph : Graph < String , Runner . Plan . Stage > = testGraph. mapValues { _, test in
384
- switch test? . isGloballySerialized {
364
+ // Figure out what stages each step should operate in.
365
+ var stageGraph : Graph < String , ClosedRange < Stage > > = testGraph. mapValues { _, test in
366
+ let bound : Stage = switch test? . isGloballySerialized {
385
367
case nil :
386
368
. default
387
369
case . some( false ) :
388
370
. parallelizationAllowed
389
371
case . some( true ) :
390
372
. globallySerialized
391
373
}
374
+ return bound ... bound
392
375
}
376
+ _recursivelyComputeStageRanges ( in: & stageGraph)
393
377
394
378
// Zip the tests, actions, and stages together and return them.
395
379
return zip ( zip ( testGraph, actionGraph) , stageGraph) . mapValues { _, tuple in
396
380
let test = tuple. 0 . 0
397
381
let action = tuple. 0 . 1
398
- let stage = tuple. 1
382
+ let stages = tuple. 1
399
383
return test. map { test in
400
- Step ( test: test, action: action, stage : stage )
384
+ Step ( test: test, action: action, stages : stages )
401
385
}
402
386
}
403
387
}
0 commit comments