use nautilus_core::{UUID4, UnixNanos};
use ustr::Ustr;
use crate::{
events::OrderDenied,
identifiers::{ClientOrderId, InstrumentId, StrategyId, TraderId},
stubs::{TestDefault, test_uuid},
};
#[derive(Debug, Clone, bon::Builder)]
#[builder(finish_fn = into_spec)]
pub struct OrderDeniedSpec {
#[builder(default = TraderId::test_default())]
pub trader_id: TraderId,
#[builder(default = StrategyId::test_default())]
pub strategy_id: StrategyId,
#[builder(default = InstrumentId::test_default())]
pub instrument_id: InstrumentId,
#[builder(default = ClientOrderId::test_default())]
pub client_order_id: ClientOrderId,
#[builder(default = Ustr::from("TEST"))]
pub reason: Ustr,
#[builder(default = test_uuid())]
pub event_id: UUID4,
#[builder(default = UnixNanos::default())]
pub ts_event: UnixNanos,
#[builder(default = UnixNanos::default())]
pub ts_init: UnixNanos,
}
impl<S: order_denied_spec_builder::IsComplete> OrderDeniedSpecBuilder<S> {
#[must_use]
pub fn build(self) -> OrderDenied {
let spec = self.into_spec();
OrderDenied::new(
spec.trader_id,
spec.strategy_id,
spec.instrument_id,
spec.client_order_id,
spec.reason,
spec.event_id,
spec.ts_event,
spec.ts_init,
)
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
use crate::stubs::reset_test_uuid_rng;
#[rstest]
fn defaults_are_sensible() {
let event = OrderDeniedSpec::builder().build();
assert_eq!(event.trader_id, TraderId::test_default());
assert_eq!(event.strategy_id, StrategyId::test_default());
assert_eq!(event.instrument_id, InstrumentId::test_default());
assert_eq!(event.client_order_id, ClientOrderId::test_default());
assert_eq!(event.reason, Ustr::from("TEST"));
assert_eq!(event.ts_event, UnixNanos::default());
assert_eq!(event.ts_init, UnixNanos::default());
}
#[rstest]
fn overrides_apply_through_constructor() {
let event = OrderDeniedSpec::builder()
.reason(Ustr::from("MAX_ORDER_RATE"))
.ts_event(UnixNanos::from(1_000))
.ts_init(UnixNanos::from(2_000))
.build();
assert_eq!(event.reason, Ustr::from("MAX_ORDER_RATE"));
assert_eq!(event.ts_event, UnixNanos::from(1_000));
assert_eq!(event.ts_init, UnixNanos::from(2_000));
assert_eq!(event.trader_id, TraderId::test_default());
}
#[rstest]
fn event_ids_are_unique_within_a_run() {
reset_test_uuid_rng();
let a = OrderDeniedSpec::builder().build();
let b = OrderDeniedSpec::builder().build();
let c = OrderDeniedSpec::builder().build();
assert_ne!(a.event_id, b.event_id);
assert_ne!(b.event_id, c.event_id);
assert_ne!(a.event_id, c.event_id);
}
#[rstest]
fn event_id_sequence_is_reproducible() {
reset_test_uuid_rng();
let first_run: Vec<_> = (0..3)
.map(|_| OrderDeniedSpec::builder().build().event_id)
.collect();
reset_test_uuid_rng();
let second_run: Vec<_> = (0..3)
.map(|_| OrderDeniedSpec::builder().build().event_id)
.collect();
assert_eq!(first_run, second_run);
}
}