Another test for the date parser

This commit is contained in:
Colin Benner 2018-10-04 10:20:21 +02:00
parent 16ecadb90c
commit 54ffee9945
3 changed files with 75 additions and 53 deletions

View file

@ -81,6 +81,7 @@ pub enum Query {
}
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
pub enum DatePattern {
Literal(String),
Match(String),

View file

@ -274,62 +274,63 @@ impl GenericDateTime {
}
}
fn attempt(date: &[DateToken], pat: &[DatePattern]) -> Result<GenericDateTime, (String, usize)> {
let mut parsed = Parsed::new();
let mut tz = None;
let mut iter = date.iter().cloned().peekable();
let res = parse_date(&mut parsed, &mut tz, &mut iter, pat);
let count = iter.count();
let res = if count > 0 && res.is_ok() {
Err(format!("Expected eof, got {}",
date[date.len()-count..].iter()
.map(ToString::to_string)
.collect::<Vec<_>>().join("")))
} else {
res
};
try!(res.map_err(|e| (e, count)));
let time = parsed.to_naive_time();
let date = parsed.to_naive_date();
if let Some(tz) = tz {
match (time, date) {
(Ok(time), Ok(date)) =>
tz.from_local_datetime(&date.and_time(time)).earliest().ok_or_else(|| (format!(
"Datetime does not represent a valid moment in time"
), count)).map(GenericDateTime::Timezone),
(Ok(time), Err(_)) =>
Ok(UTC::now().with_timezone(&tz).date().and_time(time).unwrap()).map(
GenericDateTime::Timezone),
(Err(_), Ok(date)) =>
tz.from_local_date(&date).earliest().map(|x| x.and_hms(0, 0, 0)).ok_or_else(|| (format!(
"Datetime does not represent a valid moment in time"
), count)).map(GenericDateTime::Timezone),
_ => Err((format!("Failed to construct a useful datetime"), count))
}
} else {
let offset = parsed.to_fixed_offset().unwrap_or(FixedOffset::east(0));
match (time, date) {
(Ok(time), Ok(date)) =>
Ok(GenericDateTime::Fixed(DateTime::<FixedOffset>::from_utc(
date.and_time(time), offset
))),
(Ok(time), Err(_)) =>
Ok(GenericDateTime::Fixed(UTC::now().with_timezone(
&offset
).date().and_time(time).unwrap())),
(Err(_), Ok(date)) =>
Ok(GenericDateTime::Fixed(Date::<FixedOffset>::from_utc(
date, offset
).and_hms(0, 0, 0))),
_ => Err((format!("Failed to construct a useful datetime"), count))
}
}
}
pub fn try_decode(date: &[DateToken], context: &Context) -> Result<GenericDateTime, String> {
let mut best = None;
for pat in &context.datepatterns {
//println!("Tring {:?} against {}", date, show_datepattern(pat));
let attempt = || -> Result<GenericDateTime, (String, usize)> {
let mut parsed = Parsed::new();
let mut tz = None;
let mut iter = date.iter().cloned().peekable();
let res = parse_date(&mut parsed, &mut tz, &mut iter, &pat[..]);
let count = iter.count();
let res = if count > 0 && res.is_ok() {
Err(format!("Expected eof, got {}",
date[date.len()-count..].iter()
.map(ToString::to_string)
.collect::<Vec<_>>().join("")))
} else {
res
};
try!(res.map_err(|e| (e, count)));
let time = parsed.to_naive_time();
let date = parsed.to_naive_date();
if let Some(tz) = tz {
match (time, date) {
(Ok(time), Ok(date)) =>
tz.from_local_datetime(&date.and_time(time)).earliest().ok_or_else(|| (format!(
"Datetime does not represent a valid moment in time"
), count)).map(GenericDateTime::Timezone),
(Ok(time), Err(_)) =>
Ok(UTC::now().with_timezone(&tz).date().and_time(time).unwrap()).map(
GenericDateTime::Timezone),
(Err(_), Ok(date)) =>
tz.from_local_date(&date).earliest().map(|x| x.and_hms(0, 0, 0)).ok_or_else(|| (format!(
"Datetime does not represent a valid moment in time"
), count)).map(GenericDateTime::Timezone),
_ => Err((format!("Failed to construct a useful datetime"), count))
}
} else {
let offset = parsed.to_fixed_offset().unwrap_or(FixedOffset::east(0));
match (time, date) {
(Ok(time), Ok(date)) =>
Ok(GenericDateTime::Fixed(DateTime::<FixedOffset>::from_utc(
date.and_time(time), offset
))),
(Ok(time), Err(_)) =>
Ok(GenericDateTime::Fixed(UTC::now().with_timezone(
&offset
).date().and_time(time).unwrap())),
(Err(_), Ok(date)) =>
Ok(GenericDateTime::Fixed(Date::<FixedOffset>::from_utc(
date, offset
).and_hms(0, 0, 0))),
_ => Err((format!("Failed to construct a useful datetime"), count))
}
}
};
match attempt() {
match attempt(date, pat) {
Ok(datetime) => return Ok(datetime),
Err((e, c)) => {
//println!("{}", e);

View file

@ -415,7 +415,7 @@ fn test_radix() {
fn test_comments() {
test("1 // *3", "1 (dimensionless)");
test("1 + /*2*/ 3", "4 (dimensionless)");
test("1 + /*2", "Expected `*/`, got EOF");
test("1 + /*2", "Expected term, got <Expected `*/`, got EOF>");
}
#[test]
@ -427,3 +427,23 @@ fn test_leading_dot() {
fn test_underscores_in_number() {
test("123_456\u{2009}789", "123456789 (dimensionless)");
}
#[test]
fn test_date_input() {
let input = "#2018-10-04T09:13:25 +2:00#";
let expected = "2018-10-04 11:13:25 +02:00";
let mut iter = text_query::TokenIterator::new(input.trim()).peekable();
let expr = text_query::parse_query(&mut iter);
CONTEXT.with(|ctx| {
let res = ctx.eval_outer(&expr);
let res = match res {
Ok(v) => v.to_string(),
Err(v) => v.to_string(),
};
assert!(
res.starts_with(expected),
format!("\n'{}' !=\n'{}'", res, expected)
);
});
}