diff --git a/app/src/main/java/org/searchmob/data/prefs/PersonalizationPreferences.kt b/app/src/main/java/org/searchmob/data/prefs/PersonalizationPreferences.kt index c4b7dd0..ee4ec02 100644 --- a/app/src/main/java/org/searchmob/data/prefs/PersonalizationPreferences.kt +++ b/app/src/main/java/org/searchmob/data/prefs/PersonalizationPreferences.kt @@ -14,7 +14,7 @@ import org.searchmob.engine.rank.Personalizer */ class PersonalizationPreferences(private val store: PreferencesStore) { suspend fun load(): PersonalizationModel { - val raw = store.get(KEY) ?: return PersonalizationModel() + val raw = runCatching { store.get(KEY) }.getOrNull() ?: return PersonalizationModel() return Personalizer.fromJson(raw) } diff --git a/app/src/main/java/org/searchmob/data/prefs/RankingPreferences.kt b/app/src/main/java/org/searchmob/data/prefs/RankingPreferences.kt index c7fd783..6f5f979 100644 --- a/app/src/main/java/org/searchmob/data/prefs/RankingPreferences.kt +++ b/app/src/main/java/org/searchmob/data/prefs/RankingPreferences.kt @@ -16,7 +16,7 @@ import org.searchmob.engine.rank.RankingRules */ class RankingPreferences(private val store: PreferencesStore) { suspend fun load(): RankingRules { - val raw = store.get(KEY) ?: return withDefaultLenses(RankingRules.EMPTY) + val raw = runCatching { store.get(KEY) }.getOrNull() ?: return withDefaultLenses(RankingRules.EMPTY) val parsed = runCatching { json.decodeFromString(raw) }.getOrDefault(RankingRules.EMPTY) return withDefaultLenses(parsed) } diff --git a/app/src/test/java/org/searchmob/data/RankingPreferencesTest.kt b/app/src/test/java/org/searchmob/data/RankingPreferencesTest.kt index 967b04e..1b03b18 100644 --- a/app/src/test/java/org/searchmob/data/RankingPreferencesTest.kt +++ b/app/src/test/java/org/searchmob/data/RankingPreferencesTest.kt @@ -39,6 +39,26 @@ private class FakeRankingStore : PreferencesStore { override suspend fun clear() = map.clear() } +/** A store that throws on every read, simulating a locked vault (DEK wiped from memory). */ +private class LockedStore : PreferencesStore { + private fun locked(): Nothing = error("vault is locked: DEK not present in memory") + + override fun observe(): Flow = locked() + + override suspend fun getAll(): Preferences = locked() + + override suspend fun get(key: String): String? = locked() + + override suspend fun put( + key: String, + value: String, + ) = locked() + + override suspend fun remove(key: String) = locked() + + override suspend fun clear() = locked() +} + class RankingPreferencesTest { @Test fun domainRuleSetAndClear() = @@ -92,4 +112,13 @@ class RankingPreferencesTest { val prefs = RankingPreferences(FakeRankingStore()) assertEquals(false, prefs.importJson("not json")) } + + @Test + fun loadReturnsEmptyWhenVaultIsLocked() = + runTest { + val prefs = RankingPreferences(LockedStore()) + val rules = prefs.load() + assertEquals(DEFAULT_SAMPLE_LENSES, rules.lenses) + assertTrue(rules.domainRules.isEmpty()) + } }