// // StorageTests.swift // suixinkanTests // // Created by Codex on 2026/6/20. // import XCTest @testable import suixinkan /// 本地缓存 Store 测试,覆盖 UserDefaults 中的偏好和账号快照。 final class StorageTests: XCTestCase { /// 测试 SessionTokenStore 使用 UserDefaults 保存、读取、修剪和清空正式 token。 func testSessionTokenStorePersistsTokenInUserDefaults() throws { let defaults = makeIsolatedDefaults() let store = SessionTokenStore(defaults: defaults, key: "session.token.test") try store.save(" token-123 ") XCTAssertEqual(store.load(), "token-123") try store.clear() XCTAssertNil(store.load()) } /// 测试保存空 token 会清空本地正式 token。 func testSessionTokenStoreClearsWhenSavingBlankToken() throws { let defaults = makeIsolatedDefaults() let store = SessionTokenStore(defaults: defaults, key: "session.token.blank.test") try store.save("token-123") try store.save(" \n") XCTAssertNil(store.load()) } /// 测试 AppPreferencesStore 能保存并读取上次登录手机号和协议状态。 func testAppPreferencesStorePersistsLoginPreferences() { let defaults = makeIsolatedDefaults() let store = AppPreferencesStore(defaults: defaults) store.saveLastLoginUsername(" 18651857230 ") store.savePrivacyAgreementAccepted(true) XCTAssertEqual(store.loadLastLoginUsername(), "18651857230") XCTAssertTrue(store.loadPrivacyAgreementAccepted()) } /// 测试清空登录页偏好会移除隐私协议同意状态。 func testAppPreferencesStoreClearRemovesPrivacyAgreement() { let defaults = makeIsolatedDefaults() let store = AppPreferencesStore(defaults: defaults) store.savePrivacyAgreementAccepted(true) store.clear() XCTAssertFalse(store.loadPrivacyAgreementAccepted()) } /// 测试登录协调器保存隐私同意状态后会触发回调。 @MainActor func testAuthSessionCoordinatorPrivacyPersistenceTriggersCallback() { let defaults = makeIsolatedDefaults() let store = AppPreferencesStore(defaults: defaults) var persistedValues: [Bool] = [] let coordinator = AuthSessionCoordinator( tokenStore: SessionTokenStore(defaults: defaults, key: "session.token.privacy.test"), snapshotStore: AccountSnapshotStore(defaults: defaults, key: "account.snapshot.privacy.test"), preferencesStore: store, onPrivacyAgreementPersisted: { persistedValues.append($0) } ) coordinator.savePrivacyAgreementAccepted(true) XCTAssertTrue(store.loadPrivacyAgreementAccepted()) XCTAssertEqual(persistedValues, [true]) } /// 测试退出登录会保留隐私协议状态等非敏感偏好。 @MainActor func testAuthSessionCoordinatorLogoutKeepsPrivacyAgreement() { let defaults = makeIsolatedDefaults() let store = AppPreferencesStore(defaults: defaults) let coordinator = AuthSessionCoordinator( tokenStore: SessionTokenStore(defaults: defaults, key: "session.token.logout.test"), snapshotStore: AccountSnapshotStore(defaults: defaults, key: "account.snapshot.logout.test"), preferencesStore: store ) coordinator.savePrivacyAgreementAccepted(true) coordinator.logout( appSession: AppSession(), accountContext: AccountContext(), permissionContext: PermissionContext(), scenicSpotContext: ScenicSpotContext(), appRouter: AppRouter(), toastCenter: ToastCenter() ) XCTAssertTrue(store.loadPrivacyAgreementAccepted()) } /// 测试账号快照能保存并恢复账号资料、业务作用域和当前选择。 func testAccountSnapshotStorePersistsAccountContextSnapshot() { let defaults = makeIsolatedDefaults() let store = AccountSnapshotStore(defaults: defaults) let snapshot = AccountSnapshot( profile: AccountProfile( userId: "101", displayName: "测试账号", phone: "18651857230", avatarURL: "https://cdn.example.com/avatar.jpg" ), accountType: "store_user", businessUserId: 101, scenicScopes: [ BusinessScope(id: 88, name: "东门景区", kind: .scenic) ], storeScopes: [ BusinessScope(id: 66, name: "东门门店", kind: .store) ], currentScenicId: 88, currentStoreId: 66 ) store.save(snapshot) XCTAssertEqual(store.load(), snapshot) } /// 创建独立 UserDefaults,避免测试污染真实 App 偏好。 private func makeIsolatedDefaults() -> UserDefaults { let suiteName = "suixinkan.tests.\(UUID().uuidString)" let defaults = UserDefaults(suiteName: suiteName)! defaults.removePersistentDomain(forName: suiteName) return defaults } }