From 8815105bf2462787885214a12af927d484226f21 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 30 Jul 2020 16:40:23 -0300 Subject: Split out common code into multiplatform Kotlin library --- .../kotlin/net/taler/common/AmountTest.kt | 234 +++++++++++++++++++++ .../kotlin/net/taler/common/TestUtils.kt | 26 +++ .../kotlin/net/taler/common/VersionTest.kt | 65 ++++++ 3 files changed, 325 insertions(+) create mode 100644 taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt create mode 100644 taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt create mode 100644 taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt (limited to 'taler-kotlin-common/src/commonTest/kotlin/net/taler') diff --git a/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt new file mode 100644 index 0000000..e184307 --- /dev/null +++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/AmountTest.kt @@ -0,0 +1,234 @@ +/* + * 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 + */ + +package net.taler.common + +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 { + 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("longer currency was accepted") { + Amount.fromJSONString("TESTKUDOS1234:$maxValue.99999999") + } + + // max value + 1 not accepted + assertThrows("max value + 1 was accepted") { + Amount.fromJSONString("TESTKUDOS123:${maxValue + 1}.99999999") + } + + // max fraction + 1 not accepted + assertThrows("max fraction + 1 was accepted") { + Amount.fromJSONString("TESTKUDOS123:$maxValue.999999990") + } + } + + @Test + fun testFromJSONStringRejections() { + assertThrows { + Amount.fromJSONString("TESTKUDOS:0,5") + } + assertThrows { + Amount.fromJSONString("+TESTKUDOS:0.5") + } + assertThrows { + Amount.fromJSONString("0.5") + } + assertThrows { + Amount.fromJSONString(":0.5") + } + assertThrows { + Amount.fromJSONString("EUR::0.5") + } + assertThrows { + 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("addition didn't overflow") { + Amount.fromJSONString("EUR:4503599627370496.99999999") + Amount.fromJSONString("EUR:0.00000001") + } + assertThrows("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:0"), Amount.fromJSONString("EUR:1.11") * 0) + assertEquals(Amount.fromJSONString("EUR:1.11"), Amount.fromJSONString("EUR:1.11") * 1) + assertEquals(Amount.fromJSONString("EUR:2.22"), Amount.fromJSONString("EUR:1.11") * 2) + assertEquals(Amount.fromJSONString("EUR:3.33"), Amount.fromJSONString("EUR:1.11") * 3) + assertEquals(Amount.fromJSONString("EUR:4.44"), Amount.fromJSONString("EUR:1.11") * 4) + assertEquals(Amount.fromJSONString("EUR:5.55"), Amount.fromJSONString("EUR:1.11") * 5) + assertEquals( + Amount.fromJSONString("EUR:1500000000.00000003"), + Amount.fromJSONString("EUR:500000000.00000001") * 3 + ) + assertThrows("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("subtraction didn't underflow") { + Amount.fromJSONString("EUR:23.42") - Amount.fromJSONString("EUR:42.23") + } + assertThrows("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("could compare amounts with different currencies") { + Amount.fromJSONString("EUR:0.5") < Amount.fromJSONString("USD:0.50000001") + } + } + + private inline fun assertThrows( + msg: String? = null, + function: () -> Any + ) { + try { + function.invoke() + fail(msg) + } catch (e: Exception) { + assertTrue(e is T) + } + } + +} diff --git a/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt new file mode 100644 index 0000000..e3a6c17 --- /dev/null +++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TestUtils.kt @@ -0,0 +1,26 @@ +/* + * 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 + */ + +package net.taler.common + +import kotlin.random.Random + +private val charPool: List = ('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("") diff --git a/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt new file mode 100644 index 0000000..f4f17ea --- /dev/null +++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/VersionTest.kt @@ -0,0 +1,65 @@ +/* + * 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 + */ + +package net.taler.common + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class VersionTest { + + @Test + fun testParse() { + assertNull(Version.parse("")) + assertNull(Version.parse("foo")) + assertNull(Version.parse("foo:bar:foo")) + assertNull(Version.parse("0:0:0:")) + assertNull(Version.parse("0:0:")) + assertEquals(Version(0, 0, 0), Version.parse("0:0:0")) + assertEquals(Version(1, 2, 3), Version.parse("1:2:3")) + assertEquals(Version(1337, 42, 23), Version.parse("1337:42:23")) + } + + @Test + fun testComparision() { + assertEquals( + Version.VersionMatchResult(true, 0), + Version.parse("0:0:0")!!.compare(Version.parse("0:0:0")) + ) + assertEquals( + Version.VersionMatchResult(true, -1), + Version.parse("0:0:0")!!.compare(Version.parse("1:0:1")) + ) + assertEquals( + Version.VersionMatchResult(true, -1), + Version.parse("0:0:0")!!.compare(Version.parse("1:5:1")) + ) + assertEquals( + Version.VersionMatchResult(false, -1), + Version.parse("0:0:0")!!.compare(Version.parse("1:5:0")) + ) + assertEquals( + Version.VersionMatchResult(false, 1), + Version.parse("1:0:0")!!.compare(Version.parse("0:5:0")) + ) + assertEquals( + Version.VersionMatchResult(true, 0), + Version.parse("1:0:1")!!.compare(Version.parse("1:5:1")) + ) + } + +} -- cgit v1.2.3