use crate::text_expand::{ExpandResult, ExpandTask, ExpandUnit};
use std::collections::VecDeque;
use super::ordinal_words_en;
pub struct EnDateExpandTask;
impl ExpandTask for EnDateExpandTask {
fn expand(&self, queue: &VecDeque<ExpandUnit>) -> Option<ExpandResult> {
if queue.len() < 5 {
if let Some(ExpandUnit::Number(_)) = queue.front() {
if queue.len() == 1 {
return Some(ExpandResult::Maybe);
}
if let Some(ExpandUnit::Mark('/')) = queue.get(1) {
if queue.len() == 2 {
return Some(ExpandResult::Maybe);
}
if let Some(ExpandUnit::Number(_)) = queue.get(2) {
if queue.len() == 3 {
return Some(ExpandResult::Maybe);
}
if let Some(ExpandUnit::Mark('/')) = queue.get(3)
&& queue.len() == 4
{
return Some(ExpandResult::Maybe);
}
}
}
}
return None;
}
match (
queue.front(),
queue.get(1),
queue.get(2),
queue.get(3),
queue.get(4),
) {
(
Some(ExpandUnit::Number(day)),
Some(ExpandUnit::Mark('/')),
Some(ExpandUnit::Number(month)),
Some(ExpandUnit::Mark('/')),
Some(ExpandUnit::Number(year)),
) => {
let month_name = match month.parse::<u32>().unwrap_or(0) {
1 => "January",
2 => "February",
3 => "March",
4 => "April",
5 => "May",
6 => "June",
7 => "July",
8 => "August",
9 => "September",
10 => "October",
11 => "November",
12 => "December",
_ => return None,
};
let day_val = day.parse::<u32>().unwrap_or(0);
if day_val == 0 || day_val > 31 {
return None;
}
let ordinal = ordinal_words_en(day_val);
if ordinal.is_empty() {
return None;
}
let mut units = vec![ExpandUnit::Word(month_name.into())];
units.extend(ordinal.into_iter().map(|w| ExpandUnit::Word(w.into())));
units.push(ExpandUnit::Mark(','));
units.push(ExpandUnit::Number(year.clone()));
Some(ExpandResult::Replace(5, units))
}
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_en_date_expansion() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("24".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("03".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("2026".into()));
let res = task.expand(&queue).unwrap();
if let ExpandResult::Replace(n, units) = res {
assert_eq!(n, 5);
assert_eq!(units[0], ExpandUnit::Word("March".into()));
assert_eq!(units[1], ExpandUnit::Word("twenty".into()));
assert_eq!(units[2], ExpandUnit::Word("fourth".into()));
assert_eq!(units[3], ExpandUnit::Mark(','));
} else {
panic!("Expected Replace result");
}
}
#[test]
fn test_en_date_invalid_month() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("01".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("13".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("2026".into()));
let res = task.expand(&queue);
assert!(res.is_none(), "Month 13 should return None");
}
#[test]
fn test_en_date_invalid_day_zero() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("0".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("03".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("2026".into()));
let res = task.expand(&queue);
assert!(res.is_none(), "Day 0 should return None");
}
#[test]
fn test_en_date_invalid_day_32() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("32".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("03".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("2026".into()));
let res = task.expand(&queue);
assert!(res.is_none(), "Day 32 should return None");
}
#[test]
fn test_en_date_maybe_single_number() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("24".into()));
let res = task.expand(&queue);
assert!(
matches!(res, Some(ExpandResult::Maybe)),
"Single number should return Maybe"
);
}
#[test]
fn test_en_date_maybe_number_slash() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("24".into()));
queue.push_back(ExpandUnit::Mark('/'));
let res = task.expand(&queue);
assert!(
matches!(res, Some(ExpandResult::Maybe)),
"Number + '/' should return Maybe"
);
}
#[test]
fn test_en_date_maybe_partial_date() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Number("24".into()));
queue.push_back(ExpandUnit::Mark('/'));
queue.push_back(ExpandUnit::Number("03".into()));
let res = task.expand(&queue);
assert!(
matches!(res, Some(ExpandResult::Maybe)),
"Partial date should return Maybe"
);
}
#[test]
fn test_en_date_non_date_returns_none() {
let task = EnDateExpandTask;
let mut queue = VecDeque::new();
queue.push_back(ExpandUnit::Word("hello".into()));
let res = task.expand(&queue);
assert!(res.is_none(), "Non-date input should return None");
}
}