#[cfg(test)]
mod tests {
use crate::price_level::PriceLevelStatistics;
use std::str::FromStr;
use std::sync::Arc;
use std::thread;
use std::time::{SystemTime, UNIX_EPOCH};
#[test]
fn test_new() {
let stats = PriceLevelStatistics::new();
assert_eq!(stats.orders_added(), 0);
assert_eq!(stats.orders_removed(), 0);
assert_eq!(stats.orders_executed(), 0);
assert_eq!(stats.quantity_executed(), 0);
assert_eq!(stats.value_executed(), 0);
assert_eq!(stats.last_execution_time(), 0);
assert!(stats.first_arrival_time() > 0);
assert_eq!(stats.sum_waiting_time(), 0);
}
#[test]
fn test_record_execution_error_paths() {
let stats = PriceLevelStatistics::new();
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64;
assert!(stats.record_execution(1, 100, now + 1_000, now).is_err());
assert!(stats.record_execution(u64::MAX, u128::MAX, 0, now).is_err());
}
#[test]
fn test_default() {
let stats = PriceLevelStatistics::default();
assert_eq!(stats.orders_added(), 0);
assert_eq!(stats.orders_removed(), 0);
assert_eq!(stats.orders_executed(), 0);
}
#[test]
fn test_record_operations() {
let stats = PriceLevelStatistics::new();
for _ in 0..5 {
stats.record_order_added();
}
assert_eq!(stats.orders_added(), 5);
for _ in 0..3 {
stats.record_order_removed();
}
assert_eq!(stats.orders_removed(), 3);
let execution_time: u64 = 1_716_000_000_000;
assert!(stats.record_execution(10, 100, 0, execution_time).is_ok()); assert_eq!(stats.orders_executed(), 1);
assert_eq!(stats.quantity_executed(), 10);
assert_eq!(stats.value_executed(), 1000); assert!(stats.last_execution_time() > 0);
let timestamp = execution_time - 1000;
assert!(
stats
.record_execution(5, 200, timestamp, execution_time)
.is_ok()
);
assert_eq!(stats.orders_executed(), 2);
assert_eq!(stats.quantity_executed(), 15); assert_eq!(stats.value_executed(), 2000); assert!(stats.sum_waiting_time() >= 1000); }
#[test]
fn test_average_execution_price() {
let stats = PriceLevelStatistics::new();
assert_eq!(stats.average_execution_price(), None);
let execution_time: u64 = 1_716_000_000_000;
assert!(stats.record_execution(10, 100, 0, execution_time).is_ok()); assert!(stats.record_execution(20, 150, 0, execution_time).is_ok());
let avg_price = stats.average_execution_price().unwrap();
assert!((avg_price - 133.33).abs() < 0.01);
}
#[test]
fn test_average_waiting_time() {
let stats = PriceLevelStatistics::new();
assert_eq!(stats.average_waiting_time(), None);
let now: u64 = 1_716_000_000_000;
assert!(stats.record_execution(10, 100, now - 1000, now).is_ok()); assert!(stats.record_execution(20, 150, now - 3000, now).is_ok());
let avg_wait = stats.average_waiting_time().unwrap();
assert!((1900.0..=2100.0).contains(&avg_wait));
}
#[test]
fn test_time_since_last_execution() {
let stats = PriceLevelStatistics::new();
assert_eq!(stats.time_since_last_execution(), None);
let past = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64
- 1000;
assert!(stats.record_execution(10, 100, 0, past).is_ok());
let time_since = stats.time_since_last_execution().unwrap();
assert!(time_since > 0);
}
#[test]
fn test_reset() {
let stats = PriceLevelStatistics::new();
stats.record_order_added();
stats.record_order_removed();
assert!(
stats
.record_execution(10, 100, 0, 1_716_000_000_000)
.is_ok()
);
assert_eq!(stats.orders_added(), 1);
assert_eq!(stats.orders_removed(), 1);
assert_eq!(stats.orders_executed(), 1);
stats.reset();
assert_eq!(stats.orders_added(), 0);
assert_eq!(stats.orders_removed(), 0);
assert_eq!(stats.orders_executed(), 0);
assert_eq!(stats.quantity_executed(), 0);
assert_eq!(stats.value_executed(), 0);
assert_eq!(stats.last_execution_time(), 0);
assert!(stats.first_arrival_time() > 0);
assert_eq!(stats.sum_waiting_time(), 0);
}
#[test]
fn test_display() {
let stats = PriceLevelStatistics::new();
stats.record_order_added();
stats.record_order_removed();
assert!(
stats
.record_execution(10, 100, 0, 1_716_000_000_000)
.is_ok()
);
let display_str = stats.to_string();
assert!(display_str.starts_with("PriceLevelStatistics:"));
assert!(display_str.contains("orders_added=1"));
assert!(display_str.contains("orders_removed=1"));
assert!(display_str.contains("orders_executed=1"));
assert!(display_str.contains("quantity_executed=10"));
assert!(display_str.contains("value_executed=1000"));
}
#[test]
fn test_from_str() {
let input = "PriceLevelStatistics:orders_added=5;orders_removed=3;orders_executed=2;quantity_executed=15;value_executed=2000;last_execution_time=1616823000000;first_arrival_time=1616823000001;sum_waiting_time=1000";
let stats = PriceLevelStatistics::from_str(input).unwrap();
assert_eq!(stats.orders_added(), 5);
assert_eq!(stats.orders_removed(), 3);
assert_eq!(stats.orders_executed(), 2);
assert_eq!(stats.quantity_executed(), 15);
assert_eq!(stats.value_executed(), 2000);
assert_eq!(stats.last_execution_time(), 1616823000000);
assert_eq!(stats.first_arrival_time(), 1616823000001);
assert_eq!(stats.sum_waiting_time(), 1000);
}
#[test]
fn test_from_str_invalid_format() {
let input = "InvalidFormat";
assert!(PriceLevelStatistics::from_str(input).is_err());
}
#[test]
fn test_from_str_missing_field() {
let input = "PriceLevelStatistics:orders_added=5;orders_removed=3;orders_executed=2;quantity_executed=15;value_executed=2000;last_execution_time=1616823000000;first_arrival_time=1616823000001";
assert!(PriceLevelStatistics::from_str(input).is_err());
}
#[test]
fn test_from_str_invalid_field_value() {
let input = "PriceLevelStatistics:orders_added=invalid;orders_removed=3;orders_executed=2;quantity_executed=15;value_executed=2000;last_execution_time=1616823000000;first_arrival_time=1616823000001;sum_waiting_time=1000";
assert!(PriceLevelStatistics::from_str(input).is_err());
}
#[test]
fn test_serialize_deserialize_json() {
let stats = PriceLevelStatistics::new();
stats.record_order_added();
stats.record_order_removed();
assert!(
stats
.record_execution(10, 100, 0, 1_716_000_000_000)
.is_ok()
);
let json = serde_json::to_string(&stats).unwrap();
assert!(json.contains("\"orders_added\":1"));
assert!(json.contains("\"orders_removed\":1"));
assert!(json.contains("\"orders_executed\":1"));
assert!(json.contains("\"quantity_executed\":10"));
assert!(json.contains("\"value_executed\":1000"));
let deserialized: PriceLevelStatistics = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.orders_added(), 1);
assert_eq!(deserialized.orders_removed(), 1);
assert_eq!(deserialized.orders_executed(), 1);
assert_eq!(deserialized.quantity_executed(), 10);
assert_eq!(deserialized.value_executed(), 1000);
}
#[test]
fn test_round_trip_display_parse() {
let current_time: u64 = 1616823000000;
let input = format!(
"PriceLevelStatistics:orders_added=2;orders_removed=1;orders_executed=2;quantity_executed=15;value_executed=2000;last_execution_time={};first_arrival_time={};sum_waiting_time=1000",
current_time,
current_time + 1
);
let stats = PriceLevelStatistics::from_str(&input).unwrap();
let string_representation = stats.to_string();
let parsed = PriceLevelStatistics::from_str(&string_representation).unwrap();
assert_eq!(parsed.orders_added(), stats.orders_added());
assert_eq!(parsed.orders_removed(), stats.orders_removed());
assert_eq!(parsed.orders_executed(), stats.orders_executed());
assert_eq!(parsed.quantity_executed(), stats.quantity_executed());
assert_eq!(parsed.value_executed(), stats.value_executed());
assert_eq!(parsed.last_execution_time(), stats.last_execution_time());
assert_eq!(parsed.first_arrival_time(), stats.first_arrival_time());
assert_eq!(parsed.sum_waiting_time(), stats.sum_waiting_time());
}
#[test]
fn test_thread_safety() {
let stats = PriceLevelStatistics::new();
let stats_arc = Arc::new(stats);
let mut handles = vec![];
for _ in 0..10 {
let stats_clone = Arc::clone(&stats_arc);
let handle = thread::spawn(move || {
for _ in 0..100 {
stats_clone.record_order_added();
stats_clone.record_order_removed();
if let Err(error) = stats_clone.record_execution(1, 100, 0, 1_716_000_000_000) {
panic!("record_execution failed in thread: {error}");
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(stats_arc.orders_added(), 1000); assert_eq!(stats_arc.orders_removed(), 1000);
assert_eq!(stats_arc.orders_executed(), 1000);
assert_eq!(stats_arc.quantity_executed(), 1000);
assert_eq!(stats_arc.value_executed(), 100000); }
#[test]
fn test_statistics_reset_and_verify() {
let stats = PriceLevelStatistics::new();
stats.record_order_added();
stats.record_order_added();
stats.record_order_removed();
assert!(
stats
.record_execution(10, 100, 0, 1_716_000_000_000)
.is_ok()
);
assert_eq!(stats.orders_added(), 2);
assert_eq!(stats.orders_removed(), 1);
assert_eq!(stats.orders_executed(), 1);
stats.reset();
assert_eq!(stats.orders_added(), 0);
assert_eq!(stats.orders_removed(), 0);
assert_eq!(stats.orders_executed(), 0);
assert_eq!(stats.quantity_executed(), 0);
assert_eq!(stats.value_executed(), 0);
assert_eq!(stats.last_execution_time(), 0);
assert!(stats.first_arrival_time() > 0);
assert_eq!(stats.sum_waiting_time(), 0);
}
#[test]
fn test_statistics_serialize_deserialize_fields() {
let input = "PriceLevelStatistics:orders_added=1;orders_removed=2;orders_executed=3;quantity_executed=4;value_executed=5;last_execution_time=6;first_arrival_time=7;sum_waiting_time=8";
let stats = PriceLevelStatistics::from_str(input).unwrap();
let serialized = serde_json::to_string(&stats).unwrap();
assert!(serialized.contains("\"orders_added\":1"));
assert!(serialized.contains("\"orders_removed\":2"));
assert!(serialized.contains("\"orders_executed\":3"));
assert!(serialized.contains("\"quantity_executed\":4"));
assert!(serialized.contains("\"value_executed\":5"));
assert!(serialized.contains("\"last_execution_time\":6"));
assert!(serialized.contains("\"first_arrival_time\":7"));
assert!(serialized.contains("\"sum_waiting_time\":8"));
let deserialized: PriceLevelStatistics = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.orders_added(), 1);
assert_eq!(deserialized.orders_removed(), 2);
assert_eq!(deserialized.orders_executed(), 3);
assert_eq!(deserialized.quantity_executed(), 4);
assert_eq!(deserialized.value_executed(), 5);
assert_eq!(deserialized.last_execution_time(), 6);
assert_eq!(deserialized.first_arrival_time(), 7);
assert_eq!(deserialized.sum_waiting_time(), 8);
}
#[test]
fn test_statistics_visitor_missing_fields() {
let json = r#"{
"orders_added": 1,
"orders_removed": 2,
"orders_executed": 3
}"#;
let deserialized: PriceLevelStatistics = serde_json::from_str(json).unwrap();
assert_eq!(deserialized.orders_added(), 1);
assert_eq!(deserialized.orders_removed(), 2);
assert_eq!(deserialized.orders_executed(), 3);
assert_eq!(deserialized.quantity_executed(), 0);
assert_eq!(deserialized.value_executed(), 0);
}
}