prism3_clock/controllable_clock.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Controllable clock trait for testing.
10//!
11//! This module defines the [`ControllableClock`] trait, which extends
12//! [`Clock`] to provide methods for controlling the clock's time. This is
13//! primarily useful for testing scenarios.
14//!
15//! # Author
16//!
17//! Haixing Hu
18
19use crate::Clock;
20use chrono::{DateTime, Duration, Utc};
21
22/// A trait representing a clock that can be controlled.
23///
24/// This trait extends [`Clock`] to provide methods for manually setting and
25/// advancing the clock's time. It's primarily designed for testing scenarios
26/// where you need precise control over time.
27///
28/// # Warning
29///
30/// This trait should only be used in testing code, not in production code.
31///
32/// # Examples
33///
34/// ```
35/// use prism3_clock::{Clock, ControllableClock, MockClock};
36/// use chrono::{DateTime, Duration, Utc};
37///
38/// let clock = MockClock::new();
39///
40/// // Set to a specific time
41/// let fixed_time = DateTime::parse_from_rfc3339(
42/// "2024-01-01T00:00:00Z"
43/// ).unwrap().with_timezone(&Utc);
44/// clock.set_time(fixed_time);
45///
46/// assert_eq!(clock.time(), fixed_time);
47///
48/// // Advance by 1 hour
49/// clock.add_duration(Duration::hours(1));
50/// assert_eq!(
51/// clock.time(),
52/// fixed_time + Duration::hours(1)
53/// );
54/// ```
55///
56/// # Author
57///
58/// Haixing Hu
59pub trait ControllableClock: Clock {
60 /// Sets the clock to a specific time.
61 ///
62 /// # Arguments
63 ///
64 /// * `instant` - The time to set the clock to (UTC).
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use prism3_clock::{Clock, ControllableClock, MockClock};
70 /// use chrono::{DateTime, Utc};
71 ///
72 /// let clock = MockClock::new();
73 /// let time = DateTime::parse_from_rfc3339(
74 /// "2024-01-01T00:00:00Z"
75 /// ).unwrap().with_timezone(&Utc);
76 ///
77 /// clock.set_time(time);
78 /// assert_eq!(clock.time(), time);
79 /// ```
80 fn set_time(&self, instant: DateTime<Utc>);
81
82 /// Advances the clock by the specified duration.
83 ///
84 /// # Arguments
85 ///
86 /// * `duration` - The duration to advance the clock by.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use prism3_clock::{Clock, ControllableClock, MockClock};
92 /// use chrono::Duration;
93 ///
94 /// let clock = MockClock::new();
95 /// let before = clock.time();
96 ///
97 /// clock.add_duration(Duration::hours(1));
98 ///
99 /// let after = clock.time();
100 /// assert_eq!(after - before, Duration::hours(1));
101 /// ```
102 fn add_duration(&self, duration: Duration);
103
104 /// Resets the clock to its initial state.
105 ///
106 /// The exact behavior of this method depends on the implementation. For
107 /// [`MockClock`](crate::MockClock), it resets to the time when the clock
108 /// was created.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use prism3_clock::{Clock, ControllableClock, MockClock};
114 /// use chrono::Duration;
115 ///
116 /// let clock = MockClock::new();
117 /// let initial = clock.time();
118 ///
119 /// clock.add_duration(Duration::hours(1));
120 /// clock.reset();
121 ///
122 /// // After reset, time should be close to initial time
123 /// let diff = (clock.time() - initial).num_milliseconds().abs();
124 /// assert!(diff < 100); // Allow small difference
125 /// ```
126 fn reset(&self);
127}