From 88eee88d77cb1a22215e94545e91e2efc4379c9f Mon Sep 17 00:00:00 2001 From: shamim-emon Date: Mon, 30 Sep 2024 17:39:21 +0600 Subject: [PATCH] Decimal number capability added --- gradle/libs.versions.toml | 3 + .../com/ivy/domain/features/IvyFeatures.kt | 7 +- shared/ui/core/build.gradle.kts | 2 + .../java/com/ivy/ui/FormatMoneyUseCase.kt | 23 ++-- .../java/com/ivy/ui/FormatMoneyUseCaseTest.kt | 106 +++++++++++++----- 5 files changed, 101 insertions(+), 40 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 065c223f70..8270cf471a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -120,6 +120,9 @@ androidx-work = { module = "androidx.work:work-runtime-ktx", version.ref = "andr androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidx-work" } androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version = "1.3.2" } +# Robolectric +roboelectric = { module = "org.robolectric:robolectric", version = "4.13" } + # Material material = { module = "com.google.android.material:material", version = "1.12.0" } diff --git a/shared/domain/src/main/java/com/ivy/domain/features/IvyFeatures.kt b/shared/domain/src/main/java/com/ivy/domain/features/IvyFeatures.kt index 5b69bff358..900a0b9b47 100644 --- a/shared/domain/src/main/java/com/ivy/domain/features/IvyFeatures.kt +++ b/shared/domain/src/main/java/com/ivy/domain/features/IvyFeatures.kt @@ -56,8 +56,8 @@ class IvyFeatures @Inject constructor() : Features { key = "show_decimal_number", group = FeatureGroup.Other, name = "Show Decimal Number", - description = "Show Decimal Number in amounts", - defaultValue = false + description = "Whether to show the decimal part in amounts", + defaultValue = true ) override val allFeatures: List @@ -68,6 +68,9 @@ class IvyFeatures @Inject constructor() : Features { showTitleSuggestions, showCategorySearchBar, hideTotalBalance, + /* will be uncommented when this functionality + * will be available across the application in up-coming PRs showDecimalNumber + */ ) } diff --git a/shared/ui/core/build.gradle.kts b/shared/ui/core/build.gradle.kts index 7e79fb1fd9..5c4b5e4e41 100644 --- a/shared/ui/core/build.gradle.kts +++ b/shared/ui/core/build.gradle.kts @@ -9,4 +9,6 @@ android { dependencies { implementation(projects.shared.base) implementation(projects.shared.domain) + + testImplementation(libs.roboelectric) } \ No newline at end of file diff --git a/shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt b/shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt index 477e53aa1a..e35d20a2d4 100644 --- a/shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt +++ b/shared/ui/core/src/main/java/com/ivy/ui/FormatMoneyUseCase.kt @@ -1,26 +1,29 @@ package com.ivy.ui -import androidx.compose.runtime.Composable +import android.content.Context import com.ivy.domain.features.Features import com.ivy.ui.time.DevicePreferences +import dagger.hilt.android.qualifiers.ApplicationContext import java.text.DecimalFormat import java.text.DecimalFormatSymbols -import java.util.Locale import javax.inject.Inject class FormatMoneyUseCase @Inject constructor( private val feature: Features, private val devicePreferences: DevicePreferences, + @ApplicationContext private val context: Context ) { + private val locale = devicePreferences.locale() - private val formatterWithoutDecimal = DecimalFormat("###,###", DecimalFormatSymbols(locale)) - private val formatterWithDecimal = DecimalFormat("###,###.00", DecimalFormatSymbols(locale)) - @Composable - fun format(value: Double): String { - val showDecimal = feature.showDecimalNumber.asEnabledState() - return when (showDecimal) { - true -> formatterWithDecimal.format(value) - else -> formatterWithoutDecimal.format(value) + private val withoutDecimalFormatter = DecimalFormat("###,###", DecimalFormatSymbols(locale)) + private val withDecimalFormatter = DecimalFormat("###,###.00", DecimalFormatSymbols(locale)) + + suspend fun format(value: Double): String { + val showDecimalPoint = feature.showDecimalNumber.isEnabled(context) + + return when (showDecimalPoint) { + true -> withDecimalFormatter.format(value) + false -> withoutDecimalFormatter.format(value) } } } \ No newline at end of file diff --git a/shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt b/shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt index 3014ae9176..6c5f66455b 100644 --- a/shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt +++ b/shared/ui/core/src/test/java/com/ivy/ui/FormatMoneyUseCaseTest.kt @@ -1,52 +1,102 @@ package com.ivy.ui -import androidx.compose.runtime.Composable +import android.content.Context +import androidx.test.platform.app.InstrumentationRegistry import com.ivy.domain.features.BoolFeature import com.ivy.domain.features.FeatureGroup import com.ivy.domain.features.Features import com.ivy.ui.time.DevicePreferences +import io.kotest.common.runBlocking import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk -import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.ParameterizedRobolectricTestRunner import java.util.Locale -class FormatMoneyUseCaseTest { +@RunWith(ParameterizedRobolectricTestRunner::class) +class FormatMoneyUseCaseTest(private val param: TestData) { + private val context: Context = InstrumentationRegistry.getInstrumentation().context private val features = mockk() private val devicePreferences = mockk() - private val showDecimal = BoolFeature( - key = "show_decimal_number", - group = FeatureGroup.Other, - name = "Show Decimal Number", - description = "Show Decimal Number in amounts", - defaultValue = true - ) - private val hideDecimal = BoolFeature( - key = "show_decimal_number", - group = FeatureGroup.Other, - name = "Show Decimal Number", - description = "Show Decimal Number in amounts", - defaultValue = false + class TestData( + val givenInput: Double, + val showDecimal: BoolFeature, + val locale: Locale, + val expectedOutPut: String ) private lateinit var formatMoneyUseCase: FormatMoneyUseCase - @Before - fun setup() { - formatMoneyUseCase = FormatMoneyUseCase(features,devicePreferences) - } - - @Composable @Test - fun `Format with no decimal place locale ENGLISH`() { - //given - every { features.showDecimalNumber } returns hideDecimal - every { devicePreferences.locale() } returns Locale.ENGLISH + fun `validate decimal formatting`(): Unit = runBlocking { + // given + every { features.showDecimalNumber } returns param.showDecimal + every { devicePreferences.locale() } returns param.locale + formatMoneyUseCase = FormatMoneyUseCase(features, devicePreferences, context) + + // when + val result = formatMoneyUseCase.format(value = param.givenInput) + + // then + result shouldBe param.expectedOutPut + } - val result = formatMoneyUseCase.format(value = 1000.12) - result shouldBe "1,000" + companion object { + @JvmStatic + @ParameterizedRobolectricTestRunner.Parameters(name = "Input: {0}") + fun params() = listOf( + TestData( + givenInput = 1000.12, + showDecimal = BoolFeature( + key = "show_decimal_number", + group = FeatureGroup.Other, + name = "Show Decimal Number", + description = "Whether to show the decimal part in amounts", + defaultValue = true + ), + locale = Locale.ENGLISH, + expectedOutPut = "1,000.12" + ), + TestData( + givenInput = 1000.12, + showDecimal = BoolFeature( + key = "show_decimal_number", + group = FeatureGroup.Other, + name = "Show Decimal Number", + description = "Whether to show the decimal part in amounts", + defaultValue = false + ), + locale = Locale.ENGLISH, + expectedOutPut = "1,000" + ), + TestData( + givenInput = 1000.12, + showDecimal = BoolFeature( + key = "show_decimal_number", + group = FeatureGroup.Other, + name = "Show Decimal Number", + description = "Whether to show the decimal part in amounts", + defaultValue = true + ), + locale = Locale.GERMAN, + expectedOutPut = "1.000,12" + ), + TestData( + givenInput = 1000.12, + showDecimal = BoolFeature( + key = "show_decimal_number", + group = FeatureGroup.Other, + name = "Show Decimal Number", + description = "Whether to show the decimal part in amounts", + defaultValue = false + ), + locale = Locale.GERMAN, + expectedOutPut = "1.000" + ), + ) } } \ No newline at end of file