import Foundation import Testing @testable import LocalData private struct TestRegistryKey: StorageKey { typealias Value = String let name: String let domain: StorageDomain = .userDefaults(suite: nil) let security: SecurityPolicy = .none let serializer: Serializer = .json let owner: String let description: String let availability: PlatformAvailability = .all let syncPolicy: SyncPolicy = .never init(name: String, owner: String = "Test", description: String = "Test") { self.name = name self.owner = owner self.description = description } } private struct CatalogA: StorageKeyCatalog { var allKeys: [AnyStorageKey] { [.key(TestRegistryKey(name: "key.a", owner: "ModuleA"))] } } private struct CatalogB: StorageKeyCatalog { var allKeys: [AnyStorageKey] { [.key(TestRegistryKey(name: "key.b", owner: "ModuleB"))] } } private struct CatalogCollision: StorageKeyCatalog { var allKeys: [AnyStorageKey] { [.key(TestRegistryKey(name: "key.a", owner: "ModuleCollision"))] } } @Suite(.serialized) struct ModularRegistryTests { @Test func testAdditiveRegistration() async throws { let router = StorageRouter(keychain: MockKeychainHelper()) try await router.registerCatalog(CatalogA()) #expect(await router.allRegisteredEntries().count == 1) #expect(await router.allRegisteredEntries().contains { $0.descriptor.name == "key.a" }) try await router.registerCatalog(CatalogB()) #expect(await router.allRegisteredEntries().count == 2) #expect(await router.allRegisteredEntries().contains { $0.descriptor.name == "key.b" }) } @Test func testCollisionDetectionAcrossCatalogs() async throws { let router = StorageRouter(keychain: MockKeychainHelper()) try await router.registerCatalog(CatalogA()) await #expect(throws: StorageError.self) { try await router.registerCatalog(CatalogCollision()) } } @Test func testGlobalAuditReport() async throws { let router = StorageRouter(keychain: MockKeychainHelper()) try await router.registerCatalog(CatalogA()) try await router.registerCatalog(CatalogB()) // Note: StorageAuditReport.renderGlobalRegistry() uses the shared router. // For testing isolation, we should probably add a parameter to it or // rely on the shared instance if we can reset it. // Since StorageRouter is a singleton-heavy actor, we use renderText directly on the router's entries. let entries = await router.allRegisteredEntries() let report = StorageAuditReport.renderText(entries) #expect(report.contains("key.a")) #expect(report.contains("key.b")) #expect(report.contains("catalog=CatalogA")) #expect(report.contains("catalog=CatalogB")) #expect(report.contains("ModuleA")) #expect(report.contains("ModuleB")) } @Test func testGlobalAuditReportGrouped() async throws { let router = StorageRouter(keychain: MockKeychainHelper()) try await router.registerCatalog(CatalogA()) try await router.registerCatalog(CatalogB()) let catalogs = await router.allRegisteredCatalogs() #expect(catalogs.count == 2) #expect(catalogs["CatalogA"] != nil) #expect(catalogs["CatalogB"] != nil) } }