1515/// modifying one or more of its properties, and returning the copy. You can
1616/// observe recorded issues by returning them unmodified. Or you can suppress an
1717/// issue by either filtering it using ``Trait/filterIssues(_:)`` or returning
18- /// `nil` from the closure passed to ``Trait/transformIssues (_:)``.
18+ /// `nil` from the closure passed to ``Trait/compactMapIssues (_:)``.
1919///
2020/// When an instance of this trait is applied to a suite, it is recursively
2121/// inherited by all child suites and tests.
2222///
2323/// To add this trait to a test, use one of the following functions:
2424///
25- /// - ``Trait/transformIssues (_:)``
25+ /// - ``Trait/compactMapIssues (_:)``
2626/// - ``Trait/filterIssues(_:)``
2727@_spi ( Experimental)
2828public struct IssueHandlingTrait : TestTrait , SuiteTrait {
@@ -96,15 +96,26 @@ extension IssueHandlingTrait: TestScoping {
9696 return
9797 }
9898
99+ // Ignore system issues, as they are not expected to be caused by users.
100+ if case . system = issue. kind {
101+ oldConfiguration. eventHandler ( event, context)
102+ return
103+ }
104+
99105 // Use the original configuration's event handler when invoking the
100- // transformer to avoid infinite recursion if the transformer itself
106+ // handler closure to avoid infinite recursion if the handler itself
101107 // records new issues. This means only issue handling traits whose scope
102108 // is outside this one will be allowed to handle such issues.
103109 let newIssue = Configuration . withCurrent ( oldConfiguration) {
104110 handleIssue ( issue)
105111 }
106112
107113 if let newIssue {
114+ // Prohibit assigning the issue's kind to system.
115+ if case . system = newIssue. kind {
116+ preconditionFailure ( " Issue returned by issue handling closure cannot have kind 'system': \( newIssue) " )
117+ }
118+
108119 var event = event
109120 event. kind = . issueRecorded( newIssue)
110121 oldConfiguration. eventHandler ( event, context)
@@ -120,31 +131,35 @@ extension Trait where Self == IssueHandlingTrait {
120131 /// Constructs an trait that transforms issues recorded by a test.
121132 ///
122133 /// - Parameters:
123- /// - transformer: The closure called for each issue recorded by the test
134+ /// - transform: A closure called for each issue recorded by the test
124135 /// this trait is applied to. It is passed a recorded issue, and returns
125136 /// an optional issue to replace the passed-in one.
126137 ///
127138 /// - Returns: An instance of ``IssueHandlingTrait`` that transforms issues.
128139 ///
129- /// The `transformer ` closure is called synchronously each time an issue is
140+ /// The `transform ` closure is called synchronously each time an issue is
130141 /// recorded by the test this trait is applied to. The closure is passed the
131142 /// recorded issue, and if it returns a non-`nil` value, that will be recorded
132143 /// instead of the original. Otherwise, if the closure returns `nil`, the
133144 /// issue is suppressed and will not be included in the results.
134145 ///
135- /// The `transformer ` closure may be called more than once if the test records
146+ /// The `transform ` closure may be called more than once if the test records
136147 /// multiple issues. If more than one instance of this trait is applied to a
137- /// test (including via inheritance from a containing suite), the `transformer `
148+ /// test (including via inheritance from a containing suite), the `transform `
138149 /// closure for each instance will be called in right-to-left, innermost-to-
139150 /// outermost order, unless `nil` is returned, which will skip invoking the
140151 /// remaining traits' closures.
141152 ///
142- /// Within `transformer `, you may access the current test or test case (if any)
153+ /// Within `transform `, you may access the current test or test case (if any)
143154 /// using ``Test/current`` ``Test/Case/current``, respectively. You may also
144155 /// record new issues, although they will only be handled by issue handling
145156 /// traits which precede this trait or were inherited from a containing suite.
146- public static func transformIssues( _ transformer: @escaping @Sendable ( Issue ) -> Issue ? ) -> Self {
147- Self ( handler: transformer)
157+ ///
158+ /// - Note: `transform` will never be passed an issue for which the value of
159+ /// ``Issue/kind`` is ``Issue/Kind/system``, and may not return such an
160+ /// issue.
161+ public static func compactMapIssues( _ transform: @escaping @Sendable ( Issue ) -> Issue ? ) -> Self {
162+ Self ( handler: transform)
148163 }
149164
150165 /// Constructs a trait that filters issues recorded by a test.
@@ -174,6 +189,9 @@ extension Trait where Self == IssueHandlingTrait {
174189 /// using ``Test/current`` ``Test/Case/current``, respectively. You may also
175190 /// record new issues, although they will only be handled by issue handling
176191 /// traits which precede this trait or were inherited from a containing suite.
192+ ///
193+ /// - Note: `isIncluded` will never be passed an issue for which the value of
194+ /// ``Issue/kind`` is ``Issue/Kind/system``.
177195 public static func filterIssues( _ isIncluded: @escaping @Sendable ( Issue ) -> Bool ) -> Self {
178196 Self { issue in
179197 isIncluded ( issue) ? issue : nil
0 commit comments