Skip to content

Commit d8d20a5

Browse files
Introduce a severity level when recording issues (#1070)
Introduce a severity level when recording issues ### Motivation: In order to create issues that don't fail a test this introduces a parameter to specify the severity of the issue. This is in support of work added here for an issue severity: #931 This is experimental. Example usage: `Issue.record("My comment", severity: .warning)` ### Modifications: I modified the `Issue.record` method signature to take in a severity level so that users can create issues that are not failing. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated. - [x] Add tests
1 parent 45384e5 commit d8d20a5

File tree

2 files changed

+91
-2
lines changed

2 files changed

+91
-2
lines changed

Sources/Testing/Issues/Issue+Recording.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,31 @@ extension Issue {
7373
@discardableResult public static func record(
7474
_ comment: Comment? = nil,
7575
sourceLocation: SourceLocation = #_sourceLocation
76+
) -> Self {
77+
record(comment, severity: .error, sourceLocation: sourceLocation)
78+
}
79+
80+
/// Record an issue when a running test fails unexpectedly.
81+
///
82+
/// - Parameters:
83+
/// - comment: A comment describing the expectation.
84+
/// - severity: The severity of the issue.
85+
/// - sourceLocation: The source location to which the issue should be
86+
/// attributed.
87+
///
88+
/// - Returns: The issue that was recorded.
89+
///
90+
/// Use this function if, while running a test, an issue occurs that cannot be
91+
/// represented as an expectation (using the ``expect(_:_:sourceLocation:)``
92+
/// or ``require(_:_:sourceLocation:)-5l63q`` macros.)
93+
@_spi(Experimental)
94+
@discardableResult public static func record(
95+
_ comment: Comment? = nil,
96+
severity: Severity,
97+
sourceLocation: SourceLocation = #_sourceLocation
7698
) -> Self {
7799
let sourceContext = SourceContext(backtrace: .current(), sourceLocation: sourceLocation)
78-
let issue = Issue(kind: .unconditional, comments: Array(comment), sourceContext: sourceContext)
100+
let issue = Issue(kind: .unconditional, severity: severity, comments: Array(comment), sourceContext: sourceContext)
79101
return issue.record()
80102
}
81103
}
@@ -101,10 +123,35 @@ extension Issue {
101123
_ error: any Error,
102124
_ comment: Comment? = nil,
103125
sourceLocation: SourceLocation = #_sourceLocation
126+
) -> Self {
127+
record(error, comment, severity: .error, sourceLocation: sourceLocation)
128+
}
129+
130+
/// Record a new issue when a running test unexpectedly catches an error.
131+
///
132+
/// - Parameters:
133+
/// - error: The error that caused the issue.
134+
/// - comment: A comment describing the expectation.
135+
/// - severity: The severity of the issue.
136+
/// - sourceLocation: The source location to which the issue should be
137+
/// attributed.
138+
///
139+
/// - Returns: The issue that was recorded.
140+
///
141+
/// This function can be used if an unexpected error is caught while running a
142+
/// test and it should be treated as a test failure. If an error is thrown
143+
/// from a test function, it is automatically recorded as an issue and this
144+
/// function does not need to be used.
145+
@_spi(Experimental)
146+
@discardableResult public static func record(
147+
_ error: any Error,
148+
_ comment: Comment? = nil,
149+
severity: Severity,
150+
sourceLocation: SourceLocation = #_sourceLocation
104151
) -> Self {
105152
let backtrace = Backtrace(forFirstThrowOf: error) ?? Backtrace.current()
106153
let sourceContext = SourceContext(backtrace: backtrace, sourceLocation: sourceLocation)
107-
let issue = Issue(kind: .errorCaught(error), comments: Array(comment), sourceContext: sourceContext)
154+
let issue = Issue(kind: .errorCaught(error), severity: severity, comments: Array(comment), sourceContext: sourceContext)
108155
return issue.record()
109156
}
110157

Tests/TestingTests/IssueTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,7 @@ final class IssueTests: XCTestCase {
10101010
return
10111011
}
10121012
XCTAssertFalse(issue.isKnown)
1013+
XCTAssertEqual(issue.severity, .error)
10131014
guard case .unconditional = issue.kind else {
10141015
XCTFail("Unexpected issue kind \(issue.kind)")
10151016
return
@@ -1021,6 +1022,25 @@ final class IssueTests: XCTestCase {
10211022
Issue.record("Custom message")
10221023
}.run(configuration: configuration)
10231024
}
1025+
1026+
func testWarning() async throws {
1027+
var configuration = Configuration()
1028+
configuration.eventHandler = { event, _ in
1029+
guard case let .issueRecorded(issue) = event.kind else {
1030+
return
1031+
}
1032+
XCTAssertFalse(issue.isKnown)
1033+
XCTAssertEqual(issue.severity, .warning)
1034+
guard case .unconditional = issue.kind else {
1035+
XCTFail("Unexpected issue kind \(issue.kind)")
1036+
return
1037+
}
1038+
}
1039+
1040+
await Test {
1041+
Issue.record("Custom message", severity: .warning)
1042+
}.run(configuration: configuration)
1043+
}
10241044

10251045
#if !SWT_NO_UNSTRUCTURED_TASKS
10261046
func testFailWithoutCurrentTest() async throws {
@@ -1048,6 +1068,7 @@ final class IssueTests: XCTestCase {
10481068
return
10491069
}
10501070
XCTAssertFalse(issue.isKnown)
1071+
XCTAssertEqual(issue.severity, .error)
10511072
guard case let .errorCaught(error) = issue.kind else {
10521073
XCTFail("Unexpected issue kind \(issue.kind)")
10531074
return
@@ -1060,6 +1081,27 @@ final class IssueTests: XCTestCase {
10601081
Issue.record(MyError(), "Custom message")
10611082
}.run(configuration: configuration)
10621083
}
1084+
1085+
func testWarningBecauseOfError() async throws {
1086+
var configuration = Configuration()
1087+
configuration.eventHandler = { event, _ in
1088+
guard case let .issueRecorded(issue) = event.kind else {
1089+
return
1090+
}
1091+
XCTAssertFalse(issue.isKnown)
1092+
XCTAssertEqual(issue.severity, .warning)
1093+
guard case let .errorCaught(error) = issue.kind else {
1094+
XCTFail("Unexpected issue kind \(issue.kind)")
1095+
return
1096+
}
1097+
XCTAssertTrue(error is MyError)
1098+
}
1099+
1100+
await Test {
1101+
Issue.record(MyError(), severity: .warning)
1102+
Issue.record(MyError(), "Custom message", severity: .warning)
1103+
}.run(configuration: configuration)
1104+
}
10631105

10641106
func testErrorPropertyValidForThrownErrors() async throws {
10651107
var configuration = Configuration()

0 commit comments

Comments
 (0)