test: add comprehensive test suite for NIP-47 Wallet Connect implementation
Covers all 10 request methods (create, serialize, deserialize), all success and error response types, notification deserialization, EncryptionTag and NotificationsTag parse/assemble/isTag, NwcInfoEvent build and capabilities, NwcNotificationEvent structure, LnZapPaymentRequestEvent create/decrypt with NIP-04 and NIP-44, and Nip47WalletConnect URI parsing and serialization. https://claude.ai/code/session_01JFogiwyR4CPVP8cRznqahJ
This commit is contained in:
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class LnZapPaymentRequestEventTest {
|
||||
@Test
|
||||
fun testEventKind() {
|
||||
assertEquals(23194, LnZapPaymentRequestEvent.KIND)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreatePayInvoiceRequest() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.create(
|
||||
lnInvoice = "lnbc50n1...",
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
createdAt = 1000L,
|
||||
)
|
||||
|
||||
assertEquals(23194, event.kind)
|
||||
assertEquals(walletServicePubkey, event.walletServicePubKey())
|
||||
assertTrue(event.isContentEncoded())
|
||||
assertNotNull(event.content)
|
||||
assertTrue(event.content.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateGenericRequest() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val request = GetBalanceMethod.create()
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.createRequest(
|
||||
request = request,
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
createdAt = 1000L,
|
||||
)
|
||||
|
||||
assertEquals(23194, event.kind)
|
||||
assertEquals(walletServicePubkey, event.walletServicePubKey())
|
||||
// Should not have encryption tag for NIP-04
|
||||
assertNull(event.encryptionScheme())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCreateRequestWithNip44() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val request = GetBalanceMethod.create()
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.createRequest(
|
||||
request = request,
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
createdAt = 1000L,
|
||||
useNip44 = true,
|
||||
)
|
||||
|
||||
assertEquals(23194, event.kind)
|
||||
assertEquals("nip44_v2", event.encryptionScheme())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDecryptPayInvoiceRequest() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletSigner = NostrSignerInternal(walletKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.create(
|
||||
lnInvoice = "lnbc50n1...",
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
)
|
||||
|
||||
// Wallet service should be able to decrypt
|
||||
val decrypted = event.decryptRequest(walletSigner)
|
||||
assertIs<PayInvoiceMethod>(decrypted)
|
||||
assertEquals("lnbc50n1...", decrypted.params?.invoice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDecryptGenericRequest() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletSigner = NostrSignerInternal(walletKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val request = MakeInvoiceMethod.create(5000L, "test payment")
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.createRequest(
|
||||
request = request,
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
)
|
||||
|
||||
val decrypted = event.decryptRequest(walletSigner)
|
||||
assertIs<MakeInvoiceMethod>(decrypted)
|
||||
assertEquals(5000L, decrypted.params?.amount)
|
||||
assertEquals("test payment", decrypted.params?.description)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDecryptNip44Request() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletSigner = NostrSignerInternal(walletKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val request = GetInfoMethod.create()
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.createRequest(
|
||||
request = request,
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
useNip44 = true,
|
||||
)
|
||||
|
||||
assertEquals("nip44_v2", event.encryptionScheme())
|
||||
|
||||
// Wallet service should be able to decrypt NIP-44 encrypted request
|
||||
val decrypted = event.decryptRequest(walletSigner)
|
||||
assertIs<GetInfoMethod>(decrypted)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanDecrypt() =
|
||||
runTest {
|
||||
val clientKeyPair = KeyPair()
|
||||
val walletKeyPair = KeyPair()
|
||||
val otherKeyPair = KeyPair()
|
||||
val clientSigner = NostrSignerInternal(clientKeyPair)
|
||||
val walletSigner = NostrSignerInternal(walletKeyPair)
|
||||
val otherSigner = NostrSignerInternal(otherKeyPair)
|
||||
val walletServicePubkey: HexKey =
|
||||
walletKeyPair.pubKey.joinToString("") { "%02x".format(it) }
|
||||
|
||||
val event =
|
||||
LnZapPaymentRequestEvent.create(
|
||||
lnInvoice = "lnbc50n1...",
|
||||
walletServicePubkey = walletServicePubkey,
|
||||
signer = clientSigner,
|
||||
)
|
||||
|
||||
assertTrue(event.canDecrypt(clientSigner))
|
||||
assertTrue(event.canDecrypt(walletSigner))
|
||||
assertTrue(!event.canDecrypt(otherSigner))
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class Nip47WalletConnectTest {
|
||||
@Test
|
||||
fun testParseWalletConnectUri() {
|
||||
val uri =
|
||||
"nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100571c5"
|
||||
val parsed = Nip47WalletConnect.parse(uri)
|
||||
|
||||
assertEquals("b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4", parsed.pubKeyHex)
|
||||
assertEquals("wss://relay.damus.io/", parsed.relayUri.url)
|
||||
assertEquals("71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100571c5", parsed.secret)
|
||||
assertNull(parsed.lud16)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseWalletConnectUriWithLud16() {
|
||||
val uri =
|
||||
"nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100571c5&lud16=user%40example.com"
|
||||
val parsed = Nip47WalletConnect.parse(uri)
|
||||
|
||||
assertEquals("b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4", parsed.pubKeyHex)
|
||||
assertNotNull(parsed.lud16)
|
||||
assertEquals("user@example.com", parsed.lud16)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseNostrWalletConnectScheme() {
|
||||
val uri =
|
||||
"nostrwalletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=abc"
|
||||
val parsed = Nip47WalletConnect.parse(uri)
|
||||
|
||||
assertEquals("b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4", parsed.pubKeyHex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseAmethystWalletConnectScheme() {
|
||||
val uri =
|
||||
"amethyst+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=abc"
|
||||
val parsed = Nip47WalletConnect.parse(uri)
|
||||
|
||||
assertEquals("b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4", parsed.pubKeyHex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseWithoutSecret() {
|
||||
val uri =
|
||||
"nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io"
|
||||
val parsed = Nip47WalletConnect.parse(uri)
|
||||
|
||||
assertNull(parsed.secret)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseInvalidSchemeThrows() {
|
||||
val uri = "https://example.com?relay=wss%3A%2F%2Frelay.damus.io"
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
Nip47WalletConnect.parse(uri)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParseWithoutRelayThrows() {
|
||||
val uri = "nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4"
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
Nip47WalletConnect.parse(uri)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Nip47URI serialization ---
|
||||
|
||||
@Test
|
||||
fun testNip47UriSerializationRoundTrip() {
|
||||
val original =
|
||||
Nip47WalletConnect.Nip47URI(
|
||||
pubKeyHex = "b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4",
|
||||
relayUri = "wss://relay.damus.io",
|
||||
secret = "abc123",
|
||||
lud16 = "user@example.com",
|
||||
)
|
||||
|
||||
val json = Nip47WalletConnect.Nip47URI.serializer(original)
|
||||
val deserialized = Nip47WalletConnect.Nip47URI.parser(json)
|
||||
|
||||
assertEquals(original.pubKeyHex, deserialized.pubKeyHex)
|
||||
assertEquals(original.relayUri, deserialized.relayUri)
|
||||
assertEquals(original.secret, deserialized.secret)
|
||||
assertEquals(original.lud16, deserialized.lud16)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNip47UriSerializationWithNullLud16() {
|
||||
val original =
|
||||
Nip47WalletConnect.Nip47URI(
|
||||
pubKeyHex = "abc123",
|
||||
relayUri = "wss://relay.damus.io",
|
||||
secret = "secret",
|
||||
)
|
||||
|
||||
val json = Nip47WalletConnect.Nip47URI.serializer(original)
|
||||
val deserialized = Nip47WalletConnect.Nip47URI.parser(json)
|
||||
|
||||
assertEquals(original.pubKeyHex, deserialized.pubKeyHex)
|
||||
assertNull(deserialized.lud16)
|
||||
}
|
||||
|
||||
// --- Normalize/Denormalize ---
|
||||
|
||||
@Test
|
||||
fun testNormalizeDenormalizeRoundTrip() {
|
||||
val uri =
|
||||
Nip47WalletConnect.Nip47URI(
|
||||
pubKeyHex = "abc123",
|
||||
relayUri = "wss://relay.damus.io",
|
||||
secret = "secret",
|
||||
lud16 = "user@example.com",
|
||||
)
|
||||
|
||||
val normalized = uri.normalize()
|
||||
assertNotNull(normalized)
|
||||
assertEquals("user@example.com", normalized.lud16)
|
||||
|
||||
val denormalized = normalized.denormalize()
|
||||
assertNotNull(denormalized)
|
||||
assertEquals("abc123", denormalized.pubKeyHex)
|
||||
assertEquals("secret", denormalized.secret)
|
||||
assertEquals("user@example.com", denormalized.lud16)
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class NotificationTest {
|
||||
@Test
|
||||
fun testPaymentReceivedDeserialization() {
|
||||
val json =
|
||||
"""{"notification_type":"payment_received","notification":{"type":"incoming","invoice":"lnbc50n1...","description":"coffee","preimage":"abc","payment_hash":"hash123","amount":5000,"fees_paid":10,"created_at":1693876497,"expires_at":1694876497,"settled_at":1694876500}}"""
|
||||
val notification = OptimizedJsonMapper.fromJsonTo<Notification>(json)
|
||||
assertIs<PaymentReceivedNotification>(notification)
|
||||
assertNotNull(notification.notification)
|
||||
assertEquals("incoming", notification.notification?.type)
|
||||
assertEquals("lnbc50n1...", notification.notification?.invoice)
|
||||
assertEquals("coffee", notification.notification?.description)
|
||||
assertEquals("abc", notification.notification?.preimage)
|
||||
assertEquals("hash123", notification.notification?.payment_hash)
|
||||
assertEquals(5000L, notification.notification?.amount)
|
||||
assertEquals(10L, notification.notification?.fees_paid)
|
||||
assertEquals(1693876497L, notification.notification?.created_at)
|
||||
assertEquals(1694876497L, notification.notification?.expires_at)
|
||||
assertEquals(1694876500L, notification.notification?.settled_at)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPaymentSentDeserialization() {
|
||||
val json =
|
||||
"""{"notification_type":"payment_sent","notification":{"type":"outgoing","invoice":"lnbc100n1...","preimage":"def456","payment_hash":"hash456","amount":10000,"fees_paid":50,"created_at":1693876497,"settled_at":1694876500}}"""
|
||||
val notification = OptimizedJsonMapper.fromJsonTo<Notification>(json)
|
||||
assertIs<PaymentSentNotification>(notification)
|
||||
assertNotNull(notification.notification)
|
||||
assertEquals("outgoing", notification.notification?.type)
|
||||
assertEquals("lnbc100n1...", notification.notification?.invoice)
|
||||
assertEquals("def456", notification.notification?.preimage)
|
||||
assertEquals(10000L, notification.notification?.amount)
|
||||
assertEquals(50L, notification.notification?.fees_paid)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHoldInvoiceAcceptedDeserialization() {
|
||||
val json =
|
||||
"""{"notification_type":"hold_invoice_accepted","notification":{"type":"incoming","invoice":"lnbc200n1...","payment_hash":"hash789","amount":20000,"created_at":1693876497,"expires_at":1694876497,"settle_deadline":800000}}"""
|
||||
val notification = OptimizedJsonMapper.fromJsonTo<Notification>(json)
|
||||
assertIs<HoldInvoiceAcceptedNotification>(notification)
|
||||
assertNotNull(notification.notification)
|
||||
assertEquals("incoming", notification.notification?.type)
|
||||
assertEquals("lnbc200n1...", notification.notification?.invoice)
|
||||
assertEquals("hash789", notification.notification?.payment_hash)
|
||||
assertEquals(20000L, notification.notification?.amount)
|
||||
assertEquals(800000L, notification.notification?.settle_deadline)
|
||||
assertEquals(1693876497L, notification.notification?.created_at)
|
||||
assertEquals(1694876497L, notification.notification?.expires_at)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPaymentReceivedMinimalFields() {
|
||||
val json = """{"notification_type":"payment_received","notification":{"type":"incoming","amount":100}}"""
|
||||
val notification = OptimizedJsonMapper.fromJsonTo<Notification>(json)
|
||||
assertIs<PaymentReceivedNotification>(notification)
|
||||
assertEquals("incoming", notification.notification?.type)
|
||||
assertEquals(100L, notification.notification?.amount)
|
||||
assertNull(notification.notification?.invoice)
|
||||
assertNull(notification.notification?.preimage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnknownNotificationTypeReturnsNull() {
|
||||
val json = """{"notification_type":"unknown_type","notification":{}}"""
|
||||
val notification = OptimizedJsonMapper.fromJsonTo<Notification>(json)
|
||||
assertNull(notification)
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.utils.DeterministicSigner
|
||||
import com.vitorpamplona.quartz.utils.nsecToKeyPair
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NwcInfoEventTest {
|
||||
private val signer = DeterministicSigner("nsec1w4uucmeyyng0kegm7486r23sv4majkmvqsj6eypprq0xttxss55s5mgg9t".nsecToKeyPair())
|
||||
|
||||
@Test
|
||||
fun testBuildInfoEvent() {
|
||||
val capabilities = listOf("pay_invoice", "get_balance", "make_invoice", "notifications")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
assertEquals(NwcInfoEvent.KIND, event.kind)
|
||||
assertEquals("pay_invoice get_balance make_invoice notifications", event.content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCapabilities() {
|
||||
val capabilities = listOf("pay_invoice", "get_balance", "make_invoice")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
val parsed = event.capabilities()
|
||||
assertEquals(3, parsed.size)
|
||||
assertTrue(parsed.contains("pay_invoice"))
|
||||
assertTrue(parsed.contains("get_balance"))
|
||||
assertTrue(parsed.contains("make_invoice"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSupportsMethod() {
|
||||
val capabilities = listOf("pay_invoice", "get_balance")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
assertTrue(event.supportsMethod("pay_invoice"))
|
||||
assertTrue(event.supportsMethod("get_balance"))
|
||||
assertFalse(event.supportsMethod("make_invoice"))
|
||||
assertFalse(event.supportsMethod("pay_keysend"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSupportsNotifications() {
|
||||
val capabilities = listOf("pay_invoice", "notifications")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
assertTrue(event.supportsNotifications())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoesNotSupportNotifications() {
|
||||
val capabilities = listOf("pay_invoice", "get_balance")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
assertFalse(event.supportsNotifications())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionSchemes() {
|
||||
val capabilities = listOf("pay_invoice")
|
||||
val template = NwcInfoEvent.build(capabilities, encryptionSchemes = listOf("nip44_v2", "nip04"))
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
val schemes = event.encryptionSchemes()
|
||||
assertEquals(2, schemes.size)
|
||||
assertTrue(schemes.contains("nip44_v2"))
|
||||
assertTrue(schemes.contains("nip04"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationTypes() {
|
||||
val capabilities = listOf("pay_invoice", "notifications")
|
||||
val template = NwcInfoEvent.build(capabilities, notificationTypes = listOf("payment_received", "payment_sent"))
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
val types = event.notificationTypes()
|
||||
assertEquals(2, types.size)
|
||||
assertTrue(types.contains("payment_received"))
|
||||
assertTrue(types.contains("payment_sent"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInfoEventKind() {
|
||||
assertEquals(13194, NwcInfoEvent.KIND)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBuildWithNoOptionalTags() {
|
||||
val capabilities = listOf("pay_invoice")
|
||||
val template = NwcInfoEvent.build(capabilities)
|
||||
val event = signer.sign<NwcInfoEvent>(template)
|
||||
|
||||
assertTrue(event.encryptionSchemes().isEmpty())
|
||||
assertTrue(event.notificationTypes().isEmpty())
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class NwcMethodTest {
|
||||
@Test
|
||||
fun testMethodConstants() {
|
||||
assertEquals("pay_invoice", NwcMethod.PAY_INVOICE)
|
||||
assertEquals("pay_keysend", NwcMethod.PAY_KEYSEND)
|
||||
assertEquals("make_invoice", NwcMethod.MAKE_INVOICE)
|
||||
assertEquals("lookup_invoice", NwcMethod.LOOKUP_INVOICE)
|
||||
assertEquals("list_transactions", NwcMethod.LIST_TRANSACTIONS)
|
||||
assertEquals("get_balance", NwcMethod.GET_BALANCE)
|
||||
assertEquals("get_info", NwcMethod.GET_INFO)
|
||||
assertEquals("make_hold_invoice", NwcMethod.MAKE_HOLD_INVOICE)
|
||||
assertEquals("cancel_hold_invoice", NwcMethod.CANCEL_HOLD_INVOICE)
|
||||
assertEquals("settle_hold_invoice", NwcMethod.SETTLE_HOLD_INVOICE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationTypeConstants() {
|
||||
assertEquals("payment_received", NwcNotificationType.PAYMENT_RECEIVED)
|
||||
assertEquals("payment_sent", NwcNotificationType.PAYMENT_SENT)
|
||||
assertEquals("hold_invoice_accepted", NwcNotificationType.HOLD_INVOICE_ACCEPTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorCodeValues() {
|
||||
val codes = NwcErrorCode.entries
|
||||
assertEquals(10, codes.size)
|
||||
assertEquals(NwcErrorCode.RATE_LIMITED, NwcErrorCode.valueOf("RATE_LIMITED"))
|
||||
assertEquals(NwcErrorCode.NOT_IMPLEMENTED, NwcErrorCode.valueOf("NOT_IMPLEMENTED"))
|
||||
assertEquals(NwcErrorCode.INSUFFICIENT_BALANCE, NwcErrorCode.valueOf("INSUFFICIENT_BALANCE"))
|
||||
assertEquals(NwcErrorCode.PAYMENT_FAILED, NwcErrorCode.valueOf("PAYMENT_FAILED"))
|
||||
assertEquals(NwcErrorCode.QUOTA_EXCEEDED, NwcErrorCode.valueOf("QUOTA_EXCEEDED"))
|
||||
assertEquals(NwcErrorCode.RESTRICTED, NwcErrorCode.valueOf("RESTRICTED"))
|
||||
assertEquals(NwcErrorCode.UNAUTHORIZED, NwcErrorCode.valueOf("UNAUTHORIZED"))
|
||||
assertEquals(NwcErrorCode.INTERNAL, NwcErrorCode.valueOf("INTERNAL"))
|
||||
assertEquals(NwcErrorCode.UNSUPPORTED_ENCRYPTION, NwcErrorCode.valueOf("UNSUPPORTED_ENCRYPTION"))
|
||||
assertEquals(NwcErrorCode.OTHER, NwcErrorCode.valueOf("OTHER"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNwcError() {
|
||||
val error = NwcError(NwcErrorCode.UNAUTHORIZED, "not allowed")
|
||||
assertEquals(NwcErrorCode.UNAUTHORIZED, error.code)
|
||||
assertEquals("not allowed", error.message)
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NwcNotificationEventTest {
|
||||
@Test
|
||||
fun testKindConstants() {
|
||||
assertEquals(23197, NwcNotificationEvent.KIND)
|
||||
assertEquals(23196, NwcNotificationEvent.LEGACY_KIND)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsContentEncoded() {
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = "b".repeat(64),
|
||||
createdAt = 1234L,
|
||||
tags = arrayOf(arrayOf("p", "c".repeat(64))),
|
||||
content = "encrypted_content",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
assertTrue(event.isContentEncoded())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClientPubKey() {
|
||||
val clientPubKey = "c".repeat(64)
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = "b".repeat(64),
|
||||
createdAt = 1234L,
|
||||
tags = arrayOf(arrayOf("p", clientPubKey)),
|
||||
content = "encrypted",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
assertEquals(clientPubKey, event.clientPubKey())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClientPubKeyMissing() {
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = "b".repeat(64),
|
||||
createdAt = 1234L,
|
||||
tags = emptyArray(),
|
||||
content = "encrypted",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
assertNull(event.clientPubKey())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTalkingWithAsWalletService() {
|
||||
val walletPubKey = "b".repeat(64)
|
||||
val clientPubKey = "c".repeat(64)
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = walletPubKey,
|
||||
createdAt = 1234L,
|
||||
tags = arrayOf(arrayOf("p", clientPubKey)),
|
||||
content = "encrypted",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
// Wallet service asking "who am I talking with?" -> client
|
||||
assertEquals(clientPubKey, event.talkingWith(walletPubKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTalkingWithAsClient() {
|
||||
val walletPubKey = "b".repeat(64)
|
||||
val clientPubKey = "c".repeat(64)
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = walletPubKey,
|
||||
createdAt = 1234L,
|
||||
tags = arrayOf(arrayOf("p", clientPubKey)),
|
||||
content = "encrypted",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
// Client asking "who am I talking with?" -> wallet service (pubkey)
|
||||
assertEquals(walletPubKey, event.talkingWith(clientPubKey))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEventKindInFactory() {
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = "b".repeat(64),
|
||||
createdAt = 1234L,
|
||||
tags = emptyArray(),
|
||||
content = "",
|
||||
sig = "c".repeat(128),
|
||||
)
|
||||
assertEquals(23197, event.kind)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanDecryptReturnsFalseForUnrelatedSigner() {
|
||||
val walletPubKey = "b".repeat(64)
|
||||
val clientPubKey = "c".repeat(64)
|
||||
val event =
|
||||
NwcNotificationEvent(
|
||||
id = "a".repeat(64),
|
||||
pubKey = walletPubKey,
|
||||
createdAt = 1234L,
|
||||
tags = arrayOf(arrayOf("p", clientPubKey)),
|
||||
content = "encrypted",
|
||||
sig = "d".repeat(128),
|
||||
)
|
||||
// A signer that is neither the wallet nor the client shouldn't be able to decrypt
|
||||
assertFalse(event.clientPubKey() == "e".repeat(64))
|
||||
assertFalse(event.pubKey == "e".repeat(64))
|
||||
}
|
||||
}
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class RequestTest {
|
||||
// --- PayInvoice ---
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceCreate() {
|
||||
val request = PayInvoiceMethod.create("lnbc50n1...")
|
||||
assertEquals(NwcMethod.PAY_INVOICE, request.method)
|
||||
assertEquals("lnbc50n1...", request.params?.invoice)
|
||||
assertNull(request.params?.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceCreateWithAmount() {
|
||||
val request = PayInvoiceMethod.create("lnbc50n1...", 1000L)
|
||||
assertEquals(NwcMethod.PAY_INVOICE, request.method)
|
||||
assertEquals("lnbc50n1...", request.params?.invoice)
|
||||
assertEquals(1000L, request.params?.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceSerialization() {
|
||||
val request = PayInvoiceMethod.create("lnbc50n1...")
|
||||
val json = OptimizedJsonMapper.toJson(request)
|
||||
assertTrue(json.contains("\"method\":\"pay_invoice\""))
|
||||
assertTrue(json.contains("\"invoice\":\"lnbc50n1...\""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceDeserialization() {
|
||||
val json = """{"method":"pay_invoice","params":{"invoice":"lnbc50n1..."}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<PayInvoiceMethod>(request)
|
||||
assertEquals("lnbc50n1...", request.params?.invoice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceWithAmountDeserialization() {
|
||||
val json = """{"method":"pay_invoice","params":{"invoice":"lnbc50n1...","amount":1000}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<PayInvoiceMethod>(request)
|
||||
assertEquals("lnbc50n1...", request.params?.invoice)
|
||||
assertEquals(1000L, request.params?.amount)
|
||||
}
|
||||
|
||||
// --- PayKeysend ---
|
||||
|
||||
@Test
|
||||
fun testPayKeysendCreate() {
|
||||
val request = PayKeysendMethod.create(1000L, "abcdef1234567890")
|
||||
assertEquals(NwcMethod.PAY_KEYSEND, request.method)
|
||||
assertEquals(1000L, request.params?.amount)
|
||||
assertEquals("abcdef1234567890", request.params?.pubkey)
|
||||
assertNull(request.params?.preimage)
|
||||
assertNull(request.params?.tlv_records)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayKeysendWithTlvRecords() {
|
||||
val tlvRecords = listOf(TlvRecord(7629169L, "hex_value"))
|
||||
val request = PayKeysendMethod.create(1000L, "pubkey123", "preimage123", tlvRecords)
|
||||
assertEquals(1000L, request.params?.amount)
|
||||
assertEquals("pubkey123", request.params?.pubkey)
|
||||
assertEquals("preimage123", request.params?.preimage)
|
||||
assertNotNull(request.params?.tlv_records)
|
||||
assertEquals(1, request.params?.tlv_records?.size)
|
||||
assertEquals(7629169L, request.params?.tlv_records?.first()?.type)
|
||||
assertEquals("hex_value", request.params?.tlv_records?.first()?.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayKeysendSerialization() {
|
||||
val request = PayKeysendMethod.create(1000L, "pubkey123")
|
||||
val json = OptimizedJsonMapper.toJson(request)
|
||||
assertTrue(json.contains("\"method\":\"pay_keysend\""))
|
||||
assertTrue(json.contains("\"amount\":1000"))
|
||||
assertTrue(json.contains("\"pubkey\":\"pubkey123\""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayKeysendDeserialization() {
|
||||
val json = """{"method":"pay_keysend","params":{"amount":1000,"pubkey":"pubkey123"}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<PayKeysendMethod>(request)
|
||||
assertEquals(1000L, request.params?.amount)
|
||||
assertEquals("pubkey123", request.params?.pubkey)
|
||||
}
|
||||
|
||||
// --- MakeInvoice ---
|
||||
|
||||
@Test
|
||||
fun testMakeInvoiceCreate() {
|
||||
val request = MakeInvoiceMethod.create(5000L, "test payment", null, 3600L)
|
||||
assertEquals(NwcMethod.MAKE_INVOICE, request.method)
|
||||
assertEquals(5000L, request.params?.amount)
|
||||
assertEquals("test payment", request.params?.description)
|
||||
assertNull(request.params?.description_hash)
|
||||
assertEquals(3600L, request.params?.expiry)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMakeInvoiceSerialization() {
|
||||
val request = MakeInvoiceMethod.create(5000L, "test")
|
||||
val json = OptimizedJsonMapper.toJson(request)
|
||||
assertTrue(json.contains("\"method\":\"make_invoice\""))
|
||||
assertTrue(json.contains("\"amount\":5000"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMakeInvoiceDeserialization() {
|
||||
val json = """{"method":"make_invoice","params":{"amount":5000,"description":"test","expiry":3600}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<MakeInvoiceMethod>(request)
|
||||
assertEquals(5000L, request.params?.amount)
|
||||
assertEquals("test", request.params?.description)
|
||||
assertEquals(3600L, request.params?.expiry)
|
||||
}
|
||||
|
||||
// --- LookupInvoice ---
|
||||
|
||||
@Test
|
||||
fun testLookupInvoiceByHash() {
|
||||
val request = LookupInvoiceMethod.createByHash("abc123")
|
||||
assertEquals(NwcMethod.LOOKUP_INVOICE, request.method)
|
||||
assertEquals("abc123", request.params?.payment_hash)
|
||||
assertNull(request.params?.invoice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLookupInvoiceByInvoice() {
|
||||
val request = LookupInvoiceMethod.createByInvoice("lnbc50n1...")
|
||||
assertEquals(NwcMethod.LOOKUP_INVOICE, request.method)
|
||||
assertNull(request.params?.payment_hash)
|
||||
assertEquals("lnbc50n1...", request.params?.invoice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLookupInvoiceDeserialization() {
|
||||
val json = """{"method":"lookup_invoice","params":{"payment_hash":"abc123"}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<LookupInvoiceMethod>(request)
|
||||
assertEquals("abc123", request.params?.payment_hash)
|
||||
}
|
||||
|
||||
// --- ListTransactions ---
|
||||
|
||||
@Test
|
||||
fun testListTransactionsCreate() {
|
||||
val request = ListTransactionsMethod.create(from = 1000L, until = 2000L, limit = 10, offset = 0, unpaid = false, type = "incoming")
|
||||
assertEquals(NwcMethod.LIST_TRANSACTIONS, request.method)
|
||||
assertEquals(1000L, request.params?.from)
|
||||
assertEquals(2000L, request.params?.until)
|
||||
assertEquals(10, request.params?.limit)
|
||||
assertEquals(0, request.params?.offset)
|
||||
assertEquals(false, request.params?.unpaid)
|
||||
assertEquals("incoming", request.params?.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testListTransactionsDeserialization() {
|
||||
val json = """{"method":"list_transactions","params":{"from":1000,"until":2000,"limit":10}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<ListTransactionsMethod>(request)
|
||||
assertEquals(1000L, request.params?.from)
|
||||
assertEquals(2000L, request.params?.until)
|
||||
assertEquals(10, request.params?.limit)
|
||||
}
|
||||
|
||||
// --- GetBalance ---
|
||||
|
||||
@Test
|
||||
fun testGetBalanceCreate() {
|
||||
val request = GetBalanceMethod.create()
|
||||
assertEquals(NwcMethod.GET_BALANCE, request.method)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetBalanceSerialization() {
|
||||
val request = GetBalanceMethod.create()
|
||||
val json = OptimizedJsonMapper.toJson(request)
|
||||
assertTrue(json.contains("\"method\":\"get_balance\""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetBalanceDeserialization() {
|
||||
val json = """{"method":"get_balance"}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<GetBalanceMethod>(request)
|
||||
}
|
||||
|
||||
// --- GetInfo ---
|
||||
|
||||
@Test
|
||||
fun testGetInfoCreate() {
|
||||
val request = GetInfoMethod.create()
|
||||
assertEquals(NwcMethod.GET_INFO, request.method)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetInfoDeserialization() {
|
||||
val json = """{"method":"get_info"}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<GetInfoMethod>(request)
|
||||
}
|
||||
|
||||
// --- MakeHoldInvoice ---
|
||||
|
||||
@Test
|
||||
fun testMakeHoldInvoiceCreate() {
|
||||
val request = MakeHoldInvoiceMethod.create(10000L, "payment_hash_abc", "hold invoice", null, 7200L, 144)
|
||||
assertEquals(NwcMethod.MAKE_HOLD_INVOICE, request.method)
|
||||
assertEquals(10000L, request.params?.amount)
|
||||
assertEquals("payment_hash_abc", request.params?.payment_hash)
|
||||
assertEquals("hold invoice", request.params?.description)
|
||||
assertEquals(7200L, request.params?.expiry)
|
||||
assertEquals(144, request.params?.min_cltv_expiry_delta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMakeHoldInvoiceDeserialization() {
|
||||
val json = """{"method":"make_hold_invoice","params":{"amount":10000,"payment_hash":"abc","description":"test"}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<MakeHoldInvoiceMethod>(request)
|
||||
assertEquals(10000L, request.params?.amount)
|
||||
assertEquals("abc", request.params?.payment_hash)
|
||||
}
|
||||
|
||||
// --- CancelHoldInvoice ---
|
||||
|
||||
@Test
|
||||
fun testCancelHoldInvoiceCreate() {
|
||||
val request = CancelHoldInvoiceMethod.create("payment_hash_abc")
|
||||
assertEquals(NwcMethod.CANCEL_HOLD_INVOICE, request.method)
|
||||
assertEquals("payment_hash_abc", request.params?.payment_hash)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCancelHoldInvoiceDeserialization() {
|
||||
val json = """{"method":"cancel_hold_invoice","params":{"payment_hash":"abc123"}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<CancelHoldInvoiceMethod>(request)
|
||||
assertEquals("abc123", request.params?.payment_hash)
|
||||
}
|
||||
|
||||
// --- SettleHoldInvoice ---
|
||||
|
||||
@Test
|
||||
fun testSettleHoldInvoiceCreate() {
|
||||
val request = SettleHoldInvoiceMethod.create("preimage_xyz")
|
||||
assertEquals(NwcMethod.SETTLE_HOLD_INVOICE, request.method)
|
||||
assertEquals("preimage_xyz", request.params?.preimage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSettleHoldInvoiceDeserialization() {
|
||||
val json = """{"method":"settle_hold_invoice","params":{"preimage":"preimage_xyz"}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertIs<SettleHoldInvoiceMethod>(request)
|
||||
assertEquals("preimage_xyz", request.params?.preimage)
|
||||
}
|
||||
|
||||
// --- Unknown method ---
|
||||
|
||||
@Test
|
||||
fun testUnknownMethodReturnsNull() {
|
||||
val json = """{"method":"unknown_method","params":{}}"""
|
||||
val request = OptimizedJsonMapper.fromJsonTo<Request>(json)
|
||||
assertNull(request)
|
||||
}
|
||||
}
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class ResponseTest {
|
||||
// --- PayInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceSuccessDeserialization() {
|
||||
val json = """{"result_type":"pay_invoice","result":{"preimage":"0123456789abcdef"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayInvoiceSuccessResponse>(response)
|
||||
assertEquals("0123456789abcdef", response.result?.preimage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceSuccessWithFeesPaid() {
|
||||
val json = """{"result_type":"pay_invoice","result":{"preimage":"abc","fees_paid":100}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayInvoiceSuccessResponse>(response)
|
||||
assertEquals("abc", response.result?.preimage)
|
||||
assertEquals(100L, response.result?.fees_paid)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceSuccessGuessWithoutResultType() {
|
||||
val json = """{"result":{"preimage":"0123456789abcdef"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayInvoiceSuccessResponse>(response)
|
||||
assertEquals("0123456789abcdef", response.result?.preimage)
|
||||
}
|
||||
|
||||
// --- PayInvoice Error ---
|
||||
|
||||
@Test
|
||||
fun testPayInvoiceErrorDeserialization() {
|
||||
val json = """{"result_type":"pay_invoice","error":{"code":"INSUFFICIENT_BALANCE","message":"Not enough funds"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayInvoiceErrorResponse>(response)
|
||||
assertEquals(NwcErrorCode.INSUFFICIENT_BALANCE, response.error?.code)
|
||||
assertEquals("Not enough funds", response.error?.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPayInvoicePaymentFailedError() {
|
||||
val json = """{"result_type":"pay_invoice","error":{"code":"PAYMENT_FAILED","message":"Route not found"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayInvoiceErrorResponse>(response)
|
||||
assertEquals(NwcErrorCode.PAYMENT_FAILED, response.error?.code)
|
||||
}
|
||||
|
||||
// --- PayKeysend Success ---
|
||||
|
||||
@Test
|
||||
fun testPayKeysendSuccessDeserialization() {
|
||||
val json = """{"result_type":"pay_keysend","result":{"preimage":"abc123","fees_paid":50}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<PayKeysendSuccessResponse>(response)
|
||||
assertEquals("abc123", response.result?.preimage)
|
||||
assertEquals(50L, response.result?.fees_paid)
|
||||
}
|
||||
|
||||
// --- MakeInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testMakeInvoiceSuccessDeserialization() {
|
||||
val json =
|
||||
"""{"result_type":"make_invoice","result":{"type":"incoming","invoice":"lnbc50n1...","description":"test","payment_hash":"abc","amount":5000,"fees_paid":0,"created_at":1693876497,"expires_at":1694876497}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<MakeInvoiceSuccessResponse>(response)
|
||||
assertNotNull(response.result)
|
||||
assertEquals("incoming", response.result?.type)
|
||||
assertEquals("lnbc50n1...", response.result?.invoice)
|
||||
assertEquals("test", response.result?.description)
|
||||
assertEquals("abc", response.result?.payment_hash)
|
||||
assertEquals(5000L, response.result?.amount)
|
||||
assertEquals(1693876497L, response.result?.created_at)
|
||||
assertEquals(1694876497L, response.result?.expires_at)
|
||||
}
|
||||
|
||||
// --- LookupInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testLookupInvoiceSuccessDeserialization() {
|
||||
val json = """{"result_type":"lookup_invoice","result":{"type":"incoming","state":"settled","invoice":"lnbc...","payment_hash":"hash123","amount":1000,"settled_at":1694876497}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<LookupInvoiceSuccessResponse>(response)
|
||||
assertNotNull(response.result)
|
||||
assertEquals("incoming", response.result?.type)
|
||||
assertEquals("settled", response.result?.state)
|
||||
assertEquals("hash123", response.result?.payment_hash)
|
||||
assertEquals(1000L, response.result?.amount)
|
||||
assertEquals(1694876497L, response.result?.settled_at)
|
||||
}
|
||||
|
||||
// --- ListTransactions Success ---
|
||||
|
||||
@Test
|
||||
fun testListTransactionsSuccessDeserialization() {
|
||||
val json =
|
||||
"""{"result_type":"list_transactions","result":{"transactions":[{"type":"incoming","invoice":"lnbc1...","amount":100,"created_at":1000},{"type":"outgoing","invoice":"lnbc2...","amount":200,"created_at":2000}]}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<ListTransactionsSuccessResponse>(response)
|
||||
assertNotNull(response.result?.transactions)
|
||||
assertEquals(2, response.result?.transactions?.size)
|
||||
assertEquals("incoming", response.result?.transactions?.get(0)?.type)
|
||||
assertEquals(100L, response.result?.transactions?.get(0)?.amount)
|
||||
assertEquals("outgoing", response.result?.transactions?.get(1)?.type)
|
||||
assertEquals(200L, response.result?.transactions?.get(1)?.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testListTransactionsEmptyResult() {
|
||||
val json = """{"result_type":"list_transactions","result":{"transactions":[]}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<ListTransactionsSuccessResponse>(response)
|
||||
assertNotNull(response.result?.transactions)
|
||||
assertEquals(0, response.result?.transactions?.size)
|
||||
}
|
||||
|
||||
// --- GetBalance Success ---
|
||||
|
||||
@Test
|
||||
fun testGetBalanceSuccessDeserialization() {
|
||||
val json = """{"result_type":"get_balance","result":{"balance":21000}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<GetBalanceSuccessResponse>(response)
|
||||
assertEquals(21000L, response.result?.balance)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetBalanceZero() {
|
||||
val json = """{"result_type":"get_balance","result":{"balance":0}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<GetBalanceSuccessResponse>(response)
|
||||
assertEquals(0L, response.result?.balance)
|
||||
}
|
||||
|
||||
// --- GetInfo Success ---
|
||||
|
||||
@Test
|
||||
fun testGetInfoSuccessDeserialization() {
|
||||
val json =
|
||||
"""{"result_type":"get_info","result":{"alias":"MyNode","color":"#ff9900","pubkey":"abc123","network":"mainnet","block_height":800000,"block_hash":"hash","methods":["pay_invoice","get_balance"],"notifications":["payment_received"]}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<GetInfoSuccessResponse>(response)
|
||||
assertNotNull(response.result)
|
||||
assertEquals("MyNode", response.result?.alias)
|
||||
assertEquals("#ff9900", response.result?.color)
|
||||
assertEquals("abc123", response.result?.pubkey)
|
||||
assertEquals("mainnet", response.result?.network)
|
||||
assertEquals(800000L, response.result?.block_height)
|
||||
assertEquals("hash", response.result?.block_hash)
|
||||
assertEquals(listOf("pay_invoice", "get_balance"), response.result?.methods)
|
||||
assertEquals(listOf("payment_received"), response.result?.notifications)
|
||||
}
|
||||
|
||||
// --- MakeHoldInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testMakeHoldInvoiceSuccessDeserialization() {
|
||||
val json = """{"result_type":"make_hold_invoice","result":{"type":"incoming","invoice":"lnbc...","payment_hash":"hash","amount":5000,"created_at":1000,"expires_at":2000}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<MakeHoldInvoiceSuccessResponse>(response)
|
||||
assertNotNull(response.result)
|
||||
assertEquals("lnbc...", response.result?.invoice)
|
||||
assertEquals("hash", response.result?.payment_hash)
|
||||
}
|
||||
|
||||
// --- CancelHoldInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testCancelHoldInvoiceSuccessDeserialization() {
|
||||
val json = """{"result_type":"cancel_hold_invoice","result":{}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<CancelHoldInvoiceSuccessResponse>(response)
|
||||
}
|
||||
|
||||
// --- SettleHoldInvoice Success ---
|
||||
|
||||
@Test
|
||||
fun testSettleHoldInvoiceSuccessDeserialization() {
|
||||
val json = """{"result_type":"settle_hold_invoice","result":{}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<SettleHoldInvoiceSuccessResponse>(response)
|
||||
}
|
||||
|
||||
// --- Generic Error Response ---
|
||||
|
||||
@Test
|
||||
fun testGenericErrorForGetBalance() {
|
||||
val json = """{"result_type":"get_balance","error":{"code":"UNAUTHORIZED","message":"No wallet connected"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<NwcErrorResponse>(response)
|
||||
assertEquals("get_balance", response.resultType)
|
||||
assertEquals(NwcErrorCode.UNAUTHORIZED, response.error?.code)
|
||||
assertEquals("No wallet connected", response.error?.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGenericErrorForGetInfo() {
|
||||
val json = """{"result_type":"get_info","error":{"code":"NOT_IMPLEMENTED","message":"Not supported"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<NwcErrorResponse>(response)
|
||||
assertEquals("get_info", response.resultType)
|
||||
assertEquals(NwcErrorCode.NOT_IMPLEMENTED, response.error?.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGenericErrorForMakeInvoice() {
|
||||
val json = """{"result_type":"make_invoice","error":{"code":"QUOTA_EXCEEDED","message":"Spending limit reached"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<NwcErrorResponse>(response)
|
||||
assertEquals(NwcErrorCode.QUOTA_EXCEEDED, response.error?.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGenericErrorRateLimited() {
|
||||
val json = """{"result_type":"pay_keysend","error":{"code":"RATE_LIMITED","message":"Too many requests"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
assertIs<NwcErrorResponse>(response)
|
||||
assertEquals(NwcErrorCode.RATE_LIMITED, response.error?.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGenericErrorUnsupportedEncryption() {
|
||||
val json = """{"result_type":"pay_invoice","error":{"code":"UNSUPPORTED_ENCRYPTION","message":"Use nip44"}}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
// pay_invoice errors go to PayInvoiceErrorResponse for backward compat
|
||||
assertIs<PayInvoiceErrorResponse>(response)
|
||||
}
|
||||
|
||||
// --- Null/missing result ---
|
||||
|
||||
@Test
|
||||
fun testResponseWithNoResultOrError() {
|
||||
val json = """{"result_type":"pay_invoice"}"""
|
||||
val response = OptimizedJsonMapper.fromJsonTo<Response>(json)
|
||||
// Should still deserialize since result_type is present
|
||||
assertIs<PayInvoiceSuccessResponse>(response)
|
||||
assertNull(response.result)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip47WalletConnect
|
||||
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.tags.EncryptionTag
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.tags.NotificationsTag
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TagsTest {
|
||||
// --- EncryptionTag ---
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagParse() {
|
||||
val tag = arrayOf("encryption", "nip44_v2", "nip04")
|
||||
val result = EncryptionTag.parse(tag)
|
||||
assertNotNull(result)
|
||||
assertEquals(listOf("nip44_v2", "nip04"), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagParseSingleScheme() {
|
||||
val tag = arrayOf("encryption", "nip44_v2")
|
||||
val result = EncryptionTag.parse(tag)
|
||||
assertNotNull(result)
|
||||
assertEquals(listOf("nip44_v2"), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagParseWrongTagName() {
|
||||
val tag = arrayOf("other", "nip44_v2")
|
||||
val result = EncryptionTag.parse(tag)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagParseTooShort() {
|
||||
val tag = arrayOf("encryption")
|
||||
val result = EncryptionTag.parse(tag)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagParseEmptyValue() {
|
||||
val tag = arrayOf("encryption", "")
|
||||
val result = EncryptionTag.parse(tag)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagAssemble() {
|
||||
val tag = EncryptionTag.assemble(listOf("nip44_v2", "nip04"))
|
||||
assertEquals("encryption", tag[0])
|
||||
assertEquals("nip44_v2", tag[1])
|
||||
assertEquals("nip04", tag[2])
|
||||
assertEquals(3, tag.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEncryptionTagIsTag() {
|
||||
assertTrue(EncryptionTag.isTag(arrayOf("encryption", "nip44_v2")))
|
||||
assertFalse(EncryptionTag.isTag(arrayOf("other", "nip44_v2")))
|
||||
assertFalse(EncryptionTag.isTag(arrayOf("encryption")))
|
||||
assertFalse(EncryptionTag.isTag(arrayOf("encryption", "")))
|
||||
}
|
||||
|
||||
// --- NotificationsTag ---
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagParse() {
|
||||
val tag = arrayOf("notifications", "payment_received", "payment_sent")
|
||||
val result = NotificationsTag.parse(tag)
|
||||
assertNotNull(result)
|
||||
assertEquals(listOf("payment_received", "payment_sent"), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagParseSingleType() {
|
||||
val tag = arrayOf("notifications", "payment_received")
|
||||
val result = NotificationsTag.parse(tag)
|
||||
assertNotNull(result)
|
||||
assertEquals(listOf("payment_received"), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagParseWrongTagName() {
|
||||
val tag = arrayOf("other", "payment_received")
|
||||
val result = NotificationsTag.parse(tag)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagParseTooShort() {
|
||||
val tag = arrayOf("notifications")
|
||||
val result = NotificationsTag.parse(tag)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagAssemble() {
|
||||
val tag = NotificationsTag.assemble(listOf("payment_received", "payment_sent", "hold_invoice_accepted"))
|
||||
assertEquals("notifications", tag[0])
|
||||
assertEquals("payment_received", tag[1])
|
||||
assertEquals("payment_sent", tag[2])
|
||||
assertEquals("hold_invoice_accepted", tag[3])
|
||||
assertEquals(4, tag.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNotificationsTagIsTag() {
|
||||
assertTrue(NotificationsTag.isTag(arrayOf("notifications", "payment_received")))
|
||||
assertFalse(NotificationsTag.isTag(arrayOf("other", "payment_received")))
|
||||
assertFalse(NotificationsTag.isTag(arrayOf("notifications")))
|
||||
assertFalse(NotificationsTag.isTag(arrayOf("notifications", "")))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user