#[cfg(test)]
mod tests {
use crate::orders::{Hash32, Id, OrderType, Side, TimeInForce};
use crate::price_level::order_queue::OrderQueue;
use crate::utils::{Price, Quantity, TimestampMs};
use std::str::FromStr;
use std::sync::Arc;
use tracing::info;
fn create_test_order(id: u64, price: u128, quantity: u64) -> OrderType<()> {
OrderType::<()>::Standard {
id: Id::from_u64(id),
price: Price::new(price),
quantity: Quantity::new(quantity),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000000),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
}
}
#[test]
fn test_display() {
let queue = OrderQueue::new();
queue.push(Arc::new(create_test_order(1, 1000u128, 10)));
queue.push(Arc::new(create_test_order(2, 1100u128, 20)));
let display_string = queue.to_string();
info!("Display: {}", display_string);
assert!(display_string.starts_with("OrderQueue:orders=["));
assert!(display_string.contains("id=00000000-0000-0001-0000-000000000000"));
assert!(display_string.contains("id=00000000-0000-0002-0000-000000000000"));
assert!(display_string.contains("price=1000"));
assert!(display_string.contains("price=1100"));
}
#[test]
fn test_from_str() {
let queue = OrderQueue::new();
queue.push(Arc::new(create_test_order(1, 1000u128, 10)));
queue.push(Arc::new(create_test_order(2, 1100u128, 20)));
let display_string = queue.to_string();
assert!(display_string.starts_with("OrderQueue:orders=["));
assert!(display_string.contains("id=00000000-0000-0001-0000-000000000000"));
assert!(display_string.contains("id=00000000-0000-0002-0000-000000000000"));
assert!(display_string.contains("price=1000"));
assert!(display_string.contains("price=1100"));
let input = "OrderQueue:orders=[Standard:id=00000000-0000-0001-0000-000000000000;price=1000;quantity=10;side=BUY;timestamp=1616823000000;time_in_force=GTC,Standard:id=00000000-0000-0002-0000-000000000000;price=1100;quantity=20;side=BUY;timestamp=1616823000000;time_in_force=GTC]";
let parsed_queue = match OrderQueue::from_str(input) {
Ok(q) => q,
Err(e) => {
info!("Parse error: {:?}", e);
info!("Input string: {}", input);
panic!("Failed to parse OrderQueue from string");
}
};
assert!(!parsed_queue.is_empty());
let orders = parsed_queue.to_vec();
assert_eq!(orders.len(), 2, "Expected 2 orders in parsed queue");
let has_order1 = orders.iter().any(|o| {
o.id() == Id::from_u64(1) && o.price() == Price::new(1000) && o.visible_quantity() == 10
});
let has_order2 = orders.iter().any(|o| {
o.id() == Id::from_u64(2) && o.price() == Price::new(1100) && o.visible_quantity() == 20
});
assert!(has_order1, "First order not found or incorrect");
assert!(has_order2, "Second order not found or incorrect");
let round_trip_queue = OrderQueue::from_str(&display_string).unwrap();
let round_trip_orders = round_trip_queue.to_vec();
assert_eq!(
round_trip_orders.len(),
2,
"Round-trip parsing should preserve order count"
);
let round_trip_has_order1 = round_trip_orders.iter().any(|o| {
o.id() == Id::from_u64(1) && o.price() == Price::new(1000) && o.visible_quantity() == 10
});
let round_trip_has_order2 = round_trip_orders.iter().any(|o| {
o.id() == Id::from_u64(2) && o.price() == Price::new(1100) && o.visible_quantity() == 20
});
assert!(
round_trip_has_order1,
"First order not preserved in round-trip"
);
assert!(
round_trip_has_order2,
"Second order not preserved in round-trip"
);
}
#[test]
fn test_serialize_deserialize() {
let queue = OrderQueue::new();
queue.push(Arc::new(create_test_order(1, 1000u128, 10)));
queue.push(Arc::new(create_test_order(2, 1100u128, 20)));
let serialized = serde_json::to_string(&queue).unwrap();
info!("Serialized: {}", serialized);
let deserialized: OrderQueue = serde_json::from_str(&serialized).unwrap();
let original_orders = queue.to_vec();
let deserialized_orders = deserialized.to_vec();
assert_eq!(original_orders.len(), deserialized_orders.len());
for order in original_orders {
let found = deserialized_orders.iter().any(|o| o.id() == order.id());
assert!(
found,
"Order with ID {} not found after deserialization",
order.id()
);
}
}
#[test]
fn test_round_trip() {
let queue = OrderQueue::new();
queue.push(Arc::new(create_test_order(1, 1000, 10)));
let string_rep = queue.to_string();
let parsed_queue = match OrderQueue::from_str(&string_rep) {
Ok(q) => q,
Err(e) => {
info!("Parse error: {:?}", e);
panic!("Failed to parse: {string_rep}");
}
};
let original_orders = queue.to_vec();
let parsed_orders = parsed_queue.to_vec();
assert_eq!(original_orders.len(), parsed_orders.len());
assert_eq!(original_orders[0].id(), parsed_orders[0].id());
assert_eq!(original_orders[0].price(), parsed_orders[0].price());
}
#[test]
fn test_order_queue_to_vec_empty() {
let queue = OrderQueue::new();
let vec = queue.to_vec();
assert!(vec.is_empty());
assert!(queue.is_empty());
}
#[test]
fn test_order_queue_from_str_complex() {
let complex_order = "Standard:id=00000000-0000-0001-0000-000000000000;price=10000;quantity=100;side=BUY;timestamp=1616823000000;time_in_force=GTD-1617000000000";
let input = format!("OrderQueue:orders=[{complex_order}]");
let queue = OrderQueue::from_str(&input).unwrap();
assert_eq!(queue.len(), 1);
let order = &queue.to_vec()[0];
if let OrderType::<()>::Standard {
id,
price,
quantity,
time_in_force,
..
} = **order
{
assert_eq!(id, Id::from_u64(1));
assert_eq!(price, Price::new(10000));
assert_eq!(quantity, Quantity::new(100));
assert!(matches!(time_in_force, TimeInForce::Gtd(1617000000000)));
} else {
panic!("Expected Standard order");
}
}
#[test]
fn test_order_queue_from_str_invalid_order() {
let input = "OrderQueue:orders=[InvalidOrder:id=1]";
let result = OrderQueue::from_str(input);
assert!(result.is_err());
}
#[test]
fn test_order_queue_serialization() {
fn create_standard_order(id: u64, price: u128, quantity: u64) -> OrderType<()> {
OrderType::Standard {
id: Id::from_u64(id),
price: Price::new(price),
quantity: Quantity::new(quantity),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000000),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
}
}
let queue = OrderQueue::new();
let order = create_standard_order(1, 10000u128, 100);
queue.push(Arc::new(order));
let serialized = serde_json::to_string(&queue).unwrap();
assert!(serialized.contains("\"Standard\""));
assert!(serialized.contains("\"id\":\"00000000-0000-0001-0000-000000000000\""));
assert!(serialized.contains("\"price\":10000"));
assert!(serialized.contains("\"quantity\":100"));
let deserialized: OrderQueue = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.len(), 1);
let deserialized_order = &deserialized.to_vec()[0];
if let OrderType::Standard {
id,
price,
quantity,
..
} = **deserialized_order
{
assert_eq!(id, Id::from_u64(1));
assert_eq!(price, Price::new(10000));
assert_eq!(quantity, Quantity::new(100));
} else {
panic!("Expected Standard order");
}
}
#[test]
fn test_order_queue_empty_check() {
let queue = OrderQueue::new();
assert!(queue.is_empty());
let order = OrderType::Standard {
id: Id::from_u64(1),
price: Price::new(1000),
quantity: Quantity::new(10),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000000),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
};
queue.push(Arc::new(order));
assert!(!queue.is_empty());
let _ = queue.pop();
assert!(queue.is_empty());
queue.push(Arc::new(order));
assert!(!queue.is_empty());
}
#[test]
fn test_order_queue_from_vec() {
let order1 = Arc::new(OrderType::Standard {
id: Id::from_u64(1),
price: Price::new(1000),
quantity: Quantity::new(10),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000000),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
});
let order2 = Arc::new(OrderType::Standard {
id: Id::from_u64(2),
price: Price::new(1000),
quantity: Quantity::new(20),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000001),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
});
let orders = vec![order1.clone(), order2.clone()];
let queue = OrderQueue::from_vec(orders.clone());
assert_eq!(queue.to_vec().len(), 2);
assert!(queue.to_vec().contains(&order1));
assert!(queue.to_vec().contains(&order2));
let queue_from_trait: OrderQueue = orders.clone().into();
assert_eq!(queue_from_trait.to_vec().len(), 2);
let orders_from_queue: Vec<Arc<OrderType<()>>> = queue.into();
assert_eq!(orders_from_queue.len(), 2);
assert!(orders_from_queue.contains(&order1));
assert!(orders_from_queue.contains(&order2));
}
#[test]
fn test_order_queue_from_str_parsing_with_complex_content() {
let complex_input = "OrderQueue:orders=[Standard:id=00000000-0000-0001-0000-000000000000;price=1000;quantity=10;side=BUY;timestamp=1616823000000;time_in_force=GTC,IcebergOrder:id=00000000-0000-0002-0000-000000000000;price=1000;visible_quantity=5;hidden_quantity=15;side=SELL;timestamp=1616823000001;time_in_force=GTC]";
let result = OrderQueue::from_str(complex_input);
assert!(result.is_ok());
let queue = result.unwrap();
assert_eq!(queue.to_vec().len(), 2);
let order_ids: Vec<Id> = queue.to_vec().iter().map(|order| order.id()).collect();
assert!(order_ids.contains(&Id::from_u64(1)));
assert!(order_ids.contains(&Id::from_u64(2)));
let empty_orders = "OrderQueue:orders=[]";
let result = OrderQueue::from_str(empty_orders);
assert!(result.is_ok());
let queue = result.unwrap();
assert!(queue.is_empty());
let invalid_input = "orders=[Standard:id=1;price=1000;quantity=10;side=BUY;timestamp=1616823000000;time_in_force=GTC]";
let result = OrderQueue::from_str(invalid_input);
assert!(result.is_err());
let malformed_input = "OrderQueue:orders=[Standard:id=00000000-0000-0001-0000-000000000000;price=1000;quantity=10;side=BUY;timestamp=1616823000000;time_in_force=GTC";
let result = OrderQueue::from_str(malformed_input);
assert!(result.is_err());
let invalid_order = "OrderQueue:orders=[InvalidOrder:id=00000000-0000-0001-0000-000000000000;price=1000;quantity=10;side=BUY;timestamp=1616823000000;time_in_force=GTC]";
let result = OrderQueue::from_str(invalid_order);
assert!(result.is_err());
}
#[test]
fn test_order_queue_serialization_deserialization() {
let queue = OrderQueue::new();
let order1 = OrderType::Standard {
id: Id::from_u64(1),
price: Price::new(1000),
quantity: Quantity::new(10),
side: Side::Buy,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000000),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
};
let order2 = OrderType::IcebergOrder {
id: Id::from_u64(2),
price: Price::new(1000),
visible_quantity: Quantity::new(5),
hidden_quantity: Quantity::new(15),
side: Side::Sell,
user_id: Hash32::zero(),
timestamp: TimestampMs::new(1616823000001),
time_in_force: TimeInForce::Gtc,
extra_fields: (),
};
queue.push(Arc::new(order1));
queue.push(Arc::new(order2));
let serialized = serde_json::to_string(&queue).unwrap();
assert!(serialized.contains("\"id\":\"00000000-0000-0001-0000-000000000000\""));
assert!(serialized.contains("\"id\":\"00000000-0000-0002-0000-000000000000\""));
let deserialized: OrderQueue = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.to_vec().len(), 2);
let order_ids: Vec<Id> = deserialized
.to_vec()
.iter()
.map(|order| order.id())
.collect();
assert!(order_ids.contains(&Id::from_u64(1)));
assert!(order_ids.contains(&Id::from_u64(2)));
}
}