Signal-iOS/SignalServiceKit/tests/Preconditions/NotificationPreconditionTest.swift
2025-05-02 01:03:16 -05:00

52 lines
1.9 KiB
Swift

//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import Testing
@testable import SignalServiceKit
struct NotificationPreconditionTest {
let notificationName: Notification.Name = Notification.Name(UUID().uuidString)
@Test
func testSynchronous() async {
let precondition = NotificationPrecondition(notificationName: notificationName, isSatisfied: { true })
let waitResult = await precondition.waitUntilSatisfied()
#expect(waitResult == .satisfiedImmediately)
}
@Test
func testCanceled() async {
let precondition = NotificationPrecondition(notificationName: notificationName, isSatisfied: { false })
let waitTask = Task { await precondition.waitUntilSatisfied() }
waitTask.cancel()
let waitResult = await waitTask.value
#expect(waitResult == .canceled)
}
@Test
func testRaceCondition() async {
let checkCount = AtomicValue(0, lock: .init())
let isSatisfied: @Sendable () -> Bool = {
let checkCountValue = checkCount.update { $0 += 1; return $0 }
if checkCountValue == 1 {
// Simulate the flag changing & the notification being posted while the
// result is still being returned to the caller. The test code is
// contrived, but it illustrates a real race condition.
NotificationCenter.default.post(name: notificationName, object: nil)
return false
}
if checkCountValue == 2 {
return true
}
fatalError()
}
let precondition = NotificationPrecondition(notificationName: notificationName, isSatisfied: isSatisfied)
let waitResult = await precondition.waitUntilSatisfied()
#expect(waitResult == .wasNotSatisfiedButIsNow)
}
}