@@ -48,12 +48,39 @@ public struct AttachmentSavingTrait: TestTrait, SuiteTrait {
48
48
Self { $0. hasFailed }
49
49
}
50
50
51
+ /// The testing library saves attachments if the test records a matching
52
+ /// issue.
53
+ ///
54
+ /// - Parameters:
55
+ /// - issueMatcher: A function to invoke when an issue occurs that is used
56
+ /// to determine if the testing library should save attachments for the
57
+ /// current test.
58
+ ///
59
+ /// - Returns: An instance of ``AttachmentSavingTrait/Condition`` that
60
+ /// evaluates `issueMatcher`.
61
+ public static func testRecordsIssue(
62
+ matching issueMatcher: @escaping @Sendable ( _ issue: Issue ) async throws -> Bool
63
+ ) -> Self {
64
+ Self ( inspectsIssues: true ) { context in
65
+ for issue in context. issues {
66
+ if try await issueMatcher ( issue) {
67
+ return true
68
+ }
69
+ }
70
+ return false
71
+ }
72
+ }
73
+
74
+ /// Whether or not this condition needs to inspect individual issues (which
75
+ /// implies a slower path.)
76
+ fileprivate var inspectsIssues = false
77
+
51
78
/// The condition function.
52
79
///
53
80
/// - Parameters:
54
81
/// - condition: The function to call. The result of this function
55
82
/// determines if the condition is satisfied or not.
56
- fileprivate var condition : @Sendable ( borrowing Context ) async throws -> Bool
83
+ fileprivate var body : @Sendable ( borrowing Context ) async throws -> Bool
57
84
}
58
85
59
86
/// This instance's condition.
@@ -70,7 +97,7 @@ public struct AttachmentSavingTrait: TestTrait, SuiteTrait {
70
97
// MARK: - TestScoping
71
98
72
99
extension AttachmentSavingTrait : TestScoping {
73
- /// A type representing the per-test context for this trait.
100
+ /// A type representing the per-test-case context for this trait.
74
101
///
75
102
/// An instance of this type is created for each scope this trait provides.
76
103
/// When the scope ends, the context is then passed to the trait's condition
@@ -79,8 +106,11 @@ extension AttachmentSavingTrait: TestScoping {
79
106
/// The set of events that were deferred for later conditional handling.
80
107
var deferredEvents = [ Event] ( )
81
108
82
- /// Whether or not the current test has recorded a failing issue.
109
+ /// Whether or not the current test case has recorded a failing issue.
83
110
var hasFailed = false
111
+
112
+ /// All issues recorded within the scope of the current test case.
113
+ var issues = [ Issue] ( )
84
114
}
85
115
86
116
public func scopeProvider( for test: Test , testCase: Test . Case ? ) -> Self ? {
@@ -124,7 +154,14 @@ extension AttachmentSavingTrait: TestScoping {
124
154
}
125
155
126
156
case let . issueRecorded( issue) :
127
- if issue. isFailure {
157
+ if condition. inspectsIssues {
158
+ context. withLock { context in
159
+ if issue. isFailure {
160
+ context. hasFailed = true
161
+ }
162
+ context. issues. append ( issue)
163
+ }
164
+ } else if issue. isFailure {
128
165
context. withLock { context in
129
166
context. hasFailed = true
130
167
}
@@ -161,7 +198,7 @@ extension AttachmentSavingTrait: TestScoping {
161
198
162
199
await Issue . withErrorRecording ( at: sourceLocation, configuration: configuration) {
163
200
// Evaluate the condition.
164
- guard try await condition. condition ( context) else {
201
+ guard try await condition. body ( context) else {
165
202
return
166
203
}
167
204
0 commit comments