Skip to content

Commit 9cf3e53

Browse files
authored
The async variants of expect now require Sendable values (#1071)
1 parent af03b43 commit 9cf3e53

4 files changed

Lines changed: 17 additions & 15 deletions

File tree

Sources/Nimble/AsyncExpression.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
private actor MemoizedClosure<T> {
1+
private actor MemoizedClosure<T: Sendable> {
22
var closure: @Sendable () async throws -> T
33
var cache: T?
44

@@ -25,7 +25,7 @@ private actor MemoizedClosure<T> {
2525

2626
// Memoizes the given closure, only calling the passed
2727
// closure once; even if repeat calls to the returned closure
28-
private func memoizedClosure<T>(_ closure: @escaping @Sendable () async throws -> T) -> @Sendable (Bool) async throws -> T {
28+
private func memoizedClosure<T: Sendable>(_ closure: @escaping @Sendable () async throws -> T) -> @Sendable (Bool) async throws -> T {
2929
let memoized = MemoizedClosure(closure)
3030
return { withoutCaching in
3131
try await memoized.call(withoutCaching)
@@ -43,7 +43,7 @@ private func memoizedClosure<T>(_ closure: @escaping @Sendable () async throws -
4343
///
4444
/// This provides a common consumable API for matchers to utilize to allow
4545
/// Nimble to change internals to how the captured closure is managed.
46-
public struct AsyncExpression<Value>: Sendable {
46+
public struct AsyncExpression<Value: Sendable>: Sendable {
4747
internal let _expression: @Sendable (Bool) async throws -> Value?
4848
internal let _withoutCaching: Bool
4949
public let location: SourceLocation

Sources/Nimble/DSL+AsyncAwait.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Dispatch
33
#endif
44

55
/// Make an ``AsyncExpectation`` on a given actual value. The value given is lazily evaluated.
6-
public func expect<T>(file: FileString = #file, line: UInt = #line, _ expression: @escaping @Sendable () async throws -> T?) -> AsyncExpectation<T> {
6+
public func expect<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @escaping @Sendable () async throws -> T?) -> AsyncExpectation<T> {
77
return AsyncExpectation(
88
expression: AsyncExpression(
99
expression: expression,
@@ -12,7 +12,7 @@ public func expect<T>(file: FileString = #file, line: UInt = #line, _ expression
1212
}
1313

1414
/// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked.
15-
public func expect<T>(file: FileString = #file, line: UInt = #line, _ expression: @Sendable () -> (@Sendable () async throws -> T)) -> AsyncExpectation<T> {
15+
public func expect<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @Sendable () -> (@Sendable () async throws -> T)) -> AsyncExpectation<T> {
1616
return AsyncExpectation(
1717
expression: AsyncExpression(
1818
expression: expression(),
@@ -21,7 +21,7 @@ public func expect<T>(file: FileString = #file, line: UInt = #line, _ expression
2121
}
2222

2323
/// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked.
24-
public func expect<T>(file: FileString = #file, line: UInt = #line, _ expression: @Sendable () -> (@Sendable () async throws -> T?)) -> AsyncExpectation<T> {
24+
public func expect<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @Sendable () -> (@Sendable () async throws -> T?)) -> AsyncExpectation<T> {
2525
return AsyncExpectation(
2626
expression: AsyncExpression(
2727
expression: expression(),
@@ -40,7 +40,7 @@ public func expect(file: FileString = #file, line: UInt = #line, _ expression: @
4040

4141
/// Make an ``AsyncExpectation`` on a given actual value. The value given is lazily evaluated.
4242
/// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation`.
43-
public func expecta<T>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @escaping @Sendable () async throws -> T?) async -> AsyncExpectation<T> {
43+
public func expecta<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @escaping @Sendable () async throws -> T?) async -> AsyncExpectation<T> {
4444
return AsyncExpectation(
4545
expression: AsyncExpression(
4646
expression: expression,
@@ -50,7 +50,7 @@ public func expecta<T>(file: FileString = #file, line: UInt = #line, _ expressio
5050

5151
/// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked.
5252
/// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation`
53-
public func expecta<T>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T)) async -> AsyncExpectation<T> {
53+
public func expecta<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T)) async -> AsyncExpectation<T> {
5454
return AsyncExpectation(
5555
expression: AsyncExpression(
5656
expression: expression(),
@@ -60,7 +60,7 @@ public func expecta<T>(file: FileString = #file, line: UInt = #line, _ expressio
6060

6161
/// Make an ``AsyncExpectation`` on a given actual value. The closure is lazily invoked.
6262
/// This is provided to avoid confusion between `expect -> SyncExpectation` and `expect -> AsyncExpectation`
63-
public func expecta<T>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T?)) async -> AsyncExpectation<T> {
63+
public func expecta<T: Sendable>(file: FileString = #file, line: UInt = #line, _ expression: @autoclosure @Sendable () -> (@Sendable () async throws -> T?)) async -> AsyncExpectation<T> {
6464
return AsyncExpectation(
6565
expression: AsyncExpression(
6666
expression: expression(),

Sources/Nimble/Expectation.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal func execute<T>(_ expression: AsyncExpression<T>, _ style: ExpectationS
5050
}
5151
}
5252

53-
public enum ExpectationStatus: Equatable {
53+
public enum ExpectationStatus: Equatable, Sendable {
5454

5555
/// No predicates have been performed.
5656
case pending
@@ -208,7 +208,9 @@ public struct SyncExpectation<Value>: Expectation {
208208
public func notTo(_ predicate: Predicate<Value>, description: String? = nil) -> Self {
209209
toNot(predicate, description: description)
210210
}
211+
}
211212

213+
extension SyncExpectation where Value: Sendable {
212214
// MARK: - AsyncPredicates
213215
/// Tests the actual value using a matcher to match.
214216
@discardableResult
@@ -237,7 +239,7 @@ public struct SyncExpectation<Value>: Expectation {
237239
// - NMBExpectation for Objective-C interface
238240
}
239241

240-
public struct AsyncExpectation<Value>: Expectation {
242+
public struct AsyncExpectation<Value: Sendable>: Expectation, Sendable {
241243
public let expression: AsyncExpression<Value>
242244

243245
/// The status of the test after predicates have been evaluated.

Sources/Nimble/Matchers/AsyncPredicate.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
public protocol AsyncablePredicate<T> {
2-
associatedtype T
3-
func satisfies(_ expression: AsyncExpression<T>) async throws -> PredicateResult
1+
public protocol AsyncablePredicate<Value> {
2+
associatedtype Value: Sendable
3+
func satisfies(_ expression: AsyncExpression<Value>) async throws -> PredicateResult
44
}
55

66
extension Predicate: AsyncablePredicate {
7-
public func satisfies(_ expression: AsyncExpression<T>) async throws -> PredicateResult {
7+
public func satisfies(_ expression: AsyncExpression<T>) async throws -> PredicateResult where T: Sendable {
88
try satisfies(await expression.toSynchronousExpression())
99
}
1010
}

0 commit comments

Comments
 (0)