mirror of
https://github.com/chronotope/chrono.git
synced 2025-10-02 07:21:41 +00:00
Add various tests for current parsing
Add more varying testing for most parsing functions. Tests emphasize whitespace, literals, timezones, and timezone delimiters (colons and whitespace). Add tests for multiple-byte characters and combining characters in and around data and parsing formats. These tests are added to aid humans verifying the next commit that changes parsing behavior. Issue #660
This commit is contained in:
parent
6655649e86
commit
bc58a7db52
@ -550,6 +550,9 @@ impl DateTime<FixedOffset> {
|
||||
/// RFC 2822 is the internet message standard that specifies the
|
||||
/// representation of times in HTTP and email headers.
|
||||
///
|
||||
/// The RFC 2822 standard allows arbitrary intermixed whitespace.
|
||||
/// See [RFC 2822 Appendix A.5]
|
||||
///
|
||||
/// ```
|
||||
/// # use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
|
||||
/// assert_eq!(
|
||||
@ -557,6 +560,8 @@ impl DateTime<FixedOffset> {
|
||||
/// FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5
|
||||
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||
const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
||||
let mut parsed = Parsed::new();
|
||||
|
@ -344,8 +344,10 @@ fn test_datetime_with_timezone() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_datetime_rfc2822_and_rfc3339() {
|
||||
fn test_datetime_rfc2822() {
|
||||
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
||||
|
||||
// timezone 0
|
||||
assert_eq!(
|
||||
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc2822(),
|
||||
"Wed, 18 Feb 2015 23:16:09 +0000"
|
||||
@ -354,6 +356,7 @@ fn test_datetime_rfc2822_and_rfc3339() {
|
||||
Utc.with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap().to_rfc3339(),
|
||||
"2015-02-18T23:16:09+00:00"
|
||||
);
|
||||
// timezone +05
|
||||
assert_eq!(
|
||||
edt.from_local_datetime(
|
||||
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||
@ -376,6 +379,7 @@ fn test_datetime_rfc2822_and_rfc3339() {
|
||||
.to_rfc3339(),
|
||||
"2015-02-18T23:16:09.150+05:00"
|
||||
);
|
||||
// seconds 60
|
||||
assert_eq!(
|
||||
edt.from_local_datetime(
|
||||
&NaiveDate::from_ymd_opt(2015, 2, 18)
|
||||
@ -408,7 +412,130 @@ fn test_datetime_rfc2822_and_rfc3339() {
|
||||
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"),
|
||||
edt.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||
.unwrap()
|
||||
.to_rfc2822(),
|
||||
"Wed, 18 Feb 2015 23:59:60 +0500"
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap())
|
||||
);
|
||||
|
||||
// many varying whitespace intermixed
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822(
|
||||
"\t\t\tWed,\n\t\t18 \r\n\t\tFeb \u{3000} 2015\r\n\t\t\t23:59:60 \t+0500"
|
||||
),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap())
|
||||
);
|
||||
// example from RFC 2822 Appendix A.5.
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822(
|
||||
"Thu,\n\t13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)"
|
||||
),
|
||||
Ok(FixedOffset::east_opt(-3 * 60 * 60 - 30 * 60)
|
||||
.unwrap()
|
||||
.ymd_opt(1969, 2, 13)
|
||||
.unwrap()
|
||||
.and_hms_opt(23, 32, 0)
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
// example from RFC 2822 Appendix A.5. without trailing " (Newfoundland Time)"
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822(
|
||||
"Thu,\n\t13\n Feb\n 1969\n 23:32\n -0330"
|
||||
),
|
||||
Ok(FixedOffset::east_opt(-3 * 60 * 60 - 30 * 60)
|
||||
.unwrap()
|
||||
.ymd_opt(1969, 2, 13)
|
||||
.unwrap()
|
||||
.and_hms_opt(23, 32, 0)
|
||||
.unwrap())
|
||||
);
|
||||
|
||||
// bad year
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("31 DEC 262143 23:59 -2359").is_err());
|
||||
// wrong format
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +00:00").is_err()
|
||||
);
|
||||
// full name day of week
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("Wednesday, 18 Feb 2015 23:16:09 +0000")
|
||||
.is_err());
|
||||
// full name day of week
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("Wednesday 18 Feb 2015 23:16:09 +0000")
|
||||
.is_err());
|
||||
// wrong day of week separator '.'
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc2822("Wed. 18 Feb 2015 23:16:09 +0000").is_err());
|
||||
// *trailing* space causes failure
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000 ").is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_datetime_rfc3339() {
|
||||
let edt = FixedOffset::east_opt(5 * 60 * 60).unwrap();
|
||||
assert_eq!(
|
||||
Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap().to_rfc3339(),
|
||||
"2015-02-18T23:16:09+00:00"
|
||||
);
|
||||
assert_eq!(
|
||||
edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap().to_rfc3339(),
|
||||
"2015-02-18T23:16:09.150+05:00"
|
||||
);
|
||||
assert_eq!(
|
||||
edt.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||
.unwrap()
|
||||
.to_rfc3339(),
|
||||
"2015-02-18T23:59:60.234567+05:00"
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:59.123+05:00"),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_micro_opt(23, 59, 59, 123_000).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:59.123456+05:00"),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_micro_opt(23, 59, 59, 123_456).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:59.123456789+05:00"),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_nano_opt(23, 59, 59, 123_456_789).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:16:09Z"),
|
||||
Ok(FixedOffset::east_opt(0)
|
||||
.unwrap()
|
||||
.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_opt(23, 16, 9)
|
||||
.unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
edt.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_micro_opt(23, 59, 59, 1_234_567)
|
||||
.unwrap()
|
||||
.to_rfc3339(),
|
||||
"2015-02-18T23:59:60.234567+05:00"
|
||||
);
|
||||
assert_eq!(
|
||||
edt.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap().to_rfc3339(),
|
||||
"2015-02-18T23:16:09.150+05:00"
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
|
||||
Ok(edt.ymd_opt(2015, 2, 18).unwrap().and_hms_micro_opt(23, 59, 59, 1_234_567).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:16:09Z"),
|
||||
Ok(FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
@ -434,6 +561,44 @@ fn test_datetime_rfc2822_and_rfc3339() {
|
||||
)
|
||||
.unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_opt(23, 16, 9).unwrap().to_rfc3339(),
|
||||
"2015-02-18T23:16:09+00:00"
|
||||
);
|
||||
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567 +05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:059:60.234567+05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00PST").is_err()
|
||||
);
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+PST").is_err());
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567PST").is_err());
|
||||
assert!(DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+0500").is_err());
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18 23:59:60.234567+05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567:+05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00 ").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339(" 2015-02-18T23:59:60.234567+05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015- 02-18T23:59:60.234567+05:00").is_err()
|
||||
);
|
||||
assert!(
|
||||
DateTime::<FixedOffset>::parse_from_rfc3339("2015-02-18T23:59:60.234567A+05:00").is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -575,7 +740,94 @@ fn test_datetime_from_str() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_datetime_parse_from_str() {
|
||||
fn test_parse_datetime_utc() {
|
||||
// valid cases
|
||||
let valid = [
|
||||
"2001-02-03T04:05:06Z",
|
||||
"2001-02-03T04:05:06+0000",
|
||||
"2001-02-03T04:05:06-00:00",
|
||||
"2001-02-03T04:05:06-01:00",
|
||||
"2012-12-12T12:12:12Z",
|
||||
"2012 -12-12T12:12:12Z",
|
||||
"2012 -12-12T12:12:12Z",
|
||||
"2012- 12-12T12:12:12Z",
|
||||
"2012- 12-12T12:12:12Z",
|
||||
"2012-12-12T 12:12:12Z",
|
||||
"2012-12-12T12 :12:12Z",
|
||||
"2012-12-12T12 :12:12Z",
|
||||
"2012-12-12T12: 12:12Z",
|
||||
"2012-12-12T12: 12:12Z",
|
||||
"2012-12-12T12 : 12:12Z",
|
||||
"2012-12-12T12:12:12Z ",
|
||||
" 2012-12-12T12:12:12Z",
|
||||
"2015-02-18T23:16:09.153Z",
|
||||
"2015-2-18T23:16:09.153Z",
|
||||
"+2015-2-18T23:16:09.153Z",
|
||||
"-77-02-18T23:16:09Z",
|
||||
"+82701-05-6T15:9:60.898989898989Z",
|
||||
];
|
||||
for &s in &valid {
|
||||
eprintln!("test_parse_datetime_utc valid {:?}", s);
|
||||
let d = match s.parse::<DateTime<Utc>>() {
|
||||
Ok(d) => d,
|
||||
Err(e) => panic!("parsing `{}` has failed: {}", s, e),
|
||||
};
|
||||
let s_ = format!("{:?}", d);
|
||||
// `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
|
||||
let d_ = match s_.parse::<DateTime<Utc>>() {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
|
||||
}
|
||||
};
|
||||
assert!(
|
||||
d == d_,
|
||||
"`{}` is parsed into `{:?}`, but reparsed result \
|
||||
`{:?}` does not match",
|
||||
s,
|
||||
d,
|
||||
d_
|
||||
);
|
||||
}
|
||||
|
||||
// some invalid cases
|
||||
// since `ParseErrorKind` is private, all we can do is to check if there was an error
|
||||
let invalid = [
|
||||
"", // empty
|
||||
"Z", // missing data
|
||||
"15Z", // missing data
|
||||
"15:8:9Z", // missing date
|
||||
"15-8-9Z", // missing time or date
|
||||
"Fri, 09 Aug 2013 23:54:35 GMT", // valid datetime, wrong format
|
||||
"Sat Jun 30 23:59:60 2012", // valid datetime, wrong format
|
||||
"1441497364.649", // valid datetime, wrong format
|
||||
"+1441497364.649", // valid datetime, wrong format
|
||||
"+1441497364", // valid datetime, wrong format
|
||||
"+1441497364Z", // valid datetime, wrong format
|
||||
"2014/02/03 04:05:06Z", // valid datetime, wrong format
|
||||
"2001-02-03T04:05:0600:00", // valid datetime, timezone too close
|
||||
"2015-15-15T15:15:15Z", // invalid datetime
|
||||
"2012-12-12T12:12:12x", // invalid timezone
|
||||
"2012-123-12T12:12:12Z", // invalid month
|
||||
"2012-12-77T12:12:12Z", // invalid day
|
||||
"2012-12-12T26:12:12Z", // invalid hour
|
||||
"2012-12-12T12:61:12Z", // invalid minute
|
||||
"2012-12-12T12:12:62Z", // invalid second
|
||||
"2012-12-12 T12:12:12Z", // space after date
|
||||
"2012-12-12t12:12:12Z", // wrong divider 't'
|
||||
"2012-12-12T12:12:12ZZ", // trailing literal 'Z'
|
||||
"+802701-12-12T12:12:12Z", // invalid year (out of bounds)
|
||||
"+ 2012-12-12T12:12:12Z", // invalid space before year
|
||||
" +82701 - 05 - 6 T 15 : 9 : 60.898989898989 Z", // valid datetime, wrong format
|
||||
];
|
||||
for &s in &invalid {
|
||||
eprintln!("test_parse_datetime_utc invalid {:?}", s);
|
||||
assert!(s.parse::<DateTime<Utc>>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utc_datetime_from_str() {
|
||||
let ymdhms = |y, m, d, h, n, s, off| {
|
||||
FixedOffset::east_opt(off).unwrap().with_ymd_and_hms(y, m, d, h, n, s).unwrap()
|
||||
};
|
||||
@ -590,6 +842,645 @@ fn test_datetime_parse_from_str() {
|
||||
Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", "%a, %d %b %Y %H:%M:%S GMT"),
|
||||
Ok(Utc.with_ymd_and_hms(2013, 8, 9, 23, 54, 35).unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"2015-02-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
||||
Ok(FixedOffset::east_opt(0)
|
||||
.unwrap()
|
||||
.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_milli_opt(23, 16, 9, 150)
|
||||
.unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
"2015-02-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
"2015-02-18T23:16:9.15 UTC".parse::<DateTime<Utc>>(),
|
||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
"2015-02-18T23:16:9.15UTC".parse::<DateTime<Utc>>(),
|
||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
||||
Ok(FixedOffset::east_opt(0)
|
||||
.unwrap()
|
||||
.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_milli_opt(23, 16, 9, 150)
|
||||
.unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
|
||||
Ok(FixedOffset::west_opt(10 * 3600)
|
||||
.unwrap()
|
||||
.ymd_opt(2015, 2, 18)
|
||||
.unwrap()
|
||||
.and_hms_milli_opt(13, 16, 9, 150)
|
||||
.unwrap())
|
||||
);
|
||||
assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
|
||||
|
||||
assert_eq!(
|
||||
"2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
|
||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
"2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
|
||||
Ok(Utc.ymd_opt(2015, 2, 18).unwrap().and_hms_milli_opt(23, 16, 9, 150).unwrap())
|
||||
);
|
||||
assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
|
||||
|
||||
// no test for `DateTime<Local>`, we cannot verify that much.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utc_datetime_from_str_with_spaces() {
|
||||
let dt = Utc.ymd_opt(2013, 8, 9).unwrap().and_hms_opt(23, 54, 35).unwrap();
|
||||
// with varying spaces - should succeed
|
||||
assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S "), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35 ", " %b %d %Y %H:%M:%S "), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(
|
||||
Utc.datetime_from_str("\n\tAug 09 2013 23:54:35 ", "\n\t%b %d %Y %H:%M:%S "),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(Utc.datetime_from_str("\tAug 09 2013 23:54:35\t", "\t%b %d %Y %H:%M:%S\t"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013\t23:54:35", "%b %d %Y\t%H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013\t\t23:54:35", "%b %d %Y\t\t%H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S\n"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y\t%H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S "), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", " %b %d %Y %H:%M:%S"), Ok(dt),);
|
||||
assert_eq!(Utc.datetime_from_str("Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S\n"), Ok(dt),);
|
||||
// with varying spaces - should fail
|
||||
// leading space in data
|
||||
assert!(Utc.datetime_from_str(" Aug 09 2013 23:54:35", "%b %d %Y %H:%M:%S").is_err());
|
||||
// trailing space in data
|
||||
assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35 ", "%b %d %Y %H:%M:%S").is_err());
|
||||
// trailing tab in data
|
||||
assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35\t", "%b %d %Y %H:%M:%S").is_err());
|
||||
// mismatched newlines
|
||||
assert!(Utc.datetime_from_str("\nAug 09 2013 23:54:35", "%b %d %Y %H:%M:%S\n").is_err());
|
||||
// trailing literal in data
|
||||
assert!(Utc.datetime_from_str("Aug 09 2013 23:54:35 !!!", "%b %d %Y %H:%M:%S ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_datetime_parse_from_str() {
|
||||
let dt = FixedOffset::east_opt(-9 * 60 * 60)
|
||||
.unwrap()
|
||||
.ymd_opt(2013, 8, 9)
|
||||
.unwrap()
|
||||
.and_hms_opt(23, 54, 35)
|
||||
.unwrap();
|
||||
|
||||
// timezone variations
|
||||
|
||||
//
|
||||
// %Z
|
||||
//
|
||||
// wrong timezone format
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %Z"
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data?
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 PST",
|
||||
"%b %d %Y %H:%M:%S %Z"
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 XXXXX",
|
||||
"%b %d %Y %H:%M:%S %Z"
|
||||
)
|
||||
.is_err());
|
||||
|
||||
//
|
||||
// %z
|
||||
//
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 00",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 : 00",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 --0900",
|
||||
"%b %d %Y %H:%M:%S -%z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 +-0900",
|
||||
"%b %d %Y %H:%M:%S +%z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00 ",
|
||||
"%b %d %Y %H:%M:%S %z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// trailing newline after timezone
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00\n",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00\n",
|
||||
"%b %d %Y %H:%M:%S %z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// trailing colon
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
)
|
||||
.is_err());
|
||||
// trailing colon with space
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00: ",
|
||||
"%b %d %Y %H:%M:%S %z "
|
||||
)
|
||||
.is_err());
|
||||
// trailing colon, mismatch space
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:",
|
||||
"%b %d %Y %H:%M:%S %z "
|
||||
)
|
||||
.is_err());
|
||||
// wrong timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09::00",
|
||||
"%b %d %Y %H:%M:%S %z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900::",
|
||||
"%b %d %Y %H:%M:%S %z::"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00",
|
||||
"%b %d %Y %H:%M:%S %z:00"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00 ",
|
||||
"%b %d %Y %H:%M:%S %z:00 "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
|
||||
//
|
||||
// %:z
|
||||
//
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 00",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 : 00",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 : 00:",
|
||||
"%b %d %Y %H:%M:%S %:z:"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// wrong timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09::00",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// timezone data hs too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
)
|
||||
.is_err());
|
||||
// timezone data hs too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00::",
|
||||
"%b %d %Y %H:%M:%S %:z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00::",
|
||||
"%b %d %Y %H:%M:%S %:z::"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
|
||||
//
|
||||
// %:::z
|
||||
//
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09 : 00",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// mismatching colon expectations
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09::00",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// wrong timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09001234",
|
||||
"%b %d %Y %H:%M:%S %::z1234"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:001234",
|
||||
"%b %d %Y %H:%M:%S %::z1234"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900 ",
|
||||
"%b %d %Y %H:%M:%S %::z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900\t\n",
|
||||
"%b %d %Y %H:%M:%S %::z\t\n"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900:",
|
||||
"%b %d %Y %H:%M:%S %::z:"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 :-0900:0",
|
||||
"%b %d %Y %H:%M:%S :%::z:0"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// mismatching colons and spaces
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 :-0900: ",
|
||||
"%b %d %Y %H:%M:%S :%::z::"
|
||||
)
|
||||
.is_err());
|
||||
// mismatching colons expectations
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00",
|
||||
"%b %d %Y %H:%M:%S %::z"
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -0900: 23:54:35",
|
||||
"%b %d %Y %::z: %H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 :-0900:0 23:54:35",
|
||||
"%b %d %Y :%::z:0 %H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// mismatching colons expectations mid-string
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 :-0900: 23:54:35",
|
||||
"%b %d %Y :%::z %H:%M:%S"
|
||||
)
|
||||
.is_err());
|
||||
// mismatching colons expectations, before end
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00 ",
|
||||
"%b %d %Y %H:%M:%S %::z "
|
||||
)
|
||||
.is_err());
|
||||
|
||||
//
|
||||
// %:::z
|
||||
//
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %:::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %:::z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900 ",
|
||||
"%b %d %Y %H:%M:%S %:::z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// wrong timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09",
|
||||
"%b %d %Y %H:%M:%S %:::z"
|
||||
)
|
||||
.is_err());
|
||||
|
||||
//
|
||||
// %::::z
|
||||
//
|
||||
// too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %::::z"
|
||||
)
|
||||
.is_err());
|
||||
// too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %::::z"
|
||||
)
|
||||
.is_err());
|
||||
// too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:",
|
||||
"%b %d %Y %H:%M:%S %::::z"
|
||||
)
|
||||
.is_err());
|
||||
// too many colons
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00",
|
||||
"%b %d %Y %H:%M:%S %::::z"
|
||||
)
|
||||
.is_err());
|
||||
|
||||
//
|
||||
// %#z
|
||||
//
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00 ",
|
||||
"%b %d %Y %H:%M:%S %#z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900 ",
|
||||
"%b %d %Y %H:%M:%S %#z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -0900",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09: ",
|
||||
"%b %d %Y %H:%M:%S %#z "
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35+-09",
|
||||
"%b %d %Y %H:%M:%S+%#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35--09",
|
||||
"%b %d %Y %H:%M:%S-%#z"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -09:00 23:54:35",
|
||||
"%b %d %Y %#z%H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -0900 23:54:35",
|
||||
"%b %d %Y %#z%H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -090023:54:35",
|
||||
"%b %d %Y %#z%H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
assert_eq!(
|
||||
DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -09:0023:54:35",
|
||||
"%b %d %Y %#z%H:%M:%S"
|
||||
),
|
||||
Ok(dt),
|
||||
);
|
||||
// timezone with partial minutes adjacent hours
|
||||
assert_ne!(
|
||||
DateTime::<FixedOffset>::parse_from_str("Aug 09 2013 -09023:54:35", "%b %d %Y %#z%H:%M:%S"),
|
||||
Ok(dt),
|
||||
);
|
||||
// bad timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -09:00:00",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data (partial minutes)
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -090",
|
||||
"%b %d %Y %H:%M:%S %#z"
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data (partial minutes) with trailing space
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 23:54:35 -090 ",
|
||||
"%b %d %Y %H:%M:%S %#z "
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data (partial minutes) mid-string
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -090 23:54:35",
|
||||
"%b %d %Y %#z %H:%M:%S"
|
||||
)
|
||||
.is_err());
|
||||
// bad timezone data
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -09:00:00 23:54:35",
|
||||
"%b %d %Y %#z %H:%M:%S"
|
||||
)
|
||||
.is_err());
|
||||
// timezone data ambiguous with hours
|
||||
assert!(DateTime::<FixedOffset>::parse_from_str(
|
||||
"Aug 09 2013 -09:00:23:54:35",
|
||||
"%b %d %Y %#z%H:%M:%S"
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -536,9 +536,11 @@ fn test_parse() {
|
||||
|
||||
macro_rules! check {
|
||||
($fmt:expr, $items:expr; $err:tt) => (
|
||||
eprintln!("test_parse: format {:?}", $fmt);
|
||||
assert_eq!(parse_all($fmt, &$items), Err($err))
|
||||
);
|
||||
($fmt:expr, $items:expr; $($k:ident: $v:expr),*) => (#[allow(unused_mut)] {
|
||||
eprintln!("test_parse: format {:?}", $fmt);
|
||||
let mut expected = Parsed::new();
|
||||
$(expected.$k = Some($v);)*
|
||||
assert_eq!(parse_all($fmt, &$items), Ok(expected))
|
||||
@ -549,35 +551,114 @@ fn test_parse() {
|
||||
check!("", []; );
|
||||
check!(" ", []; TOO_LONG);
|
||||
check!("a", []; TOO_LONG);
|
||||
check!("abc", []; TOO_LONG);
|
||||
check!("🤠", []; TOO_LONG);
|
||||
|
||||
// whitespaces
|
||||
check!("", [sp!("")]; );
|
||||
check!(" ", [sp!("")]; );
|
||||
check!("\t", [sp!("")]; );
|
||||
check!(" \n\r \n", [sp!("")]; );
|
||||
check!(" ", [sp!(" ")]; );
|
||||
check!(" ", [sp!(" ")]; );
|
||||
check!(" ", [sp!(" "), sp!(" ")]; );
|
||||
check!(" ", [sp!(" "), sp!(" ")]; );
|
||||
check!(" ", [sp!(" "), sp!(" ")]; );
|
||||
check!(" ", [sp!(" "), sp!(" "), sp!(" ")]; );
|
||||
check!("\t", [sp!("\t")]; );
|
||||
check!("\t\r", [sp!("\t\r")]; );
|
||||
check!("\t\r ", [sp!("\t\r ")]; );
|
||||
check!(" \n\r \n", [sp!(" \n\r \n")]; );
|
||||
check!("\u{2002}", [sp!("\u{2002}")]; );
|
||||
// most unicode whitespace characters
|
||||
check!(
|
||||
"\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{3000}",
|
||||
[sp!("\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{3000}")];
|
||||
);
|
||||
// most unicode whitespace characters
|
||||
check!(
|
||||
"\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{3000}",
|
||||
[
|
||||
sp!("\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}"),
|
||||
sp!("\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{3000}")
|
||||
];
|
||||
);
|
||||
check!("a", [sp!("")]; TOO_LONG);
|
||||
check!("a", [sp!(" ")]; TOO_LONG);
|
||||
// a Space containing a literal cannot match a literal
|
||||
check!("a", [sp!("a")]; TOO_LONG);
|
||||
check!("abc", [sp!("")]; TOO_LONG);
|
||||
check!(" ", [sp!(" ")]; );
|
||||
check!(" \t\n", [sp!(" \t")]; );
|
||||
check!("", [sp!(" ")]; );
|
||||
check!(" ", [sp!(" ")]; );
|
||||
check!(" ", [sp!(" ")]; );
|
||||
check!(" ", [sp!(" "), sp!(" ")]; );
|
||||
|
||||
// `\u{0363}` is combining diacritic mark "COMBINING LATIN SMALL LETTER A"
|
||||
|
||||
// literal
|
||||
check!("", [lit!("")]; );
|
||||
check!("", [lit!("a")]; TOO_SHORT);
|
||||
check!(" ", [lit!("a")]; INVALID);
|
||||
check!("a", [lit!("a")]; );
|
||||
// a Literal may contain whitespace and match whitespace, but this should not be done
|
||||
check!(" ", [lit!(" ")]; );
|
||||
check!("aa", [lit!("a")]; TOO_LONG);
|
||||
check!("🤠", [lit!("a")]; INVALID);
|
||||
check!("A", [lit!("a")]; INVALID);
|
||||
check!("a", [lit!("z")]; INVALID);
|
||||
check!("a", [lit!("🤠")]; TOO_SHORT);
|
||||
check!("a", [lit!("\u{0363}a")]; TOO_SHORT);
|
||||
check!("\u{0363}a", [lit!("a")]; INVALID);
|
||||
check!("\u{0363}a", [lit!("\u{0363}a")]; );
|
||||
check!("a", [lit!("ab")]; TOO_SHORT);
|
||||
check!("xy", [lit!("xy")]; );
|
||||
check!("xy", [lit!("x"), lit!("y")]; );
|
||||
check!("1", [lit!("1")]; );
|
||||
check!("1234", [lit!("1234")]; );
|
||||
check!("+1234", [lit!("+1234")]; );
|
||||
check!("PST", [lit!("PST")]; );
|
||||
check!("🤠", [lit!("🤠")]; );
|
||||
check!("🤠a", [lit!("🤠"), lit!("a")]; );
|
||||
check!("🤠a🤠", [lit!("🤠"), lit!("a🤠")]; );
|
||||
check!("a🤠b", [lit!("a"), lit!("🤠"), lit!("b")]; );
|
||||
// literals can be together
|
||||
check!("xy", [lit!("xy")]; );
|
||||
check!("xyz", [lit!("xyz")]; );
|
||||
// or literals can be apart
|
||||
check!("xy", [lit!("x"), lit!("y")]; );
|
||||
check!("xyz", [lit!("x"), lit!("yz")]; );
|
||||
check!("xyz", [lit!("xy"), lit!("z")]; );
|
||||
check!("xyz", [lit!("x"), lit!("y"), lit!("z")]; );
|
||||
//
|
||||
check!("x y", [lit!("x"), lit!("y")]; INVALID);
|
||||
check!("xy", [lit!("x"), sp!(""), lit!("y")]; );
|
||||
check!("x y", [lit!("x"), sp!(""), lit!("y")]; );
|
||||
check!("x y", [lit!("x"), sp!(" "), lit!("y")]; );
|
||||
|
||||
// whitespaces + literals
|
||||
check!("a\n", [lit!("a"), sp!("\n")]; );
|
||||
check!("\tab\n", [sp!("\t"), lit!("ab"), sp!("\n")]; );
|
||||
check!("ab\tcd\ne", [lit!("ab"), sp!("\t"), lit!("cd"), sp!("\n"), lit!("e")]; );
|
||||
check!("+1ab\tcd\r\n+,.", [lit!("+1ab"), sp!("\t"), lit!("cd"), sp!("\r\n"), lit!("+,.")]; );
|
||||
// whitespace and literals can be intermixed
|
||||
check!("a\tb", [lit!("a\tb")]; );
|
||||
check!("a\tb", [lit!("a"), sp!("\t"), lit!("b")]; );
|
||||
|
||||
// numeric
|
||||
check!("1987", [num!(Year)]; year: 1987);
|
||||
check!("1987 ", [num!(Year)]; TOO_LONG);
|
||||
check!("0x12", [num!(Year)]; TOO_LONG); // `0` is parsed
|
||||
check!("x123", [num!(Year)]; INVALID);
|
||||
check!("o123", [num!(Year)]; INVALID);
|
||||
check!("2015", [num!(Year)]; year: 2015);
|
||||
check!("0000", [num!(Year)]; year: 0);
|
||||
check!("9999", [num!(Year)]; year: 9999);
|
||||
check!(" \t987", [num!(Year)]; year: 987);
|
||||
check!(" \t987", [sp!(" \t"), num!(Year)]; year: 987);
|
||||
check!(" \t987🤠", [sp!(" \t"), num!(Year), lit!("🤠")]; year: 987);
|
||||
check!("987🤠", [num!(Year), lit!("🤠")]; year: 987);
|
||||
check!("5", [num!(Year)]; year: 5);
|
||||
check!("5\0", [num!(Year)]; TOO_LONG);
|
||||
check!("\x005", [num!(Year)]; INVALID);
|
||||
@ -587,11 +668,15 @@ fn test_parse() {
|
||||
check!("12345", [num0!(Year), lit!("5")]; year: 1234);
|
||||
check!("12341234", [num!(Year), num!(Year)]; year: 1234);
|
||||
check!("1234 1234", [num!(Year), num!(Year)]; year: 1234);
|
||||
check!("1234 1234", [num!(Year), sp!(" "), num!(Year)]; year: 1234);
|
||||
check!("1234 1235", [num!(Year), num!(Year)]; IMPOSSIBLE);
|
||||
check!("1234 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID);
|
||||
check!("1234x1234", [num!(Year), lit!("x"), num!(Year)]; year: 1234);
|
||||
check!("1234xx1234", [num!(Year), lit!("x"), num!(Year)]; INVALID);
|
||||
check!("1234 x 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID);
|
||||
check!("1234xx1234", [num!(Year), lit!("x"), num!(Year)]; INVALID);
|
||||
check!("1234xx1234", [num!(Year), lit!("xx"), num!(Year)]; year: 1234);
|
||||
check!("1234 x 1234", [num!(Year), sp!(" "), lit!("x"), sp!(" "), num!(Year)]; year: 1234);
|
||||
check!("1234 x 1235", [num!(Year), sp!(" "), lit!("x"), sp!(" "), lit!("1235")]; year: 1234);
|
||||
|
||||
// signed numeric
|
||||
check!("-42", [num!(Year)]; year: -42);
|
||||
@ -602,8 +687,14 @@ fn test_parse() {
|
||||
check!("+42195", [num!(Year)]; year: 42195);
|
||||
check!(" -42195", [num!(Year)]; year: -42195);
|
||||
check!(" +42195", [num!(Year)]; year: 42195);
|
||||
check!("-42195 ", [num!(Year)]; TOO_LONG);
|
||||
check!("+42195 ", [num!(Year)]; TOO_LONG);
|
||||
check!(" - 42", [num!(Year)]; INVALID);
|
||||
check!(" + 42", [num!(Year)]; INVALID);
|
||||
check!(" -42195", [sp!(" "), num!(Year)]; year: -42195);
|
||||
check!(" +42195", [sp!(" "), num!(Year)]; year: 42195);
|
||||
check!(" - 42", [sp!(" "), num!(Year)]; INVALID);
|
||||
check!(" + 42", [sp!(" "), num!(Year)]; INVALID);
|
||||
check!("-", [num!(Year)]; TOO_SHORT);
|
||||
check!("+", [num!(Year)]; TOO_SHORT);
|
||||
|
||||
@ -612,8 +703,16 @@ fn test_parse() {
|
||||
check!("+345", [num!(Ordinal)]; INVALID);
|
||||
check!("-345", [num!(Ordinal)]; INVALID);
|
||||
check!(" 345", [num!(Ordinal)]; ordinal: 345);
|
||||
check!(" 345", [sp!(" "), num!(Ordinal)]; ordinal: 345);
|
||||
check!("345 ", [num!(Ordinal), sp!(" ")]; ordinal: 345);
|
||||
check!("345🤠 ", [num!(Ordinal), lit!("🤠"), sp!(" ")]; ordinal: 345);
|
||||
check!("345🤠", [num!(Ordinal)]; TOO_LONG);
|
||||
check!("\u{0363}345", [num!(Ordinal)]; INVALID);
|
||||
check!(" +345", [num!(Ordinal)]; INVALID);
|
||||
check!(" -345", [num!(Ordinal)]; INVALID);
|
||||
check!("\t345", [sp!("\t"), num!(Ordinal)]; ordinal: 345);
|
||||
check!(" +345", [sp!(" "), num!(Ordinal)]; INVALID);
|
||||
check!(" -345", [sp!(" "), num!(Ordinal)]; INVALID);
|
||||
|
||||
// various numeric fields
|
||||
check!("1234 5678",
|
||||
@ -639,6 +738,7 @@ fn test_parse() {
|
||||
check!("Apr", [fix!(ShortMonthName)]; month: 4);
|
||||
check!("APR", [fix!(ShortMonthName)]; month: 4);
|
||||
check!("ApR", [fix!(ShortMonthName)]; month: 4);
|
||||
check!("\u{0363}APR", [fix!(ShortMonthName)]; INVALID);
|
||||
check!("April", [fix!(ShortMonthName)]; TOO_LONG); // `Apr` is parsed
|
||||
check!("A", [fix!(ShortMonthName)]; TOO_SHORT);
|
||||
check!("Sol", [fix!(ShortMonthName)]; INVALID);
|
||||
@ -676,7 +776,15 @@ fn test_parse() {
|
||||
check!("AM", [fix!(UpperAmPm)]; hour_div_12: 0);
|
||||
check!("PM", [fix!(UpperAmPm)]; hour_div_12: 1);
|
||||
check!("Am", [fix!(LowerAmPm)]; hour_div_12: 0);
|
||||
check!(" Am", [sp!(" "), fix!(LowerAmPm)]; hour_div_12: 0);
|
||||
check!("Am🤠", [fix!(LowerAmPm), lit!("🤠")]; hour_div_12: 0);
|
||||
check!("🤠Am", [lit!("🤠"), fix!(LowerAmPm)]; hour_div_12: 0);
|
||||
check!("\u{0363}am", [fix!(LowerAmPm)]; INVALID);
|
||||
check!("\u{0360}am", [fix!(LowerAmPm)]; INVALID);
|
||||
check!(" Am", [fix!(LowerAmPm)]; INVALID);
|
||||
check!("Am ", [fix!(LowerAmPm)]; TOO_LONG);
|
||||
check!("a.m.", [fix!(LowerAmPm)]; INVALID);
|
||||
check!("A.M.", [fix!(LowerAmPm)]; INVALID);
|
||||
check!("ame", [fix!(LowerAmPm)]; TOO_LONG); // `am` is parsed
|
||||
check!("a", [fix!(LowerAmPm)]; TOO_SHORT);
|
||||
check!("p", [fix!(LowerAmPm)]; TOO_SHORT);
|
||||
@ -693,10 +801,21 @@ fn test_parse() {
|
||||
check!(".42", [fix!(Nanosecond)]; nanosecond: 420_000_000);
|
||||
check!(".421", [fix!(Nanosecond)]; nanosecond: 421_000_000);
|
||||
check!(".42195", [fix!(Nanosecond)]; nanosecond: 421_950_000);
|
||||
check!(".421951", [fix!(Nanosecond)]; nanosecond: 421_951_000);
|
||||
check!(".4219512", [fix!(Nanosecond)]; nanosecond: 421_951_200);
|
||||
check!(".42195123", [fix!(Nanosecond)]; nanosecond: 421_951_230);
|
||||
check!(".421950803", [fix!(Nanosecond)]; nanosecond: 421_950_803);
|
||||
check!(".4219508035", [fix!(Nanosecond)]; nanosecond: 421_950_803);
|
||||
check!(".42195080354", [fix!(Nanosecond)]; nanosecond: 421_950_803);
|
||||
check!(".421950803547", [fix!(Nanosecond)]; nanosecond: 421_950_803);
|
||||
check!(".000000003", [fix!(Nanosecond)]; nanosecond: 3);
|
||||
check!(".0000000031", [fix!(Nanosecond)]; nanosecond: 3);
|
||||
check!(".0000000035", [fix!(Nanosecond)]; nanosecond: 3);
|
||||
check!(".000000003547", [fix!(Nanosecond)]; nanosecond: 3);
|
||||
check!(".0000000009", [fix!(Nanosecond)]; nanosecond: 0);
|
||||
check!(".000000000547", [fix!(Nanosecond)]; nanosecond: 0);
|
||||
check!(".0000000009999999999999999999999999", [fix!(Nanosecond)]; nanosecond: 0);
|
||||
check!(".4🤠", [fix!(Nanosecond), lit!("🤠")]; nanosecond: 400_000_000);
|
||||
check!(".", [fix!(Nanosecond)]; TOO_SHORT);
|
||||
check!(".4x", [fix!(Nanosecond)]; TOO_LONG);
|
||||
check!(". 4", [fix!(Nanosecond)]; INVALID);
|
||||
@ -708,76 +827,400 @@ fn test_parse() {
|
||||
check!("4", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("42", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("421", [internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000);
|
||||
check!("4210", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("42143", [internal_fix!(Nanosecond3NoDot), num!(Second)]; nanosecond: 421_000_000, second: 43);
|
||||
check!("421🤠", [internal_fix!(Nanosecond3NoDot), lit!("🤠")]; nanosecond: 421_000_000);
|
||||
check!("🤠421", [lit!("🤠"), internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000);
|
||||
check!("42195", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("123456789", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("4x", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [internal_fix!(Nanosecond3NoDot)]; INVALID);
|
||||
check!(".421", [internal_fix!(Nanosecond3NoDot)]; INVALID);
|
||||
|
||||
check!("", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("0", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("42195", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("1234", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("12345", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("421950", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000);
|
||||
check!("000003", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 3000);
|
||||
check!("000000", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 0);
|
||||
check!("1234567", [internal_fix!(Nanosecond6NoDot)]; TOO_LONG);
|
||||
check!("123456789", [internal_fix!(Nanosecond6NoDot)]; TOO_LONG);
|
||||
check!("4x", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [internal_fix!(Nanosecond6NoDot)]; INVALID);
|
||||
check!(".42100", [internal_fix!(Nanosecond6NoDot)]; INVALID);
|
||||
|
||||
check!("", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("42195", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("12345678", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("421950803", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803);
|
||||
check!("000000003", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 3);
|
||||
check!("42195080354", [internal_fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9
|
||||
check!("421950803547", [internal_fix!(Nanosecond9NoDot)]; TOO_LONG);
|
||||
check!("1234567890", [internal_fix!(Nanosecond9NoDot)]; TOO_LONG);
|
||||
check!("000000000", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 0);
|
||||
check!("00000000x", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(" 4", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(".42100000", [internal_fix!(Nanosecond9NoDot)]; INVALID);
|
||||
|
||||
// fixed: timezone offsets
|
||||
check!("+00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
check!("-00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
check!("+00:01", [fix!(TimezoneOffset)]; offset: 60);
|
||||
check!("-00:01", [fix!(TimezoneOffset)]; offset: -60);
|
||||
check!("+00:30", [fix!(TimezoneOffset)]; offset: 30 * 60);
|
||||
check!("-00:30", [fix!(TimezoneOffset)]; offset: -30 * 60);
|
||||
check!("+04:56", [fix!(TimezoneOffset)]; offset: 296 * 60);
|
||||
check!("-04:56", [fix!(TimezoneOffset)]; offset: -296 * 60);
|
||||
check!("+24:00", [fix!(TimezoneOffset)]; offset: 24 * 60 * 60);
|
||||
check!("-24:00", [fix!(TimezoneOffset)]; offset: -24 * 60 * 60);
|
||||
check!("+99:59", [fix!(TimezoneOffset)]; offset: (100 * 60 - 1) * 60);
|
||||
check!("-99:59", [fix!(TimezoneOffset)]; offset: -(100 * 60 - 1) * 60);
|
||||
check!("+00:59", [fix!(TimezoneOffset)]; offset: 59 * 60);
|
||||
check!("+00:60", [fix!(TimezoneOffset)]; OUT_OF_RANGE);
|
||||
check!("+00:99", [fix!(TimezoneOffset)]; OUT_OF_RANGE);
|
||||
check!("#12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+12:34 ", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!(" +12:34", [fix!(TimezoneOffset)]; offset: 754 * 60);
|
||||
check!("\t -12:34", [fix!(TimezoneOffset)]; offset: -754 * 60);
|
||||
check!("", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+1", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+12", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+123", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+1234", [fix!(TimezoneOffset)]; offset: 754 * 60);
|
||||
check!("+12345", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12345", [fix!(TimezoneOffset), num!(Day)]; offset: 754 * 60, day: 5);
|
||||
check!("Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("Z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!("z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!("Y", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("Zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0);
|
||||
check!("zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0);
|
||||
check!("+1234ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60);
|
||||
check!("+12:34ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60);
|
||||
check!("Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("+12:00", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60);
|
||||
check!("+12", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60);
|
||||
check!("CEST 5", [fix!(TimezoneName), lit!(" "), num!(Day)]; day: 5);
|
||||
|
||||
// TimezoneOffset
|
||||
check!("1", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("12", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("123", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("1234", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("12345", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("123456", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("1234567", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+1", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+12", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+123", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+1234", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12345", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+123456", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+1234567", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12345678", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+12:3", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+12:34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("-12:34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("+12:34:", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:34:5", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:34:56", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:34:56:", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12 34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12 34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("12:34:56", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+12::34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12: :34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12:::34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12::::34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12::34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("+12:34:56", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:3456", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+1234:56", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+1234:567", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
check!("-00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
check!("+00:01", [fix!(TimezoneOffset)]; offset: 60);
|
||||
check!("-00:01", [fix!(TimezoneOffset)]; offset: -60);
|
||||
check!("+00:30", [fix!(TimezoneOffset)]; offset: 1_800);
|
||||
check!("-00:30", [fix!(TimezoneOffset)]; offset: -1_800);
|
||||
check!("+24:00", [fix!(TimezoneOffset)]; offset: 86_400);
|
||||
check!("-24:00", [fix!(TimezoneOffset)]; offset: -86_400);
|
||||
check!("+99:59", [fix!(TimezoneOffset)]; offset: 359_940);
|
||||
check!("-99:59", [fix!(TimezoneOffset)]; offset: -359_940);
|
||||
check!("+00:60", [fix!(TimezoneOffset)]; OUT_OF_RANGE);
|
||||
check!("+00:99", [fix!(TimezoneOffset)]; OUT_OF_RANGE);
|
||||
check!("#12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+12:34 ", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12 34 ", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!(" +12:34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!(" -12:34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!(" +12:34", [fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!(" -12:34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("\t -12:34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12: 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 :34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 : 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 : 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 : 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12: 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 :34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("-12 : 34", [fix!(TimezoneOffset)]; offset: -45_240);
|
||||
check!("12:34 ", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!(" 12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+12345", [fix!(TimezoneOffset), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:345", [fix!(TimezoneOffset), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:34:", [fix!(TimezoneOffset), lit!(":")]; offset: 45_240);
|
||||
check!("Z12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("X12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("Z+12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("X+12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("🤠+12:34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+12:34🤠", [fix!(TimezoneOffset)]; TOO_LONG);
|
||||
check!("+12:🤠34", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+12:34🤠", [fix!(TimezoneOffset), lit!("🤠")]; offset: 45_240);
|
||||
check!("🤠+12:34", [lit!("🤠"), fix!(TimezoneOffset)]; offset: 45_240);
|
||||
check!("Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("A", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("PST", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("#Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!(":Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+Z", [fix!(TimezoneOffset)]; TOO_SHORT);
|
||||
check!("+:Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("+Z:", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!("z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!(" :Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!(" Z", [fix!(TimezoneOffset)]; INVALID);
|
||||
check!(" z", [fix!(TimezoneOffset)]; INVALID);
|
||||
|
||||
// TimezoneOffsetColon
|
||||
check!("1", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("123", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("1234", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12345", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("123456", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("1234567", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12345678", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+1", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+12", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+123", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+1234", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("-1234", [fix!(TimezoneOffsetColon)]; offset: -45_240);
|
||||
check!("+12345", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+123456", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+1234567", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12345678", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("1:", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:3", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:34", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:34:", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:34:5", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("12:34:56", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+1:", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+12:", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+12:3", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("-12:34", [fix!(TimezoneOffsetColon)]; offset: -45_240);
|
||||
check!("+12:34:", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:34:5", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:34:56", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:34:56:", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:34:56:7", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:34:56:78", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12:3456", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+1234:56", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!("+12 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12: 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12 :34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12::34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12: :34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12:::34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12::::34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("+12::34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("#1234", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("#12:34", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+12:34 ", [fix!(TimezoneOffsetColon)]; TOO_LONG);
|
||||
check!(" +12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("\t+12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("\t\t+12:34", [fix!(TimezoneOffsetColon)]; offset: 45_240);
|
||||
check!("12:34 ", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!(" 12:34", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!(":", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+12345", [fix!(TimezoneOffsetColon), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:345", [fix!(TimezoneOffsetColon), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:34:", [fix!(TimezoneOffsetColon), lit!(":")]; offset: 45_240);
|
||||
check!("Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("A", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("PST", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("#Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!(":Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+Z", [fix!(TimezoneOffsetColon)]; TOO_SHORT);
|
||||
check!("+:Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("+Z:", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!("z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!(" :Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!(" Z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
check!(" z", [fix!(TimezoneOffsetColon)]; INVALID);
|
||||
// testing `TimezoneOffsetColon` also tests same path as `TimezoneOffsetDoubleColon`
|
||||
// and `TimezoneOffsetTripleColon` for function `parse_internal`.
|
||||
// No need for separate tests for `TimezoneOffsetDoubleColon` and
|
||||
// `TimezoneOffsetTripleColon`.
|
||||
|
||||
// TimezoneOffsetZ
|
||||
check!("1", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("123", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("1234", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12345", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("123456", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("1234567", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12345678", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+1", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+12", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+123", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+1234", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("-1234", [fix!(TimezoneOffsetZ)]; offset: -45_240);
|
||||
check!("+12345", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+123456", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+1234567", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12345678", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("1:", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:3", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:34", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:34:", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:34:5", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("12:34:56", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+1:", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+12:", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+12:3", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+12:34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("-12:34", [fix!(TimezoneOffsetZ)]; offset: -45_240);
|
||||
check!("+12:34:", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12:34:5", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12:34:56", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12:34:56:", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12:34:56:7", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12:34:56:78", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12::34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12:3456", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+1234:56", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12: 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 :34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12 : 34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("12:34 ", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!(" 12:34", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+12:34 ", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("+12 34 ", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!(" +12:34", [fix!(TimezoneOffsetZ)]; offset: 45_240);
|
||||
check!("+12345", [fix!(TimezoneOffsetZ), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:345", [fix!(TimezoneOffsetZ), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:34:", [fix!(TimezoneOffsetZ), lit!(":")]; offset: 45_240);
|
||||
check!("Z12:34", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("X12:34", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("Z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!("z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!(" Z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!(" z", [fix!(TimezoneOffsetZ)]; offset: 0);
|
||||
check!("\u{0363}Z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("Z ", [fix!(TimezoneOffsetZ)]; TOO_LONG);
|
||||
check!("A", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("PST", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("#Z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!(":Z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!(":z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("-Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+A", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+🙃", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("+Z:", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!(" :Z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!(" +Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!(" -Z", [fix!(TimezoneOffsetZ)]; TOO_SHORT);
|
||||
check!("+:Z", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("Y", [fix!(TimezoneOffsetZ)]; INVALID);
|
||||
check!("Zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0);
|
||||
check!("zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0);
|
||||
check!("+1234ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 45_240);
|
||||
check!("+12:34ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 45_240);
|
||||
// Testing `TimezoneOffsetZ` also tests same path as `TimezoneOffsetColonZ`
|
||||
// in function `parse_internal`.
|
||||
// No need for separate tests for `TimezoneOffsetColonZ`.
|
||||
|
||||
// TimezoneOffsetPermissive
|
||||
check!("1", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("123", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("1234", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12345", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("123456", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("1234567", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12345678", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+1", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+12", [internal_fix!(TimezoneOffsetPermissive)]; offset: 43_200);
|
||||
check!("+123", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+1234", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("-1234", [internal_fix!(TimezoneOffsetPermissive)]; offset: -45_240);
|
||||
check!("+12345", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+123456", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+1234567", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12345678", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("1:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:3", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:34:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+1:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+12:", [internal_fix!(TimezoneOffsetPermissive)]; offset: 43_200);
|
||||
check!("+12:3", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("-12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: -45_240);
|
||||
check!("+12:34:", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:34:5", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:34:56", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:34:56:", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:34:56:7", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:34:56:78", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12::34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12 ::34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12: :34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12:: 34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12:::34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12::::34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!(" 12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+12:34 ", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!(" +12:34", [internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("+12345", [internal_fix!(TimezoneOffsetPermissive), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:345", [internal_fix!(TimezoneOffsetPermissive), num!(Day)]; offset: 45_240, day: 5);
|
||||
check!("+12:34:", [internal_fix!(TimezoneOffsetPermissive), lit!(":")]; offset: 45_240);
|
||||
check!("🤠+12:34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+12:34🤠", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("+12:🤠34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+12:34🤠", [internal_fix!(TimezoneOffsetPermissive), lit!("🤠")]; offset: 45_240);
|
||||
check!("🤠+12:34", [lit!("🤠"), internal_fix!(TimezoneOffsetPermissive)]; offset: 45_240);
|
||||
check!("Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("A", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("PST", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!(" Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!(" z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0);
|
||||
check!("Z ", [internal_fix!(TimezoneOffsetPermissive)]; TOO_LONG);
|
||||
check!("#Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!(":Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!(":z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("-Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+A", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+PST", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+🙃", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("+Z:", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!(" :Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!(" +Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!(" -Z", [internal_fix!(TimezoneOffsetPermissive)]; TOO_SHORT);
|
||||
check!("+:Z", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
check!("Y", [internal_fix!(TimezoneOffsetPermissive)]; INVALID);
|
||||
|
||||
// TimezoneName
|
||||
check!("CEST", [fix!(TimezoneName)]; );
|
||||
check!("cest", [fix!(TimezoneName)]; ); // lowercase
|
||||
check!("XXXXXXXX", [fix!(TimezoneName)]; ); // not a real timezone name
|
||||
check!("!!!!", [fix!(TimezoneName)]; ); // not a real timezone name!
|
||||
check!("CEST 5", [fix!(TimezoneName), lit!(" "), num!(Day)]; day: 5);
|
||||
check!("CEST ", [fix!(TimezoneName)]; TOO_LONG);
|
||||
check!(" CEST", [fix!(TimezoneName)]; TOO_LONG);
|
||||
check!("CE ST", [fix!(TimezoneName)]; TOO_LONG);
|
||||
|
||||
// some practical examples
|
||||
check!("2015-02-04T14:37:05+09:00",
|
||||
@ -790,10 +1233,31 @@ fn test_parse() {
|
||||
num!(Hour), num!(Minute), num!(Second), internal_fix!(Nanosecond3NoDot)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, nanosecond: 567000000);
|
||||
check!("Mon, 10 Jun 2013 09:32:37 GMT",
|
||||
check!("20150204143705.567",
|
||||
[num!(Year), num!(Month), num!(Day),
|
||||
num!(Hour), num!(Minute), num!(Second), fix!(Nanosecond)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, nanosecond: 567000000);
|
||||
check!("20150204143705.567891",
|
||||
[num!(Year), num!(Month), num!(Day),
|
||||
num!(Hour), num!(Minute), num!(Second), fix!(Nanosecond)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, nanosecond: 567891000);
|
||||
check!("20150204143705.567891023",
|
||||
[num!(Year), num!(Month), num!(Day),
|
||||
num!(Hour), num!(Minute), num!(Second), fix!(Nanosecond)];
|
||||
year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2,
|
||||
minute: 37, second: 5, nanosecond: 567891023);
|
||||
check!("Mon, 10 Jun 2013 09:32:37 GMT",
|
||||
[fix!(ShortWeekdayName), lit!(","), sp!(" "), num!(Day), sp!(" "),
|
||||
fix!(ShortMonthName), sp!(" "), num!(Year), sp!(" "), num!(Hour), lit!(":"),
|
||||
num!(Minute), lit!(":"), num!(Second), sp!(" "), lit!("GMT")];
|
||||
num!(Minute), lit!(":"), num!(Second), sp!(" "), lit!("GMT")];
|
||||
year: 2013, month: 6, day: 10, weekday: Weekday::Mon,
|
||||
hour_div_12: 0, hour_mod_12: 9, minute: 32, second: 37);
|
||||
check!("🤠Mon, 10 Jun🤠2013 09:32:37 GMT🤠",
|
||||
[lit!("🤠"), fix!(ShortWeekdayName), lit!(","), sp!(" "), num!(Day), sp!(" "),
|
||||
fix!(ShortMonthName), lit!("🤠"), num!(Year), sp!(" "), num!(Hour), lit!(":"),
|
||||
num!(Minute), lit!(":"), num!(Second), sp!(" "), lit!("GMT"), lit!("🤠")];
|
||||
year: 2013, month: 6, day: 10, weekday: Weekday::Mon,
|
||||
hour_div_12: 0, hour_mod_12: 9, minute: 32, second: 37);
|
||||
check!("Sun Aug 02 13:39:15 CEST 2020",
|
||||
@ -814,6 +1278,22 @@ fn test_parse() {
|
||||
check!("12345678901234.56789",
|
||||
[num!(Timestamp), fix!(Nanosecond)];
|
||||
nanosecond: 567_890_000, timestamp: 12_345_678_901_234);
|
||||
|
||||
// docstring examples from `impl str::FromStr`
|
||||
check!("2000-01-02T03:04:05Z",
|
||||
[num!(Year), lit!("-"), num!(Month), lit!("-"), num!(Day), lit!("T"),
|
||||
num!(Hour), lit!(":"), num!(Minute), lit!(":"), num!(Second),
|
||||
internal_fix!(TimezoneOffsetPermissive)];
|
||||
year: 2000, month: 1, day: 2,
|
||||
hour_div_12: 0, hour_mod_12: 3, minute: 4, second: 5,
|
||||
offset: 0);
|
||||
check!("2000-01-02 03:04:05Z",
|
||||
[num!(Year), lit!("-"), num!(Month), lit!("-"), num!(Day), sp!(" "),
|
||||
num!(Hour), lit!(":"), num!(Minute), lit!(":"), num!(Second),
|
||||
internal_fix!(TimezoneOffsetPermissive)];
|
||||
year: 2000, month: 1, day: 2,
|
||||
hour_div_12: 0, hour_mod_12: 3, minute: 4, second: 5,
|
||||
offset: 0);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -830,6 +1310,8 @@ fn test_rfc2822() {
|
||||
("Fri, 2 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // folding whitespace
|
||||
("Fri, 02 Jan 2015 17:35:20 -0800", Ok("Fri, 02 Jan 2015 17:35:20 -0800")), // leading zero
|
||||
("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // trailing comment
|
||||
("Tue, 20 Jan 2015 17:35:20 -0800 (UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // intermixed arbitrary whitespace
|
||||
("Tue, 20 Jan 2015\t17:35:20\t-0800\t\t(UTC)", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // intermixed arbitrary whitespace
|
||||
(
|
||||
r"Tue, 20 Jan 2015 17:35:20 -0800 ( (UTC ) (\( (a)\(( \t ) ) \\( \) ))",
|
||||
Ok("Tue, 20 Jan 2015 17:35:20 -0800"),
|
||||
@ -876,6 +1358,7 @@ fn test_rfc2822() {
|
||||
("Tue, 20 Jan 2015 17:35:20 k", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
|
||||
// named single-letter timezone "J" is specifically not valid
|
||||
("Tue, 20 Jan 2015 17:35:20 J", Err(NOT_ENOUGH)),
|
||||
("Tue, 20 Jan 2015😈17:35:20 -0800", Err(INVALID)), // bad character!
|
||||
];
|
||||
|
||||
fn rfc2822_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||
@ -963,11 +1446,26 @@ fn test_rfc3339() {
|
||||
("2015-01-20T17:35:20.000031-08:00", Ok("2015-01-20T17:35:20.000031-08:00")),
|
||||
("2015-01-20T17:35:20.000000004-08:00", Ok("2015-01-20T17:35:20.000000004-08:00")),
|
||||
("2015-01-20T17:35:20.000000000452-08:00", Ok("2015-01-20T17:35:20-08:00")), // too small
|
||||
("2015-02-30T17:35:20-08:00", Err(OUT_OF_RANGE)), // bad day of month
|
||||
("2015-01-20T25:35:20-08:00", Err(OUT_OF_RANGE)), // bad hour
|
||||
("2015-01-20T17:65:20-08:00", Err(OUT_OF_RANGE)), // bad minute
|
||||
("2015-01-20T17:35:90-08:00", Err(OUT_OF_RANGE)), // bad second
|
||||
("2015-01-20T17:35:20-24:00", Err(OUT_OF_RANGE)), // bad offset
|
||||
("2015-01-20 17:35:20.001-08:00", Err(INVALID)), // missing separator 'T'
|
||||
("2015/01/20T17:35:20.001-08:00", Err(INVALID)), // wrong separator char YMD
|
||||
("2015-01-20T17-35-20.001-08:00", Err(INVALID)), // wrong separator char HMS
|
||||
("99999-01-20T17:35:20-08:00", Err(INVALID)), // bad year value
|
||||
("-2000-01-20T17:35:20-08:00", Err(INVALID)), // bad year value
|
||||
("2015-02-30T17:35:20-08:00", Err(OUT_OF_RANGE)), // bad day of month value
|
||||
("2015-01-20T25:35:20-08:00", Err(OUT_OF_RANGE)), // bad hour value
|
||||
("2015-01-20T17:65:20-08:00", Err(OUT_OF_RANGE)), // bad minute value
|
||||
("2015-01-20T17:35:90-08:00", Err(OUT_OF_RANGE)), // bad second value
|
||||
("2015-01-20T17:35:20-24:00", Err(OUT_OF_RANGE)), // bad offset value
|
||||
("15-01-20T17:35:20-08:00", Err(INVALID)), // bad year format
|
||||
("15-01-20T17:35:20-08:00:00", Err(INVALID)), // bad year format, bad offset format
|
||||
("2015-01-20T17:35:20-0800", Err(INVALID)), // bad offset format
|
||||
("2015-01-20T17:35:20.001-08 : 00", Err(INVALID)), // bad offset format
|
||||
("2015-01-20T17:35:20-08:00:00", Err(TOO_LONG)), // bad offset format
|
||||
("2015-01-20T17:35:20-08:", Err(TOO_SHORT)), // bad offset format
|
||||
("2015-01-20T17:35:20-08", Err(TOO_SHORT)), // bad offset format
|
||||
("2015-01-20T", Err(TOO_SHORT)), // missing HMS
|
||||
("2015-01-20T00:00:1", Err(TOO_SHORT)), // missing complete S
|
||||
("2015-01-20T00:00:1-08:00", Err(INVALID)), // missing complete S
|
||||
];
|
||||
|
||||
fn rfc3339_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||
@ -982,6 +1480,7 @@ fn test_rfc3339() {
|
||||
|
||||
// Test against test data above
|
||||
for &(date, checkdate) in testdates.iter() {
|
||||
eprintln!("test_rfc3339: date {:?}, expect {:?}", date, checkdate);
|
||||
let d = rfc3339_to_datetime(date); // parse a date
|
||||
let dt = match d {
|
||||
// did we get a value?
|
||||
|
@ -513,12 +513,32 @@ impl<'a> Iterator for StrftimeItems<'a> {
|
||||
fn test_strftime_items() {
|
||||
fn parse_and_collect(s: &str) -> Vec<Item<'_>> {
|
||||
// map any error into `[Item::Error]`. useful for easy testing.
|
||||
eprintln!("test_strftime_items: parse_and_collect({:?})", s);
|
||||
let items = StrftimeItems::new(s);
|
||||
let items = items.map(|spec| if spec == Item::Error { None } else { Some(spec) });
|
||||
items.collect::<Option<Vec<_>>>().unwrap_or_else(|| vec![Item::Error])
|
||||
}
|
||||
|
||||
assert_eq!(parse_and_collect(""), []);
|
||||
assert_eq!(parse_and_collect(" "), [sp!(" ")]);
|
||||
assert_eq!(parse_and_collect(" "), [sp!(" ")]);
|
||||
// ne!
|
||||
assert_ne!(parse_and_collect(" "), [sp!(" "), sp!(" ")]);
|
||||
// eq!
|
||||
assert_eq!(parse_and_collect(" "), [sp!(" ")]);
|
||||
assert_eq!(parse_and_collect("a"), [lit!("a")]);
|
||||
assert_eq!(parse_and_collect("ab"), [lit!("ab")]);
|
||||
assert_eq!(parse_and_collect("😽"), [lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("a😽"), [lit!("a😽")]);
|
||||
assert_eq!(parse_and_collect("😽a"), [lit!("😽a")]);
|
||||
assert_eq!(parse_and_collect(" 😽"), [sp!(" "), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("😽 "), [lit!("😽"), sp!(" ")]);
|
||||
// ne!
|
||||
assert_ne!(parse_and_collect("😽😽"), [lit!("😽")]);
|
||||
assert_ne!(parse_and_collect("😽"), [lit!("😽😽")]);
|
||||
assert_ne!(parse_and_collect("😽😽"), [lit!("😽😽"), lit!("😽")]);
|
||||
// eq!
|
||||
assert_eq!(parse_and_collect("😽😽"), [lit!("😽😽")]);
|
||||
assert_eq!(parse_and_collect(" \t\n\r "), [sp!(" \t\n\r ")]);
|
||||
assert_eq!(parse_and_collect("hello?"), [lit!("hello?")]);
|
||||
assert_eq!(
|
||||
@ -532,12 +552,63 @@ fn test_strftime_items() {
|
||||
parse_and_collect("%Y-%m-%d"),
|
||||
[num0!(Year), lit!("-"), num0!(Month), lit!("-"), num0!(Day)]
|
||||
);
|
||||
assert_eq!(parse_and_collect("😽 "), [lit!("😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect("😽😽"), [lit!("😽😽")]);
|
||||
assert_eq!(parse_and_collect("😽😽😽"), [lit!("😽😽😽")]);
|
||||
assert_eq!(parse_and_collect("😽😽 😽"), [lit!("😽😽"), sp!(" "), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("😽😽a 😽"), [lit!("😽😽a"), sp!(" "), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("😽😽a b😽"), [lit!("😽😽a"), sp!(" "), lit!("b😽")]);
|
||||
assert_eq!(parse_and_collect("😽😽a b😽c"), [lit!("😽😽a"), sp!(" "), lit!("b😽c")]);
|
||||
assert_eq!(parse_and_collect("😽😽 "), [lit!("😽😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect("😽😽 😽"), [lit!("😽😽"), sp!(" "), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect(" 😽"), [sp!(" "), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect(" 😽 "), [sp!(" "), lit!("😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect(" 😽 😽"), [sp!(" "), lit!("😽"), sp!(" "), lit!("😽")]);
|
||||
assert_eq!(
|
||||
parse_and_collect(" 😽 😽 "),
|
||||
[sp!(" "), lit!("😽"), sp!(" "), lit!("😽"), sp!(" ")]
|
||||
);
|
||||
assert_eq!(
|
||||
parse_and_collect(" 😽 😽 "),
|
||||
[sp!(" "), lit!("😽"), sp!(" "), lit!("😽"), sp!(" ")]
|
||||
);
|
||||
assert_eq!(
|
||||
parse_and_collect(" 😽 😽😽 "),
|
||||
[sp!(" "), lit!("😽"), sp!(" "), lit!("😽😽"), sp!(" ")]
|
||||
);
|
||||
assert_eq!(parse_and_collect(" 😽😽"), [sp!(" "), lit!("😽😽")]);
|
||||
assert_eq!(parse_and_collect(" 😽😽 "), [sp!(" "), lit!("😽😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect(" 😽😽 "), [sp!(" "), lit!("😽😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect(" 😽😽 "), [sp!(" "), lit!("😽😽"), sp!(" ")]);
|
||||
assert_eq!(parse_and_collect(" 😽😽 "), [sp!(" "), lit!("😽😽"), sp!(" ")]);
|
||||
assert_eq!(
|
||||
parse_and_collect(" 😽 😽😽 "),
|
||||
[sp!(" "), lit!("😽"), sp!(" "), lit!("😽😽"), sp!(" ")]
|
||||
);
|
||||
assert_eq!(
|
||||
parse_and_collect(" 😽 😽はい😽 ハンバーガー"),
|
||||
[sp!(" "), lit!("😽"), sp!(" "), lit!("😽はい😽"), sp!(" "), lit!("ハンバーガー")]
|
||||
);
|
||||
assert_eq!(parse_and_collect("%%😽%%😽"), [lit!("%"), lit!("😽"), lit!("%"), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("%Y--%m"), [num0!(Year), lit!("--"), num0!(Month)]);
|
||||
assert_eq!(parse_and_collect("[%F]"), parse_and_collect("[%Y-%m-%d]"));
|
||||
assert_eq!(parse_and_collect("100%%😽"), [lit!("100"), lit!("%"), lit!("😽")]);
|
||||
assert_eq!(
|
||||
parse_and_collect("100%%😽%%a"),
|
||||
[lit!("100"), lit!("%"), lit!("😽"), lit!("%"), lit!("a")]
|
||||
);
|
||||
assert_eq!(parse_and_collect("😽100%%"), [lit!("😽100"), lit!("%")]);
|
||||
assert_eq!(parse_and_collect("%m %d"), [num0!(Month), sp!(" "), num0!(Day)]);
|
||||
assert_eq!(parse_and_collect("%"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("%%"), [lit!("%")]);
|
||||
assert_eq!(parse_and_collect("%%%"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("%a"), [fix!(ShortWeekdayName)]);
|
||||
assert_eq!(parse_and_collect("%aa"), [fix!(ShortWeekdayName), lit!("a")]);
|
||||
assert_eq!(parse_and_collect("%%a%"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("%😽"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("%😽😽"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("%%%%"), [lit!("%"), lit!("%")]);
|
||||
assert_eq!(parse_and_collect("%%%%ハンバーガー"), [lit!("%"), lit!("%"), lit!("ハンバーガー")]);
|
||||
assert_eq!(parse_and_collect("foo%?"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("bar%42"), [Item::Error]);
|
||||
assert_eq!(parse_and_collect("quux% +"), [Item::Error]);
|
||||
@ -557,6 +628,10 @@ fn test_strftime_items() {
|
||||
assert_eq!(parse_and_collect("%0e"), [num0!(Day)]);
|
||||
assert_eq!(parse_and_collect("%_e"), [nums!(Day)]);
|
||||
assert_eq!(parse_and_collect("%z"), [fix!(TimezoneOffset)]);
|
||||
assert_eq!(parse_and_collect("%:z"), [fix!(TimezoneOffsetColon)]);
|
||||
assert_eq!(parse_and_collect("%Z"), [fix!(TimezoneName)]);
|
||||
assert_eq!(parse_and_collect("%ZZZZ"), [fix!(TimezoneName), lit!("ZZZ")]);
|
||||
assert_eq!(parse_and_collect("%Z😽"), [fix!(TimezoneName), lit!("😽")]);
|
||||
assert_eq!(parse_and_collect("%#z"), [internal_fix!(TimezoneOffsetPermissive)]);
|
||||
assert_eq!(parse_and_collect("%#m"), [Item::Error]);
|
||||
}
|
||||
@ -666,6 +741,13 @@ fn test_strftime_docs() {
|
||||
assert_eq!(dt.format("%t").to_string(), "\t");
|
||||
assert_eq!(dt.format("%n").to_string(), "\n");
|
||||
assert_eq!(dt.format("%%").to_string(), "%");
|
||||
|
||||
// complex format specifiers
|
||||
assert_eq!(dt.format(" %Y%d%m%%%%%t%H%M%S\t").to_string(), " 20010807%%\t003460\t");
|
||||
assert_eq!(
|
||||
dt.format(" %Y%d%m%%%%%t%H:%P:%M%S%:::z\t").to_string(),
|
||||
" 20010807%%\t00:am:3460+09\t"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-locales")]
|
||||
|
@ -2828,16 +2828,20 @@ mod tests {
|
||||
"360-02-29",
|
||||
"0360-02-29",
|
||||
"2015-2 -18",
|
||||
"2015-02-18",
|
||||
"+70-2-18",
|
||||
"+70000-2-18",
|
||||
"+00007-2-18",
|
||||
];
|
||||
for &s in &valid {
|
||||
eprintln!("test_date_from_str valid {:?}", s);
|
||||
let d = match s.parse::<NaiveDate>() {
|
||||
Ok(d) => d,
|
||||
Err(e) => panic!("parsing `{}` has failed: {}", s, e),
|
||||
};
|
||||
eprintln!("d {:?} (NaiveDate)", d);
|
||||
let s_ = format!("{:?}", d);
|
||||
eprintln!("s_ {:?}", s_);
|
||||
// `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same
|
||||
let d_ = match s_.parse::<NaiveDate>() {
|
||||
Ok(d) => d,
|
||||
@ -2845,6 +2849,7 @@ mod tests {
|
||||
panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", s, d, e)
|
||||
}
|
||||
};
|
||||
eprintln!("d_ {:?} (NaiveDate)", d_);
|
||||
assert!(
|
||||
d == d_,
|
||||
"`{}` is parsed into `{:?}`, but reparsed result \
|
||||
@ -2857,13 +2862,27 @@ mod tests {
|
||||
|
||||
// some invalid cases
|
||||
// since `ParseErrorKind` is private, all we can do is to check if there was an error
|
||||
assert!("".parse::<NaiveDate>().is_err());
|
||||
assert!("x".parse::<NaiveDate>().is_err());
|
||||
assert!("2014".parse::<NaiveDate>().is_err());
|
||||
assert!("2014-01".parse::<NaiveDate>().is_err());
|
||||
assert!("2014-01-00".parse::<NaiveDate>().is_err());
|
||||
assert!("2014-13-57".parse::<NaiveDate>().is_err());
|
||||
assert!("9999999-9-9".parse::<NaiveDate>().is_err()); // out-of-bounds
|
||||
let invalid = [
|
||||
"", // empty
|
||||
"x", // invalid
|
||||
"Fri, 09 Aug 2013 GMT", // valid date, wrong format
|
||||
"Sat Jun 30 2012", // valid date, wrong format
|
||||
"1441497364.649", // valid datetime, wrong format
|
||||
"+1441497364.649", // valid datetime, wrong format
|
||||
"+1441497364", // valid datetime, wrong format
|
||||
"2014/02/03", // valid date, wrong format
|
||||
"2014", // datetime missing data
|
||||
"2014-01", // datetime missing data
|
||||
"2014-01-00", // invalid day
|
||||
"2014-11-32", // invalid day
|
||||
"2014-13-01", // invalid month
|
||||
"2014-13-57", // invalid month, day
|
||||
"9999999-9-9", // invalid year (out of bounds)
|
||||
];
|
||||
for &s in &invalid {
|
||||
eprintln!("test_date_from_str invalid {:?}", s);
|
||||
assert!(s.parse::<NaiveDate>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -197,11 +197,16 @@ fn test_datetime_timestamp() {
|
||||
fn test_datetime_from_str() {
|
||||
// valid cases
|
||||
let valid = [
|
||||
"2015-2-18T23:16:9.15",
|
||||
"2001-02-03T04:05:06",
|
||||
"2012-12-12T12:12:12",
|
||||
"2015-02-18T23:16:09.153",
|
||||
"2015-2-18T23:16:09.153",
|
||||
"-77-02-18T23:16:09",
|
||||
"+82701-05-6T15:9:60.898989898989",
|
||||
" +82701 - 05 - 6 T 15 : 9 : 60.898989898989 ",
|
||||
];
|
||||
for &s in &valid {
|
||||
eprintln!("test_parse_naivedatetime valid {:?}", s);
|
||||
let d = match s.parse::<NaiveDateTime>() {
|
||||
Ok(d) => d,
|
||||
Err(e) => panic!("parsing `{}` has failed: {}", s, e),
|
||||
@ -226,16 +231,34 @@ fn test_datetime_from_str() {
|
||||
|
||||
// some invalid cases
|
||||
// since `ParseErrorKind` is private, all we can do is to check if there was an error
|
||||
assert!("".parse::<NaiveDateTime>().is_err());
|
||||
assert!("x".parse::<NaiveDateTime>().is_err());
|
||||
assert!("15".parse::<NaiveDateTime>().is_err());
|
||||
assert!("15:8:9".parse::<NaiveDateTime>().is_err());
|
||||
assert!("15-8-9".parse::<NaiveDateTime>().is_err());
|
||||
assert!("2015-15-15T15:15:15".parse::<NaiveDateTime>().is_err());
|
||||
assert!("2012-12-12T12:12:12x".parse::<NaiveDateTime>().is_err());
|
||||
assert!("2012-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
|
||||
assert!("+ 82701-123-12T12:12:12".parse::<NaiveDateTime>().is_err());
|
||||
assert!("+802701-123-12T12:12:12".parse::<NaiveDateTime>().is_err()); // out-of-bound
|
||||
let invalid = [
|
||||
"", // empty
|
||||
"x", // invalid / missing data
|
||||
"15", // missing data
|
||||
"15:8:9", // looks like a time (invalid date)
|
||||
"15-8-9", // looks like a date (invalid)
|
||||
"Fri, 09 Aug 2013 23:54:35 GMT", // valid date, wrong format
|
||||
"Sat Jun 30 23:59:60 2012", // valid date, wrong format
|
||||
"1441497364.649", // valid date, wrong format
|
||||
"+1441497364.649", // valid date, wrong format
|
||||
"+1441497364", // valid date, wrong format
|
||||
"2014/02/03 04:05:06", // valid date, wrong format
|
||||
"2015-15-15T15:15:15", // invalid date
|
||||
"2012-12-12T12:12:12x", // bad timezone / trailing literal
|
||||
"2012-12-12T12:12:12+00:00", // unexpected timezone / trailing literal
|
||||
"2012-12-12T12:12:12 +00:00", // unexpected timezone / trailing literal
|
||||
"2012-12-12T12:12:12 GMT", // unexpected timezone / trailing literal
|
||||
"2012-123-12T12:12:12", // invalid month
|
||||
"2012-12-12t12:12:12", // bad divider 't'
|
||||
"2012-12-12 12:12:12", // missing divider 'T'
|
||||
"2012-12-12T12:12:12Z", // trailing char 'Z'
|
||||
"+ 82701-123-12T12:12:12", // strange year, invalid month
|
||||
"+802701-123-12T12:12:12", // out-of-bound year, invalid month
|
||||
];
|
||||
for &s in &invalid {
|
||||
eprintln!("test_datetime_from_str invalid {:?}", s);
|
||||
assert!(s.parse::<NaiveDateTime>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -235,9 +235,37 @@ fn test_date_from_str() {
|
||||
" 4 : 3 : 2.1 ",
|
||||
" 09:08:07 ",
|
||||
" 9:8:07 ",
|
||||
"01:02:03",
|
||||
"4:3:2.1",
|
||||
"9:8:7",
|
||||
"09:8:7",
|
||||
"9:08:7",
|
||||
"9:8:07",
|
||||
"09:08:7",
|
||||
"09:8:07",
|
||||
"09:08:7",
|
||||
"9:08:07",
|
||||
"09:08:07",
|
||||
"9:8:07.123",
|
||||
"9:08:7.123",
|
||||
"09:8:7.123",
|
||||
"09:08:7.123",
|
||||
"9:08:07.123",
|
||||
"09:8:07.123",
|
||||
"09:08:07.123",
|
||||
"09:08:07.123",
|
||||
"09:08:07.1234",
|
||||
"09:08:07.12345",
|
||||
"09:08:07.123456",
|
||||
"09:08:07.1234567",
|
||||
"09:08:07.12345678",
|
||||
"09:08:07.123456789",
|
||||
"09:08:07.1234567891",
|
||||
"09:08:07.12345678912",
|
||||
"23:59:60.373929310237",
|
||||
];
|
||||
for &s in &valid {
|
||||
eprintln!("test_time_parse_from_str valid {:?}", s);
|
||||
let d = match s.parse::<NaiveTime>() {
|
||||
Ok(d) => d,
|
||||
Err(e) => panic!("parsing `{}` has failed: {}", s, e),
|
||||
@ -262,15 +290,30 @@ fn test_date_from_str() {
|
||||
|
||||
// some invalid cases
|
||||
// since `ParseErrorKind` is private, all we can do is to check if there was an error
|
||||
assert!("".parse::<NaiveTime>().is_err());
|
||||
assert!("x".parse::<NaiveTime>().is_err());
|
||||
assert!("15".parse::<NaiveTime>().is_err());
|
||||
assert!("15:8".parse::<NaiveTime>().is_err());
|
||||
assert!("15:8:x".parse::<NaiveTime>().is_err());
|
||||
assert!("15:8:9x".parse::<NaiveTime>().is_err());
|
||||
assert!("23:59:61".parse::<NaiveTime>().is_err());
|
||||
assert!("12:34:56.x".parse::<NaiveTime>().is_err());
|
||||
assert!("12:34:56. 0".parse::<NaiveTime>().is_err());
|
||||
let invalid = [
|
||||
"", // empty
|
||||
"x", // invalid
|
||||
"15", // missing data
|
||||
"15:8", // missing data
|
||||
"15:8:x", // missing data, invalid data
|
||||
"15:8:9x", // missing data, invalid data
|
||||
"23:59:61", // invalid second (out of bounds)
|
||||
"23:54:35 GMT", // invalid (timezone non-sensical for NaiveTime)
|
||||
"23:54:35 +0000", // invalid (timezone non-sensical for NaiveTime)
|
||||
"1441497364.649", // valid datetime, not a NaiveTime
|
||||
"+1441497364.649", // valid datetime, not a NaiveTime
|
||||
"+1441497364", // valid datetime, not a NaiveTime
|
||||
"001:02:03", // invalid hour
|
||||
"01:002:03", // invalid minute
|
||||
"01:02:003", // invalid second
|
||||
"12:34:56.x", // invalid fraction
|
||||
"12:34:56. 0", // invalid fraction format
|
||||
"09:08:00000000007", // invalid second / invalid fraction format
|
||||
];
|
||||
for &s in &invalid {
|
||||
eprintln!("test_time_parse_from_str invalid {:?}", s);
|
||||
assert!(s.parse::<NaiveTime>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -281,6 +324,15 @@ fn test_time_parse_from_str() {
|
||||
Ok(hms(12, 34, 56))
|
||||
); // ignore date and offset
|
||||
assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), Ok(hms(12, 59, 0)));
|
||||
assert_eq!(NaiveTime::parse_from_str("12:59 \n\t PM", "%H:%M \n\t %P"), Ok(hms(12, 59, 0)));
|
||||
assert_eq!(NaiveTime::parse_from_str("\t\t12:59\tPM\t", "\t\t%H:%M\t%P\t"), Ok(hms(12, 59, 0)));
|
||||
assert_eq!(
|
||||
NaiveTime::parse_from_str("\t\t1259\t\tPM\t", "\t\t%H%M\t\t%P\t"),
|
||||
Ok(hms(12, 59, 0))
|
||||
);
|
||||
assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M\t%P").is_ok());
|
||||
assert!(NaiveTime::parse_from_str("\t\t12:59 PM\t", "\t\t%H:%M\t%P\t").is_ok());
|
||||
assert!(NaiveTime::parse_from_str("12:59 PM", "%H:%M %P").is_ok());
|
||||
assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err());
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user