Align iOS home common apps and all-functions page with Android.
Add unified HomeCommonMenu/HomeAllFunctions diagnostics, rebuild all-functions from top-level menuList permissions, and document Home and AllFunctions module logic. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
139
suixinkanTests/HomeAllFunctionsBuilderTests.swift
Normal file
139
suixinkanTests/HomeAllFunctionsBuilderTests.swift
Normal file
@ -0,0 +1,139 @@
|
||||
//
|
||||
// HomeAllFunctionsBuilderTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
// Created by Codex on 2026/6/30.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
/// 「全部功能」页菜单构建测试,覆盖 Android 对齐的过滤、顺序与拆分规则。
|
||||
final class HomeAllFunctionsBuilderTests: XCTestCase {
|
||||
/// 测试仅保留顶层权限中属于 menuList 白名单的 URI。
|
||||
func testBuildFiltersToAndroidMenuListWhitelist() {
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: [
|
||||
permission(name: "基本信息", uri: "basic_info"),
|
||||
permission(name: "位置上报", uri: "location_report"),
|
||||
permission(name: "相册管理", uri: "album_list"),
|
||||
permission(name: "我的钱包", uri: "wallet")
|
||||
],
|
||||
commonURIs: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.allFunctions.map(\.uri), ["location_report", "wallet"])
|
||||
}
|
||||
|
||||
/// 测试保持 API 顶层顺序,不使用 preferredOrder 重排。
|
||||
func testBuildPreservesTopLevelAPIOrder() {
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: [
|
||||
permission(name: "消息中心", uri: "message_center"),
|
||||
permission(name: "空间设置", uri: "space_settings"),
|
||||
permission(name: "我的钱包", uri: "wallet")
|
||||
],
|
||||
commonURIs: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.allFunctions.map(\.uri), ["message_center", "space_settings", "wallet"])
|
||||
}
|
||||
|
||||
/// 测试不会展开子权限节点。
|
||||
func testBuildIgnoresChildPermissions() {
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: [
|
||||
permission(
|
||||
name: "基本信息",
|
||||
uri: "basic_info",
|
||||
children: [permission(name: "消息中心", uri: "message_center")]
|
||||
),
|
||||
permission(name: "我的钱包", uri: "wallet")
|
||||
],
|
||||
commonURIs: []
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.allFunctions.map(\.uri), ["wallet"])
|
||||
}
|
||||
|
||||
/// 测试常用/更多按精确 URI 拆分。
|
||||
func testBuildSplitsCommonAndMoreByExactURI() {
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: [
|
||||
permission(name: "位置上报", uri: "location_report"),
|
||||
permission(name: "注册邀请", uri: "registration_invitation"),
|
||||
permission(name: "店铺管理", uri: "store"),
|
||||
permission(name: "飞行管理", uri: "fly")
|
||||
],
|
||||
commonURIs: ["registration_invitation", "location_report"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.commonFunctions.map(\.uri), ["location_report", "registration_invitation"])
|
||||
XCTAssertEqual(snapshot.moreFunctions.map(\.uri), ["store", "fly"])
|
||||
}
|
||||
|
||||
/// 测试常用区顺序跟随 allFunctions 列表顺序,而非 commonURIs 存储顺序。
|
||||
func testCommonFunctionsFollowAllFunctionsOrder() {
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: [
|
||||
permission(name: "位置上报", uri: "location_report"),
|
||||
permission(name: "注册邀请", uri: "registration_invitation"),
|
||||
permission(name: "店铺管理", uri: "store")
|
||||
],
|
||||
commonURIs: ["store", "location_report"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.commonFunctions.map(\.uri), ["location_report", "store"])
|
||||
}
|
||||
|
||||
/// 测试与 Android 日志样例一致的过滤结果。
|
||||
func testBuildMatchesAndroidSampleAccountShape() {
|
||||
let topLevelURIs = [
|
||||
"location_report",
|
||||
"basic_info",
|
||||
"registration_invitation",
|
||||
"store",
|
||||
"fly",
|
||||
"space_settings",
|
||||
"photographer_stats",
|
||||
"photographer_orders",
|
||||
"asset_management",
|
||||
"schedule_management",
|
||||
"system_settings",
|
||||
"message_center",
|
||||
"location_info",
|
||||
"checkin_points",
|
||||
"sample_management",
|
||||
"live_album",
|
||||
"live_stream_management",
|
||||
"cloud_management",
|
||||
"cooperation_order",
|
||||
"scan_qr",
|
||||
"payment_qr",
|
||||
"wallet",
|
||||
"pilot_cert",
|
||||
"task_management_editor",
|
||||
"pm_manager",
|
||||
"pilot_controller",
|
||||
"travel_album"
|
||||
]
|
||||
let snapshot = HomeAllFunctionsBuilder.build(
|
||||
topLevelPermissions: topLevelURIs.map { permission(name: $0, uri: $0) },
|
||||
commonURIs: ["location_report", "registration_invitation", "store"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(snapshot.allFunctions.count, 20)
|
||||
XCTAssertEqual(snapshot.allFunctions.first?.uri, "location_report")
|
||||
XCTAssertEqual(snapshot.commonFunctions.map(\.uri), ["location_report", "registration_invitation", "store"])
|
||||
XCTAssertEqual(snapshot.moreFunctions.first?.uri, "fly")
|
||||
XCTAssertEqual(snapshot.moreFunctions.count, 17)
|
||||
}
|
||||
|
||||
private func permission(
|
||||
name: String,
|
||||
uri: String,
|
||||
children: [PermissionItem] = []
|
||||
) -> PermissionItem {
|
||||
PermissionItem(id: uri.hashValue, name: name, uri: uri, children: children)
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
/// 首页常用应用存储测试,覆盖默认值、过滤和别名去重。
|
||||
/// 首页常用应用存储测试,覆盖默认值、过滤和 Android 对齐行为。
|
||||
final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
/// 测试首次无配置时会按顶层权限生成默认常用应用。
|
||||
func testLoadCreatesDefaultCommonMenusFromTopLevelPermissions() {
|
||||
@ -36,13 +36,6 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
|
||||
/// 测试顶层权限超过 4 个时只取前 4 个默认常用应用。
|
||||
func testDefaultCommonURIsTakeFirstFourWhenMoreThanFourPermissions() {
|
||||
let availableURIs: Set<String> = [
|
||||
"space_settings",
|
||||
"wallet",
|
||||
"cloud_management",
|
||||
"message_center",
|
||||
"task_management"
|
||||
]
|
||||
let uris = HomeCommonMenuStore.defaultCommonURIs(
|
||||
orderedTopLevelURIs: [
|
||||
"space_settings",
|
||||
@ -50,8 +43,7 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
"cloud_management",
|
||||
"message_center",
|
||||
"task_management"
|
||||
],
|
||||
availableURIs: availableURIs
|
||||
]
|
||||
)
|
||||
|
||||
XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management", "message_center"])
|
||||
@ -76,10 +68,10 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management"])
|
||||
}
|
||||
|
||||
/// 测试已保存 URI 会按当前权限和 Android 白名单过滤并解析同义 URI。
|
||||
/// 测试已保存 URI 会按当前顶层权限和白名单精确过滤。
|
||||
func testLoadFiltersSavedUrisByCurrentPermissions() {
|
||||
let defaults = makeIsolatedDefaults()
|
||||
defaults.set(["task_management", "unknown", "pm"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer")
|
||||
defaults.set(["task_management_editor", "unknown", "pm"], forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer")
|
||||
let store = HomeCommonMenuStore(defaults: defaults)
|
||||
let menus = [
|
||||
menu("task_management_editor"),
|
||||
@ -95,6 +87,26 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
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()
|
||||
@ -155,32 +167,29 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
XCTAssertEqual(roleTwo, ["cloud_management"])
|
||||
}
|
||||
|
||||
/// 测试添加常用应用时会按同义 URI 去重。
|
||||
func testAddDeduplicatesAliases() {
|
||||
/// 测试添加常用应用时使用精确 URI 匹配。
|
||||
func testAddUsesExactURIMatching() {
|
||||
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,
|
||||
topLevelPermissionURIs: ["task_management_editor"],
|
||||
roleCode: "photographer"
|
||||
)
|
||||
|
||||
XCTAssertEqual(uris, ["task_management_editor"])
|
||||
}
|
||||
|
||||
/// 测试移除常用应用时会移除同义 URI。
|
||||
func testRemoveDeletesAliases() {
|
||||
/// 测试移除常用应用时使用精确 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, ["pm_manager", "location_report"])
|
||||
XCTAssertEqual(uris, ["project_edit", "pm_manager", "location_report"])
|
||||
}
|
||||
|
||||
/// 测试无 role_code 时不读写常用应用。
|
||||
@ -239,7 +248,7 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
XCTAssertNil(defaults.stringArray(forKey: HomeCommonMenuStore.storageKeyPrefix + "photographer"))
|
||||
}
|
||||
|
||||
/// 测试 Android 白名单外的 URI 不会进入默认常用应用。
|
||||
/// 测试默认常用先取顶层前 4 个,再与 menuList 白名单求交。
|
||||
func testDefaultCommonURIsExcludeMenusMissingFromAndroidCatalog() {
|
||||
let defaults = makeIsolatedDefaults()
|
||||
let store = HomeCommonMenuStore(defaults: defaults)
|
||||
@ -260,6 +269,21 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
XCTAssertEqual(uris, ["wallet", "message_center"])
|
||||
}
|
||||
|
||||
/// 测试非白名单顶层项占用前 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()
|
||||
@ -286,8 +310,8 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
XCTAssertEqual(uris, ["space_settings", "wallet", "cloud_management", "asset_management", "message_center"])
|
||||
}
|
||||
|
||||
/// 测试默认常用只取顶层权限,不会用子权限补位。
|
||||
func testDefaultCommonURIsUseOnlyTopLevelPermissions() {
|
||||
/// 测试默认常用只取顶层权限,不会用扁平化子权限补位。
|
||||
func testDefaultCommonUsesTopLevelOnlyNotFlattenedChildren() {
|
||||
let defaults = makeIsolatedDefaults()
|
||||
let store = HomeCommonMenuStore(defaults: defaults)
|
||||
let menus = [
|
||||
@ -305,6 +329,25 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user