From c0a6d0082fec6eff98d85596932e4db70a2c965c Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 3 Sep 2025 13:09:32 -0400 Subject: [PATCH] test: clean up android instrumented tests --- .../assets/persistence_test_db.sqlite3 | Bin 0 -> 61440 bytes .../kotlin/org/bitcoindevkit/Constants.kt | 38 +++++++ .../org/bitcoindevkit/CreatingWalletTest.kt | 58 +++++++++++ .../org/bitcoindevkit/DescriptorTest.kt | 50 ++++++++++ .../org/bitcoindevkit/LiveTxBuilderTest.kt | 82 --------------- .../org/bitcoindevkit/LiveWalletTest.kt | 93 ------------------ ...flineDescriptorTest.kt => MnemonicTest.kt} | 9 +- .../org/bitcoindevkit/OfflineWalletTest.kt | 74 -------------- .../org/bitcoindevkit/PersistenceTest.kt | 53 ++++++++++ .../kotlin/org/bitcoindevkit/WalletTest.kt | 48 +++++++++ 10 files changed, 252 insertions(+), 253 deletions(-) create mode 100644 bdk-android/lib/src/androidTest/assets/persistence_test_db.sqlite3 create mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/Constants.kt create mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/CreatingWalletTest.kt create mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/DescriptorTest.kt delete mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveTxBuilderTest.kt delete mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt rename bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/{OfflineDescriptorTest.kt => MnemonicTest.kt} (88%) delete mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt create mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/PersistenceTest.kt create mode 100644 bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/WalletTest.kt diff --git a/bdk-android/lib/src/androidTest/assets/persistence_test_db.sqlite3 b/bdk-android/lib/src/androidTest/assets/persistence_test_db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..f447f8b602a9d26eb35439953177baa2636f7aa9 GIT binary patch literal 61440 zcmeI*-)`Dg90zc_q(J@`Rg+GXNlB)30rMyLqS6R)n=CZV2w9s>6EgNOco3lA zkUtlbV4AcSnDz*Lg=M>%w2R&C1*Yv8x~pC8_zz$LWtvv0DEeB^m~+hWIiK@8hxk~e zho5E*lM=n&JW)&%u zkQRPk{BCi6{`=7H3ub72c4^`M+`YM%!9?hr31uJ)0uX=z1Rwx`X%Ofbp+Gp3;k(DC zQmoRVRw-z-r8bR*S#Pr4rqQNaq1C9gCS)yUa&kH^lYDwBE0YNal2zg<-Oxy0ewruy zkJnR)-4q6tzay$YDOW zo5^=)X9MBoW&Z0yTa}txt~c$rxw~^CZE-VL-OcmsRVF$4ft-`~GxDL`Zu7iFR;|O< z)=9BiS1W}wHA-c3OncmHrB%MJpw?@;Vf_+k)N2LPIHCP_Z_5wTN7+2N7k!n2b?)I) z_g}Fy4JxZ;E> z;ZNZ=;jcH*IGhs#5P$##AOHafKmY;|fB*y_0D)HsyzASr7X;kvf9HBXC=4$X1m5d^2eNr*YPx9N(FG>fO z;#oF*vGc@eZHtnWt!T|J6SQ=k+=y&^xVC)RP?Xwb>2zvp6}4(ri>s$+W%Z(El-L&< z?CXEwM~*$PK>z{}fB*y_009U<00Izz00bZ~bpqS$kMVUv5ob%KqEc!zMkO&37ezIy z>k(a&^i5Tjip8QB6BRufQzDz2N<0-&V#!#nNNJSnN$dKb{n0;c5P$##AOHafKmY;| zfB*y_009WxU;*p<|G56Y!5xgIK>z{}fB*y_009U<00Izz00fu-?*AhUAOHafKmY;| zfB*y_009U<00K8(0QdiIejlTS5P$##AOHafKmY;|fB*y_00G?pM+`s!0uX=z1Rwwb z2tWV=5P$##ZoUBS|KI#RMhhVT0SG_<0uX=z1Rwwb2tWV=&j0^+#R*rifB*y_009U< z00Izz00bZa0SG`~>I7tdrW4{f6p#xr16LrQH!ytChD5sy8q7$KXL4V4FV8=00bZa0SG_<0uX=z1Rwx`=@Zyy z3jnkKcL4z3|DV2&MU5Z;0SG_<0uX=z1Rwwb2tWV=uUi1$|9{=0C=UV 0uL) { -// "Wallet balance must be greater than 0! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address} and try again." -// } -// -// val recipient: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.SIGNET) -// val psbt: Psbt = TxBuilder() -// .addRecipient(recipient.scriptPubkey(), Amount.fromSat(4200uL)) -// .feeRate(FeeRate.fromSatPerVb(2uL)) -// .finish(wallet) -// -// println(psbt.serialize()) -// assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") -// } -// -// @Test -// fun complexTxBuilder() { -// var conn: Persister = Persister.newInMemory() -// val wallet = Wallet(descriptor, changeDescriptor, Network.SIGNET, conn) -// val esploraClient: EsploraClient = EsploraClient(SIGNET_ESPLORA_URL) -// val fullScanRequest: FullScanRequest = wallet.startFullScan().build() -// val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) -// wallet.applyUpdate(update) -// -// println("Balance: ${wallet.balance().total.toSat()}") -// -// assert(wallet.balance().total.toSat() > 25000uL) { -// "Wallet balance must be greater than 25000 satoshis! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address} and try again." -// } -// -// val recipient1: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.SIGNET) -// val recipient2: Address = Address("tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", Network.SIGNET) -// val allRecipients: List = listOf( -// ScriptAmount(recipient1.scriptPubkey(), Amount.fromSat(4200uL)), -// ScriptAmount(recipient2.scriptPubkey(), Amount.fromSat(4200uL)), -// ) -// -// val psbt: Psbt = TxBuilder() -// .setRecipients(allRecipients) -// .feeRate(FeeRate.fromSatPerVb(4uL)) -// .finish(wallet) -// -// wallet.sign(psbt) -// assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") -// } -// } diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt deleted file mode 100644 index 5f9c8e96..00000000 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/LiveWalletTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -package org.bitcoindevkit - -import org.junit.Test -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.runner.RunWith -import kotlin.test.AfterTest -import kotlin.test.assertTrue -import java.io.File - -private const val SIGNET_ESPLORA_URL = "https://blockstream.info/signet/api/" -private const val TESTNET_ESPLORA_URL = "https://esplora.testnet.kuutamo.cloud" - -// @RunWith(AndroidJUnit4::class) -// class LiveWalletTest { -// private val persistenceFilePath = InstrumentationRegistry -// .getInstrumentation().targetContext.filesDir.path + "/bdk_persistence2.sqlite" -// private val descriptor: Descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)", Network.SIGNET) -// private val changeDescriptor: Descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)", Network.SIGNET) -// -// @AfterTest -// fun cleanup() { -// val file = File(persistenceFilePath) -// if (file.exists()) { -// file.delete() -// } -// } -// -// @Test -// fun testSyncedBalance() { -// var conn: Persister = Persister.newInMemory() -// val wallet: Wallet = Wallet(descriptor, changeDescriptor, Network.SIGNET, conn) -// val esploraClient: EsploraClient = EsploraClient(SIGNET_ESPLORA_URL) -// val fullScanRequest: FullScanRequest = wallet.startFullScan().build() -// val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) -// wallet.applyUpdate(update) -// println("Balance: ${wallet.balance().total.toSat()}") -// val balance: Balance = wallet.balance() -// println("Balance: $balance") -// -// assert(wallet.balance().total.toSat() > 0uL) { -// "Wallet balance must be greater than 0! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address} and try again." -// } -// -// println("Transactions count: ${wallet.transactions().count()}") -// val transactions = wallet.transactions().take(3) -// for (tx in transactions) { -// val sentAndReceived = wallet.sentAndReceived(tx.transaction) -// println("Transaction: ${tx.transaction.computeTxid()}") -// println("Sent ${sentAndReceived.sent.toSat()}") -// println("Received ${sentAndReceived.received.toSat()}") -// } -// } -// -// @Test -// fun testBroadcastTransaction() { -// var conn: Persister = Persister.newInMemory() -// val wallet = Wallet(descriptor, changeDescriptor, Network.SIGNET, conn) -// val esploraClient = EsploraClient(SIGNET_ESPLORA_URL) -// val fullScanRequest: FullScanRequest = wallet.startFullScan().build() -// val update = esploraClient.fullScan(fullScanRequest, 10uL, 1uL) -// wallet.applyUpdate(update) -// println("Balance: ${wallet.balance().total.toSat()}") -// -// assert(wallet.balance().total.toSat() > 0uL) { -// "Wallet balance must be greater than 0! Please send funds to ${wallet.revealNextAddress(KeychainKind.EXTERNAL).address} and try again." -// } -// -// val recipient: Address = Address("tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", Network.SIGNET) -// -// val psbt: Psbt = TxBuilder() -// .addRecipient(recipient.scriptPubkey(), Amount.fromSat(4200uL)) -// .feeRate(FeeRate.fromSatPerVb(4uL)) -// .finish(wallet) -// -// println(psbt.serialize()) -// assertTrue(psbt.serialize().startsWith("cHNi"), "PSBT should start with 'cHNi'") -// -// val walletDidSign = wallet.sign(psbt) -// assertTrue(walletDidSign) -// -// val tx: Transaction = psbt.extractTx() -// println("Txid is: ${tx.computeTxid()}") -// -// val txFee: Amount = wallet.calculateFee(tx) -// println("Tx fee is: ${txFee.toSat()}") -// -// val feeRate: FeeRate = wallet.calculateFeeRate(tx) -// println("Tx fee rate is: ${feeRate.toSatPerVbCeil()} sat/vB") -// -// esploraClient.broadcast(tx) -// } -// } diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineDescriptorTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/MnemonicTest.kt similarity index 88% rename from bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineDescriptorTest.kt rename to bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/MnemonicTest.kt index 6265d1d9..3c1ad5ad 100644 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineDescriptorTest.kt +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/MnemonicTest.kt @@ -1,14 +1,15 @@ package org.bitcoindevkit -import kotlin.test.Test -import kotlin.test.assertEquals import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.runner.RunWith +import kotlin.test.Test +import kotlin.test.assertEquals @RunWith(AndroidJUnit4::class) -class OfflineDescriptorTest { +class MnemonicTest { + // Mnemonics create valid descriptors. @Test - fun testDescriptorBip86() { + fun mnemonicsCreateValidDescriptors() { val mnemonic: Mnemonic = Mnemonic.fromString("space echo position wrist orient erupt relief museum myself grain wisdom tumble") val descriptorSecretKey: DescriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null) val descriptor: Descriptor = Descriptor.newBip86(descriptorSecretKey, KeychainKind.EXTERNAL, Network.TESTNET) diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt deleted file mode 100644 index 0cd8120f..00000000 --- a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/OfflineWalletTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.bitcoindevkit - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.test.assertFalse -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.runner.RunWith -import kotlin.test.AfterTest -import java.io.File - -@RunWith(AndroidJUnit4::class) -class OfflineWalletTest { - private val persistenceFilePath = InstrumentationRegistry - .getInstrumentation().targetContext.filesDir.path + "/bdk_persistence1.sqlite" - private val descriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)", Network.TESTNET) - private val changeDescriptor = Descriptor("wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)", Network.TESTNET) - - @AfterTest - fun cleanup() { - val file = File(persistenceFilePath) - if (file.exists()) { - file.delete() - } - } - - @Test - fun testDescriptorBip86() { - val mnemonic: Mnemonic = Mnemonic(WordCount.WORDS12) - val descriptorSecretKey: DescriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null) - val descriptor: Descriptor = Descriptor.newBip86(descriptorSecretKey, KeychainKind.EXTERNAL, Network.TESTNET) - - assertTrue(descriptor.toString().startsWith("tr"), "Bip86 Descriptor does not start with 'tr'") - } - - @Test - fun testNewAddress() { - val conn = Persister.newInMemory() - val wallet: Wallet = Wallet( - descriptor, - changeDescriptor, - Network.TESTNET, - conn - ) - val addressInfo: AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) - - assertTrue(addressInfo.address.isValidForNetwork(Network.TESTNET), "Address is not valid for testnet network") - assertTrue(addressInfo.address.isValidForNetwork(Network.SIGNET), "Address is not valid for signet network") - assertFalse(addressInfo.address.isValidForNetwork(Network.REGTEST), "Address is valid for regtest network, but it shouldn't be") - assertFalse(addressInfo.address.isValidForNetwork(Network.BITCOIN), "Address is valid for bitcoin network, but it shouldn't be") - - assertEquals( - expected = "tb1qhjys9wxlfykmte7ftryptx975uqgd6kcm6a7z4", - actual = addressInfo.address.toString() - ) - } - - @Test - fun testBalance() { - var conn: Persister = Persister.newInMemory() - val wallet: Wallet = Wallet( - descriptor, - changeDescriptor, - Network.TESTNET, - conn - ) - - assertEquals( - expected = 0uL, - actual = wallet.balance().total.toSat() - ) - } -} diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/PersistenceTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/PersistenceTest.kt new file mode 100644 index 00000000..cfa0e03c --- /dev/null +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/PersistenceTest.kt @@ -0,0 +1,53 @@ +package org.bitcoindevkit + +import androidx.test.platform.app.InstrumentationRegistry +import java.io.File +import kotlin.test.Test +import kotlin.test.assertEquals + +class PersistenceTest { + private val persistenceFilePath: String by lazy { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val dbFileName = "persistence_test_db.sqlite3" + + // Copy the file from assets to a writable location (databases dir) + val destFile = File(context.getDatabasePath(dbFileName).path) + context.assets.open(dbFileName).use { input -> + destFile.outputStream().use { output -> + input.copyTo(output) + } + } + destFile.absolutePath + } + + private val descriptor: Descriptor = Descriptor( + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)", + Network.SIGNET + ) + private val changeDescriptor: Descriptor = Descriptor( + "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/1/*)", + Network.SIGNET + ) + + // fun `Correctly load wallet from sqlite persistence`() { + @Test + fun correctlyLoadFromPersistence() { + val connection = Persister.newSqlite(persistenceFilePath) + + val wallet: Wallet = Wallet.load( + descriptor, + changeDescriptor, + connection + ) + val addressInfo: AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) + + assertEquals( + expected = 7u, + actual = addressInfo.index, + ) + assertEquals( + expected = "tb1qan3lldunh37ma6c0afeywgjyjgnyc8uz975zl2", + actual = addressInfo.address.toString(), + ) + } +} diff --git a/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/WalletTest.kt b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/WalletTest.kt new file mode 100644 index 00000000..ea53f540 --- /dev/null +++ b/bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/WalletTest.kt @@ -0,0 +1,48 @@ +package org.bitcoindevkit + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.assertFalse +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class WalletTest { + val conn: Persister = Persister.newInMemory() + + // Wallet produces valid addresses for its network. + @Test + fun walletProducesValidAddresses() { + val wallet: Wallet = Wallet( + descriptor = BIP84_DESCRIPTOR, + changeDescriptor = BIP84_CHANGE_DESCRIPTOR, + network = Network.TESTNET, + persister = conn + ) + val addressInfo: AddressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL) + + assertTrue(addressInfo.address.isValidForNetwork(Network.TESTNET), "Address is not valid for Testnet 3 network but it should be") + assertTrue(addressInfo.address.isValidForNetwork(Network.TESTNET4), "Address is not valid for Testnet 4 network but it should be") + assertTrue(addressInfo.address.isValidForNetwork(Network.SIGNET), "Address is not valid for Signet network but it should be") + + assertFalse(addressInfo.address.isValidForNetwork(Network.REGTEST), "Address is valid for Regtest network, but it should not be") + assertFalse(addressInfo.address.isValidForNetwork(Network.BITCOIN), "Address is valid for Mainnet network, but it should not be") + } + + // Wallet has 0 balance prior to sync. + @Test + fun newWalletHas0Balance() { + val wallet: Wallet = Wallet( + descriptor = BIP84_DESCRIPTOR, + changeDescriptor = BIP84_CHANGE_DESCRIPTOR, + network = Network.TESTNET, + persister = conn + ) + + assertEquals( + expected = 0uL, + actual = wallet.balance().total.toSat() + ) + } +}