Add fingerprint cache tests

This commit is contained in:
2026-07-27 15:45:15 +00:00
parent e74bb67c95
commit 82c3411fa2
@@ -0,0 +1,81 @@
import Foundation
import Testing
import Vision
@testable import Photochk
@Suite("キャッシュ")
struct FingerprintCacheTests {
private func makeFile(at directory: URL) throws -> ScannedFile {
let url = directory.appendingPathComponent("cached.jpg")
try TestImages.writeJPEG(TestImages.pattern(seed: 3), to: url, quality: 0.9)
let values = try url.resourceValues(forKeys: [.fileSizeKey, .contentModificationDateKey])
return ScannedFile(
url: url,
fileSize: Int64(values.fileSize ?? 0),
modificationDate: values.contentModificationDate ?? Date(),
creationDate: nil
)
}
@Test("dHash と feature print がディスクを経由して復元できる")
func roundTrip() async throws {
let directory = try TestImages.makeTemporaryDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
let file = try makeFile(at: directory)
let cacheURL = directory.appendingPathComponent("cache.plist")
let basics = try #require(DHash.compute(for: file.url))
let print = try await FeaturePrinter.compute(for: file.url)
let writer = FingerprintCache(fileURL: cacheURL)
await writer.store(basics: [file.url: basics], for: [file])
await writer.store(featurePrints: [file.url: print], for: [file])
await writer.save()
let reader = FingerprintCache(fileURL: cacheURL)
let restoredBasics = await reader.basics(for: [file])
let restoredPrints = await reader.featurePrints(for: [file])
#expect(restoredBasics[file.url]?.dHash == basics.dHash)
let restoredPrint = try #require(restoredPrints[file.url])
// 同一の特徴量なので距離は 0
#expect(try restoredPrint.distance(to: print) == 0)
}
@Test("ファイルが更新されていたらキャッシュは使われない")
func invalidatesOnChange() async throws {
let directory = try TestImages.makeTemporaryDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
let file = try makeFile(at: directory)
let cache = FingerprintCache(fileURL: nil)
let basics = try #require(DHash.compute(for: file.url))
await cache.store(basics: [file.url: basics], for: [file])
let changed = ScannedFile(
url: file.url,
fileSize: file.fileSize + 100,
modificationDate: file.modificationDate,
creationDate: nil
)
#expect(await cache.basics(for: [changed]).isEmpty)
#expect(await cache.basics(for: [file]).count == 1)
}
@Test("消えたファイルのエントリは prune で捨てられる")
func prunesMissingFiles() async throws {
let directory = try TestImages.makeTemporaryDirectory()
defer { try? FileManager.default.removeItem(at: directory) }
let file = try makeFile(at: directory)
let cache = FingerprintCache(fileURL: nil)
let basics = try #require(DHash.compute(for: file.url))
await cache.store(basics: [file.url: basics], for: [file])
await cache.prune(keeping: [])
#expect(await cache.basics(for: [file]).isEmpty)
}
}