summaryrefslogtreecommitdiff
path: root/impls/monero.rs
diff options
context:
space:
mode:
Diffstat (limited to 'impls/monero.rs')
-rw-r--r--impls/monero.rs/Cargo.lock150
-rw-r--r--impls/monero.rs/Cargo.toml2
-rw-r--r--impls/monero.rs/src/lib.rs22
-rw-r--r--impls/monero.rs/src/main.rs26
-rw-r--r--impls/monero.rs/tests/integration_tests.rs265
5 files changed, 428 insertions, 37 deletions
diff --git a/impls/monero.rs/Cargo.lock b/impls/monero.rs/Cargo.lock
index bf7f0e5..9e79d0f 100644
--- a/impls/monero.rs/Cargo.lock
+++ b/impls/monero.rs/Cargo.lock
@@ -12,6 +12,12 @@ dependencies = [
]
[[package]]
+name = "anstyle"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+
+[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -64,12 +70,40 @@ dependencies = [
]
[[package]]
+name = "downcast"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
+
+[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
+[[package]]
+name = "fragile"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
+
+[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -101,6 +135,12 @@ dependencies = [
]
[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -119,12 +159,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
+name = "mockall"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a"
+dependencies = [
+ "cfg-if",
+ "downcast",
+ "fragile",
+ "mockall_derive",
+ "predicates",
+ "predicates-tree",
+]
+
+[[package]]
+name = "mockall_derive"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020"
+dependencies = [
+ "cfg-if",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "monero_rust"
version = "0.0.1"
dependencies = [
"bindgen",
"libc",
"libloading",
+ "mockall",
+ "tempfile",
]
[[package]]
@@ -138,6 +206,38 @@ dependencies = [
]
[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
+[[package]]
+name = "predicates"
+version = "3.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
+dependencies = [
+ "anstyle",
+ "predicates-core",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
+dependencies = [
+ "predicates-core",
+ "termtree",
+]
+
+[[package]]
name = "prettyplease"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -201,6 +301,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
+name = "rustix"
+version = "0.38.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -218,12 +331,49 @@ dependencies = [
]
[[package]]
+name = "tempfile"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "termtree"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+
+[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/impls/monero.rs/Cargo.toml b/impls/monero.rs/Cargo.toml
index b1b7c27..fa0e6ab 100644
--- a/impls/monero.rs/Cargo.toml
+++ b/impls/monero.rs/Cargo.toml
@@ -15,6 +15,8 @@ crate-type = ["lib", "cdylib"]
[dependencies]
libc = "0.2"
libloading = "0.8.5"
+mockall = "0.13.0"
+tempfile = "3.13.0"
[build-dependencies]
bindgen = "0.70.1"
diff --git a/impls/monero.rs/src/lib.rs b/impls/monero.rs/src/lib.rs
index 7c21c9d..c9b1d81 100644
--- a/impls/monero.rs/src/lib.rs
+++ b/impls/monero.rs/src/lib.rs
@@ -6,6 +6,17 @@ use std::sync::Arc;
use libloading::{Library, Symbol};
+#[cfg(target_os = "android")]
+const LIB_NAME: &str = "libmonero_libwallet2_api_c.so";
+#[cfg(target_os = "ios")]
+const LIB_NAME: &str = "MoneroWallet.framework/MoneroWallet";
+#[cfg(target_os = "linux")]
+const LIB_NAME: &str = "monero_libwallet2_api_c.so";
+#[cfg(target_os = "macos")]
+const LIB_NAME: &str = "monero_libwallet2_api_c.dylib";
+#[cfg(target_os = "windows")]
+const LIB_NAME: &str = "monero_libwallet2_api_c.dll";
+
pub mod network {
use std::os::raw::c_int;
pub const MAINNET: c_int = 0;
@@ -28,17 +39,6 @@ pub struct WalletManager {
library: Library,
}
-#[cfg(target_os = "android")]
-const LIB_NAME: &str = "libmonero_libwallet2_api_c.so";
-#[cfg(target_os = "ios")]
-const LIB_NAME: &str = "MoneroWallet.framework/MoneroWallet";
-#[cfg(target_os = "linux")]
-const LIB_NAME: &str = "monero_libwallet2_api_c.so";
-#[cfg(target_os = "macos")]
-const LIB_NAME: &str = "monero_libwallet2_api_c.dylib";
-#[cfg(target_os = "windows")]
-const LIB_NAME: &str = "monero_libwallet2_api_c.dll";
-
impl WalletManager {
/// Creates a new `WalletManager`, loading the Monero wallet library (`wallet2_api_c`).
pub fn new(lib_path: Option<&str>) -> WalletResult<Arc<Self>> {
diff --git a/impls/monero.rs/src/main.rs b/impls/monero.rs/src/main.rs
deleted file mode 100644
index 099c6d4..0000000
--- a/impls/monero.rs/src/main.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use monero_rust::{network, WalletError, WalletManager};
-
-fn main() -> Result<(), WalletError> {
- let wallet_manager = WalletManager::new(None)?;
-
- let wallet = wallet_manager.create_wallet(
- "wallet_name",
- "password",
- "English",
- network::MAINNET,
- )?;
-
- println!("Wallet created successfully.");
-
- match wallet.get_seed("") {
- Ok(seed) => println!("Seed: {}", seed),
- Err(e) => eprintln!("Failed to get seed: {:?}", e),
- }
-
- match wallet.get_address(0, 0) {
- Ok(address) => println!("Primary address: {}", address),
- Err(e) => eprintln!("Failed to get address: {:?}", e),
- }
-
- Ok(())
-}
diff --git a/impls/monero.rs/tests/integration_tests.rs b/impls/monero.rs/tests/integration_tests.rs
new file mode 100644
index 0000000..168e882
--- /dev/null
+++ b/impls/monero.rs/tests/integration_tests.rs
@@ -0,0 +1,265 @@
+use monero_rust::{WalletManager, network, WalletError, WalletResult};
+use std::fs;
+use std::sync::Arc;
+use std::time::Instant;
+use tempfile::TempDir;
+
+const TEST_WALLET_NAMES: &[&str] = &[
+ "test_wallet",
+ "mainnet_wallet",
+ "testnet_wallet",
+ "stagenet_wallet",
+];
+
+/// Helper function to clean up existing wallet files in a temporary directory.
+fn check_and_delete_existing_wallets(temp_dir: &TempDir) -> std::io::Result<()> {
+ for name in TEST_WALLET_NAMES {
+ // Construct absolute paths for wallet files.
+ let wallet_file = temp_dir.path().join(name);
+ let keys_file = temp_dir.path().join(format!("{}.keys", name));
+ let address_file = temp_dir.path().join(format!("{}.address.txt", name)); // Added
+
+ // Delete wallet file if it exists.
+ if wallet_file.exists() {
+ if let Err(e) = fs::remove_file(&wallet_file) {
+ println!("Warning: Failed to delete wallet file {:?}: {}", wallet_file, e);
+ } else {
+ println!("Deleted existing wallet file: {:?}", wallet_file);
+ }
+ }
+
+ // Delete keys file if it exists.
+ if keys_file.exists() {
+ if let Err(e) = fs::remove_file(&keys_file) {
+ println!("Warning: Failed to delete keys file {:?}: {}", keys_file, e);
+ } else {
+ println!("Deleted existing keys file: {:?}", keys_file);
+ }
+ }
+
+ // Delete address file if it exists.
+ if address_file.exists() {
+ if let Err(e) = fs::remove_file(&address_file) {
+ println!("Warning: Failed to delete address file {:?}: {}", address_file, e);
+ } else {
+ println!("Deleted existing address file: {:?}", address_file);
+ }
+ }
+ }
+ Ok(())
+}
+
+/// Sets up the test environment by creating a temporary directory and initializing the WalletManager.
+///
+/// Returns:
+/// - An `Arc` wrapped `WalletManager` instance.
+/// - A `TempDir` representing the temporary directory.
+fn setup() -> WalletResult<(Arc<WalletManager>, TempDir)> {
+ println!("Setting up test environment...");
+ let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");
+ check_and_delete_existing_wallets(&temp_dir).expect("Failed to clean up existing wallets");
+
+ println!("Creating WalletManager...");
+ let start = Instant::now();
+ let manager = WalletManager::new(None)?;
+ println!("WalletManager creation took {:?}", start.elapsed());
+
+ Ok((manager, temp_dir))
+}
+
+/// Tears down the test environment by deleting wallet files.
+///
+/// Args:
+/// - `temp_dir`: Reference to the temporary directory.
+///
+/// Returns:
+/// - `Result<(), std::io::Error>` indicating success or failure.
+fn teardown(temp_dir: &TempDir) -> std::io::Result<()> {
+ println!("Tearing down test environment...");
+ check_and_delete_existing_wallets(temp_dir)
+}
+
+#[test]
+fn test_wallet_manager_creation() {
+ println!("Running test_wallet_manager_creation");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet_result = manager.create_wallet(wallet_str, "password123", "English", network::MAINNET);
+ assert!(wallet_result.is_ok(), "WalletManager creation seems to have failed");
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_wallet_creation() {
+ println!("Running test_wallet_creation");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager.create_wallet(wallet_str, "password123", "English", network::MAINNET);
+ assert!(wallet.is_ok(), "Failed to create wallet");
+ let wallet = wallet.unwrap();
+ assert!(wallet.is_deterministic().is_ok(), "Wallet creation seems to have failed");
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_get_seed() {
+ println!("Running test_get_seed");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager
+ .create_wallet(wallet_str, "password123", "English", network::MAINNET)
+ .expect("Failed to create wallet");
+ println!("Attempting to get seed...");
+ let start = Instant::now();
+ let result = wallet.get_seed("");
+ println!("get_seed took {:?}", start.elapsed());
+ assert!(result.is_ok(), "Failed to get seed: {:?}", result.err());
+ assert!(!result.unwrap().is_empty(), "Seed is empty");
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_get_address() {
+ println!("Running test_get_address");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager
+ .create_wallet(wallet_str, "password123", "English", network::MAINNET)
+ .expect("Failed to create wallet");
+ println!("Attempting to get address...");
+ let start = Instant::now();
+ let result = wallet.get_address(0, 0);
+ println!("get_address took {:?}", start.elapsed());
+ assert!(result.is_ok(), "Failed to get address: {:?}", result.err());
+ assert!(!result.unwrap().is_empty(), "Address is empty");
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_is_deterministic() {
+ println!("Running test_is_deterministic");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager
+ .create_wallet(wallet_str, "password123", "English", network::MAINNET)
+ .expect("Failed to create wallet");
+ println!("Checking if wallet is deterministic...");
+ let start = Instant::now();
+ let result = wallet.is_deterministic();
+ println!("is_deterministic check took {:?}", start.elapsed());
+ assert!(result.is_ok(), "Failed to check if wallet is deterministic: {:?}", result.err());
+ assert!(result.unwrap(), "Wallet should be deterministic");
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_wallet_creation_with_different_networks() {
+ println!("Running test_wallet_creation_with_different_networks");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Define wallet names and corresponding network types.
+ let wallets = vec![
+ ("mainnet_wallet", network::MAINNET),
+ ("testnet_wallet", network::TESTNET),
+ ("stagenet_wallet", network::STAGENET),
+ ];
+
+ for (name, net_type) in wallets {
+ println!("Creating wallet: {} on network type {}", name, net_type);
+
+ // Construct the full path for each wallet within temp_dir.
+ let wallet_path = temp_dir.path().join(name);
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager.create_wallet(wallet_str, "password", "English", net_type);
+ assert!(wallet.is_ok(), "Failed to create wallet: {}", name);
+ }
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_multiple_address_generation() {
+ println!("Running test_multiple_address_generation");
+ let (manager, temp_dir) = setup().expect("Failed to set up test environment");
+
+ // Construct the full path for the wallet within temp_dir.
+ let wallet_path = temp_dir.path().join("test_wallet");
+ let wallet_str = wallet_path.to_str().expect("Failed to convert wallet path to string");
+
+ let wallet = manager
+ .create_wallet(wallet_str, "password123", "English", network::MAINNET)
+ .expect("Failed to create wallet");
+
+ for i in 0..5 {
+ println!("Generating address {}...", i);
+ let start = Instant::now();
+ let result = wallet.get_address(0, i);
+ println!("Address generation took {:?}", start.elapsed());
+ assert!(result.is_ok(), "Failed to get address {}: {:?}", i, result.err());
+ assert!(!result.unwrap().is_empty(), "Address {} is empty", i);
+ }
+
+ teardown(&temp_dir).expect("Failed to clean up after test");
+}
+
+#[test]
+fn test_wallet_error_display() {
+ println!("Running test_wallet_error_display");
+
+ // Test WalletError::FfiError variant.
+ let error = WalletError::FfiError("Test error".to_string());
+ match error {
+ WalletError::FfiError(msg) => assert_eq!(msg, "Test error"),
+ _ => panic!("Expected FfiError variant"),
+ }
+
+ // Test WalletError::NullPointer variant.
+ let error = WalletError::NullPointer;
+ match error {
+ WalletError::NullPointer => assert!(true),
+ _ => panic!("Expected NullPointer variant"),
+ }
+
+ // Test WalletError::WalletErrorCode variant.
+ let error = WalletError::WalletErrorCode(2, "Sample wallet error".to_string());
+ match error {
+ WalletError::WalletErrorCode(code, msg) => {
+ assert_eq!(code, 2);
+ assert_eq!(msg, "Sample wallet error");
+ },
+ _ => panic!("Expected WalletErrorCode variant"),
+ }
+
+ // Test WalletError::LibraryLoadError variant.
+ let error = WalletError::LibraryLoadError("Failed to load library".to_string());
+ match error {
+ WalletError::LibraryLoadError(msg) => assert_eq!(msg, "Failed to load library"),
+ _ => panic!("Expected LibraryLoadError variant"),
+ }
+}