// // GlobalLoadingCenterTests.swift // suixinkanTests // // Created by Codex on 2026/6/23. // import XCTest @testable import suixinkan @MainActor /// 全局 Loading 命令中心测试,验证展示状态不会泄漏给业务页面使用。 final class GlobalLoadingCenterTests: XCTestCase { /// 测试多次 show/hide 会按引用计数控制最终显隐。 func testShowHideUsesReferenceCount() { let center = GlobalLoadingCenter() center.show(message: "加载账号") center.show(message: "加载权限") XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: true, message: "加载权限", activeCount: 2, showsMessage: false)) center.hide() XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: true, message: "加载权限", activeCount: 1, showsMessage: false)) center.hide() XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试 hide 调用次数超过 show 时不会产生负数计数。 func testHideNeverDropsReferenceCountBelowZero() { let center = GlobalLoadingCenter() center.hide() XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试更新文案只影响当前展示内容,不改变引用计数。 func testUpdateMessageOnlyChangesVisibleMessage() { let center = GlobalLoadingCenter() center.updateMessage("不会展示") XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) center.show(message: "加载中") center.updateMessage("即将完成") XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: true, message: "即将完成", activeCount: 1, showsMessage: false)) } /// 测试 withLoading 成功完成后自动隐藏 Loading。 func testWithLoadingHidesAfterSuccess() async throws { let center = GlobalLoadingCenter() let value = try await center.withLoading(message: "提交中") { XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: true, message: "提交中", activeCount: 1, showsMessage: false)) return 42 } XCTAssertEqual(value, 42) XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试 withLoading 抛错时也会自动隐藏 Loading。 func testWithLoadingHidesAfterFailure() async { let center = GlobalLoadingCenter() do { _ = try await center.withLoading(message: "提交中") { throw TestFailure.expected } as Int XCTFail("withLoading 应该向外抛出业务错误") } catch { XCTAssertEqual(error as? TestFailure, .expected) } XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试 withOptionalLoading 关闭时不会改变展示状态。 func testWithOptionalLoadingDisabledDoesNotChangeState() async throws { let center = GlobalLoadingCenter() let value = try await center.withOptionalLoading(false, message: "不展示") { XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) return "done" } XCTAssertEqual(value, "done") XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试默认不展示文案,仅在显式开启时记录展示状态。 func testShowsMessageOnlyWhenEnabled() { let center = GlobalLoadingCenter() center.show(message: "加载中") XCTAssertEqual(center.snapshotForTests.message, "加载中") XCTAssertFalse(center.snapshotForTests.showsMessage) center.hide() center.show(message: "获取定位中", showsMessage: true) XCTAssertTrue(center.snapshotForTests.showsMessage) center.hide() XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: false, message: "", activeCount: 0, showsMessage: false)) } /// 测试使用 Loading 不需要读取可观察展示状态,业务侧只能拿到命令中心类型。 func testBusinessCodeOnlyDependsOnCommandCenter() { let center = GlobalLoadingCenter() issueLoadingCommand(center) XCTAssertEqual(center.snapshotForTests, GlobalLoadingSnapshot(isVisible: true, message: "加载中", activeCount: 1, showsMessage: false)) center.hide() } /// 模拟业务代码只接收命令中心并发出展示指令。 private func issueLoadingCommand(_ center: GlobalLoadingCenter) { center.show(message: "加载中") } /// 测试用错误类型。 private enum TestFailure: Error, Equatable { case expected } }