Skip to content

Commit b98510d

Browse files
committed
Add session schedule struct encapsulating valid variants
1 parent 75821f5 commit b98510d

4 files changed

Lines changed: 358 additions & 2 deletions

File tree

crates/hotfix/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
143143
assert_eq!(config.sessions.len(), 1);
144144
let session = config.sessions.first().unwrap();
145145

146-
assert_eq!(session.schedule.is_some(), true);
146+
assert!(session.schedule.is_some());
147147
let schedule = session.schedule.as_ref().unwrap();
148148

149149
assert_eq!(schedule.start_time, NaiveTime::from_hms_opt(0, 0, 0));
@@ -185,7 +185,7 @@ end_day = "Friday"
185185
assert_eq!(config.sessions.len(), 1);
186186
let session = config.sessions.first().unwrap();
187187

188-
assert_eq!(session.schedule.is_some(), true);
188+
assert!(session.schedule.is_some());
189189
let schedule = session.schedule.as_ref().unwrap();
190190

191191
assert_eq!(schedule.start_time, NaiveTime::from_hms_opt(0, 0, 0));

crates/hotfix/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ pub enum MessageVerificationError {
1919
#[error("incorrect comp id {0}")]
2020
IncorrectCompId(String),
2121
}
22+
23+
#[derive(Debug, Error)]
24+
pub enum SessionError {
25+
#[error("Schedule configuration is invalid: {0}")]
26+
InvalidSchedule(String),
27+
}

