diff --git a/core/src/main/kotlin/plus/rua/project/ShiftPatternStorage.kt b/core/src/main/kotlin/plus/rua/project/ShiftPatternStorage.kt index 23762a1..600e9bc 100644 --- a/core/src/main/kotlin/plus/rua/project/ShiftPatternStorage.kt +++ b/core/src/main/kotlin/plus/rua/project/ShiftPatternStorage.kt @@ -21,6 +21,7 @@ class ShiftPatternStorage(private val prefs: SharedPreferences) { private const val KEY_CYCLE = "shift_cycle" private const val KEY_OVERRIDES = "shift_overrides" private const val KEY_BREAKS = "shift_breaks" + private const val KEY_NAME = "shift_name" private const val SEP = "," fun fromContext(context: Context): ShiftPatternStorage = @@ -40,6 +41,7 @@ class ShiftPatternStorage(private val prefs: SharedPreferences) { .putString(KEY_CYCLE, cycleStr) .putString(KEY_OVERRIDES, overridesStr) .putString(KEY_BREAKS, breaksStr) + .putString(KEY_NAME, pattern.name) .apply() } @@ -48,10 +50,14 @@ class ShiftPatternStorage(private val prefs: SharedPreferences) { val cycleStr = prefs.getString(KEY_CYCLE, null) ?: return null return try { val anchor = LocalDate.parse(anchorStr) - val cycle = cycleStr.split(SEP).map { if (it.trim() == "1") ShiftKind.WORK else ShiftKind.OFF } + val cycle = if (cycleStr.isBlank()) { + emptyList() + } else { + cycleStr.split(SEP).map { if (it.trim() == "1") ShiftKind.WORK else ShiftKind.OFF } + } val overrides = parseOverrides(prefs.getString(KEY_OVERRIDES, null)) val breaks = parseBreaks(prefs.getString(KEY_BREAKS, null)) - ShiftPattern(anchor, cycle, overrides, breaks) + ShiftPattern(anchor, cycle, overrides, breaks, name = prefs.getString(KEY_NAME, null) ?: "默认") } catch (e: Exception) { null } diff --git a/core/src/test/kotlin/plus/rua/project/ShiftPatternStorageTest.kt b/core/src/test/kotlin/plus/rua/project/ShiftPatternStorageTest.kt index 0da5f75..238188a 100644 --- a/core/src/test/kotlin/plus/rua/project/ShiftPatternStorageTest.kt +++ b/core/src/test/kotlin/plus/rua/project/ShiftPatternStorageTest.kt @@ -58,6 +58,44 @@ class ShiftPatternStorageTest { storage.save(pattern) assertEquals(pattern, storage.load()) } + + @Test + fun load_corruptOverrides_returnsNull() { + storage.clear() + // 通过底层 prefs 注入损坏的 overrides 值 + prefs.edit() + .putString("shift_anchor", "2026-05-15") + .putString("shift_cycle", "1,1,0,0") + .putString("shift_overrides", "not-a-date:1") + .apply() + assertNull(storage.load()) + } + + @Test + fun saveAndLoad_customName_preserved() { + storage.clear() + val pattern = ShiftPattern( + anchorDate = LocalDate(2026, 5, 15), + cycle = listOf(ShiftKind.WORK, ShiftKind.OFF), + name = "我的方案" + ) + storage.save(pattern) + val loaded = storage.load() + assertEquals(pattern, loaded) + assertEquals("我的方案", loaded?.name) + } + + @Test + fun saveAndLoad_emptyCycle_roundTrips() { + storage.clear() + val pattern = ShiftPattern( + anchorDate = LocalDate(2026, 5, 15), + cycle = emptyList() + ) + storage.save(pattern) + val loaded = storage.load() + assertEquals(pattern, loaded) + } } // 复制自 DateCheckerStorageTest(其为 private,无法共享);重命名以避免同包下 private 类同名冲突