LocalData/Tests/LocalDataTests/KeychainHelperTests.swift
Matt Bruce 54115fdf0e Update Models, Services + tests
Summary:
- Sources: Models, Services
- Tests: KeychainHelperTests.swift, LocalDataTests.swift
- Added symbols: func store

Stats:
- 4 files changed, 20 insertions(+), 24 deletions(-)
2026-01-18 14:53:29 -06:00

144 lines
4.6 KiB
Swift

import Foundation
import Testing
@testable import LocalData
struct KeychainHelperTests {
private let testService = "LocalDataTests.Keychain.\(UUID().uuidString)"
// MARK: - Basic Round Trip
@Test func keychainRoundTrip() async throws {
let key = "test.credential"
let data = Data("secret-password".utf8)
defer {
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(
data,
service: testService,
key: key,
accessibility: .afterFirstUnlock
)
let retrieved = try await KeychainHelper.shared.get(service: testService, key: key)
#expect(retrieved == data)
}
@Test func keychainNotFoundReturnsNil() async throws {
let result = try await KeychainHelper.shared.get(
service: testService,
key: "nonexistent.\(UUID().uuidString)"
)
#expect(result == nil)
}
@Test func keychainDeleteNonexistentDoesNotThrow() async throws {
// Should not throw even if item doesn't exist
try await KeychainHelper.shared.delete(
service: testService,
key: "nonexistent.\(UUID().uuidString)"
)
}
@Test func keychainExists() async throws {
let key = "test.exists.\(UUID().uuidString)"
let data = Data("test".utf8)
defer {
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
let beforeExists = try await KeychainHelper.shared.exists(service: testService, key: key)
#expect(beforeExists == false)
try await KeychainHelper.shared.set(
data,
service: testService,
key: key,
accessibility: .whenUnlocked
)
let afterExists = try await KeychainHelper.shared.exists(service: testService, key: key)
#expect(afterExists == true)
}
@Test func keychainUpdateReplacesData() async throws {
let key = "test.update.\(UUID().uuidString)"
let originalData = Data("original".utf8)
let updatedData = Data("updated".utf8)
defer {
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(
originalData,
service: testService,
key: key,
accessibility: .afterFirstUnlock
)
try await KeychainHelper.shared.set(
updatedData,
service: testService,
key: key,
accessibility: .afterFirstUnlock
)
let retrieved = try await KeychainHelper.shared.get(service: testService, key: key)
#expect(retrieved == updatedData)
}
@Test func keychainDeleteAll() async throws {
let deleteAllService = "LocalDataTests.DeleteAll.\(UUID().uuidString)"
let data = Data("test".utf8)
// Create multiple items
for i in 0..<3 {
try await KeychainHelper.shared.set(
data,
service: deleteAllService,
key: "key\(i)",
accessibility: .afterFirstUnlock
)
}
// Verify they exist
let exists0 = try await KeychainHelper.shared.exists(service: deleteAllService, key: "key0")
#expect(exists0 == true)
// Delete all
try await KeychainHelper.shared.deleteAll(service: deleteAllService)
// Verify they're gone
for i in 0..<3 {
let exists = try await KeychainHelper.shared.exists(service: deleteAllService, key: "key\(i)")
#expect(exists == false)
}
}
// MARK: - Accessibility Options
@Test(arguments: KeychainAccessibility.allCases)
func keychainAccessibilityOptions(accessibility: KeychainAccessibility) async throws {
let key = "test.accessibility.\(accessibility).\(UUID().uuidString)"
let data = Data("data-for-\(accessibility)".utf8)
defer {
Task { try? await KeychainHelper.shared.delete(service: testService, key: key) }
}
try await KeychainHelper.shared.set(
data,
service: testService,
key: key,
accessibility: accessibility
)
let retrieved = try await KeychainHelper.shared.get(service: testService, key: key)
#expect(retrieved == data)
}
}