gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-kotlin] 01/04: Add Amount class with tests


From: gnunet
Subject: [taler-wallet-kotlin] 01/04: Add Amount class with tests
Date: Wed, 24 Jun 2020 22:53:57 +0200

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a commit to branch master
in repository wallet-kotlin.

commit 7f721d00f1e10fbe3ea01fcbec1a3be558f17860
Author: Torsten Grote <t@grobox.de>
AuthorDate: Wed Jun 24 13:59:00 2020 -0300

    Add Amount class with tests
---
 .../kotlin/net/taler/wallet/kotlin/Amount.kt       | 194 +++++++++++++++
 .../net/taler/wallet/kotlin/crypto/CryptoImpl.kt   |  30 ++-
 .../kotlin/net/taler/wallet/kotlin/AmountTest.kt   | 270 +++++++++++++++++++++
 3 files changed, 485 insertions(+), 9 deletions(-)

diff --git a/src/commonMain/kotlin/net/taler/wallet/kotlin/Amount.kt 
b/src/commonMain/kotlin/net/taler/wallet/kotlin/Amount.kt
new file mode 100644
index 0000000..a078089
--- /dev/null
+++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/Amount.kt
@@ -0,0 +1,194 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.kotlin
+
+import net.taler.wallet.kotlin.crypto.CryptoImpl.Companion.toByteArray
+import kotlin.math.floor
+import kotlin.math.pow
+import kotlin.math.roundToInt
+
+class AmountParserException(msg: String? = null, cause: Throwable? = null) : 
Exception(msg, cause)
+class AmountOverflowException(msg: String? = null, cause: Throwable? = null) : 
Exception(msg, cause)
+
+data class Amount(
+    /**
+     * name of the currency using either a three-character ISO 4217 currency 
code,
+     * or a regional currency identifier starting with a "*" followed by at 
most 10 characters.
+     * ISO 4217 exponents in the name are not supported,
+     * although the "fraction" is corresponds to an ISO 4217 exponent of 6.
+     */
+    val currency: String,
+
+    /**
+     * The integer part may be at most 2^52.
+     * Note that "1" here would correspond to 1 EUR or 1 USD, depending on 
currency, not 1 cent.
+     */
+    val value: Long,
+
+    /**
+     * Unsigned 32 bit fractional value to be added to value representing
+     * an additional currency fraction, in units of one hundred millionth 
(1e-8)
+     * of the base currency value.  For example, a fraction
+     * of 50_000_000 would correspond to 50 cents.
+     */
+    val fraction: Int
+) : Comparable<Amount> {
+
+    companion object {
+
+        private const val FRACTIONAL_BASE: Int = 100000000 // 1e8
+
+        @Suppress("unused")
+        private val REGEX = 
Regex("""^[-_*A-Za-z0-9]{1,12}:([0-9]+)\.?([0-9]+)?$""")
+        private val REGEX_CURRENCY = Regex("""^[-_*A-Za-z0-9]{1,12}$""")
+        internal val MAX_VALUE = 2.0.pow(52).toLong()
+        private const val MAX_FRACTION_LENGTH = 8
+        internal const val MAX_FRACTION = 99_999_999
+
+        fun zero(currency: String): Amount {
+            return Amount(checkCurrency(currency), 0, 0)
+        }
+
+        fun fromJSONString(str: String): Amount {
+            val split = str.split(":")
+            if (split.size != 2) throw AmountParserException("Invalid Amount 
Format")
+            return fromString(split[0], split[1])
+        }
+
+        fun fromString(currency: String, str: String): Amount {
+            // value
+            val valueSplit = str.split(".")
+            val value = checkValue(valueSplit[0].toLongOrNull())
+            // fraction
+            val fraction: Int = if (valueSplit.size > 1) {
+                val fractionStr = valueSplit[1]
+                if (fractionStr.length > MAX_FRACTION_LENGTH)
+                    throw AmountParserException("Fraction $fractionStr too 
long")
+                val fraction = "0.$fractionStr".toDoubleOrNull()
+                    ?.times(FRACTIONAL_BASE)
+                    ?.roundToInt()
+                checkFraction(fraction)
+            } else 0
+            return Amount(checkCurrency(currency), value, fraction)
+        }
+
+        fun min(currency: String): Amount = Amount(currency, 0, 1)
+        fun max(currency: String): Amount = Amount(currency, MAX_VALUE, 
MAX_FRACTION)
+
+//        fun fromJsonObject(json: JSONObject): Amount {
+//            val currency = checkCurrency(json.optString("currency"))
+//            val value = checkValue(json.optString("value").toLongOrNull())
+//            val fraction = 
checkFraction(json.optString("fraction").toIntOrNull())
+//            return Amount(currency, value, fraction)
+//        }
+
+        private fun checkCurrency(currency: String): String {
+            if (!REGEX_CURRENCY.matches(currency))
+                throw AmountParserException("Invalid currency: $currency")
+            return currency
+        }
+
+        private fun checkValue(value: Long?): Long {
+            if (value == null || value > MAX_VALUE)
+                throw AmountParserException("Value $value greater than 
$MAX_VALUE")
+            return value
+        }
+
+        private fun checkFraction(fraction: Int?): Int {
+            if (fraction == null || fraction > MAX_FRACTION)
+                throw AmountParserException("Fraction $fraction greater than 
$MAX_FRACTION")
+            return fraction
+        }
+
+    }
+
+    val amountStr: String
+        get() = if (fraction == 0) "$value" else {
+            var f = fraction
+            var fractionStr = ""
+            while (f > 0) {
+                fractionStr += f / (FRACTIONAL_BASE / 10)
+                f = (f * 10) % FRACTIONAL_BASE
+            }
+            "$value.$fractionStr"
+        }
+
+    operator fun plus(other: Amount): Amount {
+        check(currency == other.currency) { "Can only subtract from same 
currency" }
+        val resultValue = value + other.value + floor((fraction + 
other.fraction).toDouble() / FRACTIONAL_BASE).toLong()
+        if (resultValue > MAX_VALUE)
+            throw AmountOverflowException()
+        val resultFraction = (fraction + other.fraction) % FRACTIONAL_BASE
+        return Amount(currency, resultValue, resultFraction)
+    }
+
+    operator fun times(factor: Int): Amount {
+        var result = this
+        for (i in 1 until factor) result += this
+        return result
+    }
+
+    operator fun minus(other: Amount): Amount {
+        check(currency == other.currency) { "Can only subtract from same 
currency" }
+        var resultValue = value
+        var resultFraction = fraction
+        if (resultFraction < other.fraction) {
+            if (resultValue < 1L)
+                throw AmountOverflowException()
+            resultValue--
+            resultFraction += FRACTIONAL_BASE
+        }
+        check(resultFraction >= other.fraction)
+        resultFraction -= other.fraction
+        if (resultValue < other.value)
+            throw AmountOverflowException()
+        resultValue -= other.value
+        return Amount(currency, resultValue, resultFraction)
+    }
+
+    fun isZero(): Boolean {
+        return value == 0L && fraction == 0
+    }
+
+    fun toJSONString(): String {
+        return "$currency:$amountStr"
+    }
+
+    fun toByteArray() = ByteArray(8 + 4 + 12).apply {
+        value.toByteArray().copyInto(this, 0, 0, 8)
+        fraction.toByteArray().copyInto(this, 8, 0, 4)
+        currency.encodeToByteArray().copyInto(this, 12)
+    }
+
+    override fun toString(): String {
+        return "$amountStr $currency"
+    }
+
+    override fun compareTo(other: Amount): Int {
+        check(currency == other.currency) { "Can only compare amounts with the 
same currency" }
+        when {
+            value == other.value -> {
+                if (fraction < other.fraction) return -1
+                if (fraction > other.fraction) return 1
+                return 0
+            }
+            value < other.value -> return -1
+            else -> return 1
+        }
+    }
+
+}
diff --git a/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoImpl.kt 
b/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoImpl.kt
index 98ee656..e6995b1 100644
--- a/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoImpl.kt
+++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/crypto/CryptoImpl.kt
@@ -1,7 +1,28 @@
 package net.taler.wallet.kotlin.crypto
 
+import net.taler.wallet.kotlin.crypto.CryptoImpl.Companion.toByteArray
+
 abstract class CryptoImpl : Crypto {
 
+    companion object {
+        fun Int.toByteArray(): ByteArray {
+            val bytes = ByteArray(4)
+            bytes[3] = (this and 0xFFFF).toByte()
+            bytes[2] = ((this ushr 8) and 0xFFFF).toByte()
+            bytes[1] = ((this ushr 16) and 0xFFFF).toByte()
+            bytes[0] = ((this ushr 24) and 0xFFFF).toByte()
+            return bytes
+        }
+
+        fun Long.toByteArray() = ByteArray(8).apply {
+            var l = this@toByteArray
+            for (i in 7 downTo 0) {
+                this[i] = (l and 0xFF).toByte()
+                l = l shr 8
+            }
+        }
+    }
+
     override fun kdf(outputLength: Int, ikm: ByteArray, salt: ByteArray, info: 
ByteArray): ByteArray {
         return Kdf.kdf(outputLength, ikm, salt, info, { sha256(it) }, { 
sha512(it) })
     }
@@ -15,13 +36,4 @@ abstract class CryptoImpl : Crypto {
         return FreshCoin(eddsaGetPublic(coinPrivateKey), coinPrivateKey, bks)
     }
 
-    private fun Int.toByteArray(): ByteArray {
-        val bytes = ByteArray(4)
-        bytes[3] = (this and 0xFFFF).toByte()
-        bytes[2] = ((this ushr 8) and 0xFFFF).toByte()
-        bytes[1] = ((this ushr 16) and 0xFFFF).toByte()
-        bytes[0] = ((this ushr 24) and 0xFFFF).toByte()
-        return bytes
-    }
-
 }
diff --git a/src/commonTest/kotlin/net/taler/wallet/kotlin/AmountTest.kt 
b/src/commonTest/kotlin/net/taler/wallet/kotlin/AmountTest.kt
new file mode 100644
index 0000000..578874d
--- /dev/null
+++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/AmountTest.kt
@@ -0,0 +1,270 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+ * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.kotlin
+
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import kotlin.test.fail
+
+class AmountTest {
+
+    companion object {
+        private val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
+        fun getRandomString(minLength: Int = 1, maxLength: Int = 
Random.nextInt(0, 1337)) = (minLength..maxLength)
+            .map { Random.nextInt(0, charPool.size) }
+            .map(charPool::get)
+            .joinToString("")
+
+        fun getRandomAmount() = getRandomAmount(getRandomString(1, 
Random.nextInt(1, 12)))
+
+        fun getRandomAmount(currency: String): Amount {
+            val value = Random.nextLong(0, Amount.MAX_VALUE)
+            val fraction = Random.nextInt(0, Amount.MAX_FRACTION)
+            return Amount(currency, value, fraction)
+        }
+    }
+
+    @Test
+    fun testFromJSONString() {
+        var str = "TESTKUDOS:23.42"
+        var amount = Amount.fromJSONString(str)
+        assertEquals(str, amount.toJSONString())
+        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)
+        assertEquals(str, amount.toJSONString())
+        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)
+        assertEquals(str, amount.toJSONString())
+        assertEquals("EUR", amount.currency)
+        assertEquals(1500000000, amount.value)
+        assertEquals(3, amount.fraction)
+        assertEquals("1500000000.00000003 EUR", amount.toString())
+    }
+
+    @Test
+    fun testFromJSONStringAcceptsMaxValuesRejectsAbove() {
+        val maxValue = 4503599627370496
+        val str = "TESTKUDOS123:$maxValue.99999999"
+        val amount = Amount.fromJSONString(str)
+        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") {
+            Amount.fromJSONString("TESTKUDOS1234:$maxValue.99999999")
+        }
+
+        // max value + 1 not accepted
+        assertThrows<AmountParserException>("max value + 1 was accepted") {
+            Amount.fromJSONString("TESTKUDOS123:${maxValue + 1}.99999999")
+        }
+
+        // max fraction + 1 not accepted
+        assertThrows<AmountParserException>("max fraction + 1 was accepted") {
+            Amount.fromJSONString("TESTKUDOS123:$maxValue.999999990")
+        }
+    }
+
+    @Test
+    fun testFromJSONStringRejections() {
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString("TESTKUDOS:0,5")
+        }
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString("+TESTKUDOS:0.5")
+        }
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString("0.5")
+        }
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString(":0.5")
+        }
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString("EUR::0.5")
+        }
+        assertThrows<AmountParserException> {
+            Amount.fromJSONString("EUR:.5")
+        }
+    }
+
+    @Test
+    fun testAddition() {
+        assertEquals(
+            Amount.fromJSONString("EUR:2"),
+            Amount.fromJSONString("EUR:1") + Amount.fromJSONString("EUR:1")
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:3"),
+            Amount.fromJSONString("EUR:1.5") + Amount.fromJSONString("EUR:1.5")
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:500000000.00000002"),
+            Amount.fromJSONString("EUR:500000000.00000001") + 
Amount.fromJSONString("EUR:0.00000001")
+        )
+        assertThrows<AmountOverflowException>("addition didn't overflow") {
+            Amount.fromJSONString("EUR:4503599627370496.99999999") + 
Amount.fromJSONString("EUR:0.00000001")
+        }
+        assertThrows<AmountOverflowException>("addition didn't overflow") {
+            Amount.fromJSONString("EUR:4000000000000000") + 
Amount.fromJSONString("EUR:4000000000000000")
+        }
+    }
+
+    @Test
+    fun testTimes() {
+        assertEquals(
+            Amount.fromJSONString("EUR:2"),
+            Amount.fromJSONString("EUR:2") * 1
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:2"),
+            Amount.fromJSONString("EUR:1") * 2
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:4.5"),
+            Amount.fromJSONString("EUR:1.5") * 3
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:1500000000.00000003"),
+            Amount.fromJSONString("EUR:500000000.00000001") * 3
+        )
+        assertThrows<AmountOverflowException>("times didn't overflow") {
+            Amount.fromJSONString("EUR:4000000000000000") * 2
+        }
+    }
+
+    @Test
+    fun testSubtraction() {
+        assertEquals(
+            Amount.fromJSONString("EUR:0"),
+            Amount.fromJSONString("EUR:1") - Amount.fromJSONString("EUR:1")
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:1.5"),
+            Amount.fromJSONString("EUR:3") - Amount.fromJSONString("EUR:1.5")
+        )
+        assertEquals(
+            Amount.fromJSONString("EUR:500000000.00000001"),
+            Amount.fromJSONString("EUR:500000000.00000002") - 
Amount.fromJSONString("EUR:0.00000001")
+        )
+        assertThrows<AmountOverflowException>("subtraction didn't underflow") {
+            Amount.fromJSONString("EUR:23.42") - 
Amount.fromJSONString("EUR:42.23")
+        }
+        assertThrows<AmountOverflowException>("subtraction didn't underflow") {
+            Amount.fromJSONString("EUR:0.5") - 
Amount.fromJSONString("EUR:0.50000001")
+        }
+    }
+
+    @Test
+    fun testIsZero() {
+        assertTrue(Amount.zero("EUR").isZero())
+        assertTrue(Amount.fromJSONString("EUR:0").isZero())
+        assertTrue(Amount.fromJSONString("EUR:0.0").isZero())
+        assertTrue(Amount.fromJSONString("EUR:0.00000").isZero())
+        assertTrue((Amount.fromJSONString("EUR:1.001") - 
Amount.fromJSONString("EUR:1.001")).isZero())
+
+        assertFalse(Amount.fromJSONString("EUR:0.00000001").isZero())
+        assertFalse(Amount.fromJSONString("EUR:1.0").isZero())
+        assertFalse(Amount.fromJSONString("EUR:0001.0").isZero())
+    }
+
+    @Test
+    fun testComparision() {
+        assertTrue(Amount.fromJSONString("EUR:0") <= 
Amount.fromJSONString("EUR:0"))
+        assertTrue(Amount.fromJSONString("EUR:0") <= 
Amount.fromJSONString("EUR:0.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:0") < 
Amount.fromJSONString("EUR:0.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:0") < 
Amount.fromJSONString("EUR:1"))
+        assertEquals(Amount.fromJSONString("EUR:0"), 
Amount.fromJSONString("EUR:0"))
+        assertEquals(Amount.fromJSONString("EUR:42"), 
Amount.fromJSONString("EUR:42"))
+        assertEquals(Amount.fromJSONString("EUR:42.00000001"), 
Amount.fromJSONString("EUR:42.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:42.00000001") >= 
Amount.fromJSONString("EUR:42.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:42.00000002") >= 
Amount.fromJSONString("EUR:42.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:42.00000002") > 
Amount.fromJSONString("EUR:42.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:0.00000002") > 
Amount.fromJSONString("EUR:0.00000001"))
+        assertTrue(Amount.fromJSONString("EUR:0.00000001") > 
Amount.fromJSONString("EUR:0"))
+        assertTrue(Amount.fromJSONString("EUR:2") > 
Amount.fromJSONString("EUR:1"))
+
+        assertThrows<IllegalStateException>("could compare amounts with 
different currencies") {
+            Amount.fromJSONString("EUR:0.5") < 
Amount.fromJSONString("USD:0.50000001")
+        }
+    }
+
+    @Test
+    fun testToByteArray() {
+        val vectors = listOf(
+            Pair("ceicWVf9GhJ:3902026702525079.40496378", 
"006XSQV3G899E0K9XKX66SB9CDBNCSHS8XM4M00"),
+            Pair("asYDLuK2A:3800267550024600.02072907", 
"006R0MNXBVHSG00ZM55P2WTS8H67AJSJ8400000"),
+            Pair("pV1m:1347558259914570.09786232", 
"002CK66VCNVMM04NADW70NHHDM0000000000000"),
+            Pair("geO82l:553744321840253.41004983", 
"000ZF855K627T0KHNYVPESAF70S6R0000000000"),
+            Pair("B9bWK7WPEO:3663912678613976.12122563", 
"006G8KS5P9HXG05RZ71M4EB2AX5KENTG8N7G000"),
+            Pair("X:1537372109907438.77850768", 
"002QCETPFYJYW153X285G000000000000000000"),
+            Pair("5:4271492725553118.39728399", 
"007JSSK6J4VXW0JY6M7KA000000000000000000"),
+            Pair("OSdV:801656289790342.08256189", 
"001DJ6H6CA4RC03XZAYMYMV4AR0000000000000"),
+            Pair("Y6:2908617536334646.94126271", 
"0055AQTB19NKC1CW82ZNJDG0000000000000000"),
+            Pair("kSHoOZj:2610656582865206.00292046", 
"004MCR6T828KC004EK76PMT8DX7NMTG00000000"),
+            Pair("GkhLXrlGES:4246330707533398.83874252", 
"007HC0Z9DFF5C17ZT764ETV89HC74V278N9G000"),
+            Pair("CNS09:738124490298524.71259462", 
"0019YMG01DA9R11ZAN346KJK60WG00000000000"),
+            Pair("sw0b1tKXZym:2132978464977419.28199478", 
"003S7VNZPZS0P0DE98V76XSGC8RQ8JTRB9WPT00"),
+            Pair("fC:1275322307696988.17178522", 
"0028FSGX3ZCNR0863YD6CGR0000000000000000"),
+            Pair("cRai6j:166032749022734.69444771", 
"0009E0C30V70W113MJHP6MK1D4V6M0000000000"),
+            Pair("KOADwTb3:3932974019564218.48282023", 
"006ZJ16ZB39BM0Q0Q6KMPKT18HVN8RHK0000000"),
+            Pair("9Fi9wcLgDe:1268366772151214.97268853", 
"002834N6WRHTW1EC6HTKJHK975VP6K378HJG000"),
+            Pair("SDN:3370670470236379.88943272", 
"005ZK6V0124DP1AD5AM56H2E000000000000000"),
+            Pair("zGCP5V:4010014441349620.76121145", 
"0073Y5HYA8GZ8149GGWQMHT3A0TNC0000000000"),
+            Pair("VsW1JjBLn:2037070181191907.99717275", 
"003KSD2WH18E61FHJ2DNCWTQ6556MGJCDR00000"),
+            Pair("A:1806895799429502.00887758", 
"0036PQ5P8NMQW00DHF742000000000000000000"),
+            Pair("njA8:4015261148004966.43708687", 
"00747PYPD116C0MTY47PWTJ1700000000000000"),
+            Pair("Bwq:3562876074139250.28829179", 
"006AGTNTRWF740DQWQXM4XVH000000000000000"),
+            Pair("8e75v8:3716241006992995.95213823", 
"006K7SP93WF661DCV3ZKGS9Q6NV3G0000000000"),
+            Pair("XrnbQTTn:3887603772953949.94721267", 
"006WZGA9X8ANT1D5AKSNGWKEC98N8N3E0000000"),
+            Pair("MIN:0.00000001", "0000000000000000000MTJAE000000000000000"),
+            Pair("MAX:4503599627370496.99999999", 
"00800000000001FNW3ZMTGAR000000000000000")
+        )
+        for (v in vectors) {
+            val amount = Amount.fromJSONString(v.first)
+            val encodedBytes = Base32Crockford.encode(amount.toByteArray())
+            assertEquals(v.second, encodedBytes)
+        }
+    }
+
+    private inline fun <reified T : Throwable> assertThrows(
+        msg: String? = null,
+        function: () -> Any
+    ) {
+        try {
+            function.invoke()
+            fail(msg)
+        } catch (e: Exception) {
+            assertTrue(e is T)
+        }
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]