Skip to content

Commit

Permalink
Implement the async variant of toEventually using structured concurre…
Browse files Browse the repository at this point in the history
…ncy (#1079)

* Implement the async variant of toEventually using structured concurrency

... mostly.

This replaces the Dispatch-based version of async toEventually with one that uses native Swift Concurrency components
This was done to eliminate the chance that the matcher could be polled more than one at a time, and to also make
way for future Sendable requirements.

* NSLocking.withLock is not available in earlier versions of the OS

* Remove NimbleTimeInterval+Duration

* Reimplement AsyncTimerSequence to use a simplified form of the Clock protocol

This allows us to longer have to verify time intervals in test, removing a source of test flakiness

* Fix swiftlint errors
  • Loading branch information
younata committed Sep 13, 2023
1 parent 8e562c7 commit 3f9773e
Show file tree
Hide file tree
Showing 11 changed files with 686 additions and 201 deletions.
30 changes: 30 additions & 0 deletions Nimble.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@
891364B029E695F300AD535E /* ObjCAllPassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */; };
891364B129E695F300AD535E /* ObjcStringersTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DF1C3F61C94FC75004B2D36 /* ObjcStringersTest.m */; };
891364B229E6963C00AD535E /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; };
891A04712AB0164500B46613 /* AsyncTimerSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A04702AB0164500B46613 /* AsyncTimerSequence.swift */; };
891A04722AB0164500B46613 /* AsyncTimerSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A04702AB0164500B46613 /* AsyncTimerSequence.swift */; };
891A04732AB0164500B46613 /* AsyncTimerSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A04702AB0164500B46613 /* AsyncTimerSequence.swift */; };
891A04742AB0164500B46613 /* AsyncTimerSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891A04702AB0164500B46613 /* AsyncTimerSequence.swift */; };
892FDF1329D3EA7700523A80 /* AsyncExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892FDF1229D3EA7700523A80 /* AsyncExpression.swift */; };
892FDF1429D3EA7700523A80 /* AsyncExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892FDF1229D3EA7700523A80 /* AsyncExpression.swift */; };
892FDF1529D3EA7700523A80 /* AsyncExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892FDF1229D3EA7700523A80 /* AsyncExpression.swift */; };
Expand All @@ -377,6 +381,14 @@
899441F92902EF2600C1FAF9 /* DSL+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899441F32902EF0900C1FAF9 /* DSL+AsyncAwait.swift */; };
899441FA2902EF2700C1FAF9 /* DSL+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899441F32902EF0900C1FAF9 /* DSL+AsyncAwait.swift */; };
899441FB2902EF2800C1FAF9 /* DSL+AsyncAwait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899441F32902EF0900C1FAF9 /* DSL+AsyncAwait.swift */; };
89C297CC2A911CDA002A143F /* AsyncTimerSequenceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */; };
89C297CE2A92AB34002A143F /* AsyncPromiseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */; };
89C297CF2A92E80D002A143F /* AsyncTimerSequenceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */; };
89C297D02A92E80E002A143F /* AsyncTimerSequenceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */; };
89C297D12A92E80F002A143F /* AsyncTimerSequenceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */; };
89C297D32A92E814002A143F /* AsyncPromiseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */; };
89C297D42A92E815002A143F /* AsyncPromiseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */; };
89C297D52A92E816002A143F /* AsyncPromiseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */; };
89EEF5A52A03293100988224 /* AsyncPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5A42A03293100988224 /* AsyncPredicate.swift */; };
89EEF5A62A03293100988224 /* AsyncPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5A42A03293100988224 /* AsyncPredicate.swift */; };
89EEF5A72A03293100988224 /* AsyncPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5A42A03293100988224 /* AsyncPredicate.swift */; };
Expand Down Expand Up @@ -788,12 +800,15 @@
7B5358C11C39155600A23FAA /* ObjCSatisfyAnyOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCSatisfyAnyOfTest.m; sourceTree = "<group>"; };
857D1848253610A900D8693A /* BeWithin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeWithin.swift; sourceTree = "<group>"; };
857D184D2536123F00D8693A /* BeWithinTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeWithinTest.swift; sourceTree = "<group>"; };
891A04702AB0164500B46613 /* AsyncTimerSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncTimerSequence.swift; sourceTree = "<group>"; };
892FDF1229D3EA7700523A80 /* AsyncExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncExpression.swift; sourceTree = "<group>"; };
896962402A5FABD000A7929D /* AsyncAllPass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAllPass.swift; sourceTree = "<group>"; };
896962452A5FAD4500A7929D /* AsyncAllPassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAllPassTest.swift; sourceTree = "<group>"; };
898F28AF25D9F4C30052B8D0 /* AlwaysFailMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlwaysFailMatcher.swift; sourceTree = "<group>"; };
899441EE2902EE4B00C1FAF9 /* AsyncAwaitTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAwaitTest.swift; sourceTree = "<group>"; };
899441F32902EF0900C1FAF9 /* DSL+AsyncAwait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DSL+AsyncAwait.swift"; sourceTree = "<group>"; };
89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncTimerSequenceTest.swift; sourceTree = "<group>"; };
89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncPromiseTest.swift; sourceTree = "<group>"; };
89EEF5A42A03293100988224 /* AsyncPredicate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncPredicate.swift; sourceTree = "<group>"; };
89EEF5B22A032C2500988224 /* AsyncPredicateTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncPredicateTest.swift; sourceTree = "<group>"; };
89EEF5BB2A06210D00988224 /* AsyncHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncHelpers.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1002,6 +1017,8 @@
89F5E095290C37B8001F9377 /* StatusTest.swift */,
1F0648D31963AAB2001F9C46 /* SynchronousTest.swift */,
899441EE2902EE4B00C1FAF9 /* AsyncAwaitTest.swift */,
89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */,
89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */,
965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */,
6CAEDD091CAEA86F003F1584 /* LinuxSupport.swift */,
1F14FB61194180A7009F2A08 /* Helpers */,
Expand Down Expand Up @@ -1128,6 +1145,7 @@
children = (
1FD8CD261968AB07008ED995 /* PollAwait.swift */,
89F5E08B290B8D22001F9377 /* AsyncAwait.swift */,
891A04702AB0164500B46613 /* AsyncTimerSequence.swift */,
1FD8CD271968AB07008ED995 /* SourceLocation.swift */,
1FD8CD281968AB07008ED995 /* Stringers.swift */,
AE4BA9AC1C88DDB500B73906 /* Errors.swift */,
Expand Down Expand Up @@ -1706,6 +1724,7 @@
896962422A5FABD000A7929D /* AsyncAllPass.swift in Sources */,
1FD8CD381968AB07008ED995 /* Expression.swift in Sources */,
1FD8CD3A1968AB07008ED995 /* FailureMessage.swift in Sources */,
891A04722AB0164500B46613 /* AsyncTimerSequence.swift in Sources */,
CDFB6A4C1F7E082500AD8CC7 /* mach_excServer.c in Sources */,
89EEF5A62A03293100988224 /* AsyncPredicate.swift in Sources */,
472FD1351B9E085700C7B8DA /* HaveCount.swift in Sources */,
Expand All @@ -1732,6 +1751,7 @@
8969624B2A5FAD6000A7929D /* AsyncAllPassTest.swift in Sources */,
1F4A56661A3B305F009E1637 /* ObjCAsyncTest.m in Sources */,
1F925EFC195C186800ED456B /* BeginWithTest.swift in Sources */,
89C297D52A92E816002A143F /* AsyncPromiseTest.swift in Sources */,
89F5E06E290765BB001F9377 /* PollingTest.swift in Sources */,
DDB4D5F019FE442800E9D9FE /* MatchTest.swift in Sources */,
1F4A56731A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */,
Expand Down Expand Up @@ -1779,6 +1799,7 @@
1F4A567F1A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */,
857D18502536124400D8693A /* BeWithinTest.swift in Sources */,
1F0648CC19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */,
89C297CF2A92E80D002A143F /* AsyncTimerSequenceTest.swift in Sources */,
1F4A56851A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */,
DD9A9A8F19CF439B00706F49 /* BeIdenticalToObjectTest.swift in Sources */,
891364B229E6963C00AD535E /* utils.swift in Sources */,
Expand Down Expand Up @@ -1830,6 +1851,7 @@
899441FA2902EF2700C1FAF9 /* DSL+AsyncAwait.swift in Sources */,
1F5DF1781BDCA0F500C3A531 /* BeAnInstanceOf.swift in Sources */,
1F5DF1771BDCA0F500C3A531 /* BeAKindOf.swift in Sources */,
891A04732AB0164500B46613 /* AsyncTimerSequence.swift in Sources */,
1F5DF17F1BDCA0F500C3A531 /* BeLessThan.swift in Sources */,
1F5DF17C1BDCA0F500C3A531 /* BeGreaterThan.swift in Sources */,
1F91DD331C74BF61002C309F /* BeVoid.swift in Sources */,
Expand Down Expand Up @@ -1891,6 +1913,7 @@
8969624C2A5FAD6100A7929D /* AsyncAllPassTest.swift in Sources */,
1F5DF1981BDCA10200C3A531 /* BeAKindOfTest.swift in Sources */,
1F5DF19B1BDCA10200C3A531 /* BeEmptyTest.swift in Sources */,
89C297D42A92E815002A143F /* AsyncPromiseTest.swift in Sources */,
7B5358BC1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */,
89F5E06F290765BB001F9377 /* PollingTest.swift in Sources */,
1F5DF1A11BDCA10200C3A531 /* BeLessThanOrEqualToTest.swift in Sources */,
Expand Down Expand Up @@ -1938,6 +1961,7 @@
7A6AB2C41E7F547E00A2F694 /* ToSucceedTest.swift in Sources */,
CD79C9A71D2CC848004B6F9A /* ObjCBeGreaterThanTest.m in Sources */,
CD79C9A51D2CC848004B6F9A /* ObjCBeginWithTest.m in Sources */,
89C297D02A92E80E002A143F /* AsyncTimerSequenceTest.swift in Sources */,
1F5DF1AA1BDCA10200C3A531 /* RaisesExceptionTest.swift in Sources */,
89F5E0A1290C37F7001F9377 /* ObjCBeLessThanTest.m in Sources */,
8913649229E6925D00AD535E /* utils.swift in Sources */,
Expand Down Expand Up @@ -2029,6 +2053,7 @@
896962412A5FABD000A7929D /* AsyncAllPass.swift in Sources */,
CDFB6A251F7E07C700AD8CC7 /* CwlCatchException.m in Sources */,
1FD8CD391968AB07008ED995 /* Expression.swift in Sources */,
891A04712AB0164500B46613 /* AsyncTimerSequence.swift in Sources */,
CDFB6A4B1F7E082500AD8CC7 /* mach_excServer.c in Sources */,
89EEF5A52A03293100988224 /* AsyncPredicate.swift in Sources */,
1FD8CD3B1968AB07008ED995 /* FailureMessage.swift in Sources */,
Expand All @@ -2055,6 +2080,7 @@
8969624A2A5FAD5F00A7929D /* AsyncAllPassTest.swift in Sources */,
1F4A56671A3B305F009E1637 /* ObjCAsyncTest.m in Sources */,
1F925EFD195C186800ED456B /* BeginWithTest.swift in Sources */,
89C297CE2A92AB34002A143F /* AsyncPromiseTest.swift in Sources */,
89F5E06D290765BB001F9377 /* PollingTest.swift in Sources */,
DDB4D5F119FE442800E9D9FE /* MatchTest.swift in Sources */,
1F4A56741A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */,
Expand Down Expand Up @@ -2102,6 +2128,7 @@
106112C52251E13B000A5848 /* BeResultTest.swift in Sources */,
1F4A56861A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */,
89F5E09B290C37B8001F9377 /* OnFailureThrowsTest.swift in Sources */,
89C297CC2A911CDA002A143F /* AsyncTimerSequenceTest.swift in Sources */,
DD9A9A9019CF43AD00706F49 /* BeIdenticalToObjectTest.swift in Sources */,
1F4BB8B61DACA0E30048464B /* ThrowAssertionTest.swift in Sources */,
8913649429E6925F00AD535E /* utils.swift in Sources */,
Expand Down Expand Up @@ -2153,6 +2180,7 @@
899441FB2902EF2800C1FAF9 /* DSL+AsyncAwait.swift in Sources */,
D95F8968267EA20A004B1B4D /* BeGreaterThan.swift in Sources */,
D95F8972267EA20A004B1B4D /* Match.swift in Sources */,
891A04742AB0164500B46613 /* AsyncTimerSequence.swift in Sources */,
D95F8986267EA20E004B1B4D /* Stringers.swift in Sources */,
D95F8985267EA20E004B1B4D /* NimbleTimeInterval.swift in Sources */,
D95F895A267EA205004B1B4D /* Expression.swift in Sources */,
Expand Down Expand Up @@ -2214,6 +2242,7 @@
8969624D2A5FAD6300A7929D /* AsyncAllPassTest.swift in Sources */,
D95F8939267EA1E8004B1B4D /* BeIdenticalToObjectTest.swift in Sources */,
891364AC29E695F300AD535E /* ObjCBeCloseToTest.m in Sources */,
89C297D32A92E814002A143F /* AsyncPromiseTest.swift in Sources */,
899441F22902EE4B00C1FAF9 /* AsyncAwaitTest.swift in Sources */,
891364AD29E695F300AD535E /* ObjCBeNilTest.m in Sources */,
D95F8937267EA1E8004B1B4D /* BeginWithTest.swift in Sources */,
Expand Down Expand Up @@ -2261,6 +2290,7 @@
D95F892F267EA1D9004B1B4D /* SynchronousTest.swift in Sources */,
8913649E29E695F300AD535E /* ObjCSatisfyAllOfTest.m in Sources */,
D95F8953267EA1EE004B1B4D /* AlwaysFailMatcher.swift in Sources */,
89C297D12A92E80F002A143F /* AsyncTimerSequenceTest.swift in Sources */,
89F5E09A290C37B8001F9377 /* StatusTest.swift in Sources */,
D95F892A267EA1D9004B1B4D /* UserDescriptionTest.swift in Sources */,
D95F893F267EA1E8004B1B4D /* BeLessThanOrEqualToTest.swift in Sources */,
Expand Down
1 change: 0 additions & 1 deletion Sources/Nimble/AsyncExpression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,3 @@ public struct AsyncExpression<Value> {
)
}
}

