Procházet zdrojové kódy

test: 改走设置原子更新真实路径

5151561 před 3 měsíci
rodič
revize
90fc73b86f

+ 0 - 9
app/src/main/java/io/legado/app/data/repository/SettingsMapping.kt

@@ -1,9 +0,0 @@
-package io.legado.app.data.repository
-
-internal inline fun <T> T.diffPrefMap(
-    transform: (T) -> T,
-    toPrefMap: (T) -> Map<String, Any?>,
-): Map<String, Any?> {
-    val previous = toPrefMap(this)
-    return toPrefMap(transform(this)).filter { (key, value) -> previous[key] != value }
-}

+ 39 - 0
app/src/test/java/io/legado/app/data/repository/AtomicSettingsTestUtils.kt

@@ -0,0 +1,39 @@
+package io.legado.app.data.repository
+
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.mutablePreferencesOf
+import io.legado.app.help.config.PendingOverlayCore
+import io.legado.app.help.config.setPrefValue
+import kotlinx.coroutines.runBlocking
+
+internal fun <T> captureAtomicUpdateValues(
+    current: T,
+    read: (Preferences) -> T,
+    toPrefMap: (T) -> Map<String, Any?>,
+    transform: (T) -> T,
+): Map<String, Any?> {
+    val initial = toPrefMap(current).toTestPreferences()
+    val writeQueue = ArrayDeque<suspend () -> Unit>()
+    var persistedValues: Map<String, Any?>? = null
+    val core = PendingOverlayCore(
+        initial = initial,
+        launchWrite = { writeQueue += it },
+        persist = { _, _ -> error("不会执行单键落盘") },
+        persistAll = { values ->
+            persistedValues = values
+            initial
+        },
+    )
+
+    core.atomicUpdate(read, toPrefMap, transform)
+    if (writeQueue.isEmpty()) return emptyMap()
+    check(writeQueue.size == 1)
+    runBlocking { writeQueue.removeFirst().invoke() }
+    return checkNotNull(persistedValues)
+}
+
+internal fun Map<String, Any?>.toTestPreferences(): Preferences {
+    val preferences = mutablePreferencesOf()
+    forEach { (key, value) -> preferences.setPrefValue(key, value) }
+    return preferences
+}

+ 5 - 11
app/src/test/java/io/legado/app/data/repository/BackupSettingsMappingTest.kt

@@ -1,10 +1,8 @@
 package io.legado.app.data.repository
 
 import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.mutablePreferencesOf
 import io.legado.app.constant.PreferKey
 import io.legado.app.domain.model.settings.BackupSettings
-import io.legado.app.help.config.setPrefValue
 import org.junit.Assert.assertEquals
 import org.junit.Test
 
@@ -30,7 +28,7 @@ class BackupSettingsMappingTest {
         )
 
         samples.forEach { expected ->
-            assertEquals(expected, expected.toPrefMap().toPreferences().toBackupSettings())
+            assertEquals(expected, expected.toPrefMap().toTestPreferences().toBackupSettings())
         }
     }
 
@@ -44,7 +42,10 @@ class BackupSettingsMappingTest {
             backupPath = "content://old/path",
         )
 
-        val diff = current.diffPrefMap(
+        val diff = captureAtomicUpdateValues(
+            current = current,
+            read = Preferences::toBackupSettings,
+            toPrefMap = BackupSettings::toPrefMap,
             transform = {
                 it.copy(
                     webDavAccount = "new-account",
@@ -54,7 +55,6 @@ class BackupSettingsMappingTest {
                     backupPath = null,
                 )
             },
-            toPrefMap = BackupSettings::toPrefMap,
         )
 
         assertEquals(
@@ -69,9 +69,3 @@ class BackupSettingsMappingTest {
         )
     }
 }
-
-private fun Map<String, Any?>.toPreferences(): Preferences {
-    val preferences = mutablePreferencesOf()
-    forEach { (key, value) -> preferences.setPrefValue(key, value) }
-    return preferences
-}

+ 20 - 24
app/src/test/java/io/legado/app/data/repository/LabSettingsMappingTest.kt

@@ -1,11 +1,9 @@
 package io.legado.app.data.repository
 
 import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.mutablePreferencesOf
 import io.legado.app.constant.PreferKey
 import io.legado.app.domain.model.settings.LabSettings
 import io.legado.app.help.config.PendingOverlayCore
-import io.legado.app.help.config.setPrefValue
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
 import org.junit.Test
@@ -23,24 +21,28 @@ class LabSettingsMappingTest {
         )
 
         samples.forEach { expected ->
-            assertEquals(expected, expected.toPrefMap().toPreferences().toLabSettings())
+            assertEquals(expected, expected.toPrefMap().toTestPreferences().toLabSettings())
         }
     }
 
     @Test
