From a33808176b01420ddd0c973f769cf3e6cb37aa8c Mon Sep 17 00:00:00 2001 From: Ricardo Villalobos Date: Thu, 15 Feb 2024 10:57:20 -0600 Subject: [PATCH] improve test coverage --- src/wallet/test/get_wallet_data.rs | 58 +++++++++++++++ src/wallet/test/get_wallet_dir.rs | 23 ++++++ src/wallet/test/mod.rs | 4 + src/wallet/test/save_new_asset.rs | 113 +++++++++++++++++++++++++++++ src/wallet/test/send_btc.rs | 4 +- src/wallet/test/sign_psbt.rs | 35 +++++++++ src/wallet/test/utils/api.rs | 57 +++++++++++++++ 7 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 src/wallet/test/get_wallet_data.rs create mode 100644 src/wallet/test/get_wallet_dir.rs create mode 100644 src/wallet/test/save_new_asset.rs create mode 100644 src/wallet/test/sign_psbt.rs diff --git a/src/wallet/test/get_wallet_data.rs b/src/wallet/test/get_wallet_data.rs new file mode 100644 index 0000000..1b31dd1 --- /dev/null +++ b/src/wallet/test/get_wallet_data.rs @@ -0,0 +1,58 @@ +use super::*; +use serial_test::parallel; + +#[test] +#[parallel] +fn success() { + let test_data_dir_str = get_test_data_dir_string(); + let test_data_dir = PathBuf::from(test_data_dir_str.clone()); + fs::create_dir_all(test_data_dir).unwrap(); + + // test manual values + let keys = generate_keys(BitcoinNetwork::Signet); + let wallet_1 = Wallet::new(WalletData { + data_dir: test_data_dir_str.clone(), + bitcoin_network: BitcoinNetwork::Signet, + database_type: DatabaseType::Sqlite, + max_allocations_per_utxo: 1, + pubkey: keys.account_xpub.clone(), + mnemonic: Some(keys.mnemonic.clone()), + vanilla_keychain: Some(2), + }) + .unwrap(); + + let wallet_1_data = test_get_wallet_data(&wallet_1); + assert_eq!(wallet_1_data.data_dir, test_data_dir_str); + assert_eq!( + wallet_1.get_wallet_dir().parent().unwrap(), + fs::canonicalize(wallet_1_data.data_dir).unwrap(), + ); + assert_eq!(wallet_1_data.bitcoin_network, BitcoinNetwork::Signet); + assert!(matches!(wallet_1_data.database_type, DatabaseType::Sqlite)); + assert_eq!(wallet_1_data.pubkey, keys.account_xpub); + assert_eq!(wallet_1_data.max_allocations_per_utxo, 1); + assert_eq!(wallet_1_data.mnemonic.unwrap(), keys.mnemonic); + assert_eq!(wallet_1_data.vanilla_keychain.unwrap(), 2); + + // test default values + let wallet_2 = Wallet::new(WalletData { + data_dir: test_data_dir_str.clone(), + bitcoin_network: BitcoinNetwork::Regtest, + database_type: DatabaseType::Sqlite, + max_allocations_per_utxo: 5, + pubkey: keys.account_xpub.clone(), + mnemonic: None, + vanilla_keychain: None, + }) + .unwrap(); + let wallet_2_data = test_get_wallet_data(&wallet_2); + assert_eq!(wallet_2_data.data_dir, test_data_dir_str); + assert_eq!(wallet_2_data.bitcoin_network, BitcoinNetwork::Regtest); + assert!(matches!(wallet_2_data.database_type, DatabaseType::Sqlite)); + assert_eq!( + wallet_2_data.max_allocations_per_utxo, + MAX_ALLOCATIONS_PER_UTXO + ); + assert!(wallet_2_data.mnemonic.is_none()); + assert!(wallet_2_data.vanilla_keychain.is_none()); +} diff --git a/src/wallet/test/get_wallet_dir.rs b/src/wallet/test/get_wallet_dir.rs new file mode 100644 index 0000000..5344588 --- /dev/null +++ b/src/wallet/test/get_wallet_dir.rs @@ -0,0 +1,23 @@ +use super::*; +use serial_test::parallel; + +#[test] +#[parallel] +fn success() { + let test_data_dir_str = get_test_data_dir_string(); + let test_data_dir = PathBuf::from(test_data_dir_str.clone()); + fs::create_dir_all(&test_data_dir).unwrap(); + + let keys = generate_keys(BitcoinNetwork::Regtest); + let wallet = Wallet::new(get_test_wallet_data( + &test_data_dir_str, + &keys.account_xpub, + &keys.mnemonic, + )) + .unwrap(); + + let expected_dir = fs::canonicalize(test_data_dir.join(keys.account_xpub_fingerprint)).unwrap(); + + let wallet_dir = test_get_wallet_dir(&wallet); + assert_eq!(wallet_dir, expected_dir); +} diff --git a/src/wallet/test/mod.rs b/src/wallet/test/mod.rs index 2f9ce44..05eae39 100644 --- a/src/wallet/test/mod.rs +++ b/src/wallet/test/mod.rs @@ -193,6 +193,8 @@ mod get_address; mod get_asset_balance; mod get_asset_metadata; mod get_btc_balance; +mod get_wallet_data; +mod get_wallet_dir; mod go_online; mod issue_asset_cfa; mod issue_asset_nia; @@ -204,6 +206,8 @@ mod list_unspents; mod list_unspents_vanilla; mod new; mod refresh; +mod save_new_asset; mod send; mod send_btc; +mod sign_psbt; mod witness_receive; diff --git a/src/wallet/test/save_new_asset.rs b/src/wallet/test/save_new_asset.rs new file mode 100644 index 0000000..2cbc4ec --- /dev/null +++ b/src/wallet/test/save_new_asset.rs @@ -0,0 +1,113 @@ +use super::*; +use serial_test::parallel; + +#[test] +#[parallel] +fn success() { + initialize(); + let asset_amount: u64 = 66; + + // wallets + let (wallet, online) = get_funded_wallet!(); + let (rcv_wallet, _rcv_online) = get_empty_wallet!(); + + // NIA + let nia_asset = test_issue_asset_nia(&wallet, &online, None); + test_save_new_asset( + &wallet, + &online, + &rcv_wallet, + &nia_asset.asset_id, + asset_amount, + ); + assert!(&rcv_wallet + .database + .check_asset_exists(nia_asset.asset_id.clone()) + .is_ok()); + let asset_model = rcv_wallet + .database + .get_asset(nia_asset.asset_id.clone()) + .unwrap() + .unwrap(); + assert_eq!(asset_model.id, nia_asset.asset_id); + assert_eq!(asset_model.issued_supply, AMOUNT.to_string()); + assert_eq!(asset_model.name, NAME); + assert_eq!(asset_model.precision, PRECISION); + assert_eq!(asset_model.ticker.unwrap(), TICKER); + assert_eq!(asset_model.schema, AssetSchema::Nia); + + // CFA + let cfa_asset = test_issue_asset_cfa(&wallet, &online, None, None); + test_save_new_asset( + &wallet, + &online, + &rcv_wallet, + &cfa_asset.asset_id, + asset_amount, + ); + assert!(&rcv_wallet + .database + .check_asset_exists(cfa_asset.asset_id.clone()) + .is_ok()); + let asset_model = rcv_wallet + .database + .get_asset(cfa_asset.asset_id.clone()) + .unwrap() + .unwrap(); + assert_eq!(asset_model.id, cfa_asset.asset_id); + assert_eq!(asset_model.issued_supply, AMOUNT.to_string()); + assert_eq!(asset_model.name, NAME); + assert_eq!(asset_model.precision, PRECISION); + assert!(asset_model.ticker.is_none()); + assert_eq!(asset_model.schema, AssetSchema::Cfa); + + // UDA + let uda_amount: u64 = 1; + let file_str = "README.md"; + let image_str = ["tests", "qrcode.png"].join(&MAIN_SEPARATOR.to_string()); + let uda_asset = test_issue_asset_uda( + &wallet, + &online, + Some(DETAILS), + Some(file_str), + vec![&image_str, file_str], + ); + test_create_utxos(&wallet, &online, false, None, None, FEE_RATE); + test_save_new_asset( + &wallet, + &online, + &rcv_wallet, + &uda_asset.asset_id, + uda_amount, + ); + assert!(&rcv_wallet + .database + .check_asset_exists(uda_asset.asset_id.clone()) + .is_ok()); + let asset_model = rcv_wallet + .database + .get_asset(uda_asset.asset_id.clone()) + .unwrap() + .unwrap(); + assert_eq!(asset_model.id, uda_asset.asset_id); + assert_eq!(asset_model.issued_supply, 1.to_string()); + assert_eq!(asset_model.name, NAME); + assert_eq!(asset_model.precision, PRECISION); + assert_eq!(asset_model.ticker.unwrap(), TICKER); + assert_eq!(asset_model.schema, AssetSchema::Uda); +} + +#[test] +#[parallel] +fn fail() { + initialize(); + + let (wallet, online) = get_funded_wallet!(); + + let asset_nia = test_issue_asset_nia(&wallet, &online, None); + let asset_nia_cid = ContractId::from_str(&asset_nia.asset_id).unwrap(); + let mut runtime = wallet._rgb_runtime().unwrap(); + + let result = wallet.save_new_asset(&mut runtime, &AssetSchema::Cfa, asset_nia_cid); + assert!(matches!(result, Err(Error::Internal { details: _ }))); +} diff --git a/src/wallet/test/send_btc.rs b/src/wallet/test/send_btc.rs index f0919b2..c45e294 100644 --- a/src/wallet/test/send_btc.rs +++ b/src/wallet/test/send_btc.rs @@ -116,8 +116,8 @@ fn fail() { assert!(matches!(result, Err(Error::OutputBelowDustLimit))); // invalid fee rate - let result = wallet.send_btc(online.clone(), test_get_address(&rcv_wallet), amount, 0.9); + let result = wallet.send_btc_begin(online.clone(), test_get_address(&rcv_wallet), amount, 0.9); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW)); - let result = wallet.send_btc(online, test_get_address(&rcv_wallet), amount, 1000.1); + let result = wallet.send_btc_begin(online, test_get_address(&rcv_wallet), amount, 1000.1); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_HIGH)); } diff --git a/src/wallet/test/sign_psbt.rs b/src/wallet/test/sign_psbt.rs new file mode 100644 index 0000000..616be2f --- /dev/null +++ b/src/wallet/test/sign_psbt.rs @@ -0,0 +1,35 @@ +use super::*; +use serial_test::parallel; + +#[test] +#[parallel] +fn success() { + initialize(); + let (wallet, online) = get_funded_wallet!(); + let address = test_get_address(&wallet); + + let unsigned_psbt_str = wallet + .send_btc_begin(online, address, AMOUNT, FEE_RATE) + .unwrap(); + + // no SignOptions + let signed_psbt = wallet.sign_psbt(unsigned_psbt_str.clone(), None).unwrap(); + assert!(BdkPsbt::from_str(&signed_psbt).is_ok()); + + // with SignOptions + let opts = SignOptions::default(); + let signed_psbt = wallet + .sign_psbt(unsigned_psbt_str.clone(), Some(opts)) + .unwrap(); + assert!(BdkPsbt::from_str(&signed_psbt).is_ok()); +} + +#[test] +#[parallel] +fn fail() { + initialize(); + let (wallet, _online) = get_funded_wallet!(); + + let result = wallet.sign_psbt("rgb1invalid".to_string(), None); + assert!(matches!(result, Err(Error::Internal { details: _ }))); // PSBT parse error +} diff --git a/src/wallet/test/utils/api.rs b/src/wallet/test/utils/api.rs index 2acd18e..dfef944 100644 --- a/src/wallet/test/utils/api.rs +++ b/src/wallet/test/utils/api.rs @@ -371,6 +371,63 @@ pub(crate) fn test_refresh_asset(wallet: &Wallet, online: &Online, asset_id: &st .unwrap() } +pub(crate) fn test_save_new_asset( + wallet: &Wallet, + online: &Online, + rcv_wallet: &Wallet, + asset_id: &String, + amount: u64, +) { + let receive_data = test_witness_receive(rcv_wallet); + let recipient_map = HashMap::from([( + asset_id.clone(), + vec![Recipient { + amount, + recipient_data: RecipientData::WitnessData { + script_buf: ScriptBuf::from_hex(&receive_data.recipient_id).unwrap(), + amount_sat: 1000, + blinding: None, + }, + transport_endpoints: TRANSPORT_ENDPOINTS.clone(), + }], + )]); + let txid = test_send(wallet, online, &recipient_map); + assert!(!txid.is_empty()); + + let txid_dir = wallet._transfers_dir().join(txid); + let asset_transfer_dir = txid_dir.join(asset_id); + let consignment_path = asset_transfer_dir.join(CONSIGNMENT_FILE); + + let bindle = Bindle::::load(consignment_path).unwrap(); + let consignment: RgbTransfer = bindle.unbindle(); + let mut contract = consignment.clone().into_contract(); + + contract.bundles = none!(); + contract.terminals = none!(); + let minimal_contract_validated = + match contract.validate(&mut rcv_wallet._blockchain_resolver().unwrap()) { + Ok(consignment) => consignment, + Err(consignment) => consignment, + }; + + let mut runtime = rcv_wallet._rgb_runtime().unwrap(); + runtime + .import_contract( + minimal_contract_validated.clone(), + &mut rcv_wallet._blockchain_resolver().unwrap(), + ) + .unwrap(); + let schema_id = minimal_contract_validated.schema_id().to_string(); + let asset_schema = AssetSchema::from_schema_id(schema_id).unwrap(); + rcv_wallet + .save_new_asset( + &mut runtime, + &asset_schema, + minimal_contract_validated.contract_id(), + ) + .unwrap(); +} + pub(crate) fn test_send( wallet: &Wallet, online: &Online,