//! Test helper utilities and common functions use chrono::Utc; // Import from workspace dependencies properly use common::{OrderSide, OrderStatus, OrderType, TimeInForce}; use rust_decimal::Decimal; use std::collections::HashMap; use trading_engine::trading_operations::TradingOrder; /// Generate a simple test ID instead of using uuid fn generate_test_id() -> String { use std::sync::atomic::{AtomicU64, Ordering}; static COUNTER: AtomicU64 = AtomicU64::new(1); format!("TEST_{}", COUNTER.fetch_add(1, Ordering::SeqCst)) } /// Create a test TradingOrder with all required fields pub fn create_test_order( symbol: &str, side: OrderSide, quantity: Decimal, price: Decimal, ) -> TradingOrder { TradingOrder { id: generate_test_id().into(), symbol: symbol.to_string(), account_id: None, side, order_type: OrderType::Limit, quantity, price, time_in_force: TimeInForce::Day, metadata: HashMap::new(), created_at: Utc::now(), submitted_at: None, executed_at: None, status: OrderStatus::Created, fill_quantity: Decimal::ZERO, average_fill_price: None, } } /// Create test configuration with sensible defaults pub fn create_test_config() -> TestConfig { TestConfig { initial_capital: Decimal::from(100_000), risk_free_rate: Decimal::new(2, 2), // 2% enable_logging: false, } } /// Test configuration structure #[derive(Debug, Clone)] pub struct TestConfig { /// Initial trading capital pub initial_capital: Decimal, /// Risk-free rate for calculations pub risk_free_rate: Decimal, /// Enable logging output pub enable_logging: bool, } impl Default for TestConfig { fn default() -> Self { create_test_config() } } /// Mock implementations for testing pub mod mock_implementations { use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::time::Duration; /// Mock performance monitor for testing #[derive(Debug, Clone)] pub struct MockPerformanceMonitor { stats: Arc>, } impl MockPerformanceMonitor { /// Create a new mock performance monitor pub fn new() -> Self { Self { stats: Arc::new(Mutex::new(PerformanceStats::default())), } } /// Record a single operation with its duration pub fn record_operation(&self, operation: &str, duration: Duration) { if let Ok(mut stats) = self.stats.lock() { stats.operations_count += 1; stats.total_duration += duration; stats.average_latency = stats.total_duration / stats.operations_count as u32; if duration > stats.max_latency { stats.max_latency = duration; } if duration < stats.min_latency || stats.min_latency == Duration::ZERO { stats.min_latency = duration; } stats .operation_latencies .insert(operation.to_string(), duration); } } /// Record a metric with a value and unit pub fn record_metric( &self, metric_name: &str, value: f64, unit: &str, ) -> Result<(), &'static str> { // Convert the metric value to a duration based on the unit let duration = match unit { "ns" => Duration::from_nanos(value as u64), "us" | "μs" => Duration::from_micros(value as u64), "ms" => Duration::from_millis(value as u64), "s" => Duration::from_secs(value as u64), // Non-time units - convert to a mock duration representation "ops/sec" | "orders/sec" | "ratio" | "ns/item" => { // For non-time units, store as microseconds for simplicity Duration::from_micros((value * 1000.0) as u64) }, _ => Duration::from_nanos(1000), // Default fallback }; self.record_operation(metric_name, duration); Ok(()) } /// Get current performance statistics pub fn get_stats(&self) -> PerformanceStats { self.stats.lock().expect("Failed to lock stats").clone() } /// Reset all statistics to default values pub fn reset(&self) { if let Ok(mut stats) = self.stats.lock() { *stats = PerformanceStats::default(); } } } impl Default for MockPerformanceMonitor { fn default() -> Self { Self::new() } } /// Performance statistics for testing #[derive(Debug, Clone)] pub struct PerformanceStats { /// Total number of operations recorded pub operations_count: u64, /// Total duration of all operations pub total_duration: Duration, /// Average operation latency pub average_latency: Duration, /// Minimum operation latency pub min_latency: Duration, /// Maximum operation latency pub max_latency: Duration, /// Individual operation latencies by name pub operation_latencies: HashMap, } impl Default for PerformanceStats { fn default() -> Self { Self { operations_count: 0, total_duration: Duration::ZERO, average_latency: Duration::ZERO, min_latency: Duration::ZERO, max_latency: Duration::ZERO, operation_latencies: HashMap::new(), } } } impl PerformanceStats { /// Calculate throughput in operations per second pub fn throughput_per_second(&self) -> f64 { if self.total_duration.as_secs_f64() > 0.0 { self.operations_count as f64 / self.total_duration.as_secs_f64() } else { 0.0 } } /// Get average latency in microseconds pub fn average_latency_micros(&self) -> u64 { self.average_latency.as_micros() as u64 } /// Get maximum latency in microseconds pub fn max_latency_micros(&self) -> u64 { self.max_latency.as_micros() as u64 } /// Get minimum latency in microseconds pub fn min_latency_micros(&self) -> u64 { self.min_latency.as_micros() as u64 } } }