Skip to content

Commit 9d0323e

Browse files
authored
[6.2] Promote Issue Handling Traits to public API (#1228)
1 parent 6952004 commit 9d0323e

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

Sources/Testing/Testing.docc/Traits.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,10 @@ types that customize the behavior of your tests.
4848
- ``Trait/bug(_:id:_:)-10yf5``
4949
- ``Trait/bug(_:id:_:)-3vtpl``
5050

51-
<!--
5251
### Handling issues
5352

5453
- ``Trait/compactMapIssues(_:)``
5554
- ``Trait/filterIssues(_:)``
56-
-->
5755

5856
### Creating custom traits
5957

@@ -67,8 +65,8 @@ types that customize the behavior of your tests.
6765
- ``Bug``
6866
- ``Comment``
6967
- ``ConditionTrait``
68+
- ``IssueHandlingTrait``
7069
- ``ParallelizationTrait``
7170
- ``Tag``
7271
- ``Tag/List``
7372
- ``TimeLimitTrait``
74-
<!--- ``IssueHandlingTrait``-->

Sources/Testing/Traits/IssueHandlingTrait.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
///
2525
/// - ``Trait/compactMapIssues(_:)``
2626
/// - ``Trait/filterIssues(_:)``
27-
@_spi(Experimental)
27+
///
28+
/// @Metadata {
29+
/// @Available(Swift, introduced: 6.2)
30+
/// }
2831
public struct IssueHandlingTrait: TestTrait, SuiteTrait {
2932
/// A function which handles an issue and returns an optional replacement.
3033
///
@@ -49,6 +52,10 @@ public struct IssueHandlingTrait: TestTrait, SuiteTrait {
4952
///
5053
/// - Returns: An issue to replace `issue`, or else `nil` if the issue should
5154
/// not be recorded.
55+
///
56+
/// @Metadata {
57+
/// @Available(Swift, introduced: 6.2)
58+
/// }
5259
public func handleIssue(_ issue: Issue) -> Issue? {
5360
_handler(issue)
5461
}
@@ -58,6 +65,9 @@ public struct IssueHandlingTrait: TestTrait, SuiteTrait {
5865
}
5966
}
6067

68+
/// @Metadata {
69+
/// @Available(Swift, introduced: 6.2)
70+
/// }
6171
extension IssueHandlingTrait: TestScoping {
6272
public func scopeProvider(for test: Test, testCase: Test.Case?) -> Self? {
6373
// Provide scope for tests at both the suite and test case levels, but not
@@ -111,9 +121,20 @@ extension IssueHandlingTrait: TestScoping {
111121
}
112122

113123
if let newIssue {
114-
// Prohibit assigning the issue's kind to system.
115-
if case .system = newIssue.kind {
124+
// Validate the value of the returned issue's 'kind' property.
125+
switch (issue.kind, newIssue.kind) {
126+
case (_, .system):
127+
// Prohibited by ST-0011.
116128
preconditionFailure("Issue returned by issue handling closure cannot have kind 'system': \(newIssue)")
129+
case (.apiMisused, .apiMisused):
130+
// This is permitted, but must be listed explicitly before the
131+
// wildcard case below.
132+
break
133+
case (_, .apiMisused):
134+
// Prohibited by ST-0011.
135+
preconditionFailure("Issue returned by issue handling closure cannot have kind 'apiMisused' when the passed-in issue had a different kind: \(newIssue)")
136+
default:
137+
break
117138
}
118139

119140
var event = event
@@ -126,7 +147,6 @@ extension IssueHandlingTrait: TestScoping {
126147
}
127148
}
128149

129-
@_spi(Experimental)
130150
extension Trait where Self == IssueHandlingTrait {
131151
/// Constructs an trait that transforms issues recorded by a test.
132152
///
@@ -158,6 +178,10 @@ extension Trait where Self == IssueHandlingTrait {
158178
/// - Note: `transform` will never be passed an issue for which the value of
159179
/// ``Issue/kind`` is ``Issue/Kind/system``, and may not return such an
160180
/// issue.
181+
///
182+
/// @Metadata {
183+
/// @Available(Swift, introduced: 6.2)
184+
/// }
161185
public static func compactMapIssues(_ transform: @escaping @Sendable (Issue) -> Issue?) -> Self {
162186
Self(handler: transform)
163187
}
@@ -192,6 +216,10 @@ extension Trait where Self == IssueHandlingTrait {
192216
///
193217
/// - Note: `isIncluded` will never be passed an issue for which the value of
194218
/// ``Issue/kind`` is ``Issue/Kind/system``.
219+
///
220+
/// @Metadata {
221+
/// @Available(Swift, introduced: 6.2)
222+
/// }
195223
public static func filterIssues(_ isIncluded: @escaping @Sendable (Issue) -> Bool) -> Self {
196224
Self { issue in
197225
isIncluded(issue) ? issue : nil

Tests/TestingTests/Traits/IssueHandlingTraitTests.swift

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
99
//
1010

11-
@testable @_spi(Experimental) @_spi(ForToolsIntegrationOnly) import Testing
11+
@testable @_spi(ForToolsIntegrationOnly) import Testing
1212

1313
@Suite("IssueHandlingTrait Tests")
1414
struct IssueHandlingTraitTests {
@@ -216,6 +216,27 @@ struct IssueHandlingTraitTests {
216216
}.run(configuration: configuration)
217217
}
218218

219+
@Test("An API misused issue can be returned by issue handler closure when the original issue had that kind")
220+
func returningAPIMisusedIssue() async throws {
221+
var configuration = Configuration()
222+
configuration.eventHandler = { event, context in
223+
if case let .issueRecorded(issue) = event.kind, case .unconditional = issue.kind {
224+
issue.record()
225+
}
226+
}
227+
228+
let handler = IssueHandlingTrait.compactMapIssues { issue in
229+
guard case .apiMisused = issue.kind else {
230+
return Issue.record("Expected an issue of kind 'apiMisused': \(issue)")
231+
}
232+
return issue
233+
}
234+
235+
await Test(handler) {
236+
Issue(kind: .apiMisused).record()
237+
}.run(configuration: configuration)
238+
}
239+
219240
#if !SWT_NO_EXIT_TESTS
220241
@Test("Disallow assigning kind to .system")
221242
func disallowAssigningSystemKind() async throws {
@@ -229,5 +250,18 @@ struct IssueHandlingTraitTests {
229250
}.run()
230251
}
231252
}
253+
254+
@Test("Disallow assigning kind to .apiMisused")
255+
func disallowAssigningAPIMisusedKind() async throws {
256+
await #expect(processExitsWith: .failure) {
257+
await Test(.compactMapIssues { issue in
258+
var issue = issue
259+
issue.kind = .apiMisused
260+
return issue
261+
}) {
262+
Issue.record("A non-system issue")
263+
}.run()
264+
}
265+
}
232266
#endif
233267
}

0 commit comments

Comments
 (0)