diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 5d893e0858..3e8a871f98 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -809,11 +809,7 @@ fn test_parse_datetime_utc() { "2001-02-03T04:05:06Z", "2001-02-03T04:05:06+0000", "2001-02-03T04:05:06-00:00", - "2001-02-03T04:05:06-00 00", "2001-02-03T04:05:06-01:00", - "2001-02-03T04:05:06-01: 00", - "2001-02-03T04:05:06-01 :00", - "2001-02-03T04:05:06-01 : 00", "2012-12-12T12:12:12Z", "2015-02-18T23:16:09.153Z", "2015-2-18T23:16:09.153Z", @@ -860,31 +856,35 @@ fn test_parse_datetime_utc() { "+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 - "2012 -12-12T12:12:12Z", // space after year - "2012 -12-12T12:12:12Z", // multi space after year - "2012- 12-12T12:12:12Z", // space after year divider - "2012- 12-12T12:12:12Z", // multi space after year divider - "2012-12-12T 12:12:12Z", // space after date-time divider - "2012-12-12T12 :12:12Z", // space after hour - "2012-12-12T12 :12:12Z", // multi space after hour - "2012-12-12T12: 12:12Z", // space before minute - "2012-12-12T12: 12:12Z", // multi space before minute - "2012-12-12T12 : 12:12Z", // space space before and after hour-minute divider - "2012-12-12T12:12:12Z ", // trailing space - " 2012-12-12T12:12:12Z", // leading space + "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 + "2012 -12-12T12:12:12Z", // space after year + "2012 -12-12T12:12:12Z", // multi space after year + "2012- 12-12T12:12:12Z", // space after year divider + "2012- 12-12T12:12:12Z", // multi space after year divider + "2012-12-12T 12:12:12Z", // space after date-time divider + "2012-12-12T12 :12:12Z", // space after hour + "2012-12-12T12 :12:12Z", // multi space after hour + "2012-12-12T12: 12:12Z", // space before minute + "2012-12-12T12: 12:12Z", // multi space before minute + "2012-12-12T12 : 12:12Z", // space space before and after hour-minute divider + "2012-12-12T12:12:12Z ", // trailing space + " 2012-12-12T12:12:12Z", // leading space + "2001-02-03T04:05:06-00 00", // invalid timezone spacing + "2001-02-03T04:05:06-01: 00", // invalid timezone spacing + "2001-02-03T04:05:06-01 :00", // invalid timezone spacing + "2001-02-03T04:05:06-01 : 00", // invalid timezone spacing "2001-02-03T04:05:06-01 : 00", // invalid timezone spacing "2001-02-03T04:05:06-01 : :00", // invalid timezone spacing " +82701 - 05 - 6 T 15 : 9 : 60.898989898989 Z", // valid datetime, wrong format @@ -1040,13 +1040,11 @@ fn test_datetime_parse_from_str() { ), Ok(dt), ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 00", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); + assert!(DateTime::::parse_from_str( + "Aug 09 2013 23:54:35 -09 00", + "%b %d %Y %H:%M:%S %z" + ) + .is_err()); assert_eq!( DateTime::::parse_from_str( "Aug 09 2013 23:54:35 -09:00", @@ -1054,13 +1052,11 @@ fn test_datetime_parse_from_str() { ), Ok(dt), ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %z" - ), - Ok(dt), - ); + assert!(DateTime::::parse_from_str( + "Aug 09 2013 23:54:35 -09 : 00", + "%b %d %Y %H:%M:%S %z" + ) + .is_err()); assert_eq!( DateTime::::parse_from_str( "Aug 09 2013 23:54:35 --0900", @@ -1161,27 +1157,21 @@ fn test_datetime_parse_from_str() { ), Ok(dt), ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 00", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %:z" - ), - Ok(dt), - ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00:", - "%b %d %Y %H:%M:%S %:z:" - ), - Ok(dt), - ); + assert!(DateTime::::parse_from_str( + "Aug 09 2013 23:54:35 -09 00", + "%b %d %Y %H:%M:%S %:z" + ) + .is_err()); + assert!(DateTime::::parse_from_str( + "Aug 09 2013 23:54:35 -09 : 00", + "%b %d %Y %H:%M:%S %:z" + ) + .is_err()); + assert!(DateTime::::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::::parse_from_str( "Aug 09 2013 23:54:35 -09", @@ -1230,13 +1220,11 @@ fn test_datetime_parse_from_str() { ), Ok(dt), ); - assert_eq!( - DateTime::::parse_from_str( - "Aug 09 2013 23:54:35 -09 : 00", - "%b %d %Y %H:%M:%S %::z" - ), - Ok(dt), - ); + assert!(DateTime::::parse_from_str( + "Aug 09 2013 23:54:35 -09 : 00", + "%b %d %Y %H:%M:%S %::z" + ) + .is_err()); // mismatching colon expectations assert!(DateTime::::parse_from_str( "Aug 09 2013 23:54:35 -09:00:00", diff --git a/src/format/parse.rs b/src/format/parse.rs index 91673af9a4..fa9b781ecd 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -453,14 +453,14 @@ where | &TimezoneOffset => { s = scan::trim1(s); let offset = - try_consume!(scan::timezone_offset(s, scan::maybe_colon_or_space)); + try_consume!(scan::timezone_offset(s, scan::consume_colon_maybe)); parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?; } &TimezoneOffsetColonZ | &TimezoneOffsetZ => { s = scan::trim1(s); let offset = - try_consume!(scan::timezone_offset_zulu(s, scan::maybe_colon_or_space)); + try_consume!(scan::timezone_offset_zulu(s, scan::consume_colon_maybe)); parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?; } @@ -470,7 +470,7 @@ where s = scan::trim1(s); let offset = try_consume!(scan::timezone_offset_permissive( s, - scan::maybe_colon_or_space + scan::consume_colon_maybe )); parsed.set_offset(i64::from(offset)).map_err(|e| (s, e))?; } @@ -929,7 +929,7 @@ fn test_parse() { 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)]; INVALID); check!("+12 34", [fix!(TimezoneOffset)]; INVALID); check!("12:34", [fix!(TimezoneOffset)]; INVALID); check!("12:34:56", [fix!(TimezoneOffset)]; INVALID); @@ -956,15 +956,15 @@ fn test_parse() { 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)]; INVALID); 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!("\t -12:34", [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)]; INVALID); + check!("-12 :34", [fix!(TimezoneOffset)]; INVALID); + check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); check!("-12 : 34", [fix!(TimezoneOffset)]; INVALID); check!("-12: 34", [fix!(TimezoneOffset)]; INVALID); @@ -1037,10 +1037,10 @@ fn test_parse() { 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)]; INVALID); + check!("+12: 34", [fix!(TimezoneOffsetColon)]; INVALID); + check!("+12 :34", [fix!(TimezoneOffsetColon)]; INVALID); + check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetColon)]; INVALID); @@ -1119,18 +1119,18 @@ fn test_parse() { check!("+12::34", [fix!(TimezoneOffsetZ)]; INVALID); 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)]; INVALID); check!("+12 34", [fix!(TimezoneOffsetZ)]; INVALID); - 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)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); check!("+12 : 34", [fix!(TimezoneOffsetZ)]; INVALID); 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)]; INVALID); 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); @@ -1202,11 +1202,11 @@ fn test_parse() { 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)]; INVALID); check!("+12 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); - 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)]; INVALID); check!("+12 :34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); check!("+12: 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); check!("+12 : 34", [internal_fix!(TimezoneOffsetPermissive)]; INVALID); diff --git a/src/format/scan.rs b/src/format/scan.rs index ffbf654b32..2ac81318a7 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -219,17 +219,9 @@ pub(super) fn trim1(s: &str) -> &str { } } -/// Is `s.next()` whitespace? -/// Helper function to `maybe_colon_or_space`. -fn next_is_whitespace(s: &str) -> bool { - s.chars().next().map(|c| c.is_whitespace()).unwrap_or_default() -} - -/// Allow a colon with possible one-character whitespace padding. -/// Consumes zero or one of these leading patterns: -/// `":"`, `" "`, `" :"`, `": "`, or `" : "`. +/// Consumes one colon char `:` if it is at the front of `s`. /// Always returns `Ok(s)`. -pub(super) fn maybe_colon_or_space(mut s: &str) -> ParseResult<&str> { +pub(super) fn consume_colon_maybe(mut s: &str) -> ParseResult<&str> { if s.is_empty() { // nothing consumed return Ok(s); @@ -237,27 +229,9 @@ pub(super) fn maybe_colon_or_space(mut s: &str) -> ParseResult<&str> { if s.starts_with(':') { s = s_next(s); - if next_is_whitespace(s) { - s = s_next(s); - } - // consumed `":"` or `": "` - return Ok(s); - } else if !next_is_whitespace(s) { - return Ok(s); - } - - s = s_next(s); - if s.starts_with(':') { - s = s_next(s); - } else { - // consumed `" "` - return Ok(s); - } - if next_is_whitespace(s) { - s = s_next(s); + // consumed `':'` } - // consumed `" :"` or `" : "` Ok(s) } @@ -503,48 +477,25 @@ fn test_trim1() { } #[test] -fn test_next_is_whitespace() { - assert!(!next_is_whitespace("")); - assert!(!next_is_whitespace("a")); - assert!(!next_is_whitespace("šŸ˜¼šŸ˜¼")); - assert!(next_is_whitespace(" ")); - assert!(next_is_whitespace("\t\t")); - assert!(next_is_whitespace("\ta\t")); - assert!(next_is_whitespace("\tšŸ˜¼\t")); -} - -#[test] -fn test_maybe_colon_or_space() { - assert_eq!(maybe_colon_or_space(""), Ok("")); - assert_eq!(maybe_colon_or_space(" "), Ok("")); - assert_eq!(maybe_colon_or_space("\n"), Ok("")); - assert_eq!(maybe_colon_or_space(" "), Ok(" ")); - assert_eq!(maybe_colon_or_space(" "), Ok(" ")); - assert_eq!(maybe_colon_or_space(" "), Ok(" ")); - assert_eq!(maybe_colon_or_space("\t\t\t\t"), Ok("\t\t\t")); - assert_eq!(maybe_colon_or_space(":"), Ok("")); - assert_eq!(maybe_colon_or_space(" :"), Ok("")); - assert_eq!(maybe_colon_or_space(": "), Ok("")); - assert_eq!(maybe_colon_or_space(" : "), Ok("")); - assert_eq!(maybe_colon_or_space(" : "), Ok(" ")); - assert_eq!(maybe_colon_or_space(" :"), Ok(" :")); - assert_eq!(maybe_colon_or_space(" : "), Ok(" : ")); - assert_eq!(maybe_colon_or_space(" :: "), Ok(": ")); - assert_eq!(maybe_colon_or_space(" : : "), Ok(": ")); - assert_eq!(maybe_colon_or_space("šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space("šŸ˜øšŸ˜ø"), Ok("šŸ˜øšŸ˜ø")); - assert_eq!(maybe_colon_or_space("šŸ˜ø:"), Ok("šŸ˜ø:")); - assert_eq!(maybe_colon_or_space("šŸ˜ø "), Ok("šŸ˜ø ")); - assert_eq!(maybe_colon_or_space(" šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space(":šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space(":šŸ˜ø "), Ok("šŸ˜ø ")); - assert_eq!(maybe_colon_or_space(" :šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space(" :šŸ˜ø "), Ok("šŸ˜ø ")); - assert_eq!(maybe_colon_or_space(" :šŸ˜ø:"), Ok("šŸ˜ø:")); - assert_eq!(maybe_colon_or_space(": šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space(": šŸ˜ø"), Ok(" šŸ˜ø")); - assert_eq!(maybe_colon_or_space(": :šŸ˜ø"), Ok(":šŸ˜ø")); - assert_eq!(maybe_colon_or_space(" : šŸ˜ø"), Ok("šŸ˜ø")); - assert_eq!(maybe_colon_or_space(" ::šŸ˜ø"), Ok(":šŸ˜ø")); - assert_eq!(maybe_colon_or_space(" :: šŸ˜ø"), Ok(": šŸ˜ø")); +fn test_consume_colon_maybe() { + assert_eq!(consume_colon_maybe(""), Ok("")); + assert_eq!(consume_colon_maybe(" "), Ok(" ")); + assert_eq!(consume_colon_maybe("\n"), Ok("\n")); + assert_eq!(consume_colon_maybe(" "), Ok(" ")); + assert_eq!(consume_colon_maybe(":"), Ok("")); + assert_eq!(consume_colon_maybe(" :"), Ok(" :")); + assert_eq!(consume_colon_maybe(": "), Ok(" ")); + assert_eq!(consume_colon_maybe(" : "), Ok(" : ")); + assert_eq!(consume_colon_maybe(": "), Ok(" ")); + assert_eq!(consume_colon_maybe(" :"), Ok(" :")); + assert_eq!(consume_colon_maybe(":: "), Ok(": ")); + assert_eq!(consume_colon_maybe("šŸ˜ø"), Ok("šŸ˜ø")); + assert_eq!(consume_colon_maybe("šŸ˜øšŸ˜ø"), Ok("šŸ˜øšŸ˜ø")); + assert_eq!(consume_colon_maybe("šŸ˜ø:"), Ok("šŸ˜ø:")); + assert_eq!(consume_colon_maybe("šŸ˜ø "), Ok("šŸ˜ø ")); + assert_eq!(consume_colon_maybe(":šŸ˜ø"), Ok("šŸ˜ø")); + assert_eq!(consume_colon_maybe(":šŸ˜ø "), Ok("šŸ˜ø ")); + assert_eq!(consume_colon_maybe(": šŸ˜ø"), Ok(" šŸ˜ø")); + assert_eq!(consume_colon_maybe(": šŸ˜ø"), Ok(" šŸ˜ø")); + assert_eq!(consume_colon_maybe(": :šŸ˜ø"), Ok(" :šŸ˜ø")); }