// // AppStoreModuleTests.swift // suixinkanTests // import XCTest @testable import suixinkan /// 验证 AppStore 子模块的持久化、账号隔离与统一清理行为。 final class AppStoreModuleTests: XCTestCase { private var suiteName: String! private var defaults: UserDefaults! private var appStore: AppStore! override func setUp() { super.setUp() suiteName = "AppStoreModuleTests.\(UUID().uuidString)" defaults = UserDefaults(suiteName: suiteName) defaults.removePersistentDomain(forName: suiteName) appStore = AppStore(defaults: defaults) } override func tearDown() { defaults.removePersistentDomain(forName: suiteName) appStore = nil defaults = nil suiteName = nil super.tearDown() } func testAccountTypeKnownAndUnknownRawValueRoundTrips() { XCTAssertEqual(AppAccountType(rawValue: "scenic_user"), .scenicUser) XCTAssertEqual(AppAccountType(rawValue: "store_user"), .storeUser) XCTAssertEqual(AppAccountType(rawValue: "future_account"), .unknown("future_account")) XCTAssertEqual(AppAccountType.scenicUser.rawValue, "scenic_user") XCTAssertEqual(AppAccountType.storeUser.rawValue, "store_user") XCTAssertEqual(AppAccountType.unknown("future_account").rawValue, "future_account") } func testSessionUsesGlobalIdentityAndScopedBusinessContext() { defaults.set("legacy-token", forKey: "key_in_token") defaults.set("future_account", forKey: "key_in_account_type") XCTAssertEqual(appStore.session.token, "legacy-token") XCTAssertEqual(appStore.session.accountType, .unknown("future_account")) appStore.session.userId = "1001" appStore.session.roleCode = "future_role" appStore.session.currentScenicId = 22 appStore.session.currentScenicName = "测试景区" appStore.session.currentStoreId = 31 XCTAssertEqual(defaults.string(forKey: "key_in_user_id"), "1001") XCTAssertNil(defaults.object(forKey: "key_in_current_scenic_id")) XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_role_code"), "future_role") XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_current_scenic_id"), "22") XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_current_scenic_name"), "测试景区") XCTAssertEqual(defaults.integer(forKey: "future_account_1001_scenic_22_scenic_store_id"), 31) XCTAssertEqual(appStore.session.accountCachePrefix, "future_account_1001") } func testIncompleteAccountScopeDoesNotWriteBusinessCache() { appStore.session.userId = "1001" appStore.session.currentScenicId = 22 appStore.session.roleCode = "photographer" appStore.permissions.savePermissionItems([HomePermissionItem(id: "1", name: "钱包", uri: "wallet")]) appStore.location.onlineStatus = true appStore.payment.isOpenReceiveVoice = true appStore.scenicQueue.punchSpotId = "33" XCTAssertEqual(appStore.session.accountCachePrefix, "") XCTAssertEqual(appStore.session.currentScenicId, 0) XCTAssertEqual(appStore.session.roleCode, "") XCTAssertTrue(appStore.permissions.permissionItems().isEmpty) XCTAssertFalse(appStore.location.onlineStatus) XCTAssertFalse(appStore.payment.isOpenReceiveVoice) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "") XCTAssertFalse(defaults.dictionaryRepresentation().keys.contains { $0.contains("guest") }) } func testFeatureStoresAreIsolatedByAccountAndDecodeSnapshots() { selectAccount(userId: "1001", type: .scenicUser) let permissions = [HomePermissionItem(id: "1", name: "钱包", uri: "wallet")] let scenicList = [ScenicInfo(id: 22, name: "测试景区", status: 1)] var queueSettings = ScenicQueueSettingsSnapshot() queueSettings.shootMinute = 8 appStore.permissions.savePermissionItems(permissions) appStore.permissions.saveRoleScenicList(scenicList) appStore.location.onlineStatus = true appStore.location.lastReportTime = 123_456 appStore.location.reminderMinutes = 10 appStore.payment.isOpenReceiveVoice = true appStore.scenicQueue.punchSpotId = "33" appStore.scenicQueue.punchSpotName = "东门" appStore.scenicQueue.remark = "请提前准备" appStore.scenicQueue.saveSettingsSnapshot(queueSettings) appStore.scenicQueue.savePresetVoices([" A ", "", "B"]) XCTAssertTrue(appStore.scenicQueue.useOfflineTTS) appStore.scenicQueue.useOfflineTTS = false selectAccount(userId: "2002", type: .storeUser) XCTAssertTrue(appStore.permissions.permissionItems().isEmpty) XCTAssertTrue(appStore.permissions.roleScenicList().isEmpty) XCTAssertFalse(appStore.location.onlineStatus) XCTAssertEqual(appStore.location.lastReportTime, 0) XCTAssertEqual(appStore.location.reminderMinutes, 0) XCTAssertFalse(appStore.payment.isOpenReceiveVoice) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "") XCTAssertNil(appStore.scenicQueue.settingsSnapshot()) XCTAssertTrue(appStore.scenicQueue.useOfflineTTS) selectAccount(userId: "1001", type: .scenicUser) XCTAssertEqual(appStore.permissions.permissionItems(), permissions) XCTAssertEqual(appStore.permissions.roleScenicList(), scenicList) XCTAssertTrue(appStore.location.onlineStatus) XCTAssertEqual(appStore.location.lastReportTime, 123_456) XCTAssertEqual(appStore.location.reminderMinutes, 10) XCTAssertTrue(appStore.payment.isOpenReceiveVoice) XCTAssertTrue(appStore.scenicQueue.hasPunchSpotSaved()) XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门") XCTAssertEqual(appStore.scenicQueue.remark, "请提前准备") XCTAssertEqual(appStore.scenicQueue.settingsSnapshot(), queueSettings) XCTAssertEqual(appStore.scenicQueue.presetVoices(), ["A", "B"]) XCTAssertFalse(appStore.scenicQueue.useOfflineTTS) } func testStoreAndQueueCachesAreIsolatedByScenicAndSpot() { selectAccount(userId: "1001", type: .scenicUser, scenicId: 22) appStore.session.currentStoreId = 220 appStore.scenicQueue.punchSpotId = "33" appStore.scenicQueue.punchSpotName = "东门" appStore.scenicQueue.remark = "东门备注" appStore.scenicQueue.useOfflineTTS = false appStore.scenicQueue.punchSpotId = "44" XCTAssertEqual(appStore.scenicQueue.punchSpotName, "") XCTAssertEqual(appStore.scenicQueue.remark, "") appStore.scenicQueue.punchSpotName = "西门" appStore.scenicQueue.remark = "西门备注" appStore.scenicQueue.punchSpotId = "33" XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门") XCTAssertEqual(appStore.scenicQueue.remark, "东门备注") appStore.session.currentScenicId = 23 XCTAssertEqual(appStore.session.currentStoreId, 0) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "") XCTAssertTrue(appStore.scenicQueue.useOfflineTTS) appStore.session.currentStoreId = 230 appStore.scenicQueue.punchSpotId = "55" appStore.scenicQueue.punchSpotName = "南门" appStore.session.currentScenicId = 22 XCTAssertEqual(appStore.session.currentStoreId, 220) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "33") XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门") XCTAssertFalse(appStore.scenicQueue.useOfflineTTS) XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_scenic_queue_punch_spot_id"), "33") XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_spot_33_scenic_queue_punch_spot_name"), "东门") XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_spot_33_scenic_queue_remark"), "东门备注") XCTAssertFalse(defaults.dictionaryRepresentation().keys.contains { $0.contains("__scenic_queue") }) } func testLogoutClearsCurrentAccountModulesAndPreservesLoginPreferences() { appStore.session.lastLoginUsername = "13800000000" appStore.session.privacyAgreementAccepted = true selectAccount(userId: "other", type: .storeUser, scenicId: 22) appStore.scenicQueue.punchSpotId = "99" selectAccount(userId: "current", type: .scenicUser, scenicId: 22) appStore.session.token = "token" appStore.permissions.legacyRoleId = 41 appStore.permissions.savePermissionItems([HomePermissionItem(id: "1", name: "钱包", uri: "wallet")]) appStore.location.onlineStatus = true appStore.payment.isOpenReceiveVoice = true appStore.scenicQueue.punchSpotId = "33" appStore.scenicQueue.punchSpotName = "东门" appStore.session.currentScenicId = 23 appStore.scenicQueue.punchSpotId = "44" appStore.scenicQueue.punchSpotName = "西门" appStore.logout() XCTAssertFalse(appStore.session.isLoggedIn) XCTAssertEqual(appStore.session.userId, "") XCTAssertEqual(appStore.session.lastLoginUsername, "13800000000") XCTAssertTrue(appStore.session.privacyAgreementAccepted) selectAccount(userId: "current", type: .scenicUser, scenicId: 22) XCTAssertEqual(appStore.permissions.legacyRoleId, 0) XCTAssertTrue(appStore.permissions.permissionItems().isEmpty) XCTAssertFalse(appStore.location.onlineStatus) XCTAssertFalse(appStore.payment.isOpenReceiveVoice) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "") appStore.session.currentScenicId = 23 XCTAssertEqual(appStore.scenicQueue.punchSpotId, "") selectAccount(userId: "other", type: .storeUser, scenicId: 22) XCTAssertEqual(appStore.scenicQueue.punchSpotId, "99") } private func selectAccount(userId: String, type: AppAccountType, scenicId: Int = 22) { appStore.session.userId = userId appStore.session.accountType = type appStore.session.currentScenicId = scenicId } }