Skip to content

Commit ae42424

Browse files
committed
fix: Fix compilation error for consolidated AsyncSemaphoreTests.
1 parent 2e8dd3b commit ae42424

File tree

1 file changed

+70
-66
lines changed

1 file changed

+70
-66
lines changed

Tests/DispatchAsyncTests/AsyncSemaphoreTests.swift

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,80 +16,84 @@ import Testing
1616

1717
@testable import DispatchAsync
1818

19-
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)
20-
@Test(.timeLimit(.minutes(1)))
21-
func asyncSemaphoreWaitSignal() async throws {
22-
let semaphore = AsyncSemaphore(value: 1)
23-
24-
// First wait should succeed immediately and bring the count to 0
25-
await semaphore.wait()
26-
27-
// Launch a task that tries to wait – it should be suspended until we signal
28-
nonisolated(unsafe) var didEnterCriticalSection = false
29-
await withCheckedContinuation { continuation in
30-
Task { @Sendable in
31-
// Ensure the rest of this test doesn't
32-
// proceed until the Task block has started executing
33-
continuation.resume()
34-
35-
await semaphore.wait()
36-
didEnterCriticalSection = true
37-
await semaphore.signal()
38-
}
39-
}
40-
41-
// Allow the task a few cycles to reach the initial semaphore.wait()
42-
try? await Task.sleep(nanoseconds: 1_000)
43-
44-
#expect(!didEnterCriticalSection) // should still be waiting
45-
46-
// Now release the semaphore – the waiter should proceed
47-
await semaphore.signal()
19+
nonisolated(unsafe) private var sharedPoolCompletionCount = 0
20+
21+
@Suite("DispatchGroup Tests")
22+
class AsyncSemaphoreTests {
23+
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)
24+
@Test(.timeLimit(.minutes(1)))
25+
func asyncSemaphoreWaitSignal() async throws {
26+
let semaphore = AsyncSemaphore(value: 1)
27+
28+
// First wait should succeed immediately and bring the count to 0
29+
await semaphore.wait()
30+
31+
// Launch a task that tries to wait – it should be suspended until we signal
32+
nonisolated(unsafe) var didEnterCriticalSection = false
33+
await withCheckedContinuation { continuation in
34+
Task { @Sendable in
35+
// Ensure the rest of this test doesn't
36+
// proceed until the Task block has started executing
37+
continuation.resume()
4838

49-
// Wait for second signal to fire from inside the task above
50-
// There is a timeout on this test, so if there is a problem
51-
// we'll either hit the timeout and fail, or didEnterCriticalSection
52-
// will be false below
53-
await semaphore.wait()
54-
55-
#expect(didEnterCriticalSection) // waiter must have run
56-
}
57-
58-
@Test func basicAsyncSemaphoreTest() async throws {
59-
nonisolated(unsafe) var sharedPoolCompletionCount = 0
60-
sharedPoolCompletionCount = 0 // Reset to 0 for each test run
61-
let totalConcurrentPools = 10
39+
await semaphore.wait()
40+
didEnterCriticalSection = true
41+
await semaphore.signal()
42+
}
43+
}
6244

63-
let semaphore = AsyncSemaphore(value: 1)
45+
// Allow the task a few cycles to reach the initial semaphore.wait()
46+
try? await Task.sleep(nanoseconds: 1_000)
6447

65-
await withTaskGroup(of: Void.self) { group in
66-
for _ in 0 ..< totalConcurrentPools {
67-
group.addTask {
68-
// Wait for any other pools currently holding the semaphore
69-
await semaphore.wait()
48+
#expect(!didEnterCriticalSection) // should still be waiting
7049

71-
// Only one task should mutate counter at a time
72-
//
73-
// If there are issues with the semaphore, then
74-
// we would expect to grab incorrect values here occasionally,
75-
// which would result in an incorrect final completion count.
76-
//
77-
let existingPoolCompletionCount = sharedPoolCompletionCount
50+
// Now release the semaphore – the waiter should proceed
51+
await semaphore.signal()
7852

79-
// Add artificial delay to amplify race conditions
80-
// Pools started shortly after this "semaphore-locked"
81-
// pool starts will run before this line, unless
82-
// this pool contains a valid lock.
83-
try? await Task.sleep(nanoseconds: 100)
53+
// Wait for second signal to fire from inside the task above
54+
// There is a timeout on this test, so if there is a problem
55+
// we'll either hit the timeout and fail, or didEnterCriticalSection
56+
// will be false below
57+
await semaphore.wait()
8458

85-
sharedPoolCompletionCount = existingPoolCompletionCount + 1
59+
#expect(didEnterCriticalSection) // waiter must have run
60+
}
8661

87-
// When we exit this flow, release our hold on the semaphore
88-
await semaphore.signal()
62+
@Test func basicAsyncSemaphoreTest() async throws {
63+
sharedPoolCompletionCount = 0 // Reset to 0 for each test run
64+
let totalConcurrentPools = 10
65+
66+
let semaphore = AsyncSemaphore(value: 1)
67+
68+
await withTaskGroup(of: Void.self) { group in
69+
for _ in 0 ..< totalConcurrentPools {
70+
group.addTask {
71+
// Wait for any other pools currently holding the semaphore
72+
await semaphore.wait()
73+
74+
// Only one task should mutate counter at a time
75+
//
76+
// If there are issues with the semaphore, then
77+
// we would expect to grab incorrect values here occasionally,
78+
// which would result in an incorrect final completion count.
79+
//
80+
let existingPoolCompletionCount = sharedPoolCompletionCount
81+
82+
// Add artificial delay to amplify race conditions
83+
// Pools started shortly after this "semaphore-locked"
84+
// pool starts will run before this line, unless
85+
// this pool contains a valid lock.
86+
try? await Task.sleep(nanoseconds: 100)
87+
88+
sharedPoolCompletionCount = existingPoolCompletionCount + 1
89+
90+
// When we exit this flow, release our hold on the semaphore
91+
await semaphore.signal()
92+
}
8993
}
9094
}
91-
}
9295

93-
// After all tasks are done, counter should be 10
94-
#expect(sharedPoolCompletionCount == totalConcurrentPools)
96+
// After all tasks are done, counter should be 10
97+
#expect(sharedPoolCompletionCount == totalConcurrentPools)
98+
}
9599
}

0 commit comments

Comments
 (0)