crates/hotfix/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod initiator;
3030
pub mod message;
3131
mod message_utils;
3232
pub(crate) mod session;
33+
mod session_schedule;
3334
pub mod store;
3435
pub(crate) mod transport;
3536

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
use chrono::{NaiveTime, Weekday};
2+
3+
use crate::config::ScheduleConfig;
4+
use crate::error::SessionError;
5+
6+
#[derive(Clone, Debug)]
7+
#[allow(dead_code)]
8+
pub enum SessionSchedule {
9+
NonStop,
10+
Daily {
11+
start_time: NaiveTime,
12+
end_time: NaiveTime,
13+
},
14+
Weekdays {
15+
start_time: NaiveTime,
16+
end_time: NaiveTime,
17+
weekdays: Vec<Weekday>,
18+
},
19+
Weekly {
20+
start_day: Weekday,
21+
start_time: NaiveTime,
22+
end_day: Weekday,
23+
end_time: NaiveTime,
24+
},
25+
}
26+
27+
impl TryFrom<ScheduleConfig> for SessionSchedule {
28+
type Error = SessionError;
29+
30+
fn try_from(config: ScheduleConfig) -> Result<Self, Self::Error> {
31+
match config {
32+
// NonStop: no configuration provided
33+
ScheduleConfig {
34+
start_time: None,
35+
end_time: None,
36+
start_day: None,
37+
end_day: None,
38+
weekdays,
39+
} if weekdays.is_empty() => Ok(SessionSchedule::NonStop),
40+
41+
// Daily/Weekdays sessions
42+
ScheduleConfig {
43+
start_time: Some(start),
44+
end_time: Some(end),
45+
start_day: None,
46+
end_day: None,
47+
weekdays,
48+
} => {
49+
if weekdays.is_empty() {
50+
if start == end {
51+
Ok(SessionSchedule::NonStop)
52+
} else {
53+
Ok(SessionSchedule::Daily {
54+
start_time: start,
55+
end_time: end,
56+
})
57+
}
58+
} else if start == end {
59+
Err(SessionError::InvalidSchedule(
60+
"Start and end times cannot be equal when weekdays is set".to_string(),
61+
))
62+
} else {
63+
Ok(SessionSchedule::Weekdays {
64+
start_time: start,
65+
end_time: end,
66+
weekdays,
67+
})
68+
}
69+
}
70+
71+
// Weekly sessions
72+
ScheduleConfig {
73+
start_time: Some(start),
74+
end_time: Some(end),
75+
start_day: Some(start_day),
76+
end_day: Some(end_day),
77+
weekdays,
78+
} => {
79+
// Weekdays should be empty for weekly sessions
80+
if !weekdays.is_empty() {
81+
return Err(SessionError::InvalidSchedule(
82+
"Weekly sessions cannot have weekdays specified".to_string(),
83+
));
84+
}
85+
86+
Ok(SessionSchedule::Weekly {
87+
start_day,
88+
start_time: start,
89+
end_day,
90+
end_time: end,
91+
})
92+
}
93+
94+
// Invalid combinations
95+
_ => Err(SessionError::InvalidSchedule(
96+
"Invalid schedule configuration: incomplete or conflicting parameters".to_string(),
97+
)),
98+
}
99+
}
100+
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use super::*;
105+
use chrono::{NaiveTime, Weekday};
106+
107+
#[test]
108+
fn test_non_stop_no_config() {
109+
let config = ScheduleConfig {
110+
start_time: None,
111+
end_time: None,
112+
start_day: None,
113+
end_day: None,
114+
weekdays: vec![],
115+
};
116+
117+
let schedule = SessionSchedule::try_from(config).unwrap();
118+
assert!(matches!(schedule, SessionSchedule::NonStop));
119+
}
120+
121+
#[test]
122+
fn test_non_stop_equal_times() {
123+
let time = NaiveTime::from_hms_opt(9, 0, 0).unwrap();
124+
let config = ScheduleConfig {
125+
start_time: Some(time),
126+
end_time: Some(time),
127+
start_day: None,
128+
end_day: None,
129+
weekdays: vec![],
130+
};
131+
132+
let schedule = SessionSchedule::try_from(config).unwrap();
133+
assert!(matches!(schedule, SessionSchedule::NonStop));
134+
}
135+
136+
#[test]
137+
fn test_daily_session() {
138+
let config = ScheduleConfig {
139+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
140+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
141+
start_day: None,
142+
end_day: None,
143+
weekdays: vec![],
144+
};
145+
146+
let schedule = SessionSchedule::try_from(config).unwrap();
147+
match schedule {
148+
SessionSchedule::Daily {
149+
start_time,
150+
end_time,
151+
} => {
152+
assert_eq!(start_time, NaiveTime::from_hms_opt(9, 0, 0).unwrap());
153+
assert_eq!(end_time, NaiveTime::from_hms_opt(17, 0, 0).unwrap());
154+
}
155+
_ => panic!("Expected Daily schedule"),
156+
}
157+
}
158+
159+
#[test]
160+
fn test_weekdays_session() {
161+
let config = ScheduleConfig {
162+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
163+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
164+
start_day: None,
165+
end_day: None,
166+
weekdays: vec![
167+
Weekday::Mon,
168+
Weekday::Tue,
169+
Weekday::Wed,
170+
Weekday::Thu,
171+
Weekday::Fri,
172+
],
173+
};
174+
175+
let schedule = SessionSchedule::try_from(config).unwrap();
176+
match schedule {
177+
SessionSchedule::Weekdays {
178+
start_time,
179+
end_time,
180+
weekdays,
181+
} => {
182+
assert_eq!(start_time, NaiveTime::from_hms_opt(9, 0, 0).unwrap());
183+
assert_eq!(end_time, NaiveTime::from_hms_opt(17, 0, 0).unwrap());
184+
assert_eq!(
185+
weekdays,
186+
vec![
187+
Weekday::Mon,
188+
Weekday::Tue,
189+
Weekday::Wed,
190+
Weekday::Thu,
191+
Weekday::Fri
192+
]
193+
);
194+
}
195+
_ => panic!("Expected Weekdays schedule"),
196+
}
197+
}
198+
199+
#[test]
200+
fn test_weekly_session() {
201+
let config = ScheduleConfig {
202+
start_time: Some(NaiveTime::from_hms_opt(18, 0, 0).unwrap()),
203+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
204+
start_day: Some(Weekday::Sun),
205+
end_day: Some(Weekday::Fri),
206+
weekdays: vec![],
207+
};
208+
209+
let schedule = SessionSchedule::try_from(config).unwrap();
210+
match schedule {
211+
SessionSchedule::Weekly {
212+
start_day,
213+
start_time,
214+
end_day,
215+
end_time,
216+
} => {
217+
assert_eq!(start_day, Weekday::Sun);
218+
assert_eq!(start_time, NaiveTime::from_hms_opt(18, 0, 0).unwrap());
219+
assert_eq!(end_day, Weekday::Fri);
220+
assert_eq!(end_time, NaiveTime::from_hms_opt(17, 0, 0).unwrap());
221+
}
222+
_ => panic!("Expected Weekly schedule"),
223+
}
224+
}
225+
226+
#[test]
227+
fn test_weekly_session_with_equal_times_is_still_weekly() {
228+
let time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
229+
let config = ScheduleConfig {
230+
start_time: Some(time),
231+
end_time: Some(time),
232+
start_day: Some(Weekday::Mon),
233+
end_day: Some(Weekday::Fri),
234+
weekdays: vec![],
235+
};
236+
237+
let schedule = SessionSchedule::try_from(config).unwrap();
238+
assert!(matches!(schedule, SessionSchedule::Weekly { .. }));
239+
}
240+
241+
#[test]
242+
fn test_invalid_weekly_with_weekdays() {
243+
let config = ScheduleConfig {
244+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
245+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
246+
start_day: Some(Weekday::Mon),
247+
end_day: Some(Weekday::Fri),
248+
weekdays: vec![Weekday::Mon], // This should cause an error
249+
};
250+
251+
let result = SessionSchedule::try_from(config);
252+
assert!(result.is_err());
253+
match result.unwrap_err() {
254+
SessionError::InvalidSchedule(msg) => {
255+
assert!(msg.contains("Weekly sessions cannot have weekdays specified"));
256+
}
257+
}
258+
}
259+
260+
#[test]
261+
fn test_invalid_partial_config_start_time_only() {
262+
let config = ScheduleConfig {
263+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
264+
end_time: None,
265+
start_day: None,
266+
end_day: None,
267+
weekdays: vec![],
268+
};
269+
270+
let result = SessionSchedule::try_from(config);
271+
assert!(result.is_err());
272+
}
273+
274+
#[test]
275+
fn test_invalid_partial_config_end_time_only() {
276+
let config = ScheduleConfig {
277+
start_time: None,
278+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
279+
start_day: None,
280+
end_day: None,
281+
weekdays: vec![],
282+
};
283+
284+
let result = SessionSchedule::try_from(config);
285+
assert!(result.is_err());
286+
}
287+
288+
#[test]
289+
fn test_invalid_partial_config_start_day_only() {
290+
let config = ScheduleConfig {
291+
start_time: None,
292+
end_time: None,
293+
start_day: Some(Weekday::Mon),
294+
end_day: None,
295+
weekdays: vec![],
296+
};
297+
298+
let result = SessionSchedule::try_from(config);
299+
assert!(result.is_err());
300+
}
301+
302+
#[test]
303+
fn test_invalid_mixed_config() {
304+
let config = ScheduleConfig {
305+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
306+
end_time: None,
307+
start_day: Some(Weekday::Mon),
308+
end_day: None,
309+
weekdays: vec![],
310+
};
311+
312+
let result = SessionSchedule::try_from(config);
313+
assert!(result.is_err());
314+
}
315+
316+
#[test]
317+
fn test_weekdays_with_single_day() {
318+
let config = ScheduleConfig {
319+
start_time: Some(NaiveTime::from_hms_opt(9, 0, 0).unwrap()),
320+
end_time: Some(NaiveTime::from_hms_opt(17, 0, 0).unwrap()),
321+
start_day: None,
322+
end_day: None,
323+
weekdays: vec![Weekday::Sat],
324+
};
325+
326+
let schedule = SessionSchedule::try_from(config).unwrap();
327+
match schedule {
328+
SessionSchedule::Weekdays { weekdays, .. } => {
329+
assert_eq!(weekdays, vec![Weekday::Sat]);
330+
}
331+
_ => panic!("Expected Weekdays schedule"),
332+
}
333+
}
334+
335+
#[test]
336+
fn test_weekdays_with_equal_times_is_invalid() {
337+
let time = NaiveTime::from_hms_opt(10, 30, 0).unwrap();
338+
let config = ScheduleConfig {
339+
start_time: Some(time),
340+
end_time: Some(time),
341+
start_day: None,
342+
end_day: None,
343+
weekdays: vec![Weekday::Mon, Weekday::Wed, Weekday::Fri],
344+
};
345+
346+
let schedule = SessionSchedule::try_from(config);
347+
assert!(schedule.is_err());
348+
}
349+
}

0 commit comments

Comments
 (0)