Skip to content

Commit

Permalink
Use deranged for earlier errors when parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Jul 27, 2023
1 parent bd678cb commit facb587
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 349 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ time-core = { path = "time-core", version = "=0.1.1" }
time-macros = { path = "time-macros", version = "=0.2.10" }

criterion = { version = "0.5.1", default-features = false }
deranged = { version = "0.3.3", default-features = false }
itoa = "1.0.1"
js-sys = "0.3.58"
libc = "0.2.98"
Expand Down
84 changes: 66 additions & 18 deletions tests/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,9 +680,9 @@ fn parse_time_err() -> time::Result<()> {
));
assert!(matches!(
Time::parse("13 PM", &fd::parse("[hour repr:12] [period]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "hour"
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("hour")
))
));
assert!(matches!(
Time::parse(" ", &fd::parse("")?),
Expand Down Expand Up @@ -878,28 +878,61 @@ fn parse_date_err() -> time::Result<()> {
));
assert!(matches!(
Date::parse("2021-12-32", &fd::parse("[year]-[month]-[day]")?),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("day")
))
));
assert!(matches!(
Date::parse("2021-02-30", &fd::parse("[year]-[month]-[day]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "day"
));
assert!(matches!(
Date::parse("2021-W54-1", &fd::parse("[year base:iso_week]-W[week_number]-[weekday repr:monday]")?),
Date::parse("2019-W53-1", &fd::parse("[year base:iso_week]-W[week_number]-[weekday repr:monday]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "week"
));
assert!(matches!(
Date::parse("2021-W54-1", &fd::parse("[year]-W[week_number repr:sunday]-[weekday repr:monday]")?),
Date::parse(
"2021-W54-1",
&fd::parse("[year base:iso_week]-W[week_number]-[weekday repr:monday]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("week number")
))
));
assert!(matches!(
Date::parse("2019-W53-1", &fd::parse("[year]-W[week_number repr:sunday]-[weekday repr:monday]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "ordinal"
));
assert!(matches!(
Date::parse("2021-W54-1", &fd::parse("[year]-W[week_number repr:monday]-[weekday repr:monday]")?),
Date::parse(
"2021-W54-1",
&fd::parse("[year]-W[week_number repr:sunday]-[weekday repr:monday]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("week number")
))
));
assert!(matches!(
Date::parse("2019-W53-1", &fd::parse("[year]-W[week_number repr:monday]-[weekday repr:monday]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "ordinal"
));
assert!(matches!(
Date::parse(
"2021-W54-1",
&fd::parse("[year]-W[week_number repr:monday]-[weekday repr:monday]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("week number")
))
));
assert!(matches!(
Date::parse("Ja", &fd::parse("[month repr:short]")?),
Err(error::Parse::ParseFromDescription(
Expand Down Expand Up @@ -953,15 +986,24 @@ fn parse_offset_err() -> time::Result<()> {
);
assert!(matches!(
UtcOffset::parse("24", &fd::parse("[offset_hour]")?),
Err(error::Parse::TryFromParsed(error::TryFromParsed::ComponentRange(component))) if component.name() == "offset hour"
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("offset hour")
))
));
assert!(matches!(
UtcOffset::parse("00:60", &fd::parse("[offset_hour]:[offset_minute]")?),
Err(error::Parse::TryFromParsed(error::TryFromParsed::ComponentRange(component))) if component.name() == "offset minute"
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("offset minute")
))
));
assert!(matches!(
UtcOffset::parse("00:00:60", &fd::parse("[offset_hour]:[offset_minute]:[offset_second]")?),
Err(error::Parse::TryFromParsed(error::TryFromParsed::ComponentRange(component))) if component.name() == "offset second"
UtcOffset::parse(
"00:00:60",
&fd::parse("[offset_hour]:[offset_minute]:[offset_second]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("offset second")
))
));

Ok(())
Expand All @@ -976,10 +1018,13 @@ fn parse_primitive_date_time_err() -> time::Result<()> {
))
));
assert!(matches!(
PrimitiveDateTime::parse("2021-001 13 PM", &fd::parse("[year]-[ordinal] [hour repr:12] [period]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "hour"
PrimitiveDateTime::parse(
"2021-001 13 PM",
&fd::parse("[year]-[ordinal] [hour repr:12] [period]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("hour")
))
));

Ok(())
Expand All @@ -1000,10 +1045,13 @@ fn parse_offset_date_time_err() -> time::Result<()> {
))
));
assert!(matches!(
OffsetDateTime::parse("2021-001 12 PM +25", &fd::parse("[year]-[ordinal] [hour repr:12] [period] [offset_hour sign:mandatory]")?),
Err(error::Parse::TryFromParsed(
error::TryFromParsed::ComponentRange(component)
)) if component.name() == "offset hour"
OffsetDateTime::parse(
"2021-001 12 PM +25",
&fd::parse("[year]-[ordinal] [hour repr:12] [period] [offset_hour sign:mandatory]")?
),
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::InvalidComponent("offset hour")
))
));

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions tests/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ fn time_error() {
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("24:00:00.0")],
"hour must be in the range 0..=23",
"the 'hour' component could not be parsed",
);
assert_de_tokens_error::<Readable<Time>>(
&[Token::BorrowedStr("24-00:00.0")],
&[Token::BorrowedStr("23-00:00.0")],
"a character literal was not valid",
);
assert_de_tokens_error::<Readable<Time>>(
Expand Down
9 changes: 5 additions & 4 deletions time/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,19 @@ large-dates = ["time-macros?/large-dates"]
local-offset = ["std", "dep:libc", "dep:num_threads"]
macros = ["dep:time-macros"]
parsing = ["time-macros?/parsing"]
quickcheck = ["dep:quickcheck", "alloc"]
rand = ["dep:rand"]
serde = ["dep:serde", "time-macros?/serde"]
quickcheck = ["dep:quickcheck", "alloc", "deranged/quickcheck"]
rand = ["dep:rand", "deranged/rand"]
serde = ["dep:serde", "time-macros?/serde", "deranged/serde"]
serde-human-readable = ["serde", "formatting", "parsing"]
# Deprecated in favor of using the relevant flags directly.
serde-well-known = ["serde", "formatting", "parsing"]
std = ["alloc"]
std = ["alloc", "deranged/std"]
wasm-bindgen = ["dep:js-sys"]

# If adding an optional dependency, be sure to use the `dep:` prefix above to avoid an implicit
# feature gate.
[dependencies]
deranged = { workspace = true }
itoa = { workspace = true, optional = true }
quickcheck = { workspace = true, optional = true }
rand = { workspace = true, optional = true }
Expand Down
6 changes: 2 additions & 4 deletions time/src/parsing/parsable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,7 @@ impl sealed::Sealed for Rfc2822 {
};

// The RFC explicitly allows leap seconds.
// Safety: The flag does not represent a field.
unsafe { parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true) };
parsed.leap_second_allowed = true;

#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
let zone_literal = first_match(
Expand Down Expand Up @@ -534,8 +533,7 @@ impl sealed::Sealed for Rfc3339 {
};

// The RFC explicitly allows leap seconds.
// Safety: The flag does not represent a field.
unsafe { parsed.set_flag(Parsed::LEAP_SECOND_ALLOWED_FLAG, true) };
parsed.leap_second_allowed = true;

if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
parsed
Expand Down
Loading

0 comments on commit facb587

Please sign in to comment.