mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 19:26:12 -04:00
test(settings): Add missing DataStore serialization and migration compat tests
Cover round-trip tests for ThemeStyle, ThemeColor, MonitorMode, ScannerMode, AutoConnectCondition, FossUpgrade, and InstantEpochMillisSerializer. Add Moshi decode tests for ThemeStyle, ThemeColor, AutoConnectCondition, FossUpgrade, and FossUpgrade.Reason annotation parity.
This commit is contained in:
@@ -9,6 +9,7 @@ import eu.darken.capod.main.core.MonitorMode
|
|||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.profiles.core.AppleDeviceProfile
|
import eu.darken.capod.profiles.core.AppleDeviceProfile
|
||||||
import eu.darken.capod.profiles.core.DeviceProfilesContainer
|
import eu.darken.capod.profiles.core.DeviceProfilesContainer
|
||||||
|
import eu.darken.capod.common.upgrade.core.FossUpgrade
|
||||||
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -16,6 +17,7 @@ import kotlinx.serialization.json.Json
|
|||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import testhelpers.BaseTest
|
import testhelpers.BaseTest
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that verify @SerialName values match @Json(name=...) values,
|
* Tests that verify @SerialName values match @Json(name=...) values,
|
||||||
@@ -68,6 +70,9 @@ class DataStoreMigrationCompatTest : BaseTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `SerialName matches Json name - PodDevice Model`() = verifyEnumSerialNameParity<PodDevice.Model>()
|
fun `SerialName matches Json name - PodDevice Model`() = verifyEnumSerialNameParity<PodDevice.Model>()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `SerialName matches Json name - FossUpgrade Reason`() = verifyEnumSerialNameParity<FossUpgrade.Reason>()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Moshi-serialized ThemeMode string is readable by kotlinx`() {
|
fun `Moshi-serialized ThemeMode string is readable by kotlinx`() {
|
||||||
// Moshi stores enums as JSON strings like: "theme.mode.dark"
|
// Moshi stores enums as JSON strings like: "theme.mode.dark"
|
||||||
@@ -103,6 +108,36 @@ class DataStoreMigrationCompatTest : BaseTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Moshi-serialized ThemeStyle string is readable by kotlinx`() {
|
||||||
|
val moshiOutput = "\"theme.style.materialyou\""
|
||||||
|
val result = json.decodeFromString(serializer<ThemeStyle>(), moshiOutput)
|
||||||
|
result shouldBe ThemeStyle.MATERIAL_YOU
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Moshi-serialized ThemeColor string is readable by kotlinx`() {
|
||||||
|
val moshiOutput = "\"theme.color.green\""
|
||||||
|
val result = json.decodeFromString(serializer<ThemeColor>(), moshiOutput)
|
||||||
|
result shouldBe ThemeColor.GREEN
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Moshi-serialized AutoConnectCondition string is readable by kotlinx`() {
|
||||||
|
val moshiOutput = "\"autoconnect.condition.seen\""
|
||||||
|
val result = json.decodeFromString(serializer<AutoConnectCondition>(), moshiOutput)
|
||||||
|
result shouldBe AutoConnectCondition.WHEN_SEEN
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Moshi-serialized FossUpgrade JSON is readable by kotlinx`() {
|
||||||
|
// Moshi with JavaInstantAdapter serializes Instant as epoch millis Long
|
||||||
|
val moshiJson = """{"upgradedAt":1709553600000,"reason":"foss.upgrade.reason.donated"}"""
|
||||||
|
val result = json.decodeFromString(serializer<FossUpgrade>(), moshiJson)
|
||||||
|
result.upgradedAt shouldBe Instant.ofEpochMilli(1709553600000)
|
||||||
|
result.reason shouldBe FossUpgrade.Reason.DONATED
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Moshi-serialized DeviceProfilesContainer JSON is readable by kotlinx`() {
|
fun `Moshi-serialized DeviceProfilesContainer JSON is readable by kotlinx`() {
|
||||||
// This is what Moshi would produce for a container with one Apple profile
|
// This is what Moshi would produce for a container with one Apple profile
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package eu.darken.capod.common.datastore
|
package eu.darken.capod.common.datastore
|
||||||
|
|
||||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||||
|
import eu.darken.capod.common.bluetooth.ScannerMode
|
||||||
import eu.darken.capod.common.serialization.ByteArrayBase64Serializer
|
import eu.darken.capod.common.serialization.ByteArrayBase64Serializer
|
||||||
|
import eu.darken.capod.common.serialization.InstantEpochMillisSerializer
|
||||||
|
import eu.darken.capod.common.theming.ThemeColor
|
||||||
import eu.darken.capod.common.theming.ThemeMode
|
import eu.darken.capod.common.theming.ThemeMode
|
||||||
|
import eu.darken.capod.common.theming.ThemeStyle
|
||||||
|
import eu.darken.capod.common.upgrade.core.FossUpgrade
|
||||||
|
import eu.darken.capod.main.core.MonitorMode
|
||||||
import kotlinx.serialization.builtins.nullable
|
import kotlinx.serialization.builtins.nullable
|
||||||
import eu.darken.capod.pods.core.PodDevice
|
import eu.darken.capod.pods.core.PodDevice
|
||||||
import eu.darken.capod.profiles.core.AppleDeviceProfile
|
import eu.darken.capod.profiles.core.AppleDeviceProfile
|
||||||
import eu.darken.capod.profiles.core.DeviceProfile
|
import eu.darken.capod.profiles.core.DeviceProfile
|
||||||
import eu.darken.capod.profiles.core.DeviceProfilesContainer
|
import eu.darken.capod.profiles.core.DeviceProfilesContainer
|
||||||
|
import eu.darken.capod.reaction.core.autoconnect.AutoConnectCondition
|
||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -16,6 +23,7 @@ import org.junit.jupiter.api.io.TempDir
|
|||||||
import testhelpers.BaseTest
|
import testhelpers.BaseTest
|
||||||
import testhelpers.coroutine.runTest2
|
import testhelpers.coroutine.runTest2
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.time.Instant
|
||||||
import eu.darken.capod.common.datastore.value
|
import eu.darken.capod.common.datastore.value
|
||||||
|
|
||||||
class DataStoreValueSerializationTest : BaseTest() {
|
class DataStoreValueSerializationTest : BaseTest() {
|
||||||
@@ -143,6 +151,97 @@ class DataStoreValueSerializationTest : BaseTest() {
|
|||||||
result!!.toList() shouldBe testBytes.toList()
|
result!!.toList() shouldBe testBytes.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `enum round-trip - ThemeStyle`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue("style", ThemeStyle.DEFAULT, json)
|
||||||
|
|
||||||
|
ThemeStyle.entries.forEach { style ->
|
||||||
|
pref.value(style)
|
||||||
|
pref.value() shouldBe style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `enum round-trip - ThemeColor`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue("color", ThemeColor.BLUE, json)
|
||||||
|
|
||||||
|
ThemeColor.entries.forEach { color ->
|
||||||
|
pref.value(color)
|
||||||
|
pref.value() shouldBe color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `enum round-trip - MonitorMode`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue("monitor", MonitorMode.MANUAL, json)
|
||||||
|
|
||||||
|
MonitorMode.entries.forEach { mode ->
|
||||||
|
pref.value(mode)
|
||||||
|
pref.value() shouldBe mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `enum round-trip - ScannerMode`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue("scanner", ScannerMode.LOW_POWER, json)
|
||||||
|
|
||||||
|
ScannerMode.entries.forEach { mode ->
|
||||||
|
pref.value(mode)
|
||||||
|
pref.value() shouldBe mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `enum round-trip - AutoConnectCondition`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue("autoconnect", AutoConnectCondition.WHEN_SEEN, json)
|
||||||
|
|
||||||
|
AutoConnectCondition.entries.forEach { condition ->
|
||||||
|
pref.value(condition)
|
||||||
|
pref.value() shouldBe condition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `data class round-trip - FossUpgrade nullable`() = runTest2 {
|
||||||
|
val ds = createDataStore()
|
||||||
|
val pref = ds.createValue<FossUpgrade?>("upgrade", null, json)
|
||||||
|
|
||||||
|
pref.value() shouldBe null
|
||||||
|
|
||||||
|
val upgrade = FossUpgrade(
|
||||||
|
upgradedAt = Instant.ofEpochMilli(1709553600000),
|
||||||
|
reason = FossUpgrade.Reason.DONATED,
|
||||||
|
)
|
||||||
|
pref.value(upgrade)
|
||||||
|
val result = pref.value()
|
||||||
|
|
||||||
|
result!!.upgradedAt shouldBe Instant.ofEpochMilli(1709553600000)
|
||||||
|
result.reason shouldBe FossUpgrade.Reason.DONATED
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `InstantEpochMillisSerializer round-trip`() {
|
||||||
|
val instant = Instant.ofEpochMilli(1709553600000)
|
||||||
|
val serialized = json.encodeToString(InstantEpochMillisSerializer, instant)
|
||||||
|
serialized shouldBe "1709553600000"
|
||||||
|
val deserialized = json.decodeFromString(InstantEpochMillisSerializer, serialized)
|
||||||
|
deserialized shouldBe instant
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `InstantEpochMillisSerializer - epoch zero`() {
|
||||||
|
val instant = Instant.EPOCH
|
||||||
|
val serialized = json.encodeToString(InstantEpochMillisSerializer, instant)
|
||||||
|
serialized shouldBe "0"
|
||||||
|
val deserialized = json.decodeFromString(InstantEpochMillisSerializer, serialized)
|
||||||
|
deserialized shouldBe instant
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `sealed interface polymorphic - DeviceProfile`() = runTest2 {
|
fun `sealed interface polymorphic - DeviceProfile`() = runTest2 {
|
||||||
val ds = createDataStore()
|
val ds = createDataStore()
|
||||||
|
|||||||
Reference in New Issue
Block a user