diff --git a/crates/xfa/src/picture.rs b/crates/xfa/src/picture.rs index 3ddb392114..f1296e495a 100644 --- a/crates/xfa/src/picture.rs +++ b/crates/xfa/src/picture.rs @@ -39,14 +39,15 @@ pub fn typed_date(tpl: &Template, som: &str, text: &str) -> Option { } let picture = f.picture.as_deref()?; let reads = |pattern: &str| pattern_to_iso(text, pattern).filter(|iso| iso_to_pattern(iso, pattern).eq_ignore_ascii_case(text.trim())); - let first = date_pattern(Some(picture)); + let mut alts = alternatives(picture).into_iter(); + let first = alts.next().filter(|a| is_date_clause(a) && date_letters(a).is_some()).map(|a| date_pattern(Some(a)))?; if reads(&first).is_some() { return None; } // The first later date pattern that reads the text and gives a date the first pattern keeps: // written in the first, it must read back as the same date (a two-digit year can't hold 1901 // or 1203), else the next pattern is tried. - alternatives(picture).into_iter().skip(1).filter(|a| is_date_clause(a)).filter_map(date_letters).find_map(|p| { + alts.filter(|a| is_date_clause(a)).filter_map(date_letters).find_map(|p| { let iso = reads(&p)?; let shown = iso_to_pattern(&iso, &first); (pattern_to_iso(&shown, &first).as_deref() == Some(iso.as_str())).then_some(shown) @@ -63,3 +64,48 @@ fn is_date_clause(clause: &str) -> bool { None => true, } } + +#[cfg(test)] +mod tests { + use super::*; + + fn tpl_with_pictures(fields: &[(&str, &str)]) -> Template { + let mut body = String::new(); + for (name, pic) in fields { + body.push_str(&format!( + "{pic}" + )); + } + let xml = format!( + "\ + \ + " + ); + crate::parse(&xml).expect("valid template").0 + } + + #[test] + fn typed_date_reads_bare_first_alternative_instead_of_whole_picture_or_later_braces() { + let tpl = tpl_with_pictures(&[("bare", "YYYYMMDD|YYMMDD"), ("mixed", "YYYYMMDD|date{YYMMDD}")]); + assert_eq!(typed_date(&tpl, "form[0].bare[0]", "261018").as_deref(), Some("20261018")); + assert_eq!(typed_date(&tpl, "form[0].bare[0]", "20261018"), None); + assert_eq!(typed_date(&tpl, "form[0].mixed[0]", "261018").as_deref(), Some("20261018")); + assert_eq!(typed_date(&tpl, "form[0].mixed[0]", "20261018"), None); + } + + #[test] + fn typed_date_rejects_non_date_or_unreadable_first_alternative() { + let tpl = tpl_with_pictures(&[ + ("text_first", "text{YYYYMMDD}|date{YYMMDD}"), + ("num_first", "num{99999999}|date{YYMMDD}"), + ("datetime_first", "date{YYYY-MM-DD HH:MM}|date{YYMMDD}"), + ]); + assert_eq!(typed_date(&tpl, "form[0].text_first[0]", "261018"), None); + assert_eq!(typed_date(&tpl, "form[0].num_first[0]", "261018"), None); + assert_eq!(typed_date(&tpl, "form[0].datetime_first[0]", "261018"), None); + } +}