Skip to content

Commit

Permalink
Pass message along in async withErrorReporting (#144)
Browse files Browse the repository at this point in the history
* Pass `message` along in async `withErrorReporting`

* Fix isolation

* wip

* wip

* wip

* wip

* wip

* wip

* wip
  • Loading branch information
stephencelis authored Jan 30, 2025
1 parent 9243488 commit 93fe160
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 58 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- debug
- release
xcode:
- '16.0'
- '16.2'
name: macOS 15
runs-on: macos-15
steps:
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.0.app
run: sudo xcode-select -s /Applications/Xcode_16.2.app
- name: Run tests
run: make build-for-library-evolution

Expand All @@ -66,7 +66,7 @@ jobs:
- Debug
- Release
xcode:
- '16.0'
- '16.2'
name: Examples
runs-on: macos-15
steps:
Expand Down Expand Up @@ -125,8 +125,8 @@ jobs:
steps:
- uses: compnerd/gha-setup-swift@main
with:
branch: swift-5.10-release
tag: 5.10-RELEASE
branch: swift-6.0.3-release
tag: 6.0.3-RELEASE
- name: Set long paths
run: git config --system core.longpaths true
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ``IssueReporting/withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf``
# ``IssueReporting/withErrorReporting(_:to:fileID:filePath:line:column:catching:)``

## Topics

### Overloads

- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-3dh1h``
- ``withErrorReporting(_:to:fileID:filePath:line:column:isolation:catching:)``
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ``IssueReporting/withIssueReporters(_:operation:)-91179``
# ``IssueReporting/withIssueReporters(_:operation:)``

## Topics

### Overloads

- ``withIssueReporters(_:operation:)-6xjha``
- ``withIssueReporters(_:isolation:operation:)``
4 changes: 2 additions & 2 deletions Sources/IssueReporting/Documentation.docc/IssueReporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ that ship in the same target as the library itself.

- ``reportIssue(_:fileID:filePath:line:column:)``
- ``withExpectedIssue(_:isIntermittent:fileID:filePath:line:column:_:)-9pinm``
- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)-89omf``
- ``withErrorReporting(_:to:fileID:filePath:line:column:catching:)``

### Issue reporters

Expand All @@ -64,7 +64,7 @@ that ship in the same target as the library itself.
### Custom reporting

- ``IssueReporter``
- ``withIssueReporters(_:operation:)-91179``
- ``withIssueReporters(_:operation:)``
- ``withIssueContext(fileID:filePath:line:column:operation:)-97lux``
- ``IssueReporters``

Expand Down
124 changes: 93 additions & 31 deletions Sources/IssueReporting/ErrorReporting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,42 +52,104 @@ public func withErrorReporting<R>(
}
}

/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - body: An asynchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () async throws -> R
) async -> R? {
if let reporters {
return await withIssueReporters(reporters) {
#if compiler(>=6)
/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - isolation: The isolation associated with the error reporting.
/// - body: An asynchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
isolation: isolated (any Actor)? = #isolation,
catching body: () async throws -> sending R
) async -> R? {
if let reporters {
return await withIssueReporters(reporters) {
do {
return try await body()
} catch {
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
} else {
do {
return try await body()
} catch {
reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column)
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
} else {
do {
return try await body()
} catch {
reportIssue(error, fileID: fileID, filePath: filePath, line: line, column: column)
return nil
}
#else
@_transparent
@_unsafeInheritExecutor
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () async throws -> R
) async -> R? {
if let reporters {
return await withIssueReporters(reporters) {
do {
return try await body()
} catch {
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
} else {
do {
return try await body()
} catch {
reportIssue(
error,
message(),
fileID: fileID,
filePath: filePath,
line: line,
column: column
)
return nil
}
}
}
}
#endif
38 changes: 25 additions & 13 deletions Sources/IssueReporting/IssueReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,28 @@ public func withIssueReporters<R>(
try IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation)
}

/// Overrides the task's issue reporters for the duration of the asynchronous operation.
///
/// An asynchronous version of ``withIssueReporters(_:operation:)-91179``.
///
/// - Parameters:
/// - reporters: Issue reporters to notify during the operation.
/// - operation: An asynchronous operation.
public func withIssueReporters<R>(
_ reporters: [any IssueReporter],
operation: () async throws -> R
) async rethrows -> R {
try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation)
}
#if compiler(>=6)
/// Overrides the task's issue reporters for the duration of the asynchronous operation.
///
/// An asynchronous version of ``withIssueReporters(_:operation:)-91179``.
///
/// - Parameters:
/// - reporters: Issue reporters to notify during the operation.
/// - isolation: The isolation associated with the operation.
/// - operation: An asynchronous operation.
public func withIssueReporters<R>(
_ reporters: [any IssueReporter],
isolation: isolated (any Actor)? = #isolation,
operation: () async throws -> R
) async rethrows -> R {
try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation)
}
#else
@_unsafeInheritExecutor
public func withIssueReporters<R>(
_ reporters: [any IssueReporter],
operation: () async throws -> R
) async rethrows -> R {
try await IssueReporters.$_current.withValue(LockIsolated(reporters), operation: operation)
}
#endif
2 changes: 1 addition & 1 deletion Tests/IssueReportingTests/SwiftTestingTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if canImport(Testing)
#if canImport(Testing) && !os(Windows)
import Testing
import IssueReporting

Expand Down
2 changes: 1 addition & 1 deletion Tests/IssueReportingTests/UnimplementedTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if canImport(Testing)
#if canImport(Testing) && !os(Windows)
import IssueReporting
import Testing

Expand Down
32 changes: 31 additions & 1 deletion Tests/IssueReportingTests/WithErrorReportingTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if canImport(Testing)
#if canImport(Testing) && !os(Windows)
import Testing
import IssueReporting

Expand All @@ -21,7 +21,37 @@
issue.description == "Caught error: SomeError(): Failed"
}
}

@Test func overload() async {
await withKnownIssue {
await withErrorReporting { () async throws in
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError()"
}

await withKnownIssue {
await withErrorReporting("Failed") { () async throws in
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError(): Failed"
}
}

@MainActor
@Test func isolation() async {
await withKnownIssue {
await withErrorReporting { () async throws in
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError()"
}
}
}

private struct SomeError: Error {}
#endif

0 comments on commit 93fe160

Please sign in to comment.