feat: implement basic cycle between work and break modes

This commit is contained in:
Stevan Freeborn
2026-07-22 19:32:28 -05:00
parent 682e17e59d
commit ef9b18c173
2 changed files with 162 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
tab_spaces = 2
+161 -1
View File
@@ -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);
}
}