diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/data/HistoryRepository.kt b/sharedUI/src/commonMain/kotlin/com/livrets/data/HistoryRepository.kt new file mode 100644 index 0000000..f85d090 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/data/HistoryRepository.kt @@ -0,0 +1,32 @@ +package com.livrets.data + +import com.livrets.game.GameResult +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.json.Json +import okio.FileSystem +import okio.Path + +class HistoryRepository( + private val filePath: Path, + private val fileSystem: FileSystem = FileSystem.SYSTEM, +) { + private val json = Json { ignoreUnknownKeys = true } + + suspend fun load(): List = withContext(Dispatchers.IO) { + if (!fileSystem.exists(filePath)) return@withContext emptyList() + fileSystem.read(filePath) { readUtf8() } + .let { json.decodeFromString(ListSerializer(GameResult.serializer()), it) } + } + + suspend fun save(result: GameResult) { + val all = load() + result + withContext(Dispatchers.IO) { + filePath.parent?.let { fileSystem.createDirectories(it) } + fileSystem.write(filePath) { + writeUtf8(json.encodeToString(ListSerializer(GameResult.serializer()), all)) + } + } + } +} diff --git a/sharedUI/src/commonTest/kotlin/com/livrets/data/HistoryRepositoryTest.kt b/sharedUI/src/commonTest/kotlin/com/livrets/data/HistoryRepositoryTest.kt new file mode 100644 index 0000000..ada650c --- /dev/null +++ b/sharedUI/src/commonTest/kotlin/com/livrets/data/HistoryRepositoryTest.kt @@ -0,0 +1,48 @@ +package com.livrets.data + +import com.livrets.game.AnswerRecord +import com.livrets.game.GameConfig +import com.livrets.game.GameResult +import com.livrets.game.Question +import kotlinx.coroutines.test.runTest +import kotlin.time.Instant +import okio.fakefilesystem.FakeFileSystem +import okio.Path.Companion.toPath +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class HistoryRepositoryTest { + + private fun gameResult(date: String, score: Int) = GameResult( + date = Instant.parse(date), + config = GameConfig(10, 10, 12), + records = List(score) { + AnswerRecord(Question.Direct(2, 3), 6, 6, true, 900L) + } + List(10 - score) { + AnswerRecord(Question.Direct(2, 3), null, 6, false, 10_000L) + }, + ) + + @Test + fun `chargement vide quand aucun fichier`() = runTest { + val fs = FakeFileSystem() + val repo = HistoryRepository("/docs/history.json".toPath(), fs) + assertTrue(repo.load().isEmpty()) + } + + @Test + fun `aller-retour sauvegarde puis chargement`() = runTest { + val fs = FakeFileSystem() + val repo = HistoryRepository("/docs/history.json".toPath(), fs) + val first = gameResult("2026-01-01T00:00:00Z", score = 7) + val second = gameResult("2026-02-02T00:00:00Z", score = 4) + + repo.save(first) + assertEquals(listOf(first), repo.load()) + + repo.save(second) + assertEquals(listOf(first, second), repo.load()) + assertTrue(fs.exists("/docs/history.json".toPath())) + } +}