切换账号时以用户选中账号为准写入展示标题与业务作用域,避免沿用旧门店名称;同时将首页举报摄影师入口 URI 对齐为 report_photographer。 Co-authored-by: Cursor <cursoragent@cursor.com>
380 lines
14 KiB
Swift
380 lines
14 KiB
Swift
//
|
||
// HomeCommonMenuStoreTests.swift
|
||
// suixinkanTests
|
||
//
|
||
// Created by Codex on 2026/6/22.
|
||
//
|
||
|
||
import XCTest
|
||
@testable import suixinkan
|
||
|
||
/// 首页常用应用存储测试,覆盖默认值、过滤和 Android 对齐行为。
|
||
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 uris = HomeCommonMenuStore.defaultCommonURIs(
|
||
orderedTopLevelURIs: [
|
||
"space_settings",
|
||
"wallet",
|
||
"cloud_management",
|
||
"message_center",
|
||
"task_management"
|
||
]
|
||
)
|
||
|
||
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 会按当前顶层权限和白名单精确过滤。
|
||
func testLoadFiltersSavedUrisByCurrentPermissions() {
|
||
let defaults = makeIsolatedDefaults()
|
||
defaults.set(["task_management_editor", "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"])
|
||
}
|
||
|
||
/// 测试已保存 URI 与当前权限不匹配时不会回退默认。
|
||
func testSavedCommonDoesNotFallbackWhenAllInvalid() {
|
||
let defaults = makeIsolatedDefaults()
|
||
defaults.set(["task_management", "unknown"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer")
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [menu("task_management_editor")]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
topLevelPermissionURIs: ["task_management_editor"]
|
||
)
|
||
|
||
XCTAssertTrue(uris.isEmpty)
|
||
XCTAssertEqual(
|
||
defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer"),
|
||
["task_management", "unknown"]
|
||
)
|
||
}
|
||
|
||
/// 测试同一角色不同账号使用独立的常用应用缓存。
|
||
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 testAddUsesExactURIMatching() {
|
||
let defaults = makeIsolatedDefaults()
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
|
||
let uris = store.add(
|
||
"task_management",
|
||
current: ["task_management_editor"],
|
||
topLevelPermissionURIs: ["task_management_editor"],
|
||
roleCode: "photographer"
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["task_management_editor"])
|
||
}
|
||
|
||
/// 测试移除常用应用时使用精确 URI 匹配。
|
||
func testRemoveUsesExactURIMatching() {
|
||
let defaults = makeIsolatedDefaults()
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
|
||
let uris = store.remove("pm", current: ["project_edit", "pm_manager", "location_report"], roleCode: "photographer")
|
||
|
||
XCTAssertEqual(uris, ["project_edit", "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"))
|
||
}
|
||
|
||
/// 测试默认常用先取顶层前 4 个,再与 menuList 白名单求交。
|
||
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"])
|
||
}
|
||
|
||
/// 测试 report_photographer 属于 Android menuList 白名单,且可加入常用应用。
|
||
func testPhotographerReportIsWhitelistedAndCanBeAddedToCommon() {
|
||
XCTAssertTrue(HomeCommonMenuStore.androidHomeMenuURIs.contains("report_photographer"))
|
||
|
||
let store = HomeCommonMenuStore(defaults: makeIsolatedDefaults())
|
||
let uris = store.add(
|
||
"report_photographer",
|
||
current: ["location_report"],
|
||
topLevelPermissionURIs: ["location_report", "report_photographer"],
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_report_photographer"
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["location_report", "report_photographer"])
|
||
}
|
||
|
||
/// 测试非白名单顶层项占用前 4 名额时,默认常用不会用后续白名单项补位。
|
||
func testDefaultCommonDoesNotBackfillAfterNonCatalogSlots() {
|
||
let uris = HomeCommonMenuStore.defaultCommonURIs(
|
||
orderedTopLevelURIs: [
|
||
"album_list",
|
||
"wallet",
|
||
"cloud_management",
|
||
"asset_management",
|
||
"task_management"
|
||
]
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["wallet", "cloud_management", "asset_management"])
|
||
}
|
||
|
||
/// 测试已保存常用应用超过 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 testDefaultCommonUsesTopLevelOnlyNotFlattenedChildren() {
|
||
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"])
|
||
}
|
||
|
||
/// 测试扁平化 menuItems 中的子权限不会扩大可用常用范围。
|
||
func testAvailableFunctionsIgnoreFlattenedChildPermissions() {
|
||
let defaults = makeIsolatedDefaults()
|
||
let store = HomeCommonMenuStore(defaults: defaults)
|
||
let menus = [
|
||
menu("wallet"),
|
||
menu("material_upload")
|
||
]
|
||
|
||
let uris = store.load(
|
||
menuItems: menus,
|
||
roleCode: "photographer",
|
||
accountScope: "scenic_user_101",
|
||
topLevelPermissionURIs: ["wallet"]
|
||
)
|
||
|
||
XCTAssertEqual(uris, ["wallet"])
|
||
}
|
||
|
||
/// 创建测试菜单实体。
|
||
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
|
||
}
|
||
}
|