Files
steipete--codexbar/Tests/CodexBarTests/ClaudeOAuthKeychainPreAlertGateTests.swift
2026-07-13 12:22:33 +08:00

97 lines
4.1 KiB
Swift

import Foundation
import Testing
@testable import CodexBarCore
#if os(macOS)
@Suite(.serialized)
struct ClaudeOAuthKeychainPreAlertGateTests {
@Test
func `acknowledgement suppresses repeated presentation until cooldown expires`() {
let store = ClaudeOAuthKeychainPreAlertGate.StateStore()
ClaudeOAuthKeychainPreAlertGate.withStateStoreOverrideForTesting(store) {
let now = Date(timeIntervalSince1970: 1000)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now, completedAt: now) { true })
#expect(
ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: now.addingTimeInterval(ClaudeOAuthKeychainPreAlertGate.cooldownInterval - 1),
completedAt: now,
present: { true }) == false)
#expect(
ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: now.addingTimeInterval(ClaudeOAuthKeychainPreAlertGate.cooldownInterval + 1),
completedAt: now,
present: { true }))
}
}
@Test
func `cooldown starts when presentation completes`() {
let store = ClaudeOAuthKeychainPreAlertGate.StateStore()
ClaudeOAuthKeychainPreAlertGate.withStateStoreOverrideForTesting(store) {
let startedAt = Date(timeIntervalSince1970: 1000)
let completedAt = Date(timeIntervalSince1970: 2000)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: startedAt,
completedAt: completedAt,
present: { true }))
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: startedAt.addingTimeInterval(ClaudeOAuthKeychainPreAlertGate.cooldownInterval + 1),
completedAt: completedAt,
present: { true }) == false)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: completedAt.addingTimeInterval(ClaudeOAuthKeychainPreAlertGate.cooldownInterval + 1),
completedAt: completedAt,
present: { true }))
}
}
@Test
func `missing prompt handler does not consume acknowledgement cooldown`() {
let store = ClaudeOAuthKeychainPreAlertGate.StateStore()
ClaudeOAuthKeychainPreAlertGate.withStateStoreOverrideForTesting(store) {
let now = Date(timeIntervalSince1970: 2000)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now, completedAt: now) { false } == false)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now, completedAt: now) { true })
}
}
@Test
func `duplicate while presentation is in flight is suppressed`() {
let store = ClaudeOAuthKeychainPreAlertGate.StateStore()
ClaudeOAuthKeychainPreAlertGate.withStateStoreOverrideForTesting(store) {
let now = Date(timeIntervalSince1970: 3000)
var nestedPresentationRan = false
var nestedResult: Bool?
let outerResult = ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now, completedAt: now) {
nestedResult = ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now) {
nestedPresentationRan = true
return true
}
return true
}
#expect(outerResult)
#expect(nestedResult == false)
#expect(nestedPresentationRan == false)
}
}
@Test
func `acknowledgement persists across in memory reset`() {
ClaudeOAuthKeychainPreAlertGate.resetForTesting()
defer { ClaudeOAuthKeychainPreAlertGate.resetForTesting() }
let now = Date(timeIntervalSince1970: 4000)
#expect(ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(now: now, completedAt: now) { true })
ClaudeOAuthKeychainPreAlertGate.resetInMemoryForTesting()
#expect(
ClaudeOAuthKeychainPreAlertGate.presentIfNeeded(
now: now.addingTimeInterval(ClaudeOAuthKeychainPreAlertGate.cooldownInterval - 1),
completedAt: now,
present: { true }) == false)
}
}
#endif