mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-11 16:31:54 -06:00
Reject signs and non-digits in parse_date fields (#3575)
Found while testing crates/engine/src/cmd/controls.rs:113-123 (parse_date) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
17bacb9a63
commit
2d2123d251
@@ -112,9 +112,11 @@ fn symbol_param(v: &Value, k: &str) -> Option<char> {
|
||||
/// A date `YYYY-MM-DD` (a full ISO date-time is fine too): (year, month, day), checked.
|
||||
pub fn parse_date(t: &str) -> Option<(i64, u32, u32)> {
|
||||
let t = t.trim();
|
||||
let y: i64 = t.get(0..4)?.parse().ok()?;
|
||||
let m: u32 = t.get(5..7)?.parse().ok()?;
|
||||
let d: u32 = t.get(8..10)?.parse().ok()?;
|
||||
// Digits only: `str::parse` would also accept a leading '+'.
|
||||
let field = |r: std::ops::Range<usize>| t.get(r).filter(|s| s.bytes().all(|b| b.is_ascii_digit()));
|
||||
let y: i64 = field(0..4)?.parse().ok()?;
|
||||
let m: u32 = field(5..7)?.parse().ok()?;
|
||||
let d: u32 = field(8..10)?.parse().ok()?;
|
||||
if t.get(4..5) != Some("-") || t.get(7..8) != Some("-") || !(1..=9999).contains(&y) || !(1..=12).contains(&m) || d == 0 || d > days_in_month(y, m)
|
||||
{
|
||||
return None;
|
||||
@@ -761,6 +763,15 @@ mod tests {
|
||||
assert_eq!(super::super::civil_from_days(days_from_civil(2000, 3, 1)), (2000, 3, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_date_rejects_signs_and_non_digits() {
|
||||
for bad in ["2024-+1-+5", "+123-01-01", "2024-01-+5", "2024-+1-05", "-024-01-01"] {
|
||||
assert_eq!(parse_date(bad), None, "{bad}");
|
||||
}
|
||||
assert_eq!(parse_date("2024-01-05"), Some((2024, 1, 5)));
|
||||
assert_eq!(parse_date("2024-01-05T10:00:00"), Some((2024, 1, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn days_from_civil_and_days_in_month_exact_beyond_chronos_range() {
|
||||
// Past `NaiveDate`'s ±262143 the 400-year cycles carry the result; values from the
|
||||
|
||||
Reference in New Issue
Block a user