//! Test Utilities Module //! //! Comprehensive test utilities for safe, reliable testing patterns //! across the Foxhunt HFT trading system. pub mod hft_utils; pub mod test_safety; // Re-export commonly used items for convenience (macros are exported at crate root) // DO NOT RE-EXPORT - Use explicit imports at usage sites // Note: test_assert and test_assert_eq macros are exported at crate root automatically // DO NOT RE-EXPORT - Use explicit imports at usage sites /// Macro to create a test with automatic error handling and context #[macro_export] macro_rules! safe_test { ($test_name:ident, $test_fn:expr) => { #[tokio::test] async fn $test_name() { match $test_fn().await { Ok(()) => {}, Err(e) => { panic!("Test {} failed: {}", stringify!($test_name), e); }, } } }; } /// Macro to create a property based test #[macro_export] macro_rules! property_test { ($test_name:ident, $iterations:expr, $test_fn:expr) => { #[tokio::test] async fn $test_name() { use crate::utils::test_safety::property; match property::run_property_test(stringify!($test_name), $iterations, $test_fn) { Ok(()) => {}, Err(e) => { panic!("Property test {} failed: {}", stringify!($test_name), e); }, } } }; } /// Macro to create a performance benchmark test #[macro_export] macro_rules! benchmark_test { ($test_name:ident, $operation:expr, $max_latency:expr) => { #[tokio::test] async fn $test_name() { use crate::utils::hft_utils::performance; use std::time::Duration; let measurements = performance::benchmark_operation( $operation, 10, // warmup iterations 100, // measurement iterations stringify!($test_name), ) .await .expect("Benchmark should complete"); let avg_latency = measurements.average().expect("Should have measurements"); let p99_latency = measurements.percentile(0.99).expect("Should have p99"); println!( "Benchmark {}: avg={:?}, p99={:?}, max={:?}", stringify!($test_name), avg_latency, p99_latency, measurements.max().unwrap_or_default() ); if avg_latency > $max_latency { panic!( "Benchmark {} failed: average latency {:?} exceeds maximum {:?}", stringify!($test_name), avg_latency, $max_latency ); } } }; } /// Test configuration for different environments #[derive(Debug, Clone)] pub struct TestConfig { pub enable_chaos: bool, pub chaos_failure_rate: f64, pub default_timeout: std::time::Duration, pub hft_latency_requirement: std::time::Duration, pub enable_performance_validation: bool, } impl Default for TestConfig { fn default() -> Self { Self { enable_chaos: false, chaos_failure_rate: 0.1, default_timeout: std::time::Duration::from_secs(30), hft_latency_requirement: std::time::Duration::from_micros(50), enable_performance_validation: true, } } } impl TestConfig { pub fn for_unit_tests() -> Self { Self { enable_chaos: false, default_timeout: std::time::Duration::from_secs(5), ..Default::default() } } pub fn for_integration_tests() -> Self { Self { enable_chaos: false, default_timeout: std::time::Duration::from_secs(30), ..Default::default() } } pub fn for_chaos_tests() -> Self { Self { enable_chaos: true, chaos_failure_rate: 0.2, default_timeout: std::time::Duration::from_secs(60), ..Default::default() } } } /// Global test configuration accessor static TEST_CONFIG: std::sync::OnceLock = std::sync::OnceLock::new(); pub fn get_test_config() -> &'static TestConfig { TEST_CONFIG.get_or_init(|| { std::env::var("TEST_MODE") .map(|mode| match mode.as_str() { "unit" => TestConfig::for_unit_tests(), "integration" => TestConfig::for_integration_tests(), "chaos" => TestConfig::for_chaos_tests(), _ => TestConfig::default(), }) .unwrap_or_default() }) } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_config_default() { let config = TestConfig::default(); assert!(!config.enable_chaos); assert_eq!(config.chaos_failure_rate, 0.1); } #[tokio::test] async fn test_config_access() { let config = get_test_config(); assert!(config.default_timeout.as_secs() > 0); } }