-    fun `update transform 只返回发生变化的键`() {
+    fun `原子 update 只入队发生变化的键`() {
         val current = LabSettings(enabled = true)
 
-        val diff = current.diffPrefMap(
-            transform = { it.copy(eyeProtection = true) },
+        val diff = captureAtomicUpdateValues(
+            current = current,
+            read = Preferences::toLabSettings,
             toPrefMap = LabSettings::toPrefMap,
+            transform = { it.copy(eyeProtection = true) },
         )
 
         assertEquals(mapOf(PreferKey.labEyeProtection to true), diff)
         assertTrue(
-            current.diffPrefMap(
-                transform = { it.copy() },
+            captureAtomicUpdateValues(
+                current = current,
+                read = Preferences::toLabSettings,
                 toPrefMap = LabSettings::toPrefMap,
+                transform = { it.copy() },
             ).isEmpty()
         )
     }
@@ -48,25 +50,25 @@ class LabSettingsMappingTest {
     @Test
     fun `基于同一快照并发更新不同字段不丢更新`() {
         val current = LabSettings()
-        val enabledDiff = current.diffPrefMap(
-            transform = { it.copy(enabled = true) },
-            toPrefMap = LabSettings::toPrefMap,
-        )
-        val eyeProtectionDiff = current.diffPrefMap(
-            transform = { it.copy(eyeProtection = true) },
-            toPrefMap = LabSettings::toPrefMap,
+        val transforms: List<(LabSettings) -> LabSettings> = listOf(
+            { it.copy(enabled = true) },
+            { it.copy(eyeProtection = true) },
         )
         val core = PendingOverlayCore(
-            initial = current.toPrefMap().toPreferences(),
+            initial = current.toPrefMap().toTestPreferences(),
             launchWrite = {},
             persist = { _, _ -> error("不会执行落盘") },
             persistAll = { error("不会执行落盘") },
         )
         val start = CountDownLatch(1)
-        val writers = listOf(enabledDiff, eyeProtectionDiff).map { diff ->
+        val writers = transforms.map { transform ->
             thread(start = true) {
                 start.await()
-                core.putAll(diff)
+                core.atomicUpdate(
+                    read = Preferences::toLabSettings,
+                    toPrefMap = LabSettings::toPrefMap,
+                    transform = transform,
+                )
             }
         }
 
@@ -79,9 +81,3 @@ class LabSettingsMappingTest {
         )
     }
 }
-
-private fun Map<String, Any?>.toPreferences(): Preferences {
-    val preferences = mutablePreferencesOf()
-    forEach { (key, value) -> preferences.setPrefValue(key, value) }
-    return preferences
-}

+ 10 - 13
app/src/test/java/io/legado/app/data/repository/MangaSettingsMappingTest.kt

@@ -7,7 +7,6 @@ import io.legado.app.constant.PreferKey
 import io.legado.app.domain.gateway.MangaSettingsGateway
 import io.legado.app.domain.model.settings.MangaSettings
 import io.legado.app.help.config.PendingOverlayCore
-import io.legado.app.help.config.setPrefValue
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -32,7 +31,7 @@ class MangaSettingsMappingTest {
     @Test
     fun `漫画设置 28 键读映射逐字段对应`() {
         mangaMappingSamples().forEach { expected ->
-            assertEquals(expected, expected.expectedPrefMap().toPreferences().toMangaSettings())
+            assertEquals(expected, expected.expectedPrefMap().toTestPreferences().toMangaSettings())
         }
     }
 
@@ -53,11 +52,13 @@ class MangaSettingsMappingTest {
 
     @Test
     fun `墨水屏更新一次产生启用关闭灰度和阈值三项差量`() {
-        val diff = MangaSettings(enableGray = true).diffPrefMap(
+        val diff = captureAtomicUpdateValues(
+            current = MangaSettings(enableGray = true),
+            read = Preferences::toMangaSettings,
+            toPrefMap = MangaSettings::toPrefMap,
             transform = {
                 it.copy(enableEInk = true, enableGray = false, eInkThreshold = 188)
             },
-            toPrefMap = MangaSettings::toPrefMap,
         )
 
         assertEquals(
@@ -72,9 +73,11 @@ class MangaSettingsMappingTest {
 
     @Test
     fun `灰度更新一次产生启用灰度和关闭墨水屏两项差量`() {
-        val diff = MangaSettings(enableEInk = true).diffPrefMap(
-            transform = { it.copy(enableEInk = false, enableGray = true) },
+        val diff = captureAtomicUpdateValues(
+            current = MangaSettings(enableEInk = true),
+            read = Preferences::toMangaSettings,
             toPrefMap = MangaSettings::toPrefMap,
+            transform = { it.copy(enableEInk = false, enableGray = true) },
         )
 
         assertEquals(
@@ -104,7 +107,7 @@ class MangaSettingsMappingTest {
     fun `并发启用墨水屏与灰度时完整 transform 串行且保持互斥`() {
         val initial = MangaSettings()
         val core = PendingOverlayCore(
-            initial = initial.expectedPrefMap().toPreferences(),
+            initial = initial.expectedPrefMap().toTestPreferences(),
             launchWrite = {},
             persist = { _, _ -> error("不会执行落盘") },
             persistAll = { error("不会执行落盘") },
@@ -235,9 +238,3 @@ private fun MangaSettings.expectedPrefMap(): Map<String, Any?> = mapOf(
     PreferKey.mangaClickActionBC to clickActionBC,
     PreferKey.mangaClickActionBR to clickActionBR,
 )
-
-private fun Map<String, Any?>.toPreferences(): Preferences {
-    val preferences = mutablePreferencesOf()
-    forEach { (key, value) -> preferences.setPrefValue(key, value) }
-    return preferences
-}

+ 5 - 7
app/src/test/java/io/legado/app/data/repository/Phase2SettingsMappingTest.kt

@@ -1,7 +1,6 @@
 package io.legado.app.data.repository
 
 import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.mutablePreferencesOf
 import io.legado.app.constant.PreferKey
 import io.legado.app.domain.model.TranslationConstants
 import io.legado.app.domain.model.settings.BookExportSettings
@@ -10,7 +9,6 @@ import io.legado.app.domain.model.settings.CoverSettings
 import io.legado.app.domain.model.settings.DownloadCacheSettings
 import io.legado.app.domain.model.settings.ImportBookSettings
 import io.legado.app.domain.model.settings.TranslationSettings
-import io.legado.app.help.config.setPrefValue
 import org.junit.Assert.assertEquals
 import org.junit.Test
 
@@ -73,9 +71,11 @@ class Phase2SettingsMappingTest {
 
         assertEquals(
             mapOf(PreferKey.importBookPath to null),
-            settings.diffPrefMap(
-                transform = { it.copy(importBookPath = null) },
+            captureAtomicUpdateValues(
+                current = settings,
+                read = Preferences::toImportBookSettings,
                 toPrefMap = ImportBookSettings::toPrefMap,
+                transform = { it.copy(importBookPath = null) },
             ),
         )
     }
@@ -159,9 +159,7 @@ private fun <T> assertRoundTrips(
     fromPreferences: (Preferences) -> T,
 ) {
     samples.forEach { expected ->
-        val preferences = mutablePreferencesOf().apply {
-            toPrefMap(expected).forEach { (key, value) -> setPrefValue(key, value) }
-        }
+        val preferences = toPrefMap(expected).toTestPreferences()
         assertEquals(expected, fromPreferences(preferences))
     }
 }