diff --git a/src/test/java/org/stellar/sdk/MemoTest.java b/src/test/java/org/stellar/sdk/MemoTest.java deleted file mode 100644 index 7972fb6d1..000000000 --- a/src/test/java/org/stellar/sdk/MemoTest.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.stellar.sdk; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import org.junit.Test; -import org.stellar.sdk.xdr.MemoType; - -public class MemoTest { - @Test - public void testMemoNone() { - MemoNone memo = Memo.none(); - assertEquals(MemoType.MEMO_NONE, memo.toXdr().getDiscriminant()); - assertEquals("", memo.toString()); - } - - @Test - public void testMemoTextSuccess() { - MemoText memo = Memo.text("test"); - assertEquals(MemoType.MEMO_TEXT, memo.toXdr().getDiscriminant()); - assertEquals("test", memo.getText()); - assertArrayEquals("test".getBytes(StandardCharsets.UTF_8), memo.getBytes()); - assertEquals("test", memo.toString()); - } - - @Test - public void testMemoTextUtf8() { - MemoText memo = Memo.text("三"); - assertEquals(MemoType.MEMO_TEXT, memo.toXdr().getDiscriminant()); - assertEquals("三", memo.getText()); - assertArrayEquals("三".getBytes(StandardCharsets.UTF_8), memo.getBytes()); - assertEquals("三", memo.toString()); - } - - @Test - public void testMemoTextTooLong() { - try { - Memo.text("12345678901234567890123456789"); - fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("text cannot be more than 28-bytes long.")); - } - } - - @Test - public void testMemoTextTooLongUtf8() { - try { - Memo.text("价值交易的开源协议!!"); - fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("text cannot be more than 28-bytes long.")); - } - } - - @Test - public void testMemoId() { - MemoId memo = Memo.id(9223372036854775807L); - assertEquals(BigInteger.valueOf(9223372036854775807L), memo.getId()); - assertEquals(MemoType.MEMO_ID, memo.toXdr().getDiscriminant()); - assertEquals( - BigInteger.valueOf(9223372036854775807L), memo.toXdr().getId().getUint64().getNumber()); - assertEquals("9223372036854775807", memo.toString()); - } - - @Test - public void testMemoNullHexHashSuccess() { - MemoHash memo = Memo.hash("0000000000000000000000000000000000000000000000000000000000000000"); - assertEquals(MemoType.MEMO_HASH, memo.toXdr().getDiscriminant()); - - assertEquals("", Util.paddedByteArrayToString(memo.getBytes())); - assertEquals( - "0000000000000000000000000000000000000000000000000000000000000000", memo.getHexValue()); - assertEquals( - "0000000000000000000000000000000000000000000000000000000000000000", memo.toString()); - } - - @Test - public void testMemoHashSuccess() { - MemoHash memo = Memo.hash("4142434445464748494a4b4c0000000000000000000000000000000000000000"); - assertEquals(MemoType.MEMO_HASH, memo.toXdr().getDiscriminant()); - String test = "ABCDEFGHIJKL"; - assertEquals(test, Util.paddedByteArrayToString(memo.getBytes())); - assertEquals("ABCDEFGHIJKL", Util.paddedByteArrayToString(memo.getBytes())); - } - - @Test - public void testMemoHashSuccessUppercase() { - - MemoHash memo = - Memo.hash("4142434445464748494a4b4c0000000000000000000000000000000000000000".toUpperCase()); - assertEquals(MemoType.MEMO_HASH, memo.toXdr().getDiscriminant()); - String test = "ABCDEFGHIJKL"; - assertEquals(test, Util.paddedByteArrayToString(memo.getBytes())); - } - - @Test - public void testMemoHashBytesSuccess() { - byte[] bytes = new byte[10]; - Arrays.fill(bytes, (byte) 'A'); - MemoHash memo = Memo.hash(Util.paddedByteArray(bytes, 32)); - assertEquals(MemoType.MEMO_HASH, memo.toXdr().getDiscriminant()); - assertEquals("AAAAAAAAAA", Util.paddedByteArrayToString(memo.getBytes())); - assertEquals( - "4141414141414141414100000000000000000000000000000000000000000000", memo.getHexValue()); - } - - @Test - public void testMemoHashTooLong() { - byte[] longer = new byte[33]; - Arrays.fill(longer, (byte) 0); - try { - Memo.hash(longer); - fail(); - } catch (Exception exception) { - assertTrue(exception.getMessage().contains("bytes must be 32-bytes long.")); - } - } - - @Test - public void testMemoHashTooShort() { - try { - Memo.hash(""); - fail(); - } catch (Exception exception) { - assertTrue(exception.getMessage().contains("bytes must be 32-bytes long.")); - } - } - - @Test - public void testMemoHashInvalidHex() { - try { - Memo.hash("test"); - fail(); - } catch (Exception e) { - // Success - } - } - - @Test - public void testMemoReturnHashSuccess() { - MemoReturnHash memo = - Memo.returnHash("4142434445464748494a4b4c0000000000000000000000000000000000000000"); - org.stellar.sdk.xdr.Memo memoXdr = memo.toXdr(); - assertEquals(MemoType.MEMO_RETURN, memoXdr.getDiscriminant()); - assertNull(memoXdr.getHash()); - assertEquals( - "4142434445464748494a4b4c0000000000000000000000000000000000000000", - Util.bytesToHex(memoXdr.getRetHash().getHash()).toLowerCase()); - } -} diff --git a/src/test/kotlin/org/stellar/sdk/MemoTest.kt b/src/test/kotlin/org/stellar/sdk/MemoTest.kt new file mode 100644 index 000000000..27b9e22a6 --- /dev/null +++ b/src/test/kotlin/org/stellar/sdk/MemoTest.kt @@ -0,0 +1,182 @@ +package org.stellar.sdk + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import java.math.BigInteger +import java.nio.charset.StandardCharsets +import org.stellar.sdk.xdr.MemoType + +class MemoTest : + FunSpec({ + context("MEMO_NONE") { + test("should create empty memo") { + val memo = Memo.none() + memo.toXdr().discriminant shouldBe MemoType.MEMO_NONE + memo.toString() shouldBe "" + } + } + + context("MEMO_TEXT") { + test("should create text memo from string") { + val memo = Memo.text("test") + memo.toXdr().discriminant shouldBe MemoType.MEMO_TEXT + memo.text shouldBe "test" + memo.bytes shouldBe "test".toByteArray(StandardCharsets.UTF_8) + memo.toString() shouldBe "test" + } + + test("should create text memo from empty string") { + val memo = Memo.text("") + memo.toXdr().discriminant shouldBe MemoType.MEMO_TEXT + memo.text shouldBe "" + memo.bytes shouldBe "".toByteArray(StandardCharsets.UTF_8) + memo.toString() shouldBe "" + } + + test("should create text memo with UTF-8 content") { + val memo = Memo.text("三") + memo.toXdr().discriminant shouldBe MemoType.MEMO_TEXT + memo.text shouldBe "三" + memo.bytes shouldBe "三".toByteArray(StandardCharsets.UTF_8) + memo.toString() shouldBe "三" + } + + test("should create text memo with exactly 28 bytes") { + val text = "1234567890123456789012345678" + text.toByteArray(StandardCharsets.UTF_8).size shouldBe 28 + val memo = Memo.text(text) + memo.toXdr().discriminant shouldBe MemoType.MEMO_TEXT + memo.text shouldBe text + memo.bytes shouldBe text.toByteArray(StandardCharsets.UTF_8) + memo.toString() shouldBe text + } + + test("should throw exception when text is too long") { + val longText = "12345678901234567890123456789" + longText.toByteArray(StandardCharsets.UTF_8).size shouldBe 29 + val exception = shouldThrow { Memo.text(longText) } + exception.message shouldBe "text cannot be more than 28-bytes long." + } + + test("should throw exception when UTF-8 text is too long") { + val longText = "价值交易的开源协议!!" // 30 bytes + longText.toByteArray(StandardCharsets.UTF_8).size shouldBe 29 + val exception = shouldThrow { Memo.text(longText) } + exception.message shouldBe "text cannot be more than 28-bytes long." + } + } + + context("MEMO_ID") { + test("should create id memo") { + val memo = Memo.id(9223372036854775807L) + memo.id shouldBe BigInteger.valueOf(9223372036854775807L) + memo.toXdr().discriminant shouldBe MemoType.MEMO_ID + memo.toXdr().id.uint64.number shouldBe BigInteger.valueOf(9223372036854775807L) + memo.toString() shouldBe "9223372036854775807" + } + + test("should create id memo with 0") { + val memo = Memo.id(0) + memo.id shouldBe BigInteger.ZERO + memo.toXdr().discriminant shouldBe MemoType.MEMO_ID + memo.toXdr().id.uint64.number shouldBe BigInteger.ZERO + memo.toString() shouldBe "0" + } + + test("should throw exception when id is negative") { + val exception = shouldThrow { Memo.id(-1) } + exception.message shouldBe "MEMO_ID must be between 0 and 2^64-1" + } + } + + context("MEMO_HASH") { + test("should create hash memo from byte array") { + val bytes = ByteArray(32) { 'A'.code.toByte() } + val memo = Memo.hash(bytes) + memo.toXdr().discriminant shouldBe MemoType.MEMO_HASH + memo.bytes shouldBe bytes + memo.hexValue shouldBe "4141414141414141414141414141414141414141414141414141414141414141" + memo.toString() shouldBe "4141414141414141414141414141414141414141414141414141414141414141" + } + + test("should create hash memo from hex string") { + val hashHex = "4142434445464748494a4b4c0000000000000000000000000000000000000000" + val memo = Memo.hash(hashHex) + memo.toXdr().discriminant shouldBe MemoType.MEMO_HASH + memo.hexValue shouldBe hashHex.lowercase() + memo.toString() shouldBe hashHex.lowercase() + } + + test("should create hash memo from uppercase hex string") { + val hashHex = "4142434445464748494a4b4c0000000000000000000000000000000000000000" + val memo = Memo.hash(hashHex.uppercase()) + memo.toXdr().discriminant shouldBe MemoType.MEMO_HASH + memo.hexValue shouldBe hashHex.lowercase() + memo.toString() shouldBe hashHex.lowercase() + } + + test("should throw exception when bytes are not 32-bytes long") { + val bytes31 = ByteArray(31) + val exception31 = shouldThrow { Memo.hash(bytes31) } + exception31.message shouldBe "bytes must be 32-bytes long." + + val bytes33 = ByteArray(33) + val exception33 = shouldThrow { Memo.hash(bytes33) } + exception33.message shouldBe "bytes must be 32-bytes long." + } + + test("should throw exception when hex string is invalid") { + shouldThrow { Memo.hash("test") } + shouldThrow { Memo.hash("") } + shouldThrow { + Memo.hash("00000000000000000000000000000000000000000000000000000000000000") + } // 63 chars + } + } + + context("MEMO_RETURN_HASH") { + test("should create return hash memo from byte array") { + val bytes = ByteArray(32) { 'A'.code.toByte() } + val memo = Memo.returnHash(bytes) + memo.toXdr().discriminant shouldBe MemoType.MEMO_RETURN + memo.bytes shouldBe bytes + memo.hexValue shouldBe "4141414141414141414141414141414141414141414141414141414141414141" + memo.toString() shouldBe "4141414141414141414141414141414141414141414141414141414141414141" + } + + test("should create return hash memo from hex string") { + val hashHex = "4142434445464748494a4b4c0000000000000000000000000000000000000000" + val memo = Memo.returnHash(hashHex) + memo.toXdr().discriminant shouldBe MemoType.MEMO_RETURN + memo.hexValue shouldBe hashHex.lowercase() + memo.toString() shouldBe hashHex.lowercase() + } + + test("should create return hash memo from uppercase hex string") { + val hashHex = "4142434445464748494a4b4c0000000000000000000000000000000000000000" + val memo = Memo.returnHash(hashHex.uppercase()) + memo.toXdr().discriminant shouldBe MemoType.MEMO_RETURN + memo.hexValue shouldBe hashHex.lowercase() + memo.toString() shouldBe hashHex.lowercase() + } + + test("should throw exception when bytes are not 32-bytes long") { + val bytes31 = ByteArray(31) + val exception31 = shouldThrow { Memo.returnHash(bytes31) } + exception31.message shouldBe "bytes must be 32-bytes long." + + val bytes33 = ByteArray(33) + val exception33 = shouldThrow { Memo.returnHash(bytes33) } + exception33.message shouldBe "bytes must be 32-bytes long." + } + + test("should throw exception when hex string is invalid") { + shouldThrow { Memo.returnHash("test") } + shouldThrow { Memo.returnHash("") } + shouldThrow { + Memo.returnHash("00000000000000000000000000000000000000000000000000000000000000") + } // 63 chars + } + } + })