From e0348dc33113b61f7e082aef887c53f78c9b63b1 Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Wed, 10 Jun 2026 19:25:58 +0300 Subject: [PATCH] feat(integration_tests): mnemonic test --- integration_tests/tests/wallet_ffi.rs | 394 ++++++++++++++++++++++++-- lez/wallet-ffi/src/wallet.rs | 3 +- lez/wallet/src/lib.rs | 24 ++ 3 files changed, 393 insertions(+), 28 deletions(-) diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 70e6d44d..92b82a7c 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -26,8 +26,7 @@ use log::info; use tempfile::tempdir; use wallet::account::HumanReadableAccount; use wallet_ffi::{ - FfiAccount, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, - FfiTransferResult, FfiU128, WalletHandle, error, + FfiAccount, FfiAccountList, FfiBytes32, FfiPrivateAccountKeys, FfiPublicAccountKey, FfiTransferResult, FfiU128, WalletHandle, error, wallet::FfiCreateWalletResult }; unsafe extern "C" { @@ -35,7 +34,7 @@ unsafe extern "C" { config_path: *const c_char, storage_path: *const c_char, password: *const c_char, - ) -> *mut WalletHandle; + ) -> FfiCreateWalletResult; fn wallet_ffi_open( config_path: *const c_char, @@ -180,12 +179,18 @@ unsafe extern "C" { handle: *mut WalletHandle, out_block_height: *mut u64, ) -> error::WalletFfiError; + + fn wallet_ffi_restore_data( + handle: *mut WalletHandle, + mnemonic: *const c_char, + password: *const c_char, + ) -> error::WalletFfiError; } fn new_wallet_ffi_with_test_context_config( ctx: &BlockingTestContext, home: &Path, -) -> Result<*mut WalletHandle> { +) -> Result { let config_path = home.join("wallet_config.json"); let storage_path = home.join("storage.json"); let mut config = ctx.ctx().wallet().config().to_owned(); @@ -206,7 +211,7 @@ fn new_wallet_ffi_with_test_context_config( let storage_path = CString::new(storage_path.to_str().unwrap())?; let password = CString::new(ctx.ctx().wallet_password())?; - let wallet_ffi_handle = unsafe { + let create_wallet_result = unsafe { wallet_ffi_create_new( config_path.as_ptr(), storage_path.as_ptr(), @@ -224,8 +229,10 @@ fn new_wallet_ffi_with_test_context_config( .unwrap() .to_string(); let private_key_hex = CString::new(private_key_hex)?; - unsafe { wallet_ffi_import_public_account(wallet_ffi_handle, private_key_hex.as_ptr()) } - .unwrap(); + unsafe { + wallet_ffi_import_public_account(create_wallet_result.wallet, private_key_hex.as_ptr()) + } + .unwrap(); } for (account_id, _chain_index) in source_key_chain.private_account_ids() { @@ -248,7 +255,7 @@ fn new_wallet_ffi_with_test_context_config( unsafe { wallet_ffi_import_private_account( - wallet_ffi_handle, + create_wallet_result.wallet, key_chain_json.as_ptr(), chain_index_ptr, &raw const identifier, @@ -258,10 +265,10 @@ fn new_wallet_ffi_with_test_context_config( .unwrap(); } - Ok(wallet_ffi_handle) + Ok(create_wallet_result) } -fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandle> { +fn new_wallet_ffi_with_default_config(password: &str) -> Result { let tempdir = tempdir()?; let config_path = tempdir.path().join("wallet_config.json"); let storage_path = tempdir.path().join("storage.json"); @@ -269,13 +276,15 @@ fn new_wallet_ffi_with_default_config(password: &str) -> Result<*mut WalletHandl let storage_path_c = CString::new(storage_path.to_str().unwrap())?; let password = CString::new(password)?; - Ok(unsafe { + let create_wallet_result = unsafe { wallet_ffi_create_new( config_path_c.as_ptr(), storage_path_c.as_ptr(), password.as_ptr(), ) - }) + }; + + Ok(create_wallet_result) } fn load_existing_ffi_wallet(home: &Path) -> Result<*mut WalletHandle> { @@ -296,7 +305,10 @@ fn wallet_ffi_create_public_accounts() -> Result<()> { let new_public_account_ids_ffi = unsafe { let mut account_ids = Vec::new(); - let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_default_config(password)?; for _ in 0..n_accounts { let mut out_account_id = FfiBytes32::from_bytes([0; 32]); wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut out_account_id).unwrap(); @@ -332,7 +344,10 @@ fn wallet_ffi_create_private_accounts() -> Result<()> { let new_npks_ffi = unsafe { let mut npks = Vec::new(); - let wallet_ffi_handle = new_wallet_ffi_with_default_config(password)?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_default_config(password)?; for _ in 0..n_accounts { let mut out_keys = FfiPrivateAccountKeys::default(); wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); @@ -361,7 +376,10 @@ fn wallet_ffi_save_and_load_persistent_storage() -> Result<()> { let home = tempfile::tempdir()?; // Create a receiving key and save let first_npk = unsafe { - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_keys = FfiPrivateAccountKeys::default(); wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); let npk = out_keys.nullifier_public_key.data; @@ -398,7 +416,10 @@ fn test_wallet_ffi_list_accounts() -> Result<()> { // Create the wallet FFI and track which account IDs were created as public/private let (wallet_ffi_handle, created_public_ids) = unsafe { - let handle = new_wallet_ffi_with_default_config(password)?; + let FfiCreateWalletResult { + wallet: handle, + mnemonic: _, + } = new_wallet_ffi_with_default_config(password)?; let mut public_ids: Vec<[u8; 32]> = Vec::new(); // Create 5 public accounts and 5 receiving keys @@ -463,7 +484,10 @@ fn test_wallet_ffi_get_balance_public() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let balance = unsafe { let mut out_balance: [u8; 16] = [0; 16]; @@ -493,7 +517,10 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_account = FfiAccount::default(); let account: Account = unsafe { @@ -530,7 +557,10 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_private_accounts()[0]; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_account = FfiAccount::default(); let account: Account = unsafe { @@ -566,7 +596,10 @@ fn test_wallet_ffi_get_public_account_keys() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_public_accounts()[0]; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut out_key = FfiPublicAccountKey::default(); let key: PublicKey = unsafe { @@ -605,7 +638,10 @@ fn test_wallet_ffi_get_private_account_keys() -> Result<()> { let ctx = BlockingTestContext::new()?; let account_id: AccountId = ctx.ctx().existing_private_accounts()[0]; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let mut keys = FfiPrivateAccountKeys::default(); unsafe { @@ -687,7 +723,10 @@ fn wallet_ffi_base58_to_account_id() -> Result<()> { fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; // Create a new uninitialized public account let mut out_account_id = FfiBytes32::from_bytes([0; 32]); @@ -750,7 +789,10 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> { fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; // Create a new private account let mut out_account_id = FfiBytes32::default(); @@ -807,7 +849,10 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> { fn test_wallet_ffi_transfer_public() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[1].into(); let amount: [u8; 16] = 100_u128.to_le_bytes(); @@ -861,7 +906,10 @@ fn test_wallet_ffi_transfer_public() -> Result<()> { fn test_wallet_ffi_transfer_shielded() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); let (to, to_keys) = unsafe { let mut out_keys = FfiPrivateAccountKeys::default(); @@ -937,7 +985,10 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { fn test_wallet_ffi_transfer_deshielded() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into(); let to: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); let amount: [u8; 16] = 100_u128.to_le_bytes(); @@ -997,7 +1048,10 @@ fn test_wallet_ffi_transfer_deshielded() -> Result<()> { fn test_wallet_ffi_transfer_private() -> Result<()> { let ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; - let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic: _, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; let from: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into(); let (to, to_keys) = unsafe { @@ -1068,3 +1122,289 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { Ok(()) } + +#[test] +fn restore_keys_from_seed_ffi() -> Result<()> { + let ctx = BlockingTestContext::new()?; + let home = tempfile::tempdir()?; + let FfiCreateWalletResult { + wallet: wallet_ffi_handle, + mnemonic, + } = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; + + // Create 2 new private accounts + let (private_account_id_1, private_account_1_keys) = unsafe { + let mut out_keys = FfiPrivateAccountKeys::default(); + wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); + let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); + let to: FfiBytes32 = account_id.into(); + (to, out_keys) + }; + + let (private_account_id_2, private_account_2_keys) = unsafe { + let mut out_keys = FfiPrivateAccountKeys::default(); + wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); + let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); + let to: FfiBytes32 = account_id.into(); + (to, out_keys) + }; + + // Create 2 new public accounts + let mut public_account_id_1 = FfiBytes32::default(); + unsafe { + wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut public_account_id_1).unwrap(); + } + + let mut public_account_id_2 = FfiBytes32::default(); + unsafe { + wallet_ffi_create_account_public(wallet_ffi_handle, &raw mut public_account_id_2).unwrap(); + } + + info!("Accounts created"); + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + // Send funds to accounts + let from_private: FfiBytes32 = ctx.ctx().existing_private_accounts()[0].into(); + let from_public: FfiBytes32 = ctx.ctx().existing_public_accounts()[0].into(); + + let amount_1: [u8; 16] = 100_u128.to_le_bytes(); + + let mut transfer_result_1 = FfiTransferResult::default(); + unsafe { + let to_identifier = FfiU128 { + data: 0_u128.to_le_bytes(), + }; + wallet_ffi_transfer_private( + wallet_ffi_handle, + &raw const from_private, + &raw const private_account_1_keys, + &raw const to_identifier, + &raw const amount_1, + &raw mut transfer_result_1, + ) + .unwrap(); + } + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + let amount_2: [u8; 16] = 101_u128.to_le_bytes(); + + let mut transfer_result_2 = FfiTransferResult::default(); + unsafe { + let to_identifier = FfiU128 { + data: 0_u128.to_le_bytes(), + }; + wallet_ffi_transfer_private( + wallet_ffi_handle, + &raw const from_private, + &raw const private_account_2_keys, + &raw const to_identifier, + &raw const amount_2, + &raw mut transfer_result_2, + ) + .unwrap(); + } + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + let amount_3: [u8; 16] = 102_u128.to_le_bytes(); + + let mut transfer_result_3 = FfiTransferResult::default(); + unsafe { + wallet_ffi_transfer_public( + wallet_ffi_handle, + &raw const from_public, + &raw const public_account_id_1, + &raw const amount_3, + &raw mut transfer_result_3, + ) + .unwrap(); + } + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + let amount_4: [u8; 16] = 103_u128.to_le_bytes(); + + let mut transfer_result_4 = FfiTransferResult::default(); + unsafe { + wallet_ffi_transfer_public( + wallet_ffi_handle, + &raw const from_public, + &raw const public_account_id_2, + &raw const amount_4, + &raw mut transfer_result_4, + ) + .unwrap(); + } + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + unsafe { + wallet_ffi_free_transfer_result(&raw mut transfer_result_1); + wallet_ffi_free_transfer_result(&raw mut transfer_result_2); + wallet_ffi_free_transfer_result(&raw mut transfer_result_3); + wallet_ffi_free_transfer_result(&raw mut transfer_result_4); + } + + info!("Preparation complete, performing keys restoration"); + + let password = CString::new(ctx.ctx().wallet_password())?; + + info!("Checking balance correctness before restoration"); + + let private_account_id_1_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const private_account_id_1, + false, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let private_account_id_2_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const private_account_id_2, + false, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let public_account_id_1_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const public_account_id_1, + true, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let public_account_id_2_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const public_account_id_2, + true, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + assert_eq!(private_account_id_1_balance, 100); + assert_eq!(private_account_id_2_balance, 101); + assert_eq!(public_account_id_1_balance, 102); + assert_eq!(public_account_id_2_balance, 103); + + unsafe { + wallet_ffi_restore_data(wallet_ffi_handle, *mnemonic, password.as_ptr()).unwrap(); + } + + // Sync private account local storage with onchain encrypted state + unsafe { + let mut current_height = 0; + wallet_ffi_get_current_block_height(wallet_ffi_handle, &raw mut current_height).unwrap(); + wallet_ffi_sync_to_block(wallet_ffi_handle, current_height).unwrap(); + }; + + info!("Checking balance correctness after restoration"); + + let private_account_id_1_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const private_account_id_1, + false, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let private_account_id_2_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const private_account_id_2, + false, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let public_account_id_1_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const public_account_id_1, + true, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + let public_account_id_2_balance = unsafe { + let mut out_balance: [u8; 16] = [0; 16]; + let _result = wallet_ffi_get_balance( + wallet_ffi_handle, + &raw const public_account_id_2, + true, + &raw mut out_balance, + ); + u128::from_le_bytes(out_balance) + }; + + assert_eq!(private_account_id_1_balance, 100); + assert_eq!(private_account_id_2_balance, 101); + assert_eq!(public_account_id_1_balance, 102); + assert_eq!(public_account_id_2_balance, 103); + + info!("Accounts restored"); + + Ok(()) +} diff --git a/lez/wallet-ffi/src/wallet.rs b/lez/wallet-ffi/src/wallet.rs index 93d5b158..02c79e5c 100644 --- a/lez/wallet-ffi/src/wallet.rs +++ b/lez/wallet-ffi/src/wallet.rs @@ -121,7 +121,8 @@ pub unsafe extern "C" fn wallet_ffi_create_new( return FfiCreateWalletResult::default(); }; - let boxed_mnemonic_string = Box::new(c_mnemonic_string.as_ptr()); + let raw_pointer = CString::into_raw(c_mnemonic_string); + let boxed_mnemonic_string = Box::new(raw_pointer.cast_const()); let raw_mnemonic_string_pointer = Box::into_raw(boxed_mnemonic_string); FfiCreateWalletResult { diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index 98e0ae19..90ef43b0 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -876,3 +876,27 @@ impl WalletCore { &self.config_overrides } } + +#[cfg(test)] +mod tests { + use std::{ffi::{CStr, CString}, str::FromStr}; + +use bip39::Mnemonic; + + #[test] + fn mnemonic_roundtrip() { + let mnemonic = Mnemonic::from_entropy(&[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]).unwrap(); + + let c_mnemonic_string = CString::new(mnemonic.to_string()).unwrap(); + + let boxed_mnemonic_string = Box::new(c_mnemonic_string.as_ptr()); + let raw_mnemonic_string_pointer = Box::into_raw(boxed_mnemonic_string); + + let c_str = unsafe { CStr::from_ptr(*raw_mnemonic_string_pointer) }; + let mn_string = c_str.to_str().unwrap(); + + let mn_ret = Mnemonic::from_str(mn_string).unwrap(); + + assert_eq!(mnemonic, mn_ret); + } +}