diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..b196eaa --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +tab_spaces = 2 diff --git a/src/main.rs b/src/main.rs index e7a11a9..c7cd600 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,163 @@ +const SECONDS_PER_MIN: i64 = 60; + +#[derive(Debug, PartialEq)] +enum TimerState { + Work, + Break, + Paused, +} + +struct Termato { + work_mins: i64, + break_mins: i64, + state: TimerState, + prior_state: TimerState, + is_running: bool, + duration_in_secs: i64, + time_remaining_in_sec: i64, +} + +impl Termato { + fn new(work_mins: i64, break_mins: i64) -> Self { + Termato { + work_mins, + break_mins, + state: TimerState::Work, + prior_state: TimerState::Work, + is_running: false, + duration_in_secs: work_mins * SECONDS_PER_MIN, + time_remaining_in_sec: break_mins * SECONDS_PER_MIN, + } + } + + fn toggle_mode(&mut self) { + let is_on_break = self.state == TimerState::Break + || (self.state == TimerState::Paused && self.prior_state == TimerState::Break); + + if is_on_break { + self.state = TimerState::Work; + self.prior_state = TimerState::Work; + self.duration_in_secs = self.work_mins * SECONDS_PER_MIN; + } else { + self.state = TimerState::Break; + self.prior_state = TimerState::Break; + self.duration_in_secs = self.break_mins * SECONDS_PER_MIN; + } + + self.time_remaining_in_sec = self.duration_in_secs; + } + + fn tick(&mut self) { + if self.is_running && self.time_remaining_in_sec > 0 { + self.time_remaining_in_sec -= 1; + + if self.time_remaining_in_sec == 0 { + self.toggle_mode(); + } + } + } +} + fn main() { - println!("Hello, world!"); + let mut termato = Termato::new(1, 1); + + loop { + termato.is_running = true; + + termato.tick(); + + println!("Time remaining: {}", termato.time_remaining_in_sec); + println!("State: {:?}", termato.state); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn termato_when_called_it_should_return_expected_starting_state() { + let result = Termato::new(1, 1); + + assert_eq!(result.work_mins, 1); + assert_eq!(result.break_mins, 1); + assert_eq!(result.state, TimerState::Work); + assert_eq!(result.prior_state, TimerState::Work); + assert!(!result.is_running); + assert_eq!(result.duration_in_secs, 60); + assert_eq!(result.time_remaining_in_sec, 60); + } + + #[test] + fn termato_tick_when_called_and_not_running_it_should_do_nothing() { + let mut termato = Termato::new(1, 1); + + termato.tick(); + + assert_eq!(termato.time_remaining_in_sec, 60); + } + + #[test] + fn termato_tick_when_called_and_no_time_remaining_it_should_do_nothing() { + let mut termato = Termato::new(1, 1); + termato.is_running = true; + termato.time_remaining_in_sec = 0; + + termato.tick(); + + assert_eq!(termato.time_remaining_in_sec, 0); + } + + #[test] + fn termato_tick_when_running_and_time_reamining_it_should_reduce_remaining_by_one() { + let mut termato = Termato::new(1, 1); + termato.is_running = true; + + termato.tick(); + + assert_eq!(termato.time_remaining_in_sec, 59); + } + + #[test] + fn termato_tick_when_running_on_work_and_time_remaining_reaches_zero_it_should_toggle_to_break() { + let mut termato = Termato::new(1, 2); + termato.is_running = true; + termato.time_remaining_in_sec = 1; + + termato.tick(); + + assert_eq!(termato.state, TimerState::Break); + assert_eq!(termato.prior_state, TimerState::Break); + assert_eq!(termato.duration_in_secs, 120); + assert_eq!(termato.time_remaining_in_sec, 120); + } + + #[test] + fn termato_tick_when_running_on_break_and_time_remaining_reaches_zero_it_should_toggle_to_work() { + let mut termato = Termato::new(2, 1); + termato.state = TimerState::Break; + termato.is_running = true; + termato.time_remaining_in_sec = 1; + + termato.tick(); + + assert_eq!(termato.state, TimerState::Work); + assert_eq!(termato.prior_state, TimerState::Work); + assert_eq!(termato.duration_in_secs, 120); + assert_eq!(termato.time_remaining_in_sec, 120); + } + + #[test] + fn termato_toggle_mode_when_paused_and_previous_state_is_break_it_should_toggle_to_work() { + let mut termato = Termato::new(2, 1); + termato.state = TimerState::Paused; + termato.prior_state = TimerState::Break; + + termato.toggle_mode(); + + assert_eq!(termato.state, TimerState::Work); + assert_eq!(termato.prior_state, TimerState::Work); + assert_eq!(termato.duration_in_secs, 120); + assert_eq!(termato.time_remaining_in_sec, 120); + } }