From 364f3774cb271283d063c6856bdef8f243463dd8 Mon Sep 17 00:00:00 2001 From: Leonardo Colman Lopes Date: Wed, 23 Oct 2024 16:38:01 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=A5=85=20Add=20UUID=20field=20handling=20?= =?UTF-8?q?to=20UseCsvParser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance UseCsvParser to handle an optional UUID field, generating new UUIDs when absent. Introduce corresponding tests to ensure proper UUID parsing and generation. Signed-off-by: Leonardo Colman Lopes --- .../colman/petals/use/io/UseIOModuleTest.kt | 60 +++++++++++++++++++ .../petals/use/io/input/UseCsvParser.kt | 16 +++-- .../petals/use/io/input/UseCsvParserTest.kt | 25 ++++++++ 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 app/src/androidTest/kotlin/br/com/colman/petals/use/io/UseIOModuleTest.kt diff --git a/app/src/androidTest/kotlin/br/com/colman/petals/use/io/UseIOModuleTest.kt b/app/src/androidTest/kotlin/br/com/colman/petals/use/io/UseIOModuleTest.kt new file mode 100644 index 00000000..a8d575c1 --- /dev/null +++ b/app/src/androidTest/kotlin/br/com/colman/petals/use/io/UseIOModuleTest.kt @@ -0,0 +1,60 @@ +package br.com.colman.petals.use.io + +import android.content.Context +import android.content.Intent +import androidx.activity.compose.ManagedActivityResultLauncher +import androidx.activity.result.ActivityResult +import androidx.core.net.toUri +import androidx.test.core.app.ApplicationProvider +import br.com.colman.kotest.FunSpec +import br.com.colman.petals.koin +import br.com.colman.petals.use.io.input.UseCsvFileImporter +import br.com.colman.petals.use.io.output.UseExporter +import io.kotest.core.spec.IsolationMode.InstancePerTest +import io.kotest.matchers.file.shouldHaveSameStructureAndContentAs +import io.mockk.mockk +import io.mockk.verify +import java.io.File +import java.time.LocalDate +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin + +class UseIOModuleTest : FunSpec({ + + val useCsvFileImporter = koin.get() + val useExporter = koin.get() + + test("should import and export data maintaining integrity") { + val inputFile = File(ApplicationProvider.getApplicationContext().filesDir, "test_input.csv") + + inputFile.writeText( + """ + date,amount,cost_per_gram,id + 2024-03-21T19:01:47.163,0.08,22.2,80204597-00eb-4412-b7ee-223388806fe2 + """.trimIndent() + ) + + useCsvFileImporter.importCsvFile(inputFile.toUri()) + + val mockLauncher = mockk>(relaxed = true) + + useExporter.exportUses(mockLauncher) + + verify { + mockLauncher.launch(match { intent -> + intent.action == Intent.ACTION_SEND && + intent.type == "text/plain" && + intent.flags == Intent.FLAG_GRANT_READ_URI_PERMISSION + }) + } + + val exportsDir = File(ApplicationProvider.getApplicationContext().filesDir, "exports") + val expectedFileName = "PetalsExport-${LocalDate.now()}.csv" + val exportedFile = File(exportsDir, expectedFileName) + + + inputFile shouldHaveSameStructureAndContentAs exportedFile + + } + +}) diff --git a/app/src/main/kotlin/br/com/colman/petals/use/io/input/UseCsvParser.kt b/app/src/main/kotlin/br/com/colman/petals/use/io/input/UseCsvParser.kt index 92962040..b24dd549 100644 --- a/app/src/main/kotlin/br/com/colman/petals/use/io/input/UseCsvParser.kt +++ b/app/src/main/kotlin/br/com/colman/petals/use/io/input/UseCsvParser.kt @@ -3,16 +3,24 @@ package br.com.colman.petals.use.io.input import br.com.colman.petals.use.repository.Use import com.github.doyaaaaaken.kotlincsv.dsl.csvReader import java.time.LocalDateTime -import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME +import java.util.UUID.randomUUID object UseCsvParser { private val csvReader = csvReader() fun parse(line: String): Result = runCatching { - val (date, amount, cost) = csvReader.readAll(line).single() + val values = csvReader.readAll(line).single() - val dateTime = LocalDateTime.parse(date, DateTimeFormatter.ISO_LOCAL_DATE_TIME) + val dateTime = parseDateTime(values[0]) + val amount = values[1].toBigDecimal() + val cost = values[2].toBigDecimal() + val id = parseOrGenerateUUID(values.getOrNull(3)) - Use(dateTime, amount.toBigDecimal(), cost.toBigDecimal()) + Use(dateTime, amount, cost, id) } + + private fun parseDateTime(date: String) = LocalDateTime.parse(date, ISO_LOCAL_DATE_TIME) + + private fun parseOrGenerateUUID(uuid: String?) = if (uuid.isNullOrBlank()) randomUUID().toString() else uuid } diff --git a/app/src/test/kotlin/br/com/colman/petals/use/io/input/UseCsvParserTest.kt b/app/src/test/kotlin/br/com/colman/petals/use/io/input/UseCsvParserTest.kt index f8b73034..2707c05f 100644 --- a/app/src/test/kotlin/br/com/colman/petals/use/io/input/UseCsvParserTest.kt +++ b/app/src/test/kotlin/br/com/colman/petals/use/io/input/UseCsvParserTest.kt @@ -5,6 +5,7 @@ import br.com.colman.petals.use.io.UseCsvArb import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.result.shouldBeFailure import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldBeUUID import io.kotest.property.arbitrary.filter import io.kotest.property.arbitrary.next import io.kotest.property.arbitrary.take @@ -36,6 +37,30 @@ class UseCsvParserTest : FunSpec({ UseCsvParser.parse(useCsv).shouldBeFailure() } + test("Parses the id field if it's present") { + val use = UseArb.next() + val useCsv = use.columns().joinToString(",") + val parsed = UseCsvParser.parse(useCsv) + + parsed.getOrThrow().id shouldBe use.id + } + + test("Creates new id if id field is empty") { + val use = UseArb.next().copy(id = "") + val useCsv = use.columns().joinToString(",") + val parsed = UseCsvParser.parse(useCsv) + + parsed.getOrThrow().id.shouldBeUUID() + } + + test("Creates new id if id field is not present") { + val use = UseArb.next().copy(id = "") + val useCsv = use.columns().dropLast(1).joinToString(",") + val parsed = UseCsvParser.parse(useCsv) + + parsed.getOrThrow().id.shouldBeUUID() + } + test("Parses successfully even if extra fields are present") { val use = UseArb.next() val extraField = "extra"