Coverage Summary for Class: RemoteConfigMirrorImpl (com.georgeci.moneysurfer.data.config)

Class Class, % Method, % Branch, % Line, % Instruction, %
RemoteConfigMirrorImpl 100% (1/1) 100% (6/6) 100% (9/9) 100% (44/44)


 package com.georgeci.moneysurfer.data.config
 
 import androidx.datastore.core.DataStore
 import androidx.datastore.preferences.core.Preferences
 import androidx.datastore.preferences.core.stringPreferencesKey
 import com.georgeci.moneysurfer.appconfig.RemoteConfigMirror
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 
 /** File name of the server-flag mirror. Deliberately not the app's settings file. */
 internal const val REMOTE_FLAGS_FILE_NAME = "moneysurfer_remote_flags.preferences_pb"
 
 /**
  * [RemoteConfigMirror] on its own DataStore file, alongside the other DataStore-backed layers.
  *
  * Its own file for two reasons. The contents are server-owned and disposable, so they must not ride
  * along in the user's settings file through backup and export; and being disposable is what lets the
  * store replace itself on corruption, which the settings file deliberately does not do because it
  * also holds the session pointers.
  *
  * The store is **not** a Koin binding: a second unqualified `DataStore<Preferences>` would collide
  * with the app's own one in `sharedPlatformModule` and both would end up reading the same file. Each
  * platform's `createRemoteConfigMirror(...)` builds it and hands it straight to this constructor —
  * the same shape `DebugConfigSourceImpl` already uses.
  *
  * Values are stored under the bare key name; the file is dedicated, so there is nothing to namespace
  * against.
  */
 class RemoteConfigMirrorImpl(
     dataStore: DataStore<Preferences>,
     scope: CoroutineScope,
 ) : RemoteConfigMirror {
 
     private val mirror = PreferencesMirror(dataStore, scope)
 
     override fun raw(name: String): String? = mirror.raw(name)
 
     override val changes: Flow<Unit> = mirror.changes
 
     override suspend fun hydrate() = mirror.hydrate()
 
     override val isDegraded: Boolean get() = mirror.isDegraded
 
     override suspend fun replaceAll(values: Map<String, String>) {
         mirror.edit { preferences ->
             // Clear first: this is a replace, not a merge, so a flag the owner removed from the
             // document stops being served instead of being pinned at its last value forever.
             preferences.clear()
             values.forEach { (name, raw) -> preferences[stringPreferencesKey(name)] = raw }
         }
     }
 }