habitrs/src/model.rs

102 lines
2.4 KiB
Rust

use std::collections::HashSet;
use anyhow::{anyhow, bail};
pub struct Date {
pub day: u8,
pub month: u8,
pub year: u16,
}
impl Date {
/// Create a day from String. Expects strings in format '06-26-2026'
pub fn from_string(val: &str) -> anyhow::Result<Self> {
let mut parts = val.split("-");
let month = parts
.next()
.ok_or(anyhow!("Month missing from date string"))?
.parse()?;
if month > 12 || month == 0 {
bail!("Month should be > 0 and <= 12")
}
let day = parts
.next()
.ok_or(anyhow!("Day missing from date string"))?
.parse()?;
if day == 0 {
bail!("Day must be > 0")
}
match month {
2 => {
if day > 29 {
bail!("February can have a max of 29 days (on leap years)")
}
}
4 | 6 | 9 | 11 => {
if day > 30 {
bail!("The provided month only has 30 days")
}
}
1 | 3 | 5 | 7 | 8 | 10 | 12 => {
if day > 31 {
bail!("The provided month only has 31 days")
}
}
_ => unreachable!(),
}
let year = parts
.next()
.ok_or(anyhow!("Year missing from date string"))?
.parse()?;
Ok(Date { day, month, year })
}
}
pub struct Habit {
pub name: String,
pub days_completed: HashSet<Date>,
}
#[cfg(test)]
mod test {
use crate::model::Date;
#[test]
fn correct_date_gets_parsed() {
let date = Date::from_string("06-16-2026").unwrap();
assert_eq!(date.day, 16);
assert_eq!(date.month, 6);
assert_eq!(date.year, 2026);
let date = Date::from_string("6-16-2026").unwrap();
assert_eq!(date.day, 16);
assert_eq!(date.month, 6);
assert_eq!(date.year, 2026);
let date = Date::from_string("6-6-2026").unwrap();
assert_eq!(date.day, 6);
assert_eq!(date.month, 6);
assert_eq!(date.year, 2026);
}
#[test]
fn bad_date_doesnt_get_parsed() {
let date = Date::from_string("-12-2026");
assert!(date.is_err());
let date = Date::from_string("13-01-2026");
assert!(date.is_err());
let date = Date::from_string("01-32-2026");
assert!(date.is_err());
}
}