Skip to main content

appletheia_application/outbox/
outbox_published_at.rs

1use std::{fmt, fmt::Display};
2
3use chrono::{DateTime, Utc};
4
5#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
6pub struct OutboxPublishedAt(DateTime<Utc>);
7
8impl OutboxPublishedAt {
9    pub fn now() -> Self {
10        Self(Utc::now())
11    }
12
13    pub fn value(&self) -> DateTime<Utc> {
14        self.0
15    }
16}
17
18impl Default for OutboxPublishedAt {
19    fn default() -> Self {
20        Self::now()
21    }
22}
23
24impl From<DateTime<Utc>> for OutboxPublishedAt {
25    fn from(value: DateTime<Utc>) -> Self {
26        Self(value)
27    }
28}
29
30impl From<OutboxPublishedAt> for DateTime<Utc> {
31    fn from(value: OutboxPublishedAt) -> Self {
32        value.0
33    }
34}
35
36impl Display for OutboxPublishedAt {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{}", self.value())
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use chrono::TimeZone;
46
47    #[test]
48    fn new_produces_timestamp_close_to_now() {
49        let before = Utc::now();
50        let published_at = OutboxPublishedAt::now();
51        let after = Utc::now();
52
53        let published_at = published_at.value();
54        assert!(
55            published_at >= before,
56            "expected {published_at} to be after {before}"
57        );
58        assert!(
59            published_at <= after,
60            "expected {published_at} to be before {after}"
61        );
62    }
63
64    #[test]
65    fn value_returns_inner_datetime() {
66        let timestamp = Utc.with_ymd_and_hms(2024, 1, 2, 3, 4, 5).unwrap();
67        let published_at = OutboxPublishedAt::from(timestamp);
68
69        assert_eq!(published_at.value(), timestamp);
70    }
71
72    #[test]
73    fn conversions_round_trip() {
74        let timestamp = Utc.with_ymd_and_hms(2022, 6, 7, 8, 9, 10).unwrap();
75        let published_at: OutboxPublishedAt = timestamp.into();
76        let back_into_datetime: DateTime<Utc> = published_at.into();
77
78        assert_eq!(back_into_datetime, timestamp);
79    }
80
81    #[test]
82    fn display_matches_inner_datetime() {
83        let timestamp = Utc.with_ymd_and_hms(2030, 12, 31, 23, 59, 59).unwrap();
84        let published_at = OutboxPublishedAt::from(timestamp);
85
86        assert_eq!(published_at.to_string(), timestamp.to_string());
87    }
88}