LocalData/Tests/LocalDataTests/MigrationTests.swift
Matt Bruce e27e2e38bb Tests AnyCodableTests.swift, AnyStorageKeyTests.swift, AuditTests.swift (+8 more)
Summary:
- Tests: AnyCodableTests.swift, AnyStorageKeyTests.swift, AuditTests.swift, EncryptionLogicTests.swift, FileStorageHelperTests.swift (+6 more)
- Added symbols: struct NonCodable, struct StringKey, typealias Value, struct AuditCatalog, struct TestKey, struct RawProvider (+11 more)

Stats:
- 11 files changed, 698 insertions(+)
2026-01-18 14:53:29 -06:00

111 lines
3.7 KiB
Swift

import Foundation
import Testing
@testable import LocalData
private struct LegacyKey: StorageKey {
typealias Value = String
let name: String
let domain: StorageDomain
let security: SecurityPolicy = .none
let serializer: Serializer<String> = .json
let owner: String = "Legacy"
let description: String = "Legacy key"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
}
private struct ModernKey: StorageKey {
typealias Value = String
let name: String
let domain: StorageDomain
let security: SecurityPolicy = .keychain(accessibility: .afterFirstUnlock, accessControl: .none)
let serializer: Serializer<String> = .json
let owner: String = "Modern"
let description: String = "Modern key"
let availability: PlatformAvailability = .all
let syncPolicy: SyncPolicy = .never
let migrationSources: [AnyStorageKey]
init(name: String, domain: StorageDomain, migrationSources: [AnyStorageKey]) {
self.name = name
self.domain = domain
self.migrationSources = migrationSources
}
}
@Suite(.serialized)
struct MigrationTests {
private let router = StorageRouter(keychain: MockKeychainHelper())
@Test func automaticMigrationFromUserDefaultsToKeychain() async throws {
let legacyName = "legacy.user.name"
let modernName = "user.name"
let suiteName = "MigrationTests.\(UUID().uuidString)"
let secretValue = "Matt Bruce"
defer {
UserDefaults().removePersistentDomain(forName: suiteName)
}
// 1. Setup legacy data manually in UserDefaults
let legacyKey = LegacyKey(name: legacyName, domain: .userDefaults(suite: suiteName))
try await router.set(secretValue, for: legacyKey)
// Verify it exists in legacy location
let existsInLegacy = try await router.exists(legacyKey)
#expect(existsInLegacy == true)
// 2. Setup modern key with legacy source
let modernKey = ModernKey(
name: modernName,
domain: .keychain(service: "test.migration"),
migrationSources: [.key(legacyKey)]
)
// 3. Trigger automatic migration via GET
let migratedValue = try await router.get(modernKey)
#expect(migratedValue == secretValue)
// 4. Verify data moved
// Modern should now exist
let existsInModern = try await router.exists(modernKey)
#expect(existsInModern == true)
// Legacy should be gone
let existsInLegacyAfter = try await router.exists(legacyKey)
#expect(existsInLegacyAfter == false)
}
@Test func manualMigrationSweep() async throws {
let legacyName = "legacy.manual.key"
let modernName = "modern.manual.key"
let suiteName = "MigrationTests.Manual.\(UUID().uuidString)"
let value = "Manual Data"
defer {
UserDefaults().removePersistentDomain(forName: suiteName)
}
// 1. Setup legacy data
let legacyKey = LegacyKey(name: legacyName, domain: .userDefaults(suite: suiteName))
try await router.set(value, for: legacyKey)
// 2. Setup modern key
let modernKey = ModernKey(
name: modernName,
domain: .userDefaults(suite: suiteName),
migrationSources: [.key(legacyKey)]
)
// 3. Trigger manual migration
try await router.migrate(for: modernKey)
// 4. Verify
let hasModern = try await router.exists(modernKey)
#expect(hasModern == true)
let hasLegacy = try await router.exists(legacyKey)
#expect(hasLegacy == false)
}
}