use crate::text_expand::{ExpandResult, ExpandTask, ExpandUnit};
use std::collections::VecDeque;
pub struct EnHourExpandTask;
impl ExpandTask for EnHourExpandTask {
fn expand(&self, queue: &VecDeque<ExpandUnit>) -> Option<ExpandResult> {
if queue.len() < 3 {
if let Some(ExpandUnit::Number(_)) = queue.front() {
if queue.len() == 1 {
return Some(ExpandResult::Maybe);
}
if let Some(ExpandUnit::Mark(':')) = queue.get(1) {
return Some(ExpandResult::Maybe);
}
}
return None;
}
if let (
Some(ExpandUnit::Number(hh)),
Some(ExpandUnit::Mark(':')),
Some(ExpandUnit::Number(mm)),
) = (queue.front(), queue.get(1), queue.get(2))
{
let h_val = hh.parse::<u32>().unwrap_or(25);
let m_val = mm.parse::<u32>().unwrap_or(61);
if h_val < 24 && m_val < 60 && mm.len() == 2 {
let mut replacement = vec![];
replacement.push(ExpandUnit::Number(hh.clone()));
if m_val == 0 {
replacement.push(ExpandUnit::Word("o'clock".into()));
} else {
if m_val < 10 {
replacement.push(ExpandUnit::Word("oh".into()));
}
replacement.push(ExpandUnit::Number(mm.clone()));
}
return Some(ExpandResult::Replace(3, replacement));
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_en_hour_expansion() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("12".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("05".into()));
let res = task.expand(&queue).unwrap();
if let ExpandResult::Replace(n, units) = res {
assert_eq!(n, 3);
assert_eq!(
units,
vec![
ExpandUnit::Number("12".into()),
ExpandUnit::Word("oh".into()),
ExpandUnit::Number("05".into()),
]
);
} else {
panic!("Expected Replace result");
}
}
#[test]
fn test_en_hour_no_expand_ratio() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("16".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("9".into()));
let res = task.expand(&queue);
assert!(
res.is_none(),
"16:9 should not be expanded as a time (it's an aspect ratio)"
);
}
#[test]
fn test_en_hour_midnight() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("00".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("00".into()));
let res = task.expand(&queue).unwrap();
if let ExpandResult::Replace(n, units) = res {
assert_eq!(n, 3);
assert_eq!(
units,
vec![
ExpandUnit::Number("00".into()),
ExpandUnit::Word("o'clock".into()),
]
);
} else {
panic!("Expected Replace result for midnight");
}
}
#[test]
fn test_en_hour_invalid_hour() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("25".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("30".into()));
let res = task.expand(&queue);
assert!(
res.is_none(),
"25:30 has invalid hour and should not expand"
);
}
#[test]
fn test_en_hour_invalid_minute() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("12".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("61".into()));
let res = task.expand(&queue);
assert!(
res.is_none(),
"12:61 has invalid minute and should not expand"
);
}
#[test]
fn test_en_hour_maybe_single_number() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("12".into()));
let res = task.expand(&queue);
assert!(
matches!(res, Some(ExpandResult::Maybe)),
"Single number should return Maybe"
);
}
#[test]
fn test_en_hour_maybe_number_colon() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("12".into()));
queue.push_back(ExpandUnit::Mark(':'));
let res = task.expand(&queue);
assert!(
matches!(res, Some(ExpandResult::Maybe)),
"Number + ':' without minutes should return Maybe"
);
}
#[test]
fn test_en_hour_thirty_minutes() {
let task = EnHourExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("12".into()));
queue.push_back(ExpandUnit::Mark(':'));
queue.push_back(ExpandUnit::Number("30".into()));
let res = task.expand(&queue).unwrap();
if let ExpandResult::Replace(n, units) = res {
assert_eq!(n, 3);
assert_eq!(
units,
vec![
ExpandUnit::Number("12".into()),
ExpandUnit::Number("30".into()),
]
);
} else {
panic!("Expected Replace result");
}
}
}