summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-02-20 14:11:56 -0600
committerTorsten Grote <t@grobox.de>2024-03-27 14:26:43 -0300
commit390b562828b8ef0da98c2c8cf06a88055b2c8695 (patch)
tree14f7462d740ef14f2f86c31328c17e01ae4bef20
parente305ddba1455a33e8dec037d4fcef8498e0b21a5 (diff)
downloadtaler-android-390b562828b8ef0da98c2c8cf06a88055b2c8695.tar.gz
taler-android-390b562828b8ef0da98c2c8cf06a88055b2c8695.tar.bz2
taler-android-390b562828b8ef0da98c2c8cf06a88055b2c8695.zip
[wallet] Improve DD51 unit rendering and adapt tests accordingly
(cherry picked from commit c7b2cbe5c39192648336746a719ecdfa88221b28)
-rw-r--r--cashier/src/main/java/net/taler/cashier/SignedAmount.kt8
-rw-r--r--taler-kotlin-android/src/main/java/net/taler/common/Amount.kt48
-rw-r--r--taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt46
3 files changed, 74 insertions, 28 deletions
diff --git a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
index 4f624ae..45bc3af 100644
--- a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
+++ b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
@@ -23,8 +23,10 @@ data class SignedAmount(
val amount: Amount
) {
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
+ override fun toString() = toString(showSymbol = true)
+ fun toString(showSymbol: Boolean) = amount.toString(
+ showSymbol = showSymbol,
+ negative = !positive,
+ )
}
diff --git a/taler-kotlin-android/src/main/java/net/taler/common/Amount.kt b/taler-kotlin-android/src/main/java/net/taler/common/Amount.kt
index d6188cf..1652056 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/Amount.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/Amount.kt
@@ -23,6 +23,7 @@ import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.text.DecimalFormat
+import java.text.DecimalFormatSymbols
import java.text.NumberFormat
import kotlin.math.floor
import kotlin.math.pow
@@ -214,32 +215,39 @@ public data class Amount(
fun toString(
showSymbol: Boolean = true,
negative: Boolean = false,
+ symbols: DecimalFormatSymbols = DecimalFormat().decimalFormatSymbols,
): String {
- val symbols = DecimalFormat().decimalFormatSymbols
-
- val format = if (showSymbol) {
- NumberFormat.getCurrencyInstance()
- } else {
- // Make sure monetary separators are the ones used!
- symbols.decimalSeparator = symbols.monetaryDecimalSeparator
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- symbols.groupingSeparator = symbols.monetaryGroupingSeparator
+ // We clone the object to safely/cleanly modify it
+ val s = symbols.clone() as DecimalFormatSymbols
+ val amount = (if (negative) "-$amountStr" else amountStr).toBigDecimal()
+
+ // No currency spec, so we render normally
+ if (spec == null) {
+ val format = NumberFormat.getInstance()
+ format.maximumFractionDigits = MAX_FRACTION_LENGTH
+ format.minimumFractionDigits = 0
+ if (Build.VERSION.SDK_INT >= 34) {
+ s.groupingSeparator = s.monetaryGroupingSeparator
}
+ s.decimalSeparator = s.monetaryDecimalSeparator
+ (format as DecimalFormat).decimalFormatSymbols = s
- NumberFormat.getInstance()
+ val fmt = format.format(amount)
+ return if (showSymbol) "$fmt $currency" else fmt
}
- if (spec != null) {
- symbols.currencySymbol = spec.symbol(this)
- format.maximumFractionDigits = spec.numFractionalNormalDigits
- format.minimumFractionDigits = spec.numFractionalTrailingZeroDigits
- } else {
- symbols.currencySymbol = currency
+ // There is currency spec, so we can do things right
+ val format = NumberFormat.getCurrencyInstance()
+ format.maximumFractionDigits = spec.numFractionalNormalDigits
+ format.minimumFractionDigits = spec.numFractionalTrailingZeroDigits
+ s.currencySymbol = spec.symbol(this)
+ (format as DecimalFormat).decimalFormatSymbols = s
+
+ val fmt = format.format(amount)
+ return if (showSymbol) fmt else {
+ // We should do better than manually removing the symbol here
+ fmt.replace(s.currencySymbol, "").trim()
}
-
- (format as DecimalFormat).decimalFormatSymbols = symbols
-
- return format.format((if (negative) "-$amountStr" else amountStr).toBigDecimal())
}
override fun compareTo(other: Amount): Int {
diff --git a/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt b/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt
index 7072426..e7fb273 100644
--- a/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt
+++ b/taler-kotlin-android/src/test/java/net/taler/common/AmountTest.kt
@@ -16,10 +16,12 @@
package net.taler.common
+import android.os.Build
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
+import java.text.DecimalFormatSymbols
import kotlin.random.Random
class AmountTest {
@@ -41,7 +43,6 @@ class AmountTest {
assertEquals("TESTKUDOS", amount.currency)
assertEquals(23, amount.value)
assertEquals((0.42 * 1e8).toInt(), amount.fraction)
- assertEquals("23.42 TESTKUDOS", amount.toString())
str = "EUR:500000000.00000001"
amount = Amount.fromJSONString(str)
@@ -49,7 +50,6 @@ class AmountTest {
assertEquals("EUR", amount.currency)
assertEquals(500000000, amount.value)
assertEquals(1, amount.fraction)
- assertEquals("500000000.00000001 EUR", amount.toString())
str = "EUR:1500000000.00000003"
amount = Amount.fromJSONString(str)
@@ -57,14 +57,51 @@ class AmountTest {
assertEquals("EUR", amount.currency)
assertEquals(1500000000, amount.value)
assertEquals(3, amount.fraction)
- assertEquals("1500000000.00000003 EUR", amount.toString())
}
@Test
fun testToString() {
+ val symbols = DecimalFormatSymbols.getInstance()
+ symbols.decimalSeparator = '.'
+ symbols.groupingSeparator = ','
+ symbols.monetaryDecimalSeparator = '.'
+ if (Build.VERSION.SDK_INT >= 34) {
+ symbols.monetaryGroupingSeparator = ','
+ }
+
+ val spec = CurrencySpecification(
+ name = "Bitcoin",
+ numFractionalInputDigits = 8,
+ numFractionalNormalDigits = 8,
+ numFractionalTrailingZeroDigits = 0,
+ altUnitNames = mapOf(
+ 0 to "₿",
+ // TODO: uncomment when units get implemented
+ // and then write tests for units, please
+// -1 to "d₿",
+// -2 to "c₿",
+// -3 to "m₿",
+// -6 to "µ₿",
+// -8 to "sat",
+ ),
+ )
+
Amount.fromString("BITCOINBTC", "0.00000001").let { amount ->
- assertEquals("0.00000001 BITCOINBTC", amount.toString())
+ // Only the raw amount
assertEquals("0.00000001", amount.amountStr)
+
+ // The amount without currency spec
+ assertEquals("0.00000001 BITCOINBTC", amount.toString(symbols = symbols))
+ assertEquals("0.00000001", amount.toString(symbols = symbols, showSymbol = false))
+ assertEquals("-0.00000001 BITCOINBTC", amount.toString(symbols = symbols, negative = true))
+ assertEquals("-0.00000001", amount.toString(symbols = symbols, showSymbol = false, negative = true))
+
+ // The amount with currency spec
+ val withSpec = amount.withSpec(spec)
+ assertEquals("₿0.00000001", withSpec.toString(symbols = symbols))
+ assertEquals("0.00000001", withSpec.toString(symbols = symbols, showSymbol = false))
+ assertEquals("-₿0.00000001", withSpec.toString(symbols = symbols, negative = true))
+ assertEquals("-0.00000001", withSpec.toString(symbols = symbols, showSymbol = false, negative = true))
}
}
@@ -76,7 +113,6 @@ class AmountTest {
assertEquals(str, amount.toJSONString())
assertEquals("TESTKUDOS123", amount.currency)
assertEquals(maxValue, amount.value)
- assertEquals("$maxValue.99999999 TESTKUDOS123", amount.toString())
// longer currency not accepted
assertThrows<AmountParserException>("longer currency was accepted") {