Files
OSGKeyboard/OSGKeyboardTests/FlowPiPRecoveryPolicyTests.swift
T
Rocky 10bc457c72
CI / Validate manifests (push) Has been cancelled
CI / SwiftLint (push) Has been cancelled
CI / iOS / Extension (push) Has been cancelled
CI / macOS (push) Has been cancelled
feat(app): add resilient Flow recovery and privacy-safe analytics
Unify PiP recovery across startup and foreground transitions, surface actionable status, and add privacy-safe analytics plus the refreshed onboarding and account experience. Update documentation assets and advance the release build to 84.
2026-08-20 20:22:20 +08:00

150 lines
4.2 KiB
Swift

// FlowPiPRecoveryPolicyTests.swift
// OSGKeyboardTests
@testable import OSGKeyboard
import XCTest
final class FlowPiPRecoveryPolicyTests: XCTestCase {
// MARK: - Reconciliation
func testNoSessionIntentNeverStartsRecovery() {
XCTAssertEqual(
FlowPiPRecoveryPolicy.reconciliationDecision(
wantsActiveSession: false,
isAppForeground: true,
isPictureInPictureActive: false
),
.noSessionIntent
)
}
func testActivePiPIsIdempotent() {
XCTAssertEqual(
FlowPiPRecoveryPolicy.reconciliationDecision(
wantsActiveSession: true,
isAppForeground: true,
isPictureInPictureActive: true
),
.alreadyActive
)
}
func testTakeoverWaitsWhileAppIsInBackground() {
XCTAssertEqual(
FlowPiPRecoveryPolicy.reconciliationDecision(
wantsActiveSession: true,
isAppForeground: false,
isPictureInPictureActive: false
),
.waitForForeground
)
}
func testReturningToForegroundStartsRecovery() {
XCTAssertEqual(
FlowPiPRecoveryPolicy.reconciliationDecision(
wantsActiveSession: true,
isAppForeground: true,
isPictureInPictureActive: false
),
.startRecovery
)
}
// MARK: - Bounded retry
func testRetryPolicyUsesThreeIncreasingBoundedAttempts() {
XCTAssertEqual(FlowPiPRecoveryPolicy.maxAttempts, 3)
XCTAssertEqual(
(1...FlowPiPRecoveryPolicy.maxAttempts).map {
FlowPiPRecoveryPolicy.retryDelay(beforeAttempt: $0)
},
[0, 0.25, 0.6]
)
XCTAssertEqual(FlowPiPRecoveryPolicy.totalBudget, 5)
}
func testRetryTimeoutsNeverExceedRemainingBudget() {
XCTAssertEqual(
FlowPiPRecoveryPolicy.hostTimeout(attempt: 1, remainingBudget: 0.4),
0.4
)
XCTAssertEqual(
FlowPiPRecoveryPolicy.hostTimeout(attempt: 2, remainingBudget: 4),
0.25
)
XCTAssertEqual(
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 0.3),
0.3
)
XCTAssertEqual(
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 4),
1.4
)
XCTAssertEqual(
FlowPiPRecoveryPolicy.activeTimeout(remainingBudget: 0.01),
0.01
)
}
// MARK: - Late completion safety
func testCurrentForegroundOperationCanContinue() {
XCTAssertTrue(
FlowPiPRecoveryPolicy.canContinue(
operation: 7,
currentOperation: 7,
wantsActiveSession: true,
isAppForeground: true,
taskIsCancelled: false
)
)
}
func testOldGenerationCannotOverwriteNewRecovery() {
XCTAssertFalse(
FlowPiPRecoveryPolicy.canContinue(
operation: 6,
currentOperation: 7,
wantsActiveSession: true,
isAppForeground: true,
taskIsCancelled: false
)
)
}
func testExplicitEndPreventsLateRecovery() {
XCTAssertFalse(
FlowPiPRecoveryPolicy.canContinue(
operation: 7,
currentOperation: 8,
wantsActiveSession: false,
isAppForeground: true,
taskIsCancelled: true
)
)
}
func testBackgroundAndCancellationBothStopRecovery() {
XCTAssertFalse(
FlowPiPRecoveryPolicy.canContinue(
operation: 7,
currentOperation: 7,
wantsActiveSession: true,
isAppForeground: false,
taskIsCancelled: false
)
)
XCTAssertFalse(
FlowPiPRecoveryPolicy.canContinue(
operation: 7,
currentOperation: 7,
wantsActiveSession: true,
isAppForeground: true,
taskIsCancelled: true
)
)
}
}