import Foundation import Testing @testable import LocalData private func makeMockKey(name: String, domain: StorageDomain) -> StorageKey { StorageKey( name: name, domain: domain, security: .none, owner: "ErrorTests", description: "Test key" ) } private struct PartialCatalog: StorageKeyCatalog { var allKeys: [AnyStorageKey] { [.key(makeMockKey(name: "registered.key", domain: .userDefaults(suite: nil)))] } } @Suite(.serialized) struct RouterErrorTests { private let router: StorageRouter init() { let testBaseURL = FileManager.default.temporaryDirectory.appending(path: "RouterErrorTests-\(UUID().uuidString)") router = StorageRouter( keychain: MockKeychainHelper(), encryption: EncryptionHelper(keychain: MockKeychainHelper()), file: FileStorageHelper(configuration: FileStorageConfiguration(baseURL: testBaseURL)), defaults: UserDefaultsHelper(defaults: UserDefaults(suiteName: "RouterErrorTests-\(UUID().uuidString)")!) ) } @Test func unregisteredKeyThrows() async throws { try await router.registerCatalog(PartialCatalog()) let badKey = makeMockKey(name: "unregistered.key", domain: .userDefaults(suite: nil)) await #expect(throws: StorageError.unregisteredKey("unregistered.key")) { try await router.set("value", for: badKey) } } @Test func resolveIdentifierThrowsIfNoDefault() async { // Clear default app group ID await router.updateStorageConfiguration(StorageConfiguration( defaultKeychainService: "test", defaultAppGroupIdentifier: nil )) let appGroupKey = makeMockKey(name: "appgroup.key", domain: .appGroupUserDefaults(identifier: nil)) await #expect(throws: StorageError.invalidAppGroupIdentifier("none")) { try await router.set("value", for: appGroupKey) } } @Test func resolveServiceThrowsIfNoDefault() async { // Clear default keychain service await router.updateStorageConfiguration(StorageConfiguration( defaultKeychainService: nil, defaultAppGroupIdentifier: "test" )) let _ = makeMockKey(name: "keychain.key", domain: .keychain(service: nil)) // Note: Keychain security policy must match keychain domain in descriptor // but descriptor is usually created from key. // MockKey by default has .none security, which might cause applySecurity to return early // BUT the store() method for .keychain domain checks security. } }