1use thiserror::Error;
2
3mod cal;
4mod event;
5
6pub use cal::EventCalendar;
7pub use event::Event;
8
9#[derive(Error, Debug)]
11pub enum EventError {
12 #[error("start time/date cannot be after end time/date")]
14 InvalidStartTime,
15
16 #[error("end time/date cannot be before start time/date")]
18 InvalidEndTime,
19}
20
21#[cfg(test)]
27mod test {
28 use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
29
30 use super::*;
31
32 fn first_day_2023_nd() -> NaiveDate {
35 NaiveDate::from_ymd_opt(2023, 1, 1).unwrap()
36 }
37
38 fn first_time_nt() -> NaiveTime {
40 NaiveTime::from_hms_opt(0, 0, 0).unwrap()
41 }
42
43 fn last_time_nt() -> NaiveTime {
45 NaiveTime::from_hms_opt(23, 59, 59).unwrap()
46 }
47
48 fn first_day_2023_ndt() -> NaiveDateTime {
50 let nd = first_day_2023_nd();
51 let nt = first_time_nt();
52 NaiveDateTime::new(nd, nt)
53 }
54
55 #[test]
60 fn test_new_event() {
61 let naive_date = first_day_2023_nd();
62
63 let first_time = first_time_nt();
65 let last_time = last_time_nt();
66
67 let event = Event::new(String::from("Birthday Party"), &naive_date);
69
70 let assumed_start_time = NaiveDateTime::new(naive_date, first_time);
72 let assumed_end_time = NaiveDateTime::new(naive_date, last_time);
73
74 assert_eq!(event.start(), assumed_start_time);
75 assert_eq!(event.end(), assumed_end_time);
76 }
77
78 #[test]
79 fn test_event_start_time_change() {
80 let naive_date = first_day_2023_nd();
82
83 let mut event = Event::new(String::from("Birthday Party"), &naive_date);
85 let new_start_time = NaiveTime::from_hms_opt(10, 30, 0).unwrap();
87
88 event = event
89 .with_start(NaiveDateTime::new(naive_date, new_start_time))
90 .unwrap();
91 assert_eq!(
92 event.start(),
93 NaiveDateTime::new(naive_date, new_start_time)
94 )
95 }
96
97 #[test]
98 fn test_event_end_time_change() {
99 let naive_date = first_day_2023_nd();
101
102 let mut event = Event::new(String::from("Birthday Party"), &naive_date);
104 let new_end_time = NaiveTime::from_hms_opt(22, 30, 0).unwrap();
106
107 event = event
108 .with_end(NaiveDateTime::new(naive_date, new_end_time))
109 .unwrap();
110
111 assert_eq!(event.end(), NaiveDateTime::new(naive_date, new_end_time))
112 }
113
114 #[test]
115 fn test_invalid_event_time_change() {
116 let naive_date = first_day_2023_nd();
118 let start_time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
119 let invalid_end_time = NaiveTime::from_hms_opt(10, 0, 0).unwrap();
120
121 let mut event = Event::new("Birthday".into(), &naive_date);
122
123 event = event
124 .with_start(NaiveDateTime::new(naive_date, start_time))
125 .unwrap();
126
127 assert_eq!(
128 true,
129 event
130 .with_end(NaiveDateTime::new(naive_date, invalid_end_time))
131 .is_err()
132 );
133 }
134
135 #[test]
136 fn invalid_events_test() {
137 let naive_date = first_day_2023_nd();
139
140 let first_time = first_time_nt();
142 let last_time = last_time_nt();
143
144 let mut event = Event::new(String::from("Birthday Party"), &naive_date);
146
147 let assumed_start_time = NaiveDateTime::new(naive_date, first_time);
149 let assumed_end_time = NaiveDateTime::new(naive_date, last_time);
150
151 assert_eq!(event.start(), assumed_start_time);
152 assert_eq!(event.end(), assumed_end_time);
153
154 let new_start_time = NaiveTime::from_hms_opt(10, 30, 0).unwrap();
156
157 event = event
159 .with_start(NaiveDateTime::new(naive_date, new_start_time))
160 .unwrap();
161
162 assert_eq!(
163 event.start(),
164 NaiveDateTime::new(naive_date, new_start_time)
165 );
166
167 let new_end_time = NaiveTime::from_hms_opt(22, 30, 0).unwrap();
169
170 event = event
172 .with_end(NaiveDateTime::new(naive_date, new_end_time))
173 .unwrap();
174
175 assert_eq!(event.end(), NaiveDateTime::new(naive_date, new_end_time));
176
177 let status = event.with_start(NaiveDateTime::new(naive_date, last_time));
179 assert_eq!(true, status.is_err());
180
181 let event = Event::new(String::from("Birthday Party"), &naive_date);
183 let status = event.with_end(NaiveDateTime::new(naive_date, first_time));
184 assert_eq!(true, status.is_err());
185 }
186
187 #[test]
188 fn test_event_ordering_lt_start_cmp() {
189 use std::cmp::Ordering;
190 let ndt = first_day_2023_ndt();
191 let d1 = Event::new("A".into(), &ndt.date());
192
193 let mut d2 = Event::new("A".into(), &ndt.date());
195 d2 = d2.with_start(d1.start().with_second(1).unwrap()).unwrap();
196 assert_eq!(d1.cmp(&d2), Ordering::Less);
197
198 let mut d3 = Event::new("A".into(), &ndt.date());
200 d3 = d3.with_start(d1.start().with_minute(1).unwrap()).unwrap();
201 assert_eq!(d1.cmp(&d3), Ordering::Less);
202
203 let mut d4 = Event::new("A".into(), &ndt.date());
205 d4 = d4.with_start(d1.start().with_hour(1).unwrap()).unwrap();
206 assert_eq!(d1.cmp(&d4), Ordering::Less);
207
208 let d5 = Event::new("A".into(), &ndt.date().with_year(2024).unwrap());
210 assert_eq!(d1.cmp(&d5), Ordering::Less);
211
212 let mut d6 = Event::new("A".into(), &ndt.date());
214 d6 = d6.with_end(d1.start().with_day(3).unwrap()).unwrap();
215 d6 = d6.with_start(d1.start().with_day(2).unwrap()).unwrap();
216 assert_eq!(d1.cmp(&d6), Ordering::Less);
217
218 let mut d7 = Event::new("A".into(), &ndt.date());
220 d7 = d7.with_end(d1.start().with_month(3).unwrap()).unwrap();
221 d7 = d7.with_start(d1.start().with_month(2).unwrap()).unwrap();
222 assert_eq!(d1.cmp(&d7), Ordering::Less);
223 }
224
225 #[test]
226 fn test_event_range() {
227 let nd1 = first_day_2023_nd();
228 let nd2 = nd1.with_day(2).unwrap();
229 let nd3 = nd1.with_day(3).unwrap();
230 let nd4 = nd1.with_day(4).unwrap();
231 let nd5 = nd1.with_day(5).unwrap();
232
233 let e1 = Event::new("A".into(), &nd1);
234 let e2 = Event::new("A".into(), &nd2);
235 let e3 = Event::new("A".into(), &nd3);
236 let e4 = Event::new("A".into(), &nd4);
237 let e5 = Event::new("A".into(), &nd5);
238
239 let range_start = NaiveDateTime::new(nd2, NaiveTime::from_hms_opt(11, 0, 0).unwrap());
240 let range_end = NaiveDateTime::new(nd4, last_time_nt());
241
242 let mut cal = EventCalendar::default();
243 cal.add_event(e1);
244 cal.add_event(e2);
245 cal.add_event(e3);
246 cal.add_event(e4);
247 cal.add_event(e5);
248
249 let mut iter = cal.events_in_range(range_start, range_end);
250 assert_eq!(
251 iter.next().map(|(_, e)| e),
252 Some(&Event::new("A".into(), &nd2))
253 );
254 assert_eq!(
255 iter.next().map(|(_, e)| e),
256 Some(&Event::new("A".into(), &nd3))
257 );
258 assert_eq!(
259 iter.next().map(|(_, e)| e),
260 Some(&Event::new("A".into(), &nd4))
261 );
262 assert_eq!(iter.next(), None);
263 }
264
265 #[test]
266 fn test_event_serialize() {
267 let nd = first_day_2023_nd();
268 let e = Event::new("A".into(), &nd);
269
270 let first_time = first_day_2023_ndt().format("%Y-%m-%dT%H:%M:%S").to_string();
271 let last_time = NaiveDateTime::new(nd, last_time_nt())
272 .format("%Y-%m-%dT%H:%M:%S")
273 .to_string();
274
275 assert_eq!(
276 e.serialize(),
277 format!("{{\"start\":\"{first_time}\",\"end\":\"{last_time}\",\"name\":\"A\"}}",)
278 )
279 }
280}