// // HomeCommonMenuStoreTests.swift // suixinkanTests // // Created by Codex on 2026/6/22. // import XCTest @testable import suixinkan /// 首页常用应用存储测试,覆盖默认值、过滤和别名去重。 final class HomeCommonMenuStoreTests: XCTestCase { /// 测试首次无配置时会按顶层权限生成默认常用应用。 func testLoadCreatesDefaultCommonMenusFromTopLevelPermissions() { let defaults = makeIsolatedDefaults() let store = HomeCommonMenuStore(defaults: defaults) let menus = [ menu("space_settings"), menu("wallet"), menu("cloud_management"), menu("message_center") ] let uris = store.load( menuItems: menus, roleCode: "photographer", topLevelPermissionURIs: ["space_settings", "wallet", "cloud_management", "message_center"] ) XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management", "message_center"]) XCTAssertEqual( defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer"), ["space_settings", "wallet", "cloud_management", "message_center"] ) } /// 测试顶层权限超过 4 个时只取前 4 个默认常用应用。 func testDefaultCommonURIsTakeFirstFourWhenMoreThanFourPermissions() { let availableURIs: Set = [ "space_settings", "wallet", "cloud_management", "message_center", "task_management" ] let uris = HomeCommonMenuStore.defaultCommonURIs( orderedTopLevelURIs: [ "space_settings", "wallet", "cloud_management", "message_center", "task_management" ], availableURIs: availableURIs ) XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management", "message_center"]) } /// 测试角色没有旧硬编码默认 URI 时仍能从权限列表生成常用应用。 func testLoadCreatesDefaultsWithoutLegacyPreferredURIs() { let defaults = makeIsolatedDefaults() let store = HomeCommonMenuStore(defaults: defaults) let menus = [ menu("space_settings"), menu("wallet"), menu("cloud_management") ] let uris = store.load( menuItems: menus, roleCode: "editor", topLevelPermissionURIs: ["space_settings", "wallet", "cloud_management"] ) XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management"]) } /// 测试已保存 URI 会按当前权限过滤并解析同义 URI。 func testLoadFiltersSavedUrisByCurrentPermissions() { let defaults = makeIsolatedDefaults() defaults.set(["task_management", "unknown", "pm"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer") let store = HomeCommonMenuStore(defaults: defaults) let menus = [ menu("task_management_editor"), menu("project_edit") ] let uris = store.load( menuItems: menus, roleCode: "photographer", topLevelPermissionURIs: ["task_management_editor", "project_edit"] ) XCTAssertEqual(uris, ["task_management_editor", "project_edit"]) } /// 测试不同角色使用独立存储 key。 func testLoadUsesRoleScopedStorageKeys() { let defaults = makeIsolatedDefaults() defaults.set(["wallet"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer") defaults.set(["cloud_management"], forKey: HomeCommonMenuStore.storageKeyPrefix + "editor") let store = HomeCommonMenuStore(defaults: defaults) let menus = [ menu("wallet"), menu("cloud_management") ] let roleOne = store.load( menuItems: menus, roleCode: "photographer", topLevelPermissionURIs: ["wallet", "cloud_management"] ) let roleTwo = store.load( menuItems: menus, roleCode: "editor", topLevelPermissionURIs: ["wallet", "cloud_management"] ) XCTAssertEqual(roleOne, ["wallet"]) XCTAssertEqual(roleTwo, ["cloud_management"]) } /// 测试添加常用应用时会按同义 URI 去重。 func testAddDeduplicatesAliases() { let defaults = makeIsolatedDefaults() let store = HomeCommonMenuStore(defaults: defaults) let menus = [ menu("task_management_editor") ] let uris = store.add( "task_management", current: ["task_management_editor"], menuItems: menus, roleCode: "photographer" ) XCTAssertEqual(uris, ["task_management_editor"]) } /// 测试移除常用应用时会移除同义 URI。 func testRemoveDeletesAliases() { let defaults = makeIsolatedDefaults() let store = HomeCommonMenuStore(defaults: defaults) let uris = store.remove("pm", current: ["project_edit", "pm_manager", "location_report"], roleCode: "photographer") XCTAssertEqual(uris, ["pm_manager", "location_report"]) } /// 测试无 role_code 时不读写常用应用。 func testLoadReturnsEmptyWhenRoleCodeIsMissing() { let defaults = makeIsolatedDefaults() let store = HomeCommonMenuStore(defaults: defaults) let uris = store.load( menuItems: [menu("wallet")], roleCode: nil, topLevelPermissionURIs: ["wallet"] ) XCTAssertTrue(uris.isEmpty) XCTAssertNil(defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer")) } /// 测试从 legacy role id key 一次性迁移常用菜单。 func testLoadMigratesLegacyRoleIdStorageKey() { let defaults = makeIsolatedDefaults() defaults.set(["wallet", "cloud_management"], forKey: HomeCommonMenuStore.storageKeyPrefix + "46") let store = HomeCommonMenuStore(defaults: defaults) let menus = [menu("wallet"), menu("cloud_management")] let uris = store.load( menuItems: menus, roleCode: "store_admin", legacyRoleId: 46, topLevelPermissionURIs: ["wallet", "cloud_management"] ) XCTAssertEqual(uris, ["wallet", "cloud_management"]) XCTAssertEqual(defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "store_admin"), ["wallet", "cloud_management"]) XCTAssertNil(defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "46")) } /// 创建测试菜单实体。 private func menu(_ uri: String) -> HomeMenuItem { HomeMenuItem(title: HomeMenuRouter.title(for: uri), uri: uri, iconSrc: nil) } /// 创建独立 UserDefaults,避免测试污染真实 App 偏好。 private func makeIsolatedDefaults() -> UserDefaults { let suiteName = "suixinkan.home.tests.\(UUID().uuidString)" let defaults = UserDefaults(suiteName: suiteName)! defaults.removePersistentDomain(forName: suiteName) return defaults } }