// // AppStoreCacheMigrationTests.swift // suixinkanTests // import XCTest @testable import suixinkan /// 验证覆盖升级清理、强制退出以及缓存结构版本幂等性。 final class AppStoreCacheMigrationTests: XCTestCase { private var suiteName: String! private var defaults: UserDefaults! override func setUp() { super.setUp() suiteName = "AppStoreCacheMigrationTests.\(UUID().uuidString)" defaults = UserDefaults(suiteName: suiteName) defaults.removePersistentDomain(forName: suiteName) } override func tearDown() { defaults.removePersistentDomain(forName: suiteName) defaults = nil suiteName = nil super.tearDown() } func testFirstInitializationClearsLegacyAndPreReleaseKeysAndForcesLogout() { let exactKeysToRemove = [ "suixinkan.session.v1", "apns_device_token", "apns_uploaded_token", "home.common.menu.uris", "home.common.menu.android.baseline.v2", "home.routing.unknown.records", "payment.voice.broadcast.enabled", "key_in_token", "key_last_login_username", "key_privacy_agreement_accepted", "key_in_user_id", "key_in_user_name", "key_in_real_name", "key_in_avatar", "key_in_phone", "key_in_account_type", "key_in_account_display_name", "key_in_role_id", "key_in_role_code", "key_in_role_name", "key_in_current_scenic_id", "key_in_current_scenic_name", "key_in_current_store_id", "key_role_permission_list", "key_in_permission", "key_current_role_scenic_list", "key_online_status", "key_last_location_report_time", "key_location_reminder_minutes", "key_is_open_receive_voice", "scenic_queue_tts_enabled", "scenic_queue_background_poll_enabled", "scenic_queue_selected_spot_id", "scenic_queue_selected_spot_name", "scenic_queue_custom_tts_text", "scenic_queue_photo_estimate_seconds", "scenic_queue_broadcast_interval_seconds", "scenic_queue_countdown_threshold_seconds", "scenic_queue_show_start_shooting_button", "scenic_queue_auto_call_ahead_count", "scenic_queue_quick_call_button_enabled", "scenic_queue_prepare_call_button_enabled", "scenic_queue_config_logs", "scenic_queue_settings_snapshot", "scenic_queue_preset_voices", ] let dynamicKeysToRemove = [ "account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_id", "account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_name", "account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33", "account_store_user_1001_31_22_scenic_22_scenic_queue_settings_snapshot_spot_33", "account_store_user_1001_31_22_scenic_22_scenic_queue_preset_voices_spot_33", "scenic_22_spot_33_scenic_queue_settings_snapshot", "scenic_22_spot_33_scenic_queue_preset_voices", "scenic_22_scenic_queue_settings_snapshot", "1001_store_user_key_in_role_id", "1001_store_user_key_role_permission_list", "1001_store_user_key_in_permission", "1001_store_user_key_current_role_scenic_list", "1001_store_user_key_online_status", "1001_store_user_key_last_location_report_time", "1001_store_user_key_location_reminder_minutes", "1001_store_user_key_is_open_receive_voice", "1001_store_user_role__common_uris", "1001_store_user_role_photographer_common_uris", "1001_store_user__scenic_queue_punch_spot_id", "1001_store_user__scenic_queue_punch_spot_name", "1001_store_user__scenic_queue_punch_spot_remark", "1001_store_user__scenic_queue_remark", "1001_store_user__scenic_queue_settings_snapshot", "1001_store_user__scenic_queue_offline_tts_v1", "1001_store_user__scenic_queue_preset_voices_v1", ] let keysToPreserve = [ "third_party.sentinel", "home.common.menu.uris.extra", "account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_identifier", "account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33_backup", "scenic_22_spot_33_scenic_queue_settings_snapshot_backup", "unrelated_key_in_permission_extra", "scenic_user_1001_key_in_role_code", "scenic_user_1001_scenic_22_scenic_queue_punch_spot_id", "scenic_user_1001_scenic_22_spot_33_scenic_queue_settings_snapshot", ] let keysToRemove = exactKeysToRemove + dynamicKeysToRemove keysToRemove.forEach { defaults.set("legacy", forKey: $0) } keysToPreserve.forEach { defaults.set("keep", forKey: $0) } defaults.set(true, forKey: "key_privacy_agreement_accepted") let store = AppStore(defaults: defaults) XCTAssertFalse(store.session.isLoggedIn) XCTAssertNil(store.session.lastLoginUsername) XCTAssertFalse(store.session.privacyAgreementAccepted) keysToRemove.forEach { XCTAssertNil(defaults.object(forKey: $0), "未清理 Key:\($0)") } keysToPreserve.forEach { XCTAssertEqual(defaults.string(forKey: $0), "keep", "误清理 Key:\($0)") } XCTAssertEqual( defaults.integer(forKey: AppStoreCacheMigrator.schemaVersionKey), AppStoreCacheMigrator.currentSchemaVersion ) } func testMigrationRunsOnlyOnceAndPreservesNewSession() { defaults.set("keep", forKey: "third_party.sentinel") var store = AppStore(defaults: defaults) store.session.token = "new-token" store.session.lastLoginUsername = "13800000000" store.session.privacyAgreementAccepted = true store.session.userId = "1001" store.session.accountType = .scenicUser store.session.roleCode = "photographer" store.session.currentScenicId = 22 store.scenicQueue.punchSpotId = "33" store.scenicQueue.punchSpotName = "东门" store = AppStore(defaults: defaults) XCTAssertTrue(store.session.isLoggedIn) XCTAssertEqual(store.session.token, "new-token") XCTAssertEqual(store.session.lastLoginUsername, "13800000000") XCTAssertTrue(store.session.privacyAgreementAccepted) XCTAssertEqual(store.session.roleCode, "photographer") XCTAssertEqual(store.session.currentScenicId, 22) XCTAssertEqual(store.scenicQueue.punchSpotId, "33") XCTAssertEqual(store.scenicQueue.punchSpotName, "东门") XCTAssertEqual(defaults.string(forKey: "third_party.sentinel"), "keep") } }