diff --git a/app/src/main/java/eu/darken/capod/monitor/core/battery/BatteryTier.kt b/app/src/main/java/eu/darken/capod/monitor/core/battery/BatteryTier.kt new file mode 100644 index 00000000..19bd4ea6 --- /dev/null +++ b/app/src/main/java/eu/darken/capod/monitor/core/battery/BatteryTier.kt @@ -0,0 +1,23 @@ +package eu.darken.capod.monitor.core.battery + +/** Battery bands behind the overview's colour semantics. */ +enum class BatteryTier { + UNKNOWN, + CRITICAL, + WARN, + GOOD, +} + +/** + * Maps a battery fraction onto a [BatteryTier]. Only a finite, non-negative fraction has a level; + * anything else is [BatteryTier.UNKNOWN]. Values above 1 count as full. + */ +fun batteryTier(percent: Float): BatteryTier { + if (!percent.isFinite() || percent < 0f) return BatteryTier.UNKNOWN + val clamped = percent.coerceIn(0f, 1f) + return when { + clamped > 0.30f -> BatteryTier.GOOD + clamped >= 0.15f -> BatteryTier.WARN + else -> BatteryTier.CRITICAL + } +} diff --git a/app/src/test/java/eu/darken/capod/monitor/core/battery/BatteryTierTest.kt b/app/src/test/java/eu/darken/capod/monitor/core/battery/BatteryTierTest.kt new file mode 100644 index 00000000..bc7cd366 --- /dev/null +++ b/app/src/test/java/eu/darken/capod/monitor/core/battery/BatteryTierTest.kt @@ -0,0 +1,50 @@ +package eu.darken.capod.monitor.core.battery + +import eu.darken.capod.pods.core.apple.ble.BATTERY_UNKNOWN +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class BatteryTierTest : BaseTest() { + + @Test + fun `unknown battery has no tier`() { + batteryTier(BATTERY_UNKNOWN) shouldBe BatteryTier.UNKNOWN + batteryTier(-0.01f) shouldBe BatteryTier.UNKNOWN + batteryTier(-100f) shouldBe BatteryTier.UNKNOWN + } + + @Test + fun `non-finite values have no tier`() { + batteryTier(Float.NaN) shouldBe BatteryTier.UNKNOWN + batteryTier(Float.POSITIVE_INFINITY) shouldBe BatteryTier.UNKNOWN + batteryTier(Float.NEGATIVE_INFINITY) shouldBe BatteryTier.UNKNOWN + } + + @Test + fun `values at and above full are good`() { + batteryTier(1f) shouldBe BatteryTier.GOOD + batteryTier(1.5f) shouldBe BatteryTier.GOOD + batteryTier(Float.MAX_VALUE) shouldBe BatteryTier.GOOD + } + + @Test + fun `the good boundary is exclusive`() { + batteryTier(0.30f) shouldBe BatteryTier.WARN + batteryTier(0.30f + 0.0001f) shouldBe BatteryTier.GOOD + batteryTier(0.30f - 0.0001f) shouldBe BatteryTier.WARN + } + + @Test + fun `the warn boundary is inclusive`() { + batteryTier(0.15f) shouldBe BatteryTier.WARN + batteryTier(0.15f + 0.0001f) shouldBe BatteryTier.WARN + batteryTier(0.15f - 0.0001f) shouldBe BatteryTier.CRITICAL + } + + @Test + fun `an empty battery is critical`() { + batteryTier(0f) shouldBe BatteryTier.CRITICAL + batteryTier(0.05f) shouldBe BatteryTier.CRITICAL + } +}