321 lines
12 KiB
Swift
321 lines
12 KiB
Swift
//
|
||
// 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<String> = [
|
||
"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 会按当前权限和 Android 白名单过滤并解析同义 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"])
|
||
}
|
||
|
||
/// 测试同一角色不同账号使用独立的常用应用缓存。
|
||
func testLoadUsesAccountScopedStorageKeys() {
|
||
let defaults = makeIsolatedDefaults()
|
||
defaults.set(
|
||
["wallet"],
|
||
forKey: HomeCommonMenuStore.storageKey(roleCode: "photographer", accountScope: "scenic_user_101")
|
||
)
|
||
defaults.set(
|
||
["cloud_management"],
|
||
forKey: HomeCommonMenuStore.storageKey(roleCode: "photographer", accountScope: "store_user_101")
|
||
)
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [
|
||
menu("wallet"),
|
||
menu("cloud_management")
|
||
]
|
||
|
||
let scenic = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: ["wallet", "cloud_management"]
|
||
)
|
||
let storeAccount = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "store_user_101",
|
||
topLevelPermissionURIs: ["wallet", "cloud_management"]
|
||
)
|
||
|
||
XCTAssertEqual(scenic, ["wallet"])
|
||
XCTAssertEqual(storeAccount, ["cloud_management"])
|
||
}
|
||
|
||
/// 测试不同角色使用独立存储 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"))
|
||
}
|
||
|
||
/// 测试旧 roleCode key 会迁移到账号作用域 key。
|
||
func testLoadMigratesLegacyRoleCodeStorageKeyToAccountScopedKey() {
|
||
let defaults = makeIsolatedDefaults()
|
||
defaults.set(["wallet", "cloud_management"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer")
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [menu("wallet"), menu("cloud_management")]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: ["wallet", "cloud_management"]
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["wallet", "cloud_management"])
|
||
XCTAssertEqual(
|
||
defaults.stringArray(forKey: HomeCommonMenuStore.storageKey(roleCode: "photographer", accountScope: "scenic_user_101")),
|
||
["wallet", "cloud_management"]
|
||
)
|
||
XCTAssertNil(defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer"))
|
||
}
|
||
|
||
/// 测试 Android 白名单外的 URI 不会进入默认常用应用。
|
||
func testDefaultCommonURIsExcludeMenusMissingFromAndroidCatalog() {
|
||
let defaults = makeIsolatedDefaults()
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [
|
||
menu("wallet"),
|
||
menu("album_list"),
|
||
menu("cloud_storage_transit"),
|
||
menu("message_center")
|
||
]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: ["wallet", "album_list", "cloud_storage_transit", "message_center"]
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["wallet", "message_center"])
|
||
}
|
||
|
||
/// 测试已保存常用应用超过 4 个时只过滤权限,不会被强制截断。
|
||
func testSavedCommonURIsAreNotTruncatedToFour() {
|
||
let defaults = makeIsolatedDefaults()
|
||
defaults.set(
|
||
["space_settings", "wallet", "cloud_management", "asset_management", "message_center"],
|
||
forKey: HomeCommonMenuStore.storageKey(roleCode: "photographer", accountScope: "scenic_user_101")
|
||
)
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [
|
||
menu("space_settings"),
|
||
menu("wallet"),
|
||
menu("cloud_management"),
|
||
menu("asset_management"),
|
||
menu("message_center")
|
||
]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: menus.map(\.uri)
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management", "asset_management", "message_center"])
|
||
}
|
||
|
||
/// 测试默认常用只取顶层权限,不会用子权限补位。
|
||
func testDefaultCommonURIsUseOnlyTopLevelPermissions() {
|
||
let defaults = makeIsolatedDefaults()
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [
|
||
menu("task_management"),
|
||
menu("message_center")
|
||
]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: ["task_management"]
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["task_management"])
|
||
}
|
||
|
||
/// 创建测试菜单实体。
|
||
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
|
||
}
|
||
}
|