1use std::fmt;
2
3#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
15pub struct Date {
16 date: DateImpl,
17}
18
19impl Date {
20 pub fn new(year: u16, month: u8, day: u8) -> Self {
32 Self {
33 date: DateImpl { year, month, day },
34 }
35 }
36
37 pub fn year(&self) -> u16 {
39 self.date.year
40 }
41
42 pub fn month(&self) -> u8 {
44 self.date.month
45 }
46
47 pub fn day(&self) -> u8 {
49 self.date.day
50 }
51
52 pub fn ymd(&self) -> impl fmt::Display {
64 let y = self.date.year;
65 let m = self.date.month;
66 let d = self.date.day;
67
68 format!("{y:04}-{m:02}-{d:02}")
69 }
70}
71
72#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
77struct DateImpl {
78 year: u16,
79 month: u8,
80 day: u8,
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use std::cmp::Ordering;
87
88 #[yare::parameterized(
89 zeroes = { Date::new(0, 0, 0), 0, 0, 0 },
90 one_two_three = { Date::new(1, 2, 3), 1, 2, 3 },
91 max = { Date::new(u16::MAX, u8::MAX, u8::MAX), u16::MAX, u8::MAX, u8::MAX },
92 )]
93 fn create_release_date(date: Date, year: u16, month: u8, day: u8) {
94 let expected = Date {
95 date: DateImpl { year, month, day },
96 };
97
98 assert_eq!(date, expected);
99 }
100
101 #[test]
102 fn compare_year() {
103 let smaller = Date::new(2000, 1, 1);
104 let bigger = Date::new(2001, 1, 1);
105
106 assert!(smaller < bigger);
107 assert!(smaller <= bigger);
108 }
109
110 #[test]
111 fn compare_month() {
112 let smaller = Date::new(2000, 1, 1);
113 let bigger = Date::new(2000, 2, 1);
114
115 assert!(smaller < bigger);
116 assert!(smaller <= bigger);
117 }
118
119 #[test]
120 fn compare_day() {
121 let smaller = Date::new(2000, 1, 1);
122 let bigger = Date::new(2000, 1, 2);
123
124 assert!(smaller < bigger);
125 assert!(smaller <= bigger);
126 }
127
128 #[yare::parameterized(
129 zeroes = { Date::new(0, 0, 0), "0000-00-00" },
130 fill_y = { Date::new(1, 10, 10), "0001-10-10" },
131 fill_m = { Date::new(1000, 1, 10), "1000-01-10" },
132 fill_d = { Date::new(1000, 10, 1), "1000-10-01" },
133 invalid_month_is_not_rejected = { Date::new(1000, 100, 1), "1000-100-01" },
134 invalid_day_is_not_rejected = { Date::new(1000, 1, 100), "1000-01-100" },
135 )]
136 fn to_string(date: Date, expected: &str) {
137 assert_eq!(date.ymd().to_string(), expected.to_string());
138 }
139
140 #[test]
141 fn newer_date() {
142 let newer = Date::new(2000, 1, 1);
143 let older = Date::new(1999, 1, 1);
144
145 assert_eq!(newer.cmp(&older), Ordering::Greater);
146 }
147}