7 changes: 1 addition & 6 deletions Sources/Nimble/DSL+AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ private func throwableUntil(
file: FileString = #file,
line: UInt = #line,
action: @escaping (@escaping () -> Void) async throws -> Void) async {
let awaiter = NimbleEnvironment.activeInstance.awaiter
let leeway = timeout.divided
let result = await awaiter.performBlock(file: file, line: line) { @MainActor (done: @escaping (ErrorResult) -> Void) async throws -> Void in
let result = await performBlock(timeoutInterval: timeout, leeway: leeway, file: file, line: line) { @MainActor (done: @escaping (ErrorResult) -> Void) async throws -> Void in
do {
try await action {
done(.none)
Expand All @@ -127,8 +126,6 @@ private func throwableUntil(
done(.error(e))
}
}
.timeout(timeout, forcefullyAbortTimeout: leeway)
.wait("waitUntil(...)", file: file, line: line)

switch result {
case .incomplete: internalError("Reached .incomplete state for waitUntil(...).")
Expand All @@ -137,8 +134,6 @@ private func throwableUntil(
file: file, line: line)
case .timedOut:
fail("Waited more than \(timeout.description)", file: file, line: line)
case let .raisedException(exception):
fail("Unexpected exception raised: \(exception)")
case let .errorThrown(error):
fail("Unexpected error thrown: \(error)")
case .completed(.error(let error)):
Expand Down
1 change: 0 additions & 1 deletion Sources/Nimble/DSL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ internal func internalError(_ msg: String, file: FileString = #file, line: UInt
Please file a bug to Nimble: https://github.com/Quick/Nimble/issues with the code snippet that caused this error.
"""
)
// swiftlint:enable line_length
}

#if canImport(Darwin)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Nimble/Polling+AsyncAwait.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private actor Poller<T> {
self.updatePredicateResult(result: try await predicateRunner())
.toBoolean(expectation: style)
}
return processPollResult(result, matchStyle: matchStyle, lastPredicateResult: lastPredicateResult, fnName: fnName)
return processPollResult(result.toPollResult(), matchStyle: matchStyle, lastPredicateResult: lastPredicateResult, fnName: fnName)
}

func updatePredicateResult(result: PredicateResult) -> PredicateResult {
Expand Down
Loading

0 comments on commit 3f9773e

Please sign in to comment.