170 lines
5.9 KiB
Kotlin
170 lines
5.9 KiB
Kotlin
package com.bitcointxoko.gudariwallet.util
|
|
|
|
import android.net.Uri
|
|
import io.mockk.every
|
|
import io.mockk.mockkStatic
|
|
import io.mockk.unmockkStatic
|
|
import org.junit.After
|
|
import org.junit.Assert.assertEquals
|
|
import org.junit.Assert.assertTrue
|
|
import org.junit.Before
|
|
import org.junit.Test
|
|
|
|
class Bip21ParserTest {
|
|
|
|
@Before
|
|
fun setUp() {
|
|
// Mock android.net.Uri.decode so tests run on the JVM without Android
|
|
mockkStatic(Uri::class)
|
|
// Default: pass-through (no encoding in most test inputs)
|
|
every { Uri.decode(any()) } answers { firstArg() }
|
|
}
|
|
|
|
@After
|
|
fun tearDown() {
|
|
unmockkStatic(Uri::class)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Full BIP-21 URI
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `full URI with single param returns correct map`() {
|
|
val result = Bip21Parser.parseParams("bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf?amount=0.001")
|
|
assertEquals(mapOf("amount" to "0.001"), result)
|
|
}
|
|
|
|
@Test
|
|
fun `full URI with multiple params returns all params`() {
|
|
val result = Bip21Parser.parseParams(
|
|
"bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf?amount=0.5&label=Foo&message=Bar"
|
|
)
|
|
assertEquals(
|
|
mapOf("amount" to "0.5", "label" to "Foo", "message" to "Bar"),
|
|
result
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun `full URI with no query string returns empty map`() {
|
|
val result = Bip21Parser.parseParams("bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf")
|
|
assertTrue(result.isEmpty())
|
|
}
|
|
|
|
@Test
|
|
fun `full URI with empty query string after question mark returns empty map`() {
|
|
val result = Bip21Parser.parseParams("bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7Divf?")
|
|
assertTrue(result.isEmpty())
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Raw query string (no URI prefix)
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `bare query string with single param returns correct map`() {
|
|
val result = Bip21Parser.parseParams("amount=0.001")
|
|
assertEquals(mapOf("amount" to "0.001"), result)
|
|
}
|
|
|
|
@Test
|
|
fun `bare query string with multiple params returns all params`() {
|
|
val result = Bip21Parser.parseParams("amount=0.001&label=Satoshi")
|
|
assertEquals(mapOf("amount" to "0.001", "label" to "Satoshi"), result)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// URI-encoded values
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `percent-encoded value is decoded`() {
|
|
every { Uri.decode("Hello%20World") } returns "Hello World"
|
|
val result = Bip21Parser.parseParams("label=Hello%20World")
|
|
assertEquals(mapOf("label" to "Hello World"), result)
|
|
}
|
|
|
|
@Test
|
|
fun `percent-encoded value in full URI is decoded`() {
|
|
every { Uri.decode("Thank%20You") } returns "Thank You"
|
|
val result = Bip21Parser.parseParams(
|
|
"bitcoin:addr?message=Thank%20You"
|
|
)
|
|
assertEquals(mapOf("message" to "Thank You"), result)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Edge cases — blank / empty input
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `empty string returns empty map`() {
|
|
val result = Bip21Parser.parseParams("")
|
|
assertTrue(result.isEmpty())
|
|
}
|
|
|
|
@Test
|
|
fun `blank string returns empty map`() {
|
|
val result = Bip21Parser.parseParams(" ")
|
|
assertTrue(result.isEmpty())
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Malformed pairs
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `pair with no equals sign is skipped`() {
|
|
// "label" has no '=', "amount=0.1" is valid
|
|
val result = Bip21Parser.parseParams("label&amount=0.1")
|
|
assertEquals(mapOf("amount" to "0.1"), result)
|
|
}
|
|
|
|
@Test
|
|
fun `pair starting with equals sign (empty key) is skipped`() {
|
|
// idx == 0, which is < 1, so this pair should be dropped
|
|
val result = Bip21Parser.parseParams("=value&amount=0.1")
|
|
assertEquals(mapOf("amount" to "0.1"), result)
|
|
}
|
|
|
|
@Test
|
|
fun `all malformed pairs return empty map`() {
|
|
val result = Bip21Parser.parseParams("noequalssign&=emptykey")
|
|
assertTrue(result.isEmpty())
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Param with empty value
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `param with empty value is included with empty string`() {
|
|
val result = Bip21Parser.parseParams("label=")
|
|
assertEquals(mapOf("label" to ""), result)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Duplicate keys
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `duplicate keys — last value wins`() {
|
|
// Kotlin's toMap() on a list of pairs keeps the last value for duplicates
|
|
val result = Bip21Parser.parseParams("amount=0.001&amount=0.999")
|
|
assertEquals(mapOf("amount" to "0.999"), result)
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Lightning / BIP-21 extensions (lightning param)
|
|
// -------------------------------------------------------------------------
|
|
|
|
@Test
|
|
fun `lightning param is parsed correctly`() {
|
|
val bolt11 = "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx"
|
|
every { Uri.decode(bolt11) } returns bolt11
|
|
val result = Bip21Parser.parseParams("amount=0.001&lightning=$bolt11")
|
|
assertEquals(bolt11, result["lightning"])
|
|
}
|
|
}
|