Skip to main content

nautilus_model/events/order/spec/
emulated.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_core::{UUID4, UnixNanos};
17
18use crate::{
19    events::OrderEmulated,
20    identifiers::{ClientOrderId, InstrumentId, StrategyId, TraderId},
21    stubs::{TestDefault, test_uuid},
22};
23
24/// Test-only fluent spec for [`OrderEmulated`].
25///
26/// All fields carry sensible defaults so callers only set what differs.
27/// `build()` constructs the event through [`OrderEmulated::new`] so any future invariants
28/// added to the production constructor are exercised by tests built on this spec.
29#[derive(Debug, Clone, bon::Builder)]
30#[builder(finish_fn = into_spec)]
31pub struct OrderEmulatedSpec {
32    #[builder(default = TraderId::test_default())]
33    pub trader_id: TraderId,
34    #[builder(default = StrategyId::test_default())]
35    pub strategy_id: StrategyId,
36    #[builder(default = InstrumentId::test_default())]
37    pub instrument_id: InstrumentId,
38    #[builder(default = ClientOrderId::test_default())]
39    pub client_order_id: ClientOrderId,
40    #[builder(default = test_uuid())]
41    pub event_id: UUID4,
42    #[builder(default = UnixNanos::default())]
43    pub ts_event: UnixNanos,
44    #[builder(default = UnixNanos::default())]
45    pub ts_init: UnixNanos,
46}
47
48impl<S: order_emulated_spec_builder::IsComplete> OrderEmulatedSpecBuilder<S> {
49    /// Builds the spec and constructs an [`OrderEmulated`] through its production constructor.
50    #[must_use]
51    pub fn build(self) -> OrderEmulated {
52        let spec = self.into_spec();
53        OrderEmulated::new(
54            spec.trader_id,
55            spec.strategy_id,
56            spec.instrument_id,
57            spec.client_order_id,
58            spec.event_id,
59            spec.ts_event,
60            spec.ts_init,
61        )
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use rstest::rstest;
68
69    use super::*;
70    use crate::stubs::reset_test_uuid_rng;
71
72    #[rstest]
73    fn defaults_are_sensible() {
74        // Pin the spec's no-arg defaults so accidental drift in any individual default surfaces here,
75        // rather than as silent behavior change in downstream tests.
76        let event = OrderEmulatedSpec::builder().build();
77        assert_eq!(event.trader_id, TraderId::test_default());
78        assert_eq!(event.strategy_id, StrategyId::test_default());
79        assert_eq!(event.instrument_id, InstrumentId::test_default());
80        assert_eq!(event.client_order_id, ClientOrderId::test_default());
81        assert_eq!(event.ts_event, UnixNanos::default());
82        assert_eq!(event.ts_init, UnixNanos::default());
83    }
84
85    #[rstest]
86    fn overrides_apply_through_constructor() {
87        let event = OrderEmulatedSpec::builder()
88            .ts_event(UnixNanos::from(1_000))
89            .ts_init(UnixNanos::from(2_000))
90            .build();
91
92        assert_eq!(event.ts_event, UnixNanos::from(1_000));
93        assert_eq!(event.ts_init, UnixNanos::from(2_000));
94        assert_eq!(event.trader_id, TraderId::test_default());
95    }
96
97    #[rstest]
98    fn event_ids_are_unique_within_a_run() {
99        reset_test_uuid_rng();
100        let a = OrderEmulatedSpec::builder().build();
101        let b = OrderEmulatedSpec::builder().build();
102        let c = OrderEmulatedSpec::builder().build();
103        assert_ne!(a.event_id, b.event_id);
104        assert_ne!(b.event_id, c.event_id);
105        assert_ne!(a.event_id, c.event_id);
106    }
107
108    #[rstest]
109    fn event_id_sequence_is_reproducible() {
110        // Reset before each draw so the comparison is run-order independent.
111        reset_test_uuid_rng();
112        let first_run: Vec<_> = (0..3)
113            .map(|_| OrderEmulatedSpec::builder().build().event_id)
114            .collect();
115
116        reset_test_uuid_rng();
117        let second_run: Vec<_> = (0..3)
118            .map(|_| OrderEmulatedSpec::builder().build().event_id)
119            .collect();
120
121        assert_eq!(first_run, second_run);
122    }
123}