Skip to content

Commit a120b3e

Browse files
committed
Drop 'Custom' prefix from proposed API names
1 parent 4d88f1c commit a120b3e

File tree

5 files changed

+87
-84
lines changed

5 files changed

+87
-84
lines changed

Documentation/Proposals/NNNN-custom-test-execution-traits.md

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
* Implementation: [swiftlang/swift-testing#733](https://github.com/swiftlang/swift-testing/pull/733), [swiftlang/swift-testing#86](https://github.com/swiftlang/swift-testing/pull/86)
77
* Review: ([pitch](https://forums.swift.org/...))
88

9+
### Revision history
10+
11+
* **v1**: Initial pitch.
12+
* **v2**: Dropped 'Custom' prefix from the proposed API names (although kept the
13+
word in certain documentation passages where it clarified behavior).
14+
915
## Introduction
1016

1117
This introduces API which enables a custom `Trait`-conforming type to customize
@@ -190,21 +196,19 @@ these scoped access calls to only the traits which require it.
190196

191197
I propose the following new APIs:
192198

193-
- A new protocol `CustomTestExecuting` with a single required `execute(...)`
194-
method. This will be called to run a test, and allows the conforming type to
195-
perform custom logic before or after.
196-
- A new property `customTestExecutor` on the `Trait` protocol whose type is an
197-
`Optional` value of a type conforming to `CustomTestExecuting`. A `nil` value
198-
from this property will skip calling the `execute(...)` method.
199-
- A default implementation of `Trait.customTestExecutor` whose value is `nil`.
200-
- A conditional implementation of `Trait.customTestExecutor` whose value is
201-
`self` in the common case where the trait type conforms to
202-
`CustomTestExecuting` itself.
203-
204-
Since the `customTestExecutor` property is optional and `nil` by default, the
205-
testing library cannot invoke the `execute(...)` method unless a trait
206-
customizes test behavior. This avoids the "unnecessarily lengthy backtraces"
207-
problem above.
199+
- A new protocol `TestExecuting` with a single required `execute(...)` method.
200+
This will be called to run a test, and allows the conforming type to perform
201+
custom logic before or after.
202+
- A new property `testExecutor` on the `Trait` protocol whose type is an
203+
`Optional` value of a type conforming to `TestExecuting`. A `nil` value for
204+
this property will skip calling the `execute(...)` method.
205+
- A default implementation of `Trait.testExecutor` whose value is `nil`.
206+
- A conditional implementation of `Trait.testExecutor` whose value is `self`
207+
in the common case where the trait type conforms to `TestExecuting` itself.
208+
209+
Since the `testExecutor` property is optional and `nil` by default, the testing
210+
library cannot invoke the `execute(...)` method unless a trait customizes test
211+
behavior. This avoids the "unnecessarily lengthy backtraces" problem above.
208212

209213
Below are the proposed interfaces:
210214

@@ -215,12 +219,12 @@ Below are the proposed interfaces:
215219
///
216220
/// Types conforming to this protocol may be used in conjunction with a
217221
/// ``Trait``-conforming type by implementing the
218-
/// ``Trait/customTestExecutor-1dwpt`` property, allowing custom traits to
222+
/// ``Trait/testExecutor-714gp`` property, allowing custom traits to
219223
/// customize the execution of tests. Consolidating common set-up and tear-down
220224
/// logic for tests which have similar needs allows each test function to be
221225
/// more succinct with less repetitive boilerplate so it can focus on what makes
222226
/// it unique.
223-
public protocol CustomTestExecuting: Sendable {
227+
public protocol TestExecuting: Sendable {
224228
/// Execute a function for the specified test and/or test case.
225229
///
226230
/// - Parameters:
@@ -241,8 +245,8 @@ public protocol CustomTestExecuting: Sendable {
241245
/// When the testing library is preparing to run a test, it finds all traits
242246
/// applied to that test (including those inherited from containing suites)
243247
/// and asks each for the value of its
244-
/// ``Trait/customTestExecutor-1dwpt`` property. It then calls this method on
245-
/// all non-`nil` instances, giving each an opportunity to perform
248+
/// ``Trait/testExecutor-714gp`` property. It then calls this method
249+
/// on all non-`nil` instances, giving each an opportunity to perform
246250
/// arbitrary work before or after invoking `function`.
247251
///
248252
/// This method should either invoke `function` once before returning or throw
@@ -259,42 +263,42 @@ public protocol CustomTestExecuting: Sendable {
259263
public protocol Trait: Sendable {
260264
// ...
261265

262-
/// The type of the custom test executor for this trait.
266+
/// The type of the test executor for this trait.
263267
///
264268
/// The default type is `Never`, which cannot be instantiated. This means the
265-
/// value of the ``customTestExecutor-1dwpt`` property for all traits with the
266-
/// default custom executor type is `nil`, meaning such traits will not
269+
/// value of the ``testExecutor-714gp`` property for all traits with
270+
/// the default custom executor type is `nil`, meaning such traits will not
267271
/// perform any custom execution for the tests they're applied to.
268-
associatedtype CustomTestExecutor: CustomTestExecuting = Never
272+
associatedtype TestExecutor: TestExecuting = Never
269273

270-
/// The custom test executor for this trait, if any.
274+
/// The test executor for this trait, if any.
271275
///
272-
/// If this trait's type conforms to ``CustomTestExecuting``, the default
273-
/// value of this property is `self` and this trait will be used to customize
274-
/// test execution. This is the most straightforward way to implement a trait
275-
/// which customizes the execution of tests.
276+
/// If this trait's type conforms to ``TestExecuting``, the default value of
277+
/// this property is `self` and this trait will be used to customize test
278+
/// execution. This is the most straightforward way to implement a trait which
279+
/// customizes the execution of tests.
276280
///
277281
/// If the value of this property is an instance of a different type
278-
/// conforming to ``CustomTestExecuting``, that instance will be used to
279-
/// perform custom test execution instead.
282+
/// conforming to ``TestExecuting``, that instance will be used to perform
283+
/// test execution instead.
280284
///
281285
/// The default value of this property is `nil` (with the default type
282286
/// `Never?`), meaning that instances of this type will not perform any custom
283287
/// test execution for tests they are applied to.
284-
var customTestExecutor: CustomTestExecutor? { get }
288+
var testExecutor: TestExecutor? { get }
285289
}
286290

287-
extension Trait where Self: CustomTestExecuting {
291+
extension Trait where Self: TestExecuting {
288292
// Returns `self`.
289-
public var customTestExecutor: Self? { get }
293+
public var testExecutor: Self? {
290294
}
291295

292-
extension Trait where CustomTestExecutor == Never {
296+
extension Trait where TestExecutor == Never {
293297
// Returns `nil`.
294-
public var customTestExecutor: CustomTestExecutor? { get }
298+
public var testExecutor: TestExecutor? {
295299
}
296300

297-
extension Never: CustomTestExecuting {}
301+
extension Never: TestExecuting {}
298302
```
299303

300304
Here is a complete example of the usage scenario described earlier, showcasing
@@ -306,7 +310,7 @@ func example() {
306310
// ...validate API usage, referencing `APICredentials.current`...
307311
}
308312

309-
struct MockAPICredentialsTrait: TestTrait, CustomTestExecuting {
313+
struct MockAPICredentialsTrait: TestTrait, TestExecuting {
310314
func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws {
311315
let mockCredentials = APICredentials(apiKey: "...")
312316
try await APICredentials.$current.withValue(mockCredentials) {
@@ -357,26 +361,26 @@ concurrency technique and reduces the potential for test parallelization.
357361
### Add `execute(...)` directly to the `Trait` protocol
358362

359363
The proposed `execute(...)` method could be added as a requirement of the
360-
`Trait` protocol instead of being part of a separate `CustomTestExecuting`
361-
protocol, and it could have a default implementation which directly invokes the
362-
passed-in closure. But this approach would suffer from the lengthy backtrace
363-
problem described above.
364+
`Trait` protocol instead of being part of a separate `TestExecuting` protocol,
365+
and it could have a default implementation which directly invokes the passed-in
366+
closure. But this approach would suffer from the lengthy backtrace problem
367+
described above.
364368

365369
### Extend the `Trait` protocol
366370

367371
The original, experimental implementation of this feature included a protocol
368372
named`CustomExecutionTrait` which extended `Trait` and had roughly the same
369-
method requirement as the `CustomTestExecuting` protocol proposed above. This
370-
design worked, provided scoped access, and avoided the lengthy backtrace problem.
373+
method requirement as the `TestExecuting` protocol proposed above. This design
374+
worked, provided scoped access, and avoided the lengthy backtrace problem.
371375

372376
After evaluating the design and usage of this SPI though, it seemed unfortunate
373377
to structure it as a sub-protocol of `Trait` because it means that the full
374378
capabilities of the trait system are spread across multiple protocols. In the
375-
proposed design, the ability to provide a custom test executor value is exposed
376-
via the main `Trait` protocol, and it relies on an associated type to
377-
conditionally opt-in to custom test behavior. In other words, the proposed
378-
design expresses custom test behavior as just a _capability_ that a trait may
379-
have, rather than a distinct sub-type of trait.
379+
proposed design, the ability to provide a test executor value is exposed via the
380+
main `Trait` protocol, and it relies on an associated type to conditionally
381+
opt-in to custom test behavior. In other words, the proposed design expresses
382+
custom test behavior as just a _capability_ that a trait may have, rather than a
383+
distinct sub-type of trait.
380384

381385
Also, the implementation of this approach within the testing library was not
382386
ideal as it required a conditional `trait as? CustomExecutionTrait` downcast at

Sources/Testing/Running/Runner.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,19 @@ public struct Runner: Sendable {
5656
// MARK: - Running tests
5757

5858
extension Runner {
59-
/// Execute the ``CustomTestExecuting/execute(_:for:testCase:)`` functions of
60-
/// any custom test executors for traits associated with the test in a plan
61-
/// step.
59+
/// Execute the ``TestExecuting/execute(_:for:testCase:)`` functions of any
60+
/// test executors for traits associated with the test in a plan step.
6261
///
6362
/// - Parameters:
6463
/// - step: The step being performed.
6564
/// - testCase: The test case, if applicable, for which to execute the
6665
/// function.
6766
/// - body: A function to execute from within the
68-
/// ``CustomTestExecuting/execute(_:for:testCase:)`` function of each
69-
/// non-`nil` custom test executor of the traits applied to `step.test`.
67+
/// ``TestExecuting/execute(_:for:testCase:)`` function of each non-`nil`
68+
/// test executor of the traits applied to `step.test`.
7069
///
7170
/// - Throws: Whatever is thrown by `body` or by any of the
72-
/// ``CustomTestExecuting/execute(_:for:testCase:)`` functions.
71+
/// ``TestExecuting/execute(_:for:testCase:)`` functions.
7372
private func _executeTraits(
7473
for step: Plan.Step,
7574
testCase: Test.Case?,
@@ -91,7 +90,7 @@ extension Runner {
9190
// and ultimately the first trait is the first one to be invoked.
9291
let executeAllTraits = step.test.traits.lazy
9392
.reversed()
94-
.compactMap { $0.customTestExecutor }
93+
.compactMap { $0.testExecutor }
9594
.map { $0.execute(_:for:testCase:) }
9695
.reduce(body) { executeAllTraits, testExecutor in
9796
{

Sources/Testing/Testing.docc/Traits/Trait.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ See https://swift.org/CONTRIBUTORS.txt for Swift project authors
4848

4949
### Customizing the execution of tests
5050

51-
- ``CustomTestExecuting``
52-
- ``Trait/customTestExecutor-1dwpt``
53-
- ``Trait/CustomTestExecutor``
51+
- ``TestExecuting``
52+
- ``Trait/testExecutor-714gp``
53+
- ``Trait/TestExecutor``

Sources/Testing/Traits/Trait.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,29 @@ public protocol Trait: Sendable {
4242
/// By default, the value of this property is an empty array.
4343
var comments: [Comment] { get }
4444

45-
/// The type of the custom test executor for this trait.
45+
/// The type of the test executor for this trait.
4646
///
4747
/// The default type is `Never`, which cannot be instantiated. This means the
48-
/// value of the ``customTestExecutor-1dwpt`` property for all traits with the
49-
/// default custom executor type is `nil`, meaning such traits will not
48+
/// value of the ``testExecutor-714gp`` property for all traits with
49+
/// the default custom executor type is `nil`, meaning such traits will not
5050
/// perform any custom execution for the tests they're applied to.
51-
associatedtype CustomTestExecutor: CustomTestExecuting = Never
51+
associatedtype TestExecutor: TestExecuting = Never
5252

53-
/// The custom test executor for this trait, if any.
53+
/// The test executor for this trait, if any.
5454
///
55-
/// If this trait's type conforms to ``CustomTestExecuting``, the default
56-
/// value of this property is `self` and this trait will be used to customize
57-
/// test execution. This is the most straightforward way to implement a trait
58-
/// which customizes the execution of tests.
55+
/// If this trait's type conforms to ``TestExecuting``, the default value of
56+
/// this property is `self` and this trait will be used to customize test
57+
/// execution. This is the most straightforward way to implement a trait which
58+
/// customizes the execution of tests.
5959
///
6060
/// If the value of this property is an instance of a different type
61-
/// conforming to ``CustomTestExecuting``, that instance will be used to
62-
/// perform custom test execution instead.
61+
/// conforming to ``TestExecuting``, that instance will be used to perform
62+
/// test execution instead.
6363
///
6464
/// The default value of this property is `nil` (with the default type
6565
/// `Never?`), meaning that instances of this type will not perform any custom
6666
/// test execution for tests they are applied to.
67-
var customTestExecutor: CustomTestExecutor? { get }
67+
var testExecutor: TestExecutor? { get }
6868
}
6969

7070
/// A protocol that allows customizing the execution of a test function (and
@@ -73,12 +73,12 @@ public protocol Trait: Sendable {
7373
///
7474
/// Types conforming to this protocol may be used in conjunction with a
7575
/// ``Trait``-conforming type by implementing the
76-
/// ``Trait/customTestExecutor-1dwpt`` property, allowing custom traits to
76+
/// ``Trait/testExecutor-714gp`` property, allowing custom traits to
7777
/// customize the execution of tests. Consolidating common set-up and tear-down
7878
/// logic for tests which have similar needs allows each test function to be
7979
/// more succinct with less repetitive boilerplate so it can focus on what makes
8080
/// it unique.
81-
public protocol CustomTestExecuting: Sendable {
81+
public protocol TestExecuting: Sendable {
8282
/// Execute a function for the specified test and/or test case.
8383
///
8484
/// - Parameters:
@@ -99,8 +99,8 @@ public protocol CustomTestExecuting: Sendable {
9999
/// When the testing library is preparing to run a test, it finds all traits
100100
/// applied to that test (including those inherited from containing suites)
101101
/// and asks each for the value of its
102-
/// ``Trait/customTestExecutor-1dwpt`` property. It then calls this method on
103-
/// all non-`nil` instances, giving each an opportunity to perform
102+
/// ``Trait/testExecutor-714gp`` property. It then calls this method
103+
/// on all non-`nil` instances, giving each an opportunity to perform
104104
/// arbitrary work before or after invoking `function`.
105105
///
106106
/// This method should either invoke `function` once before returning or throw
@@ -114,13 +114,13 @@ public protocol CustomTestExecuting: Sendable {
114114
func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws
115115
}
116116

117-
extension Trait where Self: CustomTestExecuting {
118-
public var customTestExecutor: Self? {
117+
extension Trait where Self: TestExecuting {
118+
public var testExecutor: Self? {
119119
self
120120
}
121121
}
122122

123-
extension Never: CustomTestExecuting {
123+
extension Never: TestExecuting {
124124
public func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws {}
125125
}
126126

@@ -153,8 +153,8 @@ extension Trait {
153153
}
154154
}
155155

156-
extension Trait where CustomTestExecutor == Never {
157-
public var customTestExecutor: CustomTestExecutor? {
156+
extension Trait where TestExecutor == Never {
157+
public var testExecutor: TestExecutor? {
158158
nil
159159
}
160160
}

Tests/TestingTests/Traits/CustomTestExecutingTraitTests.swift renamed to Tests/TestingTests/Traits/TestExecutingTraitTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
@testable @_spi(Experimental) @_spi(ForToolsIntegrationOnly) import Testing
1212

13-
@Suite("CustomTestExecuting-conforming Trait Tests")
14-
struct CustomTestExecutingTraitTests {
13+
@Suite("TestExecuting-conforming Trait Tests")
14+
struct TestExecutingTraitTests {
1515
@Test("Execute code before and after a non-parameterized test.")
1616
func executeCodeBeforeAndAfterNonParameterizedTest() async {
1717
// `expectedCount` is 2 because we run it both for the test and the test case
@@ -65,7 +65,7 @@ struct CustomTestExecutingTraitTests {
6565

6666
// MARK: - Fixtures
6767

68-
private struct CustomTrait: TestTrait, CustomTestExecuting {
68+
private struct CustomTrait: TestTrait, TestExecuting {
6969
var before: Confirmation
7070
var after: Confirmation
7171
func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws {
@@ -77,15 +77,15 @@ private struct CustomTrait: TestTrait, CustomTestExecuting {
7777
}
7878
}
7979

80-
private struct CustomThrowingErrorTrait: TestTrait, CustomTestExecuting {
80+
private struct CustomThrowingErrorTrait: TestTrait, TestExecuting {
8181
fileprivate struct CustomTraitError: Error {}
8282

8383
func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws {
8484
throw CustomTraitError()
8585
}
8686
}
8787

88-
struct DoSomethingBeforeAndAfterTrait: SuiteTrait, TestTrait, CustomTestExecuting {
88+
struct DoSomethingBeforeAndAfterTrait: SuiteTrait, TestTrait, TestExecuting {
8989
static let state = Locked(rawValue: 0)
9090

9191
func execute(_ function: @Sendable () async throws -> Void, for test: Test, testCase: Test.Case?) async throws {

0 commit comments

Comments
 (0)