use std::{error::Error, str::FromStr, time::Duration};
use alloy_primitives::Address;
use onemoney_protocol::{Client, ClientBuilder, Network};
const TEST_TIMEOUT: Duration = Duration::from_secs(30);
mod test_utils {
use super::*;
pub fn create_test_client() -> Result<Client, Box<dyn std::error::Error>> {
Ok(ClientBuilder::new()
.network(Network::Testnet)
.timeout(TEST_TIMEOUT)
.build()?)
}
pub fn test_address() -> Address {
Address::from_str("0x1234567890abcdef1234567890abcdef12345678").expect("Valid test address")
}
}
#[tokio::test]
#[ignore]
async fn test_client_creation() -> std::result::Result<(), Box<dyn Error>> {
let _mainnet_client = Client::mainnet()?;
let _testnet_client = Client::testnet()?;
let _local_client = Client::local()?;
let _builder_client = ClientBuilder::new()
.network(Network::Local)
.timeout(Duration::from_secs(10))
.build()?;
let _custom_client = ClientBuilder::new()
.network(Network::Custom("http://localhost:8080".into()))
.timeout(Duration::from_secs(5))
.build()?;
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_network_connectivity() -> Result<(), Box<dyn Error>> {
let client = test_utils::create_test_client()?;
match client.fetch_chain_id_from_network().await {
Ok(chain_id) => {
println!("Successfully connected to test node. Chain ID: {}", chain_id);
assert!(chain_id > 0, "Chain ID should be positive");
}
Err(e) => {
println!("No test node available, skipping connectivity test: {}", e);
}
}
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_address_validation() -> Result<(), Box<dyn Error>> {
let valid_addresses = [
"0x1234567890abcdef1234567890abcdef12345678",
"0xAbCdEf1234567890AbCdEf1234567890AbCdEf12",
"0x0000000000000000000000000000000000000000",
"0xffffffffffffffffffffffffffffffffffffffff",
];
for addr_str in &valid_addresses {
let result = Address::from_str(addr_str);
assert!(result.is_ok(), "Address {} should be valid", addr_str);
}
let invalid_addresses = [
"", "0x123", "0x1234567890abcdef1234567890abcdef123456789", "0xGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", "0x 1234567890abcdef1234567890abcdef12345678", "not_a_valid_address", ];
for addr_str in &invalid_addresses {
let result = Address::from_str(addr_str);
assert!(result.is_err(), "Address {} should be invalid", addr_str);
}
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_error_handling() -> Result<(), Box<dyn Error>> {
let client = ClientBuilder::new()
.network(Network::Custom("http://127.0.0.1:1".into())) .timeout(Duration::from_secs(1))
.build()?;
let result = client.fetch_chain_id_from_network().await;
assert!(result.is_err(), "Should fail to connect to invalid endpoint");
match result {
Err(e) => {
println!("Expected error: {}", e);
let _debug_str = format!("{:?}", e);
let _display_str = format!("{}", e);
}
Ok(_) => panic!("Expected error but got success"),
}
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_timeout_handling() -> Result<(), Box<dyn Error>> {
let client = ClientBuilder::new()
.network(Network::Custom("http://httpbin.org/delay/10".into())) .timeout(Duration::from_millis(100)) .build()?;
let result = client.fetch_chain_id_from_network().await;
assert!(result.is_err(), "Should timeout with short timeout duration");
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_account_operations_offline() -> Result<(), Box<dyn Error>> {
let address = test_utils::test_address();
let address_str = address.to_string();
assert!(address_str.starts_with("0x"));
assert_eq!(address_str.len(), 42);
let parsed_address = Address::from_str(&address_str).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
assert_eq!(address, parsed_address);
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_chain_operations() -> Result<(), Box<dyn Error>> {
let client = test_utils::create_test_client()?;
let chain_id = client.fetch_chain_id_from_network().await?;
assert!(chain_id > 0);
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_account_operations() -> Result<(), Box<dyn Error>> {
let client = test_utils::create_test_client()?;
let address = test_utils::test_address();
match client.get_account_nonce(address).await {
Ok(nonce) => {
println!("Account nonce: {}", nonce);
}
Err(e) => {
println!("Account not found (expected): {}", e);
}
}
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_token_metadata() -> Result<(), Box<dyn Error>> {
let client = test_utils::create_test_client()?;
let token_address = test_utils::test_address();
match client.get_token_metadata(token_address).await {
Ok(metadata) => {
println!("Token metadata: {}", metadata);
}
Err(e) => {
println!("Token not found (expected): {}", e);
}
}
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_concurrent_requests() -> Result<(), Box<dyn Error>> {
use tokio::time::{Duration, timeout};
let mut handles = Vec::new();
for i in 0..5 {
let handle = tokio::spawn(async move {
println!("Starting request {}", i);
let client = test_utils::create_test_client().expect("Should create client");
let result = client.fetch_chain_id_from_network().await;
println!("Completed request {}: {:?}", i, result.is_ok());
result
});
handles.push(handle);
}
let timeout_duration = Duration::from_secs(10);
let results = timeout(timeout_duration, async {
let mut results = Vec::new();
for handle in handles {
results.push(handle.await.expect("Task should complete"));
}
results
})
.await
.expect("All requests should complete within timeout");
println!("Concurrent request results: {} total", results.len());
Ok(())
}
#[ignore]
#[tokio::test]
async fn test_performance_characteristics() -> Result<(), Box<dyn Error>> {
use std::time::Instant;
let client = test_utils::create_test_client()?;
let start = Instant::now();
let _result = client.fetch_chain_id_from_network().await;
let duration = start.elapsed();
println!("Single request took: {:?}", duration);
assert!(duration < Duration::from_secs(5), "Request should complete quickly");
Ok(())
}