Coverage Summary for Class: ConfigDebugLayerCell (com.georgeci.moneysurfer.domain.config)

Class Class, % Method, % Branch, % Line, % Instruction, %
ConfigDebugLayerCell 100% (1/1) 100% (1/1) 100% (4/4) 100% (17/17)


 package com.georgeci.moneysurfer.domain.config
 
 import kotlinx.coroutines.flow.Flow
 
 /**
  * Read/write view of every configuration key, for the QA panel in debug builds.
  *
  * Everything is pre-rendered as strings and the write path is keyed by name, so no `ConfigKey<*>`
  * — and no `app-config` dependency — reaches `feature/settings`.
  */
 interface DebugConfigInspector {
 
     /**
      * `false` in release builds, where the Debug layer is empty. The panel and its entry point are
      * hidden rather than shown broken.
      */
     val isAvailable: Boolean
 
     val rows: Flow<List<ConfigDebugRow>>
 
     /**
      * Names of layers whose store could not be read at startup, pre-rendered. Empty on the happy
      * path.
      *
      * Their rows resolve as if the layer were empty, so without this the panel would report a stale
      * fallback as the real answer. Recovery is automatic once the store is readable again.
      */
     val degradedLayers: List<String>
 
     /** Fails when [raw] does not decode through the key's codec, or when the key is unknown. */
     suspend fun override(name: String, raw: String): Result<Unit>
 
     suspend fun clearOverride(name: String)
 
     suspend fun resetAll()
 }
 
 /**
  * One key as the panel sees it.
  *
  * @param effectiveValue the resolved value, encoded.
  * @param winner name of the layer that won, or `"default"` when no layer holds the key.
  * @param kind which control to render — a text field for `PaletteSource`'s `PRESET:<seed>` format
  *   is a routine way to fail.
  * @param overridden `true` when the Debug layer holds anything for this key, i.e. this row can be
  *   cleared. Deliberately not "the Debug layer won": an override the codec can no longer read does
  *   not win, and it is exactly the one a tester needs to remove.
  * @param hostOwned `true` for a key that describes the build itself (`host.*`). Overriding one of
  *   these changes what the app believes it is while its DI graph stays as compiled — useful for QA,
  *   but not the same kind of switch as a feature flag, so the panel says so.
  */
 data class ConfigDebugRow(
     val name: String,
     val effectiveValue: String,
     val winner: String,
     val kind: ConfigDebugRowKind,
     val overridden: Boolean,
     val hostOwned: Boolean = false,
     val layers: List<ConfigDebugLayerCell>,
 )
 
 sealed interface ConfigDebugRowKind {
     data object Bool : ConfigDebugRowKind
     data class Choice(val choices: List<String>) : ConfigDebugRowKind
     data object FreeText : ConfigDebugRowKind
 }
 
 /**
  * One layer's contribution. [value] is `null` when the layer does not hold the key; [undecodable]
  * distinguishes "stored but rejected by the codec" from that, which is the whole reason the panel
  * shows per-layer cells at all.
  */
 data class ConfigDebugLayerCell(
     val layer: String,
     val value: String?,
     val undecodable: Boolean,
 )