diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 5e693ea5c7..366bbe6ad7 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1933,89 +1933,3 @@ where /// -------- /// 719163 const UNIX_EPOCH_DAY: i64 = 719_163; - -#[cfg(all(test, feature = "serde"))] -fn test_encodable_json(to_string_utc: FUtc, to_string_fixed: FFixed) -where - FUtc: Fn(&DateTime) -> Result, - FFixed: Fn(&DateTime) -> Result, - E: ::core::fmt::Debug, -{ - assert_eq!( - to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), - Some(r#""2014-07-24T12:34:06Z""#.into()) - ); - - assert_eq!( - to_string_fixed( - &FixedOffset::east_opt(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - ) - .ok(), - Some(r#""2014-07-24T12:34:06+01:01""#.into()) - ); - assert_eq!( - to_string_fixed( - &FixedOffset::east_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - ) - .ok(), - // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute. - // In this case `+01:00:50` becomes `+01:01` - Some(r#""2014-07-24T12:34:06+01:01""#.into()) - ); -} - -#[cfg(all(test, feature = "clock", feature = "serde"))] -fn test_decodable_json( - utc_from_str: FUtc, - fixed_from_str: FFixed, - local_from_str: FLocal, -) where - FUtc: Fn(&str) -> Result, E>, - FFixed: Fn(&str) -> Result, E>, - FLocal: Fn(&str) -> Result, E>, - E: ::core::fmt::Debug, -{ - // should check against the offset as well (the normal DateTime comparison will ignore them) - fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { - dt.as_ref().map(|dt| (dt, dt.offset())) - } - - assert_eq!( - norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) - ); - assert_eq!( - norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap())) - ); - - assert_eq!( - norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()), - norm(&Some( - FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - )) - ); - assert_eq!( - norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), - norm(&Some( - FixedOffset::east_opt(60 * 60 + 23 * 60) - .unwrap() - .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) - .unwrap() - )) - ); - - // we don't know the exact local offset but we can check that - // the conversion didn't change the instant itself - assert_eq!( - local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local should parse"), - Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - ); - assert_eq!( - local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"), - Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() - ); - - assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); - assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); -} diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 724c1ae717..6f048a4568 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -1209,24 +1209,87 @@ pub mod ts_seconds_option { #[cfg(test)] mod tests { #[cfg(feature = "clock")] - use crate::datetime::test_decodable_json; - use crate::datetime::test_encodable_json; + use crate::Local; use crate::{DateTime, FixedOffset, TimeZone, Utc}; use core::fmt; #[test] fn test_serde_serialize() { - test_encodable_json(serde_json::to_string, serde_json::to_string); + assert_eq!( + serde_json::to_string(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), + Some(r#""2014-07-24T12:34:06Z""#.to_owned()) + ); + assert_eq!( + serde_json::to_string( + &FixedOffset::east_opt(3660) + .unwrap() + .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) + .unwrap() + ) + .ok(), + Some(r#""2014-07-24T12:34:06+01:01""#.to_owned()) + ); + assert_eq!( + serde_json::to_string( + &FixedOffset::east_opt(3650) + .unwrap() + .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) + .unwrap() + ) + .ok(), + // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute. + // In this case `+01:00:50` becomes `+01:01` + Some(r#""2014-07-24T12:34:06+01:01""#.to_owned()) + ); } - #[cfg(feature = "clock")] #[test] fn test_serde_deserialize() { - test_decodable_json( - |input| serde_json::from_str(input), - |input| serde_json::from_str(input), - |input| serde_json::from_str(input), + // should check against the offset as well (the normal DateTime comparison will ignore them) + fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { + dt.as_ref().map(|dt| (dt, dt.offset())) + } + + let dt: Option> = serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok(); + assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); + let dt: Option> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok(); + assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); + + let dt: Option> = + serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok(); + assert_eq!( + norm(&dt), + norm(&Some( + FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() + )) + ); + let dt: Option> = + serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok(); + assert_eq!( + norm(&dt), + norm(&Some( + FixedOffset::east_opt(60 * 60 + 23 * 60) + .unwrap() + .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) + .unwrap() + )) ); + + // we don't know the exact local offset but we can check that + // the conversion didn't change the instant itself + #[cfg(feature = "clock")] + { + let dt: DateTime = + serde_json::from_str(r#""2014-07-24T12:34:06Z""#).expect("local should parse"); + assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); + + let dt: DateTime = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#) + .expect("local should parse with offset"); + assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); + } + + assert!(serde_json::from_str::>(r#""2014-07-32T12:34:06Z""#).is_err()); + assert!(serde_json::from_str::>(r#""2014-07-32T12:34:06Z""#).is_err()); } #[test] diff --git a/src/naive/date/mod.rs b/src/naive/date/mod.rs index 4e626d9f7c..75e4c30958 100644 --- a/src/naive/date/mod.rs +++ b/src/naive/date/mod.rs @@ -2387,71 +2387,6 @@ const YEAR_DELTAS: &[u8; 401] = &[ 96, 97, 97, 97, 97, // 400+1 ]; -#[cfg(all(test, feature = "serde"))] -fn test_encodable_json(to_string: F) -where - F: Fn(&NaiveDate) -> Result, - E: ::std::fmt::Debug, -{ - assert_eq!( - to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(), - Some(r#""2014-07-24""#.into()) - ); - assert_eq!( - to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(), - Some(r#""0000-01-01""#.into()) - ); - assert_eq!( - to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(), - Some(r#""-0001-12-31""#.into()) - ); - assert_eq!(to_string(&NaiveDate::MIN).ok(), Some(r#""-262143-01-01""#.into())); - assert_eq!(to_string(&NaiveDate::MAX).ok(), Some(r#""+262142-12-31""#.into())); -} - -#[cfg(all(test, feature = "serde"))] -fn test_decodable_json(from_str: F) -where - F: Fn(&str) -> Result, - E: ::std::fmt::Debug, -{ - use std::{i32, i64}; - - assert_eq!( - from_str(r#""2016-07-08""#).ok(), - Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()) - ); - assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap())); - assert_eq!(from_str(r#""+002016-07-08""#).ok(), NaiveDate::from_ymd_opt(2016, 7, 8)); - assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); - assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap())); - assert_eq!( - from_str(r#""-0001-12-31""#).ok(), - Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()) - ); - assert_eq!(from_str(r#""-262143-01-01""#).ok(), Some(NaiveDate::MIN)); - assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX)); - - // bad formats - assert!(from_str(r#""""#).is_err()); - assert!(from_str(r#""20001231""#).is_err()); - assert!(from_str(r#""2000-00-00""#).is_err()); - assert!(from_str(r#""2000-02-30""#).is_err()); - assert!(from_str(r#""2001-02-29""#).is_err()); - assert!(from_str(r#""2002-002-28""#).is_err()); - assert!(from_str(r#""yyyy-mm-dd""#).is_err()); - assert!(from_str(r#"0"#).is_err()); - assert!(from_str(r#"20.01"#).is_err()); - assert!(from_str(&i32::MIN.to_string()).is_err()); - assert!(from_str(&i32::MAX.to_string()).is_err()); - assert!(from_str(&i64::MIN.to_string()).is_err()); - assert!(from_str(&i64::MAX.to_string()).is_err()); - assert!(from_str(r#"{}"#).is_err()); - // pre-0.3.0 rustc-serialize format is now invalid - assert!(from_str(r#"{"ymdf":20}"#).is_err()); - assert!(from_str(r#"null"#).is_err()); -} - #[cfg(feature = "serde")] mod serde { use super::NaiveDate; @@ -2507,17 +2442,79 @@ mod serde { #[cfg(test)] mod tests { - use crate::naive::date::{test_decodable_json, test_encodable_json}; use crate::NaiveDate; #[test] fn test_serde_serialize() { - test_encodable_json(serde_json::to_string); + assert_eq!( + serde_json::to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap()).ok(), + Some(r#""2014-07-24""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveDate::from_ymd_opt(0, 1, 1).unwrap()).ok(), + Some(r#""0000-01-01""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()).ok(), + Some(r#""-0001-12-31""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveDate::MIN).ok(), + Some(r#""-262143-01-01""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveDate::MAX).ok(), + Some(r#""+262142-12-31""#.into()) + ); } #[test] fn test_serde_deserialize() { - test_decodable_json(|input| serde_json::from_str(input)); + let from_str = serde_json::from_str::; + + assert_eq!( + from_str(r#""2016-07-08""#).ok(), + Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()) + ); + assert_eq!( + from_str(r#""2016-7-8""#).ok(), + Some(NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()) + ); + assert_eq!(from_str(r#""+002016-07-08""#).ok(), NaiveDate::from_ymd_opt(2016, 7, 8)); + assert_eq!( + from_str(r#""0000-01-01""#).ok(), + Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()) + ); + assert_eq!( + from_str(r#""0-1-1""#).ok(), + Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap()) + ); + assert_eq!( + from_str(r#""-0001-12-31""#).ok(), + Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap()) + ); + assert_eq!(from_str(r#""-262143-01-01""#).ok(), Some(NaiveDate::MIN)); + assert_eq!(from_str(r#""+262142-12-31""#).ok(), Some(NaiveDate::MAX)); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""20001231""#).is_err()); + assert!(from_str(r#""2000-00-00""#).is_err()); + assert!(from_str(r#""2000-02-30""#).is_err()); + assert!(from_str(r#""2001-02-29""#).is_err()); + assert!(from_str(r#""2002-002-28""#).is_err()); + assert!(from_str(r#""yyyy-mm-dd""#).is_err()); + assert!(from_str(r#"0"#).is_err()); + assert!(from_str(r#"20.01"#).is_err()); + let min = i32::MIN.to_string(); + assert!(from_str(&min).is_err()); + let max = i32::MAX.to_string(); + assert!(from_str(&max).is_err()); + let min = i64::MIN.to_string(); + assert!(from_str(&min).is_err()); + let max = i64::MAX.to_string(); + assert!(from_str(&max).is_err()); + assert!(from_str(r#"{}"#).is_err()); } #[test] diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index e74f0d82f9..a2ffc69674 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -2149,114 +2149,3 @@ impl Default for NaiveDateTime { Self::UNIX_EPOCH } } - -#[cfg(all(test, feature = "serde"))] -fn test_encodable_json(to_string: F) -where - F: Fn(&NaiveDateTime) -> Result, - E: ::std::fmt::Debug, -{ - assert_eq!( - to_string( - &NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) - .ok(), - Some(r#""2016-07-08T09:10:48.090""#.into()) - ); - assert_eq!( - to_string(&NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()) - .ok(), - Some(r#""2014-07-24T12:34:06""#.into()) - ); - assert_eq!( - to_string( - &NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap() - ) - .ok(), - Some(r#""0000-01-01T00:00:60""#.into()) - ); - assert_eq!( - to_string( - &NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap() - ) - .ok(), - Some(r#""-0001-12-31T23:59:59.000000007""#.into()) - ); - assert_eq!( - to_string(&NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()).ok(), - Some(r#""-262143-01-01T00:00:00""#.into()) - ); - assert_eq!( - to_string(&NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(), - Some(r#""+262142-12-31T23:59:60.999999999""#.into()) - ); -} - -#[cfg(all(test, feature = "serde"))] -fn test_decodable_json(from_str: F) -where - F: Fn(&str) -> Result, - E: ::std::fmt::Debug, -{ - assert_eq!( - from_str(r#""2016-07-08T09:10:48.090""#).ok(), - Some( - NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) - ); - assert_eq!( - from_str(r#""2016-7-8T9:10:48.09""#).ok(), - Some( - NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap() - ) - ); - assert_eq!( - from_str(r#""2014-07-24T12:34:06""#).ok(), - Some(NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()) - ); - assert_eq!( - from_str(r#""0000-01-01T00:00:60""#).ok(), - Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap()) - ); - assert_eq!( - from_str(r#""0-1-1T0:0:60""#).ok(), - Some(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().and_hms_milli_opt(0, 0, 59, 1_000).unwrap()) - ); - assert_eq!( - from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(), - Some(NaiveDate::from_ymd_opt(-1, 12, 31).unwrap().and_hms_nano_opt(23, 59, 59, 7).unwrap()) - ); - assert_eq!( - from_str(r#""-262143-01-01T00:00:00""#).ok(), - Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()) - ); - assert_eq!( - from_str(r#""+262142-12-31T23:59:60.999999999""#).ok(), - Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) - ); - assert_eq!( - from_str(r#""+262142-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored - Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) - ); - - // bad formats - assert!(from_str(r#""""#).is_err()); - assert!(from_str(r#""2016-07-08""#).is_err()); - assert!(from_str(r#""09:10:48.090""#).is_err()); - assert!(from_str(r#""20160708T091048.090""#).is_err()); - assert!(from_str(r#""2000-00-00T00:00:00""#).is_err()); - assert!(from_str(r#""2000-02-30T00:00:00""#).is_err()); - assert!(from_str(r#""2001-02-29T00:00:00""#).is_err()); - assert!(from_str(r#""2002-02-28T24:00:00""#).is_err()); - assert!(from_str(r#""2002-02-28T23:60:00""#).is_err()); - assert!(from_str(r#""2002-02-28T23:59:61""#).is_err()); - assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err()); - assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err()); - assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err()); - assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err()); - assert!(from_str(r#"20160708000000"#).is_err()); - assert!(from_str(r#"{}"#).is_err()); - // pre-0.3.0 rustc-serialize format is now invalid - assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err()); - assert!(from_str(r#"null"#).is_err()); -} diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 2beda08745..ae06578b5c 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -1128,7 +1128,6 @@ pub mod ts_seconds_option { #[cfg(test)] mod tests { - use crate::naive::datetime::{test_decodable_json, test_encodable_json}; use crate::serde::ts_nanoseconds_option; use crate::{DateTime, NaiveDate, NaiveDateTime, TimeZone, Utc}; @@ -1137,12 +1136,142 @@ mod tests { #[test] fn test_serde_serialize() { - test_encodable_json(serde_json::to_string); + assert_eq!( + serde_json::to_string( + &NaiveDate::from_ymd_opt(2016, 7, 8) + .unwrap() + .and_hms_milli_opt(9, 10, 48, 90) + .unwrap() + ) + .ok(), + Some(r#""2016-07-08T09:10:48.090""#.into()) + ); + assert_eq!( + serde_json::to_string( + &NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap() + ) + .ok(), + Some(r#""2014-07-24T12:34:06""#.into()) + ); + assert_eq!( + serde_json::to_string( + &NaiveDate::from_ymd_opt(0, 1, 1) + .unwrap() + .and_hms_milli_opt(0, 0, 59, 1_000) + .unwrap() + ) + .ok(), + Some(r#""0000-01-01T00:00:60""#.into()) + ); + assert_eq!( + serde_json::to_string( + &NaiveDate::from_ymd_opt(-1, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 7) + .unwrap() + ) + .ok(), + Some(r#""-0001-12-31T23:59:59.000000007""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()).ok(), + Some(r#""-262143-01-01T00:00:00""#.into()) + ); + assert_eq!( + serde_json::to_string( + &NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap() + ) + .ok(), + Some(r#""+262142-12-31T23:59:60.999999999""#.into()) + ); } #[test] fn test_serde_deserialize() { - test_decodable_json(|input| serde_json::from_str(input)); + let from_str = serde_json::from_str::; + + assert_eq!( + from_str(r#""2016-07-08T09:10:48.090""#).ok(), + Some( + NaiveDate::from_ymd_opt(2016, 7, 8) + .unwrap() + .and_hms_milli_opt(9, 10, 48, 90) + .unwrap() + ) + ); + assert_eq!( + from_str(r#""2016-7-8T9:10:48.09""#).ok(), + Some( + NaiveDate::from_ymd_opt(2016, 7, 8) + .unwrap() + .and_hms_milli_opt(9, 10, 48, 90) + .unwrap() + ) + ); + assert_eq!( + from_str(r#""2014-07-24T12:34:06""#).ok(), + Some(NaiveDate::from_ymd_opt(2014, 7, 24).unwrap().and_hms_opt(12, 34, 6).unwrap()) + ); + assert_eq!( + from_str(r#""0000-01-01T00:00:60""#).ok(), + Some( + NaiveDate::from_ymd_opt(0, 1, 1) + .unwrap() + .and_hms_milli_opt(0, 0, 59, 1_000) + .unwrap() + ) + ); + assert_eq!( + from_str(r#""0-1-1T0:0:60""#).ok(), + Some( + NaiveDate::from_ymd_opt(0, 1, 1) + .unwrap() + .and_hms_milli_opt(0, 0, 59, 1_000) + .unwrap() + ) + ); + assert_eq!( + from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(), + Some( + NaiveDate::from_ymd_opt(-1, 12, 31) + .unwrap() + .and_hms_nano_opt(23, 59, 59, 7) + .unwrap() + ) + ); + assert_eq!( + from_str(r#""-262143-01-01T00:00:00""#).ok(), + Some(NaiveDate::MIN.and_hms_opt(0, 0, 0).unwrap()) + ); + assert_eq!( + from_str(r#""+262142-12-31T23:59:60.999999999""#).ok(), + Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + ); + assert_eq!( + from_str(r#""+262142-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored + Some(NaiveDate::MAX.and_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + ); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""2016-07-08""#).is_err()); + assert!(from_str(r#""09:10:48.090""#).is_err()); + assert!(from_str(r#""20160708T091048.090""#).is_err()); + assert!(from_str(r#""2000-00-00T00:00:00""#).is_err()); + assert!(from_str(r#""2000-02-30T00:00:00""#).is_err()); + assert!(from_str(r#""2001-02-29T00:00:00""#).is_err()); + assert!(from_str(r#""2002-02-28T24:00:00""#).is_err()); + assert!(from_str(r#""2002-02-28T23:60:00""#).is_err()); + assert!(from_str(r#""2002-02-28T23:59:61""#).is_err()); + assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err()); + assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err()); + assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err()); + assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err()); + assert!(from_str(r#"20160708000000"#).is_err()); + assert!(from_str(r#"{}"#).is_err()); + // pre-0.3.0 rustc-serialize format is now invalid + assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err()); + assert!(from_str(r#"null"#).is_err()); } // Bincode is relevant to test separately from JSON because diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 2d9178fdf0..f32d828080 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -1641,99 +1641,3 @@ impl Default for NaiveTime { NaiveTime::from_hms_opt(0, 0, 0).unwrap() } } - -#[cfg(all(test, feature = "serde"))] -fn test_encodable_json(to_string: F) -where - F: Fn(&NaiveTime) -> Result, - E: ::std::fmt::Debug, -{ - assert_eq!( - to_string(&NaiveTime::from_hms_opt(0, 0, 0).unwrap()).ok(), - Some(r#""00:00:00""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()).ok(), - Some(r#""00:00:00.950""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()).ok(), - Some(r#""00:00:60""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_opt(0, 1, 2).unwrap()).ok(), - Some(r#""00:01:02""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()).ok(), - Some(r#""03:05:07.098765432""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_opt(7, 8, 9).unwrap()).ok(), - Some(r#""07:08:09""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()).ok(), - Some(r#""12:34:56.000789""#.into()) - ); - assert_eq!( - to_string(&NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()).ok(), - Some(r#""23:59:60.999999999""#.into()) - ); -} - -#[cfg(all(test, feature = "serde"))] -fn test_decodable_json(from_str: F) -where - F: Fn(&str) -> Result, - E: ::std::fmt::Debug, -{ - assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); - assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); - assert_eq!( - from_str(r#""00:00:00.950""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) - ); - assert_eq!( - from_str(r#""0:0:0.95""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) - ); - assert_eq!( - from_str(r#""00:00:60""#).ok(), - Some(NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()) - ); - assert_eq!(from_str(r#""00:01:02""#).ok(), Some(NaiveTime::from_hms_opt(0, 1, 2).unwrap())); - assert_eq!( - from_str(r#""03:05:07.098765432""#).ok(), - Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()) - ); - assert_eq!(from_str(r#""07:08:09""#).ok(), Some(NaiveTime::from_hms_opt(7, 8, 9).unwrap())); - assert_eq!( - from_str(r#""12:34:56.000789""#).ok(), - Some(NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()) - ); - assert_eq!( - from_str(r#""23:59:60.999999999""#).ok(), - Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) - ); - assert_eq!( - from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored - Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) - ); - - // bad formats - assert!(from_str(r#""""#).is_err()); - assert!(from_str(r#""000000""#).is_err()); - assert!(from_str(r#""00:00:61""#).is_err()); - assert!(from_str(r#""00:60:00""#).is_err()); - assert!(from_str(r#""24:00:00""#).is_err()); - assert!(from_str(r#""23:59:59,1""#).is_err()); - assert!(from_str(r#""012:34:56""#).is_err()); - assert!(from_str(r#""hh:mm:ss""#).is_err()); - assert!(from_str(r#"0"#).is_err()); - assert!(from_str(r#"86399"#).is_err()); - assert!(from_str(r#"{}"#).is_err()); - // pre-0.3.0 rustc-serialize format is now invalid - assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err()); - assert!(from_str(r#"null"#).is_err()); -} diff --git a/src/naive/time/serde.rs b/src/naive/time/serde.rs index 0992fb59f2..c1df410292 100644 --- a/src/naive/time/serde.rs +++ b/src/naive/time/serde.rs @@ -42,17 +42,91 @@ impl<'de> de::Deserialize<'de> for NaiveTime { #[cfg(test)] mod tests { - use crate::naive::time::{test_decodable_json, test_encodable_json}; use crate::NaiveTime; #[test] fn test_serde_serialize() { - test_encodable_json(serde_json::to_string); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_opt(0, 0, 0).unwrap()).ok(), + Some(r#""00:00:00""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()).ok(), + Some(r#""00:00:00.950""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()).ok(), + Some(r#""00:00:60""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_opt(0, 1, 2).unwrap()).ok(), + Some(r#""00:01:02""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()).ok(), + Some(r#""03:05:07.098765432""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_opt(7, 8, 9).unwrap()).ok(), + Some(r#""07:08:09""#.into()) + ); + assert_eq!( + serde_json::to_string(&NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()).ok(), + Some(r#""12:34:56.000789""#.into()) + ); + let leap = NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap(); + assert_eq!(serde_json::to_string(&leap).ok(), Some(r#""23:59:60.999999999""#.into())); } #[test] fn test_serde_deserialize() { - test_decodable_json(|input| serde_json::from_str(input)); + let from_str = serde_json::from_str::; + + assert_eq!(from_str(r#""00:00:00""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); + assert_eq!(from_str(r#""0:0:0""#).ok(), Some(NaiveTime::from_hms_opt(0, 0, 0).unwrap())); + assert_eq!( + from_str(r#""00:00:00.950""#).ok(), + Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) + ); + assert_eq!( + from_str(r#""0:0:0.95""#).ok(), + Some(NaiveTime::from_hms_milli_opt(0, 0, 0, 950).unwrap()) + ); + assert_eq!( + from_str(r#""00:00:60""#).ok(), + Some(NaiveTime::from_hms_milli_opt(0, 0, 59, 1_000).unwrap()) + ); + assert_eq!(from_str(r#""00:01:02""#).ok(), Some(NaiveTime::from_hms_opt(0, 1, 2).unwrap())); + assert_eq!( + from_str(r#""03:05:07.098765432""#).ok(), + Some(NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap()) + ); + assert_eq!(from_str(r#""07:08:09""#).ok(), Some(NaiveTime::from_hms_opt(7, 8, 9).unwrap())); + assert_eq!( + from_str(r#""12:34:56.000789""#).ok(), + Some(NaiveTime::from_hms_micro_opt(12, 34, 56, 789).unwrap()) + ); + assert_eq!( + from_str(r#""23:59:60.999999999""#).ok(), + Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + ); + assert_eq!( + from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored + Some(NaiveTime::from_hms_nano_opt(23, 59, 59, 1_999_999_999).unwrap()) + ); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""000000""#).is_err()); + assert!(from_str(r#""00:00:61""#).is_err()); + assert!(from_str(r#""00:60:00""#).is_err()); + assert!(from_str(r#""24:00:00""#).is_err()); + assert!(from_str(r#""23:59:59,1""#).is_err()); + assert!(from_str(r#""012:34:56""#).is_err()); + assert!(from_str(r#""hh:mm:ss""#).is_err()); + assert!(from_str(r#"0"#).is_err()); + assert!(from_str(r#"86399"#).is_err()); + assert!(from_str(r#"{}"#).is_err()); } #[test]