Stores leben jetzt im Package mit App-übergreifenden Keys (mana.llm.backend, mana.llm.allowCellular). Auto-Migration aus memoro.* Legacy-Keys beim ersten Read (memoro.llmBackend, memoro.onDeviceLLMEnabled Bool-Toggle, memoro.llmDownloadOverCellular). Ermöglicht ManaLLMUI in mana-swift-ui 0.8.0 als geteilte Settings- Schicht für alle 4 Konsumenten (Memoro, Pageta, Comicello, Herbatrium). Außerdem: - LLMBackend.removeCachedModel() als Protocol-Methode mit Default- No-Op. GemmaBackend überschreibt (async throws statt throws). - 13 neue Tests in LLMPreferenceStoresTests (.serialized wegen UserDefaults.standard). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
98 lines
3.7 KiB
Swift
98 lines
3.7 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import ManaLLM
|
|
|
|
/// Tests für die UserDefaults-basierten Preference-Stores.
|
|
///
|
|
/// **Serialized:** Die Stores greifen hart auf `UserDefaults.standard`
|
|
/// zu (bewusst — App-Wide). Tests müssen daher seriell laufen, sonst
|
|
/// rennen sie sich gegenseitig in den State. `.serialized` reicht hier,
|
|
/// weil die Tests trivial schnell sind (<20 ms total).
|
|
@Suite(.serialized)
|
|
struct LLMPreferenceStoresTests {
|
|
// MARK: - LLMBackendPreferenceStore
|
|
|
|
@Test func returnsDefaultWhenNoKeySet() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
#expect(LLMBackendPreferenceStore.current == .appleFM)
|
|
}
|
|
}
|
|
|
|
@Test func roundTripsValue() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
LLMBackendPreferenceStore.set(.gemmaE4B)
|
|
#expect(LLMBackendPreferenceStore.current == .gemmaE4B)
|
|
}
|
|
}
|
|
|
|
@Test func migratesMemoroStringKey() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
UserDefaults.standard.set("gemmaE2B", forKey: "memoro.llmBackend")
|
|
#expect(LLMBackendPreferenceStore.current == .gemmaE2B)
|
|
// Legacy-Key wurde gelöscht
|
|
#expect(UserDefaults.standard.object(forKey: "memoro.llmBackend") == nil)
|
|
// Neuer Key gesetzt
|
|
#expect(UserDefaults.standard.string(forKey: "mana.llm.backend") == "gemmaE2B")
|
|
}
|
|
}
|
|
|
|
@Test func migratesMemoroBoolToggleTrueToAppleFM() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
UserDefaults.standard.set(true, forKey: "memoro.onDeviceLLMEnabled")
|
|
#expect(LLMBackendPreferenceStore.current == .appleFM)
|
|
#expect(UserDefaults.standard.object(forKey: "memoro.onDeviceLLMEnabled") == nil)
|
|
}
|
|
}
|
|
|
|
@Test func migratesMemoroBoolToggleFalseToNoOp() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
UserDefaults.standard.set(false, forKey: "memoro.onDeviceLLMEnabled")
|
|
#expect(LLMBackendPreferenceStore.current == .noOp)
|
|
}
|
|
}
|
|
|
|
@Test func newKeyTrumpsLegacy() {
|
|
withClean(keys: ["mana.llm.backend", "memoro.llmBackend", "memoro.onDeviceLLMEnabled"]) {
|
|
UserDefaults.standard.set("gemmaE4B", forKey: "mana.llm.backend")
|
|
UserDefaults.standard.set("appleFM", forKey: "memoro.llmBackend")
|
|
#expect(LLMBackendPreferenceStore.current == .gemmaE4B)
|
|
// Legacy bleibt unangetastet wenn neuer Key schon existiert
|
|
#expect(UserDefaults.standard.string(forKey: "memoro.llmBackend") == "appleFM")
|
|
}
|
|
}
|
|
|
|
// MARK: - LLMDownloadOverCellularStore
|
|
|
|
@Test func cellularDefaultsToFalse() {
|
|
withClean(keys: ["mana.llm.allowCellular", "memoro.llmDownloadOverCellular"]) {
|
|
#expect(LLMDownloadOverCellularStore.isAllowed == false)
|
|
}
|
|
}
|
|
|
|
@Test func cellularRoundTripsTrue() {
|
|
withClean(keys: ["mana.llm.allowCellular", "memoro.llmDownloadOverCellular"]) {
|
|
LLMDownloadOverCellularStore.set(true)
|
|
#expect(LLMDownloadOverCellularStore.isAllowed == true)
|
|
}
|
|
}
|
|
|
|
@Test func cellularMigratesMemoroKey() {
|
|
withClean(keys: ["mana.llm.allowCellular", "memoro.llmDownloadOverCellular"]) {
|
|
UserDefaults.standard.set(true, forKey: "memoro.llmDownloadOverCellular")
|
|
#expect(LLMDownloadOverCellularStore.isAllowed == true)
|
|
#expect(UserDefaults.standard.object(forKey: "memoro.llmDownloadOverCellular") == nil)
|
|
#expect(UserDefaults.standard.bool(forKey: "mana.llm.allowCellular") == true)
|
|
}
|
|
}
|
|
|
|
// MARK: - Helpers
|
|
|
|
/// Räumt vor und nach dem Block bestimmte Keys ab, damit Tests
|
|
/// reproduzierbar starten und kein Test-State über Tests hinweg
|
|
/// leakt.
|
|
private func withClean(keys: [String], _ block: () -> Void) {
|
|
for key in keys { UserDefaults.standard.removeObject(forKey: key) }
|
|
defer { for key in keys { UserDefaults.standard.removeObject(forKey: key) } }
|
|
block()
|
|
}
|
|
}
|