From b6cc4dbe63d672acba5eeca9080fcea5acf75d2f Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 1 Jun 2023 16:23:08 +0900 Subject: [PATCH 01/48] Format toml with taplo (#1117) --- .github/workflows/lint.yml | 8 ++++++++ Cargo.toml | 4 ++-- ci/core-test/Cargo.toml | 6 +++--- deny.toml | 6 +++--- taplo.toml | 4 ++++ 5 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 taplo.toml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7e26d4e6..a0cf75d9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,6 +27,14 @@ jobs: env: RUSTFLAGS: "-Dwarnings" + toml: + runs-on: ubuntu-latest + container: + image: tamasfe/taplo:0.8.0 + steps: + - run: taplo lint + - run: taplo fmt --check --diff + cargo-deny: runs-on: ubuntu-latest steps: diff --git a/Cargo.toml b/Cargo.toml index b8997542..2745c67e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,12 +35,12 @@ rustc-serialize = { version = "0.3.20", optional = true } serde = { version = "1.0.99", default-features = false, optional = true } pure-rust-locales = { version = "0.5.2", optional = true } criterion = { version = "0.4.0", optional = true } -rkyv = {version = "0.7", optional = true} +rkyv = { version = "0.7", optional = true } arbitrary = { version = "1.0.0", features = ["derive"], optional = true } [target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies] wasm-bindgen = { version = "0.2", optional = true } -js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API +js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API [target.'cfg(windows)'.dependencies] diff --git a/ci/core-test/Cargo.toml b/ci/core-test/Cargo.toml index b35ff9a7..4258f9d9 100644 --- a/ci/core-test/Cargo.toml +++ b/ci/core-test/Cargo.toml @@ -2,8 +2,8 @@ name = "core-test" version = "0.1.0" authors = [ - "Kang Seonghoon ", - "Brandon W Maister ", + "Kang Seonghoon ", + "Brandon W Maister ", ] edition = "2018" @@ -11,4 +11,4 @@ edition = "2018" chrono = { path = "../..", default-features = false, features = ["serde"] } [features] -alloc = ["chrono/alloc"] \ No newline at end of file +alloc = ["chrono/alloc"] diff --git a/deny.toml b/deny.toml index 13b9fac5..0e486c84 100644 --- a/deny.toml +++ b/deny.toml @@ -4,9 +4,9 @@ copyleft = "deny" [advisories] ignore = [ - "RUSTSEC-2020-0071", # time 0.1, doesn't affect the API we use - "RUSTSEC-2021-0145", # atty (dev-deps only, dependency of criterion) - "RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility + "RUSTSEC-2020-0071", # time 0.1, doesn't affect the API we use + "RUSTSEC-2021-0145", # atty (dev-deps only, dependency of criterion) + "RUSTSEC-2022-0004", # rustc_serialize, cannot remove due to compatibility ] unmaintained = "deny" unsound = "deny" diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 00000000..5fe42eb8 --- /dev/null +++ b/taplo.toml @@ -0,0 +1,4 @@ +include = ["deny.toml", "**/Cargo.toml"] + +[formatting] +inline_table_expand = false From 01833a18114fb3f732594d7a1c3e5f32eb738f80 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 1 Jun 2023 18:05:42 +0200 Subject: [PATCH 02/48] Use `Borrow` in `DateTime::signed_duration_since` --- src/datetime/mod.rs | 8 +++++--- src/datetime/tests.rs | 9 +++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 65a39aa8..f3e79ee6 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -8,7 +8,6 @@ extern crate alloc; #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::{String, ToString}; -#[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::Write; @@ -409,8 +408,11 @@ impl DateTime { /// This does not overflow or underflow at all. #[inline] #[must_use] - pub fn signed_duration_since(self, rhs: DateTime) -> OldDuration { - self.datetime.signed_duration_since(rhs.datetime) + pub fn signed_duration_since( + self, + rhs: impl Borrow>, + ) -> OldDuration { + self.datetime.signed_duration_since(rhs.borrow().datetime) } /// Returns a view to the naive UTC datetime. diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index c6be142d..e86ac4f0 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -313,6 +313,15 @@ fn test_datetime_offset() { assert!(*edt.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap().offset() != est); } +#[test] +fn signed_duration_since_autoref() { + let dt1 = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap(); + let dt2 = Utc.with_ymd_and_hms(2014, 3, 4, 5, 6, 7).unwrap(); + let diff1 = dt1.signed_duration_since(dt2); // Copy/consume + let diff2 = dt2.signed_duration_since(&dt1); // Take by reference + assert_eq!(diff1, -diff2); +} + #[test] fn test_datetime_date_and_time() { let tz = FixedOffset::east_opt(5 * 60 * 60).unwrap(); From 2dbf66f391f2c9a590fa5a27d3f32bcc8fb21277 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 10:22:59 +0200 Subject: [PATCH 03/48] Add `Sub` implementation that takes rhs by reference --- src/datetime/mod.rs | 9 +++++++++ src/datetime/tests.rs | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index f3e79ee6..14ce537a 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1048,6 +1048,15 @@ impl Sub> for DateTime { } } +impl Sub<&DateTime> for DateTime { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: &DateTime) -> OldDuration { + self.signed_duration_since(rhs) + } +} + impl Add for DateTime { type Output = DateTime; diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index e86ac4f0..7b3c1644 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -320,6 +320,10 @@ fn signed_duration_since_autoref() { let diff1 = dt1.signed_duration_since(dt2); // Copy/consume let diff2 = dt2.signed_duration_since(&dt1); // Take by reference assert_eq!(diff1, -diff2); + + let diff1 = dt1 - &dt2; // We can choose to substract rhs by reference + let diff2 = dt2 - dt1; // Or consume rhs + assert_eq!(diff1, -diff2); } #[test] From 1187e3ee043d579dbfc2f8ae61383e6dd17f8c78 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sun, 4 Jun 2023 10:23:35 +0200 Subject: [PATCH 04/48] Stop vendoring `saturating_abs` --- src/offset/local/tz_info/timezone.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/offset/local/tz_info/timezone.rs b/src/offset/local/tz_info/timezone.rs index 33c89060..d2de0602 100644 --- a/src/offset/local/tz_info/timezone.rs +++ b/src/offset/local/tz_info/timezone.rs @@ -321,7 +321,7 @@ impl<'a> TimeZoneRef<'a> { // Check leap seconds if !(self.leap_seconds.is_empty() || self.leap_seconds[0].unix_leap_time >= 0 - && saturating_abs(self.leap_seconds[0].correction) == 1) + && self.leap_seconds[0].correction.saturating_abs() == 1) { return Err(Error::TimeZone("invalid leap second")); } @@ -336,7 +336,7 @@ impl<'a> TimeZoneRef<'a> { let diff_unix_leap_time = x1.unix_leap_time.saturating_sub(x0.unix_leap_time); let abs_diff_correction = - saturating_abs(x1.correction.saturating_sub(x0.correction)); + x1.correction.saturating_sub(x0.correction).saturating_abs(); if !(diff_unix_leap_time >= min_interval && abs_diff_correction == 1) { return Err(Error::TimeZone("invalid leap second")); @@ -615,17 +615,6 @@ fn find_tz_file(path: impl AsRef) -> Result { } } -#[inline] -const fn saturating_abs(v: i32) -> i32 { - if v.is_positive() { - v - } else if v == i32::min_value() { - i32::max_value() - } else { - -v - } -} - // Possible system timezone directories #[cfg(unix)] const ZONE_INFO_DIRECTORIES: [&str; 4] = From c1c272a575061990014b53abad4ff363040b585f Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sun, 4 Jun 2023 08:44:14 +0200 Subject: [PATCH 05/48] Ensure `timestamp_nanos` panics on overflow in release builds --- src/naive/datetime/mod.rs | 6 ++++-- src/naive/datetime/tests.rs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 0a3f7038..d32a388e 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -480,8 +480,10 @@ impl NaiveDateTime { #[inline] #[must_use] pub fn timestamp_nanos(&self) -> i64 { - let as_ns = self.timestamp() * 1_000_000_000; - as_ns + i64::from(self.timestamp_subsec_nanos()) + self.timestamp() + .checked_mul(1_000_000_000) + .and_then(|ns| ns.checked_add(i64::from(self.timestamp_subsec_nanos()))) + .expect("value can not be represented in a timestamp with nanosecond precision.") } /// Returns the number of milliseconds since the last whole non-leap second. diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index 07309a48..53422c8c 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -329,6 +329,24 @@ fn test_nanosecond_range() { ); } +#[test] +#[should_panic] +fn test_nanosecond_just_beyond_range() { + let maximum = "2262-04-11T23:47:16.854775804"; + let parsed: NaiveDateTime = maximum.parse().unwrap(); + let beyond_max = parsed + Duration::milliseconds(300); + let _ = beyond_max.timestamp_nanos(); +} + +#[test] +#[should_panic] +fn test_nanosecond_far_beyond_range() { + let maximum = "2262-04-11T23:47:16.854775804"; + let parsed: NaiveDateTime = maximum.parse().unwrap(); + let beyond_max = parsed + Duration::days(365); + let _ = beyond_max.timestamp_nanos(); +} + #[test] fn test_and_local_timezone() { let ndt = NaiveDate::from_ymd_opt(2022, 6, 15).unwrap().and_hms_opt(18, 59, 36).unwrap(); From 5c3f40cc670887398ecf84dfe8b5004b0ec01f13 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 5 Jun 2023 06:45:32 +0200 Subject: [PATCH 06/48] Fix dead code error when running dateutils test on Windows --- tests/dateutils.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/dateutils.rs b/tests/dateutils.rs index d671ecca..f49659d2 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -64,6 +64,7 @@ const DATE_PATH: &'static str = "/usr/bin/date"; const DATE_PATH: &'static str = "/opt/freeware/bin/date"; #[cfg(test)] +#[cfg(unix)] /// test helper to sanity check the date command behaves as expected /// asserts the command succeeded fn assert_run_date_version() { From 3760f2a23df43baa9e21573e1f16ee9ff3911dc7 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Mon, 5 Jun 2023 06:46:37 +0200 Subject: [PATCH 07/48] [CI] Run all test on Windows and MacOS --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee616c77..c97c0b16 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,8 +28,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: cargo test --lib --all-features --color=always -- --color=always - - run: cargo test --doc --all-features --color=always -- --color=always + - run: cargo test --all-features --color=always -- --color=always # later this may be able to be included with the below # kept separate for now as the following don't compile on 1.56.1 From dfd7a807177f87ef6dbe90a271e89b11fff061e2 Mon Sep 17 00:00:00 2001 From: Eugene Lomov Date: Mon, 5 Jun 2023 15:54:47 +0300 Subject: [PATCH 08/48] Added Ord and Eq traits for types, which already derives PartialOrd and PartialEq (#1128) --- src/month.rs | 4 ++-- src/naive/date.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/month.rs b/src/month.rs index 11df7613..4c6321e1 100644 --- a/src/month.rs +++ b/src/month.rs @@ -28,7 +28,7 @@ use crate::OutOfRange; /// Allows mapping from and to month, from 1-January to 12-December. /// Can be Serialized/Deserialized with serde // Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior. -#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] @@ -218,7 +218,7 @@ impl num_traits::FromPrimitive for Month { } /// A duration in calendar months -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Months(pub(crate) u32); diff --git a/src/naive/date.rs b/src/naive/date.rs index b9404a15..6ad560b9 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -137,7 +137,7 @@ impl NaiveWeek { /// that adding `Duration::days(1)` doesn't increment the day value as expected due to it being a /// fixed number of seconds. This difference applies only when dealing with `DateTime` data types /// and in other cases `Duration::days(n)` and `Days::new(n)` are equivalent. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct Days(pub(crate) u64); impl Days { From 70a25b1f9f799152db1fc83430a04baf519afcde Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 09:45:43 +0200 Subject: [PATCH 09/48] Document panicking of `NaiveWeek` --- src/naive/date.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/naive/date.rs b/src/naive/date.rs index 6ad560b9..7e6d66d6 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -66,6 +66,11 @@ pub struct NaiveWeek { impl NaiveWeek { /// Returns a date representing the first day of the week. /// + /// # Panics + /// + /// Panics if the first day of the week happens to fall just out of range of `NaiveDate` + /// (more than ca. 262,000 years away from common era). + /// /// # Examples /// /// ``` @@ -89,6 +94,11 @@ impl NaiveWeek { /// Returns a date representing the last day of the week. /// + /// # Panics + /// + /// Panics if the last day of the week happens to fall just out of range of `NaiveDate` + /// (more than ca. 262,000 years away from common era). + /// /// # Examples /// /// ``` @@ -114,6 +124,11 @@ impl NaiveWeek { /// [first_day](./struct.NaiveWeek.html#method.first_day) and /// [last_day](./struct.NaiveWeek.html#method.last_day) functions. /// + /// # Panics + /// + /// Panics if the either the first or last day of the week happens to fall just out of range of + /// `NaiveDate` (more than ca. 262,000 years away from common era). + /// /// # Examples /// /// ``` From cafd845f065c2509cc42918597e2614f6f4c7063 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 09:46:10 +0200 Subject: [PATCH 10/48] Clearly document errors and panics for `NaiveDate` --- src/naive/date.rs | 162 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 132 insertions(+), 30 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 7e6d66d6..9b43ba8b 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -300,7 +300,10 @@ impl NaiveDate { /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) /// (year, month and day). /// - /// Panics on the out-of-range date, invalid month and/or day. + /// # Panics + /// + /// Panics if the specified calendar day does not exist, on invalid values for `month` or `day`, + /// or if `year` is out of range for `NaiveDate`. #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] #[must_use] pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { @@ -310,7 +313,12 @@ impl NaiveDate { /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) /// (year, month and day). /// - /// Returns `None` on the out-of-range date, invalid month and/or day. + /// # Errors + /// + /// Returns `None` if: + /// - The specified calendar day does not exist (for example 2023-04-31). + /// - The value for `month` or `day` is invalid. + /// - `year` is out of range for `NaiveDate`. /// /// # Example /// @@ -335,7 +343,10 @@ impl NaiveDate { /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) /// (year and day of the year). /// - /// Panics on the out-of-range date and/or invalid day of year. + /// # Panics + /// + /// Panics if the specified ordinal day does not exist, on invalid values for `ordinal`, or if + /// `year` is out of range for `NaiveDate`. #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] #[must_use] pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { @@ -345,7 +356,12 @@ impl NaiveDate { /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) /// (year and day of the year). /// - /// Returns `None` on the out-of-range date and/or invalid day of year. + /// # Errors + /// + /// Returns `None` if: + /// - The specified ordinal day does not exist (for example 2023-366). + /// - The value for `ordinal` is invalid (for example: `0`, `400`). + /// - `year` is out of range for `NaiveDate`. /// /// # Example /// @@ -372,7 +388,10 @@ impl NaiveDate { /// (year, week number and day of the week). /// The resulting `NaiveDate` may have a different year from the input year. /// - /// Panics on the out-of-range date and/or invalid week number. + /// # Panics + /// + /// Panics if the specified week does not exist in that year, on invalid values for `week`, or + /// if the resulting date is out of range for `NaiveDate`. #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] #[must_use] pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { @@ -383,7 +402,12 @@ impl NaiveDate { /// (year, week number and day of the week). /// The resulting `NaiveDate` may have a different year from the input year. /// - /// Returns `None` on the out-of-range date and/or invalid week number. + /// # Errors + /// + /// Returns `None` if: + /// - The specified week does not exist in that year (for example 2023 week 53). + /// - The value for `week` is invalid (for example: `0`, `60`). + /// - If the resulting date is out of range for `NaiveDate`. /// /// # Example /// @@ -459,6 +483,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with /// January 1, 1 being day 1. /// + /// # Panics + /// /// Panics if the date is out of range. #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] #[inline] @@ -470,6 +496,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` from a day's number in the proleptic Gregorian calendar, with /// January 1, 1 being day 1. /// + /// # Errors + /// /// Returns `None` if the date is out of range. /// /// # Example @@ -497,15 +525,15 @@ impl NaiveDate { } /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week - /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. /// + /// `n` is 1-indexed. + /// /// # Panics /// - /// The resulting `NaiveDate` is guaranteed to be in `month`. If `n` is larger than the number - /// of `weekday` in `month` (eg. the 6th Friday of March 2017) then this function will panic. - /// - /// `n` is 1-indexed. Passing `n=0` will cause a panic. + /// Panics if the specified day does not exist in that month, on invalid values for `month` or + /// `n`, or if `year` is out of range for `NaiveDate`. #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] #[must_use] pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { @@ -513,17 +541,25 @@ impl NaiveDate { } /// Makes a new `NaiveDate` by counting the number of occurrences of a particular day-of-week - /// since the beginning of the given month. For instance, if you want the 2nd Friday of March - /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. `n` is 1-indexed. + /// since the beginning of the given month. For instance, if you want the 2nd Friday of March + /// 2017, you would use `NaiveDate::from_weekday_of_month(2017, 3, Weekday::Fri, 2)`. + /// + /// `n` is 1-indexed. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The specified day does not exist in that month (for example the 5th Monday of Apr. 2023). + /// - The value for `month` or `n` is invalid. + /// - `year` is out of range for `NaiveDate`. + /// + /// # Example /// /// ``` /// use chrono::{NaiveDate, Weekday}; /// assert_eq!(NaiveDate::from_weekday_of_month_opt(2017, 3, Weekday::Fri, 2), /// NaiveDate::from_ymd_opt(2017, 3, 10)) /// ``` - /// - /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in - /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. #[must_use] pub fn from_weekday_of_month_opt( year: i32, @@ -612,10 +648,14 @@ impl NaiveDate { /// Add a duration in [`Months`] to the date /// - /// If the day would be out of range for the resulting month, use the last day for that month. + /// Uses the last day of the month if the day does not exist in the resulting month. + /// + /// # Errors /// /// Returns `None` if the resulting date would be out of range. /// + /// # Example + /// /// ``` /// # use chrono::{NaiveDate, Months}; /// assert_eq!( @@ -641,10 +681,14 @@ impl NaiveDate { /// Subtract a duration in [`Months`] from the date /// - /// If the day would be out of range for the resulting month, use the last day for that month. + /// Uses the last day of the month if the day does not exist in the resulting month. + /// + /// # Errors /// /// Returns `None` if the resulting date would be out of range. /// + /// # Example + /// /// ``` /// # use chrono::{NaiveDate, Months}; /// assert_eq!( @@ -715,8 +759,12 @@ impl NaiveDate { /// Add a duration in [`Days`] to the date /// + /// # Errors + /// /// Returns `None` if the resulting date would be out of range. /// + /// # Example + /// /// ``` /// # use chrono::{NaiveDate, Days}; /// assert_eq!( @@ -743,8 +791,12 @@ impl NaiveDate { /// Subtract a duration in [`Days`] from the date /// + /// # Errors + /// /// Returns `None` if the resulting date would be out of range. /// + /// # Example + /// /// ``` /// # use chrono::{NaiveDate, Days}; /// assert_eq!( @@ -798,6 +850,8 @@ impl NaiveDate { /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. /// + /// # Panics + /// /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] #[inline] @@ -811,6 +865,8 @@ impl NaiveDate { /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. /// + /// # Errors + /// /// Returns `None` on invalid hour, minute and/or second. /// /// # Example @@ -835,6 +891,8 @@ impl NaiveDate { /// The millisecond part can exceed 1,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] #[inline] @@ -848,6 +906,8 @@ impl NaiveDate { /// The millisecond part can exceed 1,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or millisecond. /// /// # Example @@ -880,6 +940,8 @@ impl NaiveDate { /// The microsecond part can exceed 1,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or microsecond. /// /// # Example @@ -907,6 +969,8 @@ impl NaiveDate { /// The microsecond part can exceed 1,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or microsecond. /// /// # Example @@ -939,6 +1003,8 @@ impl NaiveDate { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] #[inline] @@ -952,6 +1018,8 @@ impl NaiveDate { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or nanosecond. /// /// # Example @@ -1010,6 +1078,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` for the next calendar date. /// + /// # Panics + /// /// Panics when `self` is the last representable date. #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] #[inline] @@ -1020,6 +1090,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` for the next calendar date. /// + /// # Errors + /// /// Returns `None` when `self` is the last representable date. /// /// # Example @@ -1042,6 +1114,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` for the previous calendar date. /// + /// # Panics + /// /// Panics when `self` is the first representable date. #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] #[inline] @@ -1052,6 +1126,8 @@ impl NaiveDate { /// Makes a new `NaiveDate` for the previous calendar date. /// + /// # Errors + /// /// Returns `None` when `self` is the first representable date. /// /// # Example @@ -1072,9 +1148,11 @@ impl NaiveDate { } } - /// Adds the `days` part of given `Duration` to the current date. + /// Adds the number of whole days in the given `Duration` to the current date. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -1104,9 +1182,11 @@ impl NaiveDate { NaiveDate::from_ordinal_and_flags(year_div_400 * 400 + year_mod_400 as i32, ordinal, flags) } - /// Subtracts the `days` part of given `Duration` from the current date. + /// Subtracts the number of whole days in the given `Duration` from the current date. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -1172,6 +1252,10 @@ impl NaiveDate { } /// Returns the number of whole years from the given `base` until `self`. + /// + /// # Errors + /// + /// Returns `None` if `base < self`. #[must_use] pub fn years_since(&self, base: Self) -> Option { let mut years = self.year() - base.year(); @@ -1555,9 +1639,12 @@ impl Datelike for NaiveDate { isoweek::iso_week_from_yof(self.year(), self.of()) } - /// Makes a new `NaiveDate` with the year number changed. + /// Makes a new `NaiveDate` with the year number changed, while keeping the same month and day. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or when the `NaiveDate` would be + /// out of range. /// /// # Example /// @@ -1591,7 +1678,9 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the month number (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month` is invalid. /// /// # Example /// @@ -1610,7 +1699,10 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the month number (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month0` is + /// invalid. /// /// # Example /// @@ -1630,7 +1722,9 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day` is invalid. /// /// # Example /// @@ -1649,7 +1743,9 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day0` is invalid. /// /// # Example /// @@ -1669,7 +1765,10 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal` is + /// invalid. /// /// # Example /// @@ -1693,7 +1792,10 @@ impl Datelike for NaiveDate { /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal0` is + /// invalid. /// /// # Example /// From cbfd21b3cf88958015cd20c3e843edb2325c55ef Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 12:04:58 +0200 Subject: [PATCH 11/48] Clearly document errors and panics for `NaiveTime` --- src/naive/time/mod.rs | 46 +++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 3700c5cb..328f2cbf 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -212,6 +212,8 @@ impl NaiveTime { /// No [leap second](#leap-second-handling) is allowed here; /// use `NaiveTime::from_hms_*` methods with a subsecond parameter instead. /// + /// # Panics + /// /// Panics on invalid hour, minute and/or second. #[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")] #[inline] @@ -225,6 +227,8 @@ impl NaiveTime { /// No [leap second](#leap-second-handling) is allowed here; /// use `NaiveTime::from_hms_*_opt` methods with a subsecond parameter instead. /// + /// # Errors + /// /// Returns `None` on invalid hour, minute and/or second. /// /// # Example @@ -251,6 +255,8 @@ impl NaiveTime { /// The millisecond part can exceed 1,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or millisecond. #[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")] #[inline] @@ -264,6 +270,8 @@ impl NaiveTime { /// The millisecond part can exceed 1,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or millisecond. /// /// # Example @@ -294,6 +302,8 @@ impl NaiveTime { /// The microsecond part can exceed 1,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or microsecond. #[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")] #[inline] @@ -307,6 +317,8 @@ impl NaiveTime { /// The microsecond part can exceed 1,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or microsecond. /// /// # Example @@ -335,6 +347,8 @@ impl NaiveTime { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid hour, minute, second and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")] #[inline] @@ -348,6 +362,8 @@ impl NaiveTime { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid hour, minute, second and/or nanosecond. /// /// # Example @@ -380,6 +396,8 @@ impl NaiveTime { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Panics + /// /// Panics on invalid number of seconds and/or nanosecond. #[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")] #[inline] @@ -393,6 +411,8 @@ impl NaiveTime { /// The nanosecond part can exceed 1,000,000,000 /// in order to represent the [leap second](#leap-second-handling). /// + /// # Errors + /// /// Returns `None` on invalid number of seconds and/or nanosecond. /// /// # Example @@ -506,10 +526,8 @@ impl NaiveTime { parsed.to_naive_time().map(|t| (t, remainder)) } - /// Adds given `Duration` to the current time, - /// and also returns the number of *seconds* + /// Adds given `Duration` to the current time, and also returns the number of *seconds* /// in the integral number of days ignored from the addition. - /// (We cannot return `Duration` because it is subject to overflow or underflow.) /// /// # Example /// @@ -589,10 +607,8 @@ impl NaiveTime { (NaiveTime { secs: secs as u32, frac: frac as u32 }, morerhssecs) } - /// Subtracts given `Duration` from the current time, - /// and also returns the number of *seconds* + /// Subtracts given `Duration` from the current time, and also returns the number of *seconds* /// in the integral number of days ignored from the subtraction. - /// (We cannot return `Duration` because it is subject to overflow or underflow.) /// /// # Example /// @@ -886,7 +902,9 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with the hour number changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// # Errors + /// + /// Returns `None` if the value for `hour` is invalid. /// /// # Example /// @@ -908,7 +926,9 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with the minute number changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// # Errors + /// + /// Returns `None` if the value for `minute` is invalid. /// /// # Example /// @@ -930,10 +950,13 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with the second number changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. /// As with the [`second`](#method.second) method, /// the input range is restricted to 0 through 59. /// + /// # Errors + /// + /// Returns `None` if the value for `second` is invalid. + /// /// # Example /// /// ``` @@ -954,10 +977,13 @@ impl Timelike for NaiveTime { /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second changed. /// - /// Returns `None` when the resulting `NaiveTime` would be invalid. /// As with the [`nanosecond`](#method.nanosecond) method, /// the input range can exceed 1,000,000,000 for leap seconds. /// + /// # Errors + /// + /// Returns `None` if `nanosecond >= 2,000,000,000`. + /// /// # Example /// /// ``` From c0b634cac05c0e82893a4e2186520510130904b9 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 09:20:30 +0200 Subject: [PATCH 12/48] Clearly document errors and panics for `NaiveDateTime` --- src/naive/datetime/mod.rs | 142 ++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 51 deletions(-) diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index d32a388e..1bd17d57 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -113,7 +113,11 @@ impl NaiveDateTime { /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX /// timestamp" cannot represent a leap second unambiguously.) /// - /// Panics on the out-of-range number of seconds and/or invalid nanosecond. + /// # Panics + /// + /// Panics if the number of seconds would be out of range for a `NaiveDateTime` (more than + /// ca. 262,000 years away from common era), and panics on an invalid nanosecond (2 seconds or + /// more). #[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")] #[inline] #[must_use] @@ -126,7 +130,10 @@ impl NaiveDateTime { /// /// The UNIX epoch starts on midnight, January 1, 1970, UTC. /// - /// Returns `None` on an out-of-range number of milliseconds. + /// # Errors + /// + /// Returns `None` if the number of milliseconds would be out of range for a `NaiveDateTime` + /// (more than ca. 262,000 years away from common era) /// /// # Example /// @@ -155,7 +162,10 @@ impl NaiveDateTime { /// /// The UNIX epoch starts on midnight, January 1, 1970, UTC. /// - /// Returns `None` on an out-of-range number of microseconds. + /// # Errors + /// + /// Returns `None` if the number of microseconds would be out of range for a `NaiveDateTime` + /// (more than ca. 262,000 years away from common era) /// /// # Example /// @@ -189,8 +199,11 @@ impl NaiveDateTime { /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) /// - /// Returns `None` on the out-of-range number of seconds (more than 262 000 years away - /// from common era) and/or invalid nanosecond (2 seconds or more). + /// # Errors + /// + /// Returns `None` if the number of seconds would be out of range for a `NaiveDateTime` (more + /// than ca. 262,000 years away from common era), and panics on an invalid nanosecond + /// (2 seconds or more). /// /// # Example /// @@ -390,11 +403,6 @@ impl NaiveDateTime { /// Note that this does *not* account for the timezone! /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. /// - /// Note also that this does reduce the number of years that can be - /// represented from ~584 Billion to ~584 Million. (If this is a problem, - /// please file an issue to let me know what domain needs millisecond - /// precision over billions of years, I'm curious.) - /// /// # Example /// /// ``` @@ -421,11 +429,6 @@ impl NaiveDateTime { /// Note that this does *not* account for the timezone! /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. /// - /// Note also that this does reduce the number of years that can be - /// represented from ~584 Billion to ~584 Thousand. (If this is a problem, - /// please file an issue to let me know what domain needs microsecond - /// precision over millennia, I'm curious.) - /// /// # Example /// /// ``` @@ -451,13 +454,11 @@ impl NaiveDateTime { /// /// # Panics /// - /// Note also that this does reduce the number of years that can be - /// represented from ~584 Billion to ~584 years. The dates that can be - /// represented as nanoseconds are between 1677-09-21T00:12:44.0 and - /// 2262-04-11T23:47:16.854775804. + /// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on + /// an out of range `NaiveDateTime`. /// - /// (If this is a problem, please file an issue to let me know what domain - /// needs nanosecond precision over millennia, I'm curious.) + /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and + /// 2262-04-11T23:47:16.854775804. /// /// # Example /// @@ -559,7 +560,9 @@ impl NaiveDateTime { /// except when the `NaiveDateTime` itself represents a leap second /// in which case the assumption becomes that **there is exactly a single leap second ever**. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -632,9 +635,11 @@ impl NaiveDateTime { /// Adds given `Months` to the current date and time. /// - /// Returns `None` when it will result in overflow. + /// Uses the last day of the month if the day does not exist in the resulting month. /// - /// Overflow returns `None`. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -665,7 +670,9 @@ impl NaiveDateTime { /// except when the `NaiveDateTime` itself represents a leap second /// in which case the assumption becomes that **there is exactly a single leap second ever**. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -734,9 +741,11 @@ impl NaiveDateTime { /// Subtracts given `Months` from the current date and time. /// - /// Returns `None` when it will result in overflow. + /// Uses the last day of the month if the day does not exist in the resulting month. /// - /// Overflow returns `None`. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. /// /// # Example /// @@ -1097,12 +1106,16 @@ impl Datelike for NaiveDateTime { self.date.iso_week() } - /// Makes a new `NaiveDateTime` with the year number changed. - /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// Makes a new `NaiveDateTime` with the year number changed, while keeping the same month and + /// day. /// /// See also the [`NaiveDate::with_year`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or when the `NaiveDateTime` would be + /// out of range. + /// /// # Example /// /// ``` @@ -1119,10 +1132,12 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_month`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month` is invalid. + /// /// # Example /// /// ``` @@ -1140,10 +1155,13 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the month number (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_month0`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `month0` is + /// invalid. + /// /// # Example /// /// ``` @@ -1161,10 +1179,12 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the day of month (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_day`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day` is invalid. + /// /// # Example /// /// ``` @@ -1181,10 +1201,12 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the day of month (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_day0`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `day0` is invalid. + /// /// # Example /// /// ``` @@ -1201,10 +1223,13 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the day of year (starting from 1) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_ordinal`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal` is + /// invalid. + /// /// # Example /// /// ``` @@ -1228,10 +1253,13 @@ impl Datelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the day of year (starting from 0) changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveDate::with_ordinal0`] method. /// + /// # Errors + /// + /// Returns `None` if the resulting date does not exist, or if the value for `ordinal0` is + /// invalid. + /// /// # Example /// /// ``` @@ -1327,10 +1355,12 @@ impl Timelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the hour number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. - /// /// See also the [`NaiveTime::with_hour`] method. /// + /// # Errors + /// + /// Returns `None` if the value for `hour` is invalid. + /// /// # Example /// /// ``` @@ -1348,10 +1378,11 @@ impl Timelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the minute number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// See also the [`NaiveTime::with_minute`] method. /// - /// See also the - /// [`NaiveTime::with_minute`] method. + /// # Errors + /// + /// Returns `None` if the value for `minute` is invalid. /// /// # Example /// @@ -1370,12 +1401,15 @@ impl Timelike for NaiveDateTime { /// Makes a new `NaiveDateTime` with the second number changed. /// - /// Returns `None` when the resulting `NaiveDateTime` would be invalid. As - /// with the [`NaiveDateTime::second`] method, the input range is - /// restricted to 0 through 59. + /// As with the [`second`](#method.second) method, + /// the input range is restricted to 0 through 59. /// /// See also the [`NaiveTime::with_second`] method. /// + /// # Errors + /// + /// Returns `None` if the value for `second` is invalid. + /// /// # Example /// /// ``` @@ -1399,6 +1433,10 @@ impl Timelike for NaiveDateTime { /// /// See also the [`NaiveTime::with_nanosecond`] method. /// + /// # Errors + /// + /// Returns `None` if `nanosecond >= 2,000,000,000`. + /// /// # Example /// /// ``` @@ -1423,7 +1461,9 @@ impl Timelike for NaiveDateTime { /// second ever**, except when the `NaiveDateTime` itself represents a leap second in which case /// the assumption becomes that **there is exactly a single leap second ever**. /// -/// Panics on underflow or overflow. Use [`NaiveDateTime::checked_add_signed`] +/// # Panics +/// +/// Panics if the resulting date would be out of range. Use [`NaiveDateTime::checked_add_signed`] /// to detect that. /// /// # Example From 401c298b8f0e92232aa65f395f06c1ce7a699264 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 2 Jun 2023 12:56:45 +0200 Subject: [PATCH 13/48] Clearly document errors and panics for `DateTime` --- src/datetime/mod.rs | 266 ++++++++++++++++++++++++++++++++++++-------- src/traits.rs | 2 +- 2 files changed, 218 insertions(+), 50 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 14ce537a..23a5cde8 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -120,6 +120,13 @@ impl DateTime { /// Makes a new `DateTime` with given **local** datetime and offset that /// presents local timezone. /// + /// # Panics + /// + /// Panics if the local datetime can't be converted to UTC because it would be out of range. + /// + /// This can happen if `datetime` is near the end of the representable range of `NaiveDateTime`, + /// and the offset from UTC pushes it beyond that. + /// /// # Example /// /// ``` @@ -149,11 +156,19 @@ impl DateTime { DateTime { datetime: datetime_utc, offset } } - /// Retrieves a date component + /// Retrieves the date component with an associated timezone. /// /// Unless you are immediately planning on turning this into a `DateTime` - /// with the same Timezone you should use the - /// [`date_naive`](DateTime::date_naive) method. + /// with the same timezone you should use the [`date_naive`](DateTime::date_naive) method. + /// + /// [`NaiveDate`] is a more well-defined type, and has more traits implemented on it, + /// so should be preferred to [`Date`] any time you truly want to operate on dates. + /// + /// # Panics + /// + /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This + /// method will panic if the offset from UTC would push the local date outside of the + /// representable range of a [`Date`]. #[inline] #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")] #[allow(deprecated)] @@ -162,10 +177,15 @@ impl DateTime { Date::from_utc(self.naive_local().date(), self.offset.clone()) } - /// Retrieves the Date without an associated timezone + /// Retrieves the date component. /// - /// [`NaiveDate`] is a more well-defined type, and has more traits implemented on it, - /// so should be preferred to [`Date`] any time you truly want to operate on Dates. + /// # Panics + /// + /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This + /// method will panic if the offset from UTC would push the local date outside of the + /// representable range of a [`NaiveDate`]. + /// + /// # Example /// /// ``` /// use chrono::prelude::*; @@ -181,8 +201,7 @@ impl DateTime { NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap() } - /// Retrieves a time component. - /// Unlike `date`, this is not associated to the time zone. + /// Retrieves the time component. #[inline] #[must_use] pub fn time(&self) -> NaiveTime { @@ -197,12 +216,7 @@ impl DateTime { self.datetime.timestamp() } - /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC - /// - /// Note that this does reduce the number of years that can be represented - /// from ~584 Billion to ~584 Million. (If this is a problem, please file - /// an issue to let me know what domain needs millisecond precision over - /// billions of years, I'm curious.) + /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC. /// /// # Example /// @@ -221,12 +235,7 @@ impl DateTime { self.datetime.timestamp_millis() } - /// Returns the number of non-leap-microseconds since January 1, 1970 UTC - /// - /// Note that this does reduce the number of years that can be represented - /// from ~584 Billion to ~584 Thousand. (If this is a problem, please file - /// an issue to let me know what domain needs microsecond precision over - /// millennia, I'm curious.) + /// Returns the number of non-leap-microseconds since January 1, 1970 UTC. /// /// # Example /// @@ -245,12 +254,15 @@ impl DateTime { self.datetime.timestamp_micros() } - /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC + /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC. /// - /// Note that this does reduce the number of years that can be represented - /// from ~584 Billion to ~584. (If this is a problem, please file - /// an issue to let me know what domain needs nanosecond precision over - /// millennia, I'm curious.) + /// # Panics + /// + /// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on + /// an out of range `DateTime`. + /// + /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and + /// 2262-04-11T23:47:16.854775804. /// /// # Example /// @@ -269,22 +281,18 @@ impl DateTime { self.datetime.timestamp_nanos() } - /// Returns the number of milliseconds since the last second boundary + /// Returns the number of milliseconds since the last second boundary. /// - /// warning: in event of a leap second, this may exceed 999 - /// - /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC + /// In event of a leap second this may exceed 999. #[inline] #[must_use] pub fn timestamp_subsec_millis(&self) -> u32 { self.datetime.timestamp_subsec_millis() } - /// Returns the number of microseconds since the last second boundary + /// Returns the number of microseconds since the last second boundary. /// - /// warning: in event of a leap second, this may exceed 999_999 - /// - /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC + /// In event of a leap second this may exceed 999,999. #[inline] #[must_use] pub fn timestamp_subsec_micros(&self) -> u32 { @@ -293,9 +301,7 @@ impl DateTime { /// Returns the number of nanoseconds since the last second boundary /// - /// warning: in event of a leap second, this may exceed 999_999_999 - /// - /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC + /// In event of a leap second this may exceed 999,999,999. #[inline] #[must_use] pub fn timestamp_subsec_nanos(&self) -> u32 { @@ -317,7 +323,8 @@ impl DateTime { } /// Changes the associated time zone. - /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone. + /// The returned `DateTime` references the same instant of time from the perspective of the + /// provided time zone. #[inline] #[must_use] pub fn with_timezone(&self, tz: &Tz2) -> DateTime { @@ -334,7 +341,9 @@ impl DateTime { /// Adds given `Duration` to the current date and time. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. #[inline] #[must_use] pub fn checked_add_signed(self, rhs: OldDuration) -> Option> { @@ -345,10 +354,16 @@ impl DateTime { /// Adds given `Months` to the current date and time. /// - /// Returns `None` when it will result in overflow, or if the - /// local time is not valid on the newly calculated date. + /// Uses the last day of the month if the day does not exist in the resulting month. /// - /// See [`NaiveDate::checked_add_months`] for more details on behavior + /// See [`NaiveDate::checked_add_months`] for more details on behavior. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date would be out of range. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[must_use] pub fn checked_add_months(self, rhs: Months) -> Option> { self.naive_local() @@ -359,7 +374,9 @@ impl DateTime { /// Subtracts given `Duration` from the current date and time. /// - /// Returns `None` when it will result in overflow. + /// # Errors + /// + /// Returns `None` if the resulting date would be out of range. #[inline] #[must_use] pub fn checked_sub_signed(self, rhs: OldDuration) -> Option> { @@ -370,10 +387,16 @@ impl DateTime { /// Subtracts given `Months` from the current date and time. /// - /// Returns `None` when it will result in overflow, or if the - /// local time is not valid on the newly calculated date. + /// Uses the last day of the month if the day does not exist in the resulting month. /// - /// See [`NaiveDate::checked_sub_months`] for more details on behavior + /// See [`NaiveDate::checked_sub_months`] for more details on behavior. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date would be out of range. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[must_use] pub fn checked_sub_months(self, rhs: Months) -> Option> { self.naive_local() @@ -382,9 +405,14 @@ impl DateTime { .single() } - /// Add a duration in [`Days`] to the date part of the `DateTime` + /// Add a duration in [`Days`] to the date part of the `DateTime`. /// - /// Returns `None` if the resulting date would be out of range. + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date would be out of range. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[must_use] pub fn checked_add_days(self, days: Days) -> Option { self.naive_local() @@ -393,9 +421,14 @@ impl DateTime { .single() } - /// Subtract a duration in [`Days`] from the date part of the `DateTime` + /// Subtract a duration in [`Days`] from the date part of the `DateTime`. /// - /// Returns `None` if the resulting date would be out of range. + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date would be out of range. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[must_use] pub fn checked_sub_days(self, days: Days) -> Option { self.naive_local() @@ -423,6 +456,12 @@ impl DateTime { } /// Returns a view to the naive local datetime. + /// + /// # Panics + /// + /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This + /// method will panic if the offset from UTC would push the local datetime outside of the + /// representable range of a [`NaiveDateTime`]. #[inline] #[must_use] pub fn naive_local(&self) -> NaiveDateTime { @@ -430,6 +469,10 @@ impl DateTime { } /// Retrieve the elapsed years from now to the given [`DateTime`]. + /// + /// # Errors + /// + /// Returns `None` if `base < self`. #[must_use] pub fn years_since(&self, base: Self) -> Option { let mut years = self.year() - base.year(); @@ -661,6 +704,11 @@ where Tz::Offset: fmt::Display, { /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. + /// + /// # Panics + /// + /// Panics if the date can not be represented in this format: the year may not be negative and + /// can not have more than 4 digits. #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[must_use] @@ -866,35 +914,112 @@ impl Datelike for DateTime { } #[inline] + /// Makes a new `DateTime` with the year number changed, while keeping the same month and day. + /// + /// See also the [`NaiveDate::with_year`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - When the `NaiveDateTime` would be out of range. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. fn with_year(&self, year: i32) -> Option> { map_local(self, |datetime| datetime.with_year(year)) } + /// Makes a new `DateTime` with the month number (starting from 1) changed. + /// + /// See also the [`NaiveDate::with_month`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `month` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_month(&self, month: u32) -> Option> { map_local(self, |datetime| datetime.with_month(month)) } + /// Makes a new `DateTime` with the month number (starting from 0) changed. + /// + /// See also the [`NaiveDate::with_month0`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `month0` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_month0(&self, month0: u32) -> Option> { map_local(self, |datetime| datetime.with_month0(month0)) } + /// Makes a new `DateTime` with the month number (starting from 0) changed. + /// + /// See also the [`NaiveDate::with_day`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `day` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_day(&self, day: u32) -> Option> { map_local(self, |datetime| datetime.with_day(day)) } + /// Makes a new `DateTime` with the month number (starting from 0) changed. + /// + /// See also the [`NaiveDate::with_day0`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `day0` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_day0(&self, day0: u32) -> Option> { map_local(self, |datetime| datetime.with_day0(day0)) } + /// Makes a new `DateTime` with the month number (starting from 0) changed. + /// + /// See also the [`NaiveDate::with_ordinal`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `ordinal` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_ordinal(&self, ordinal: u32) -> Option> { map_local(self, |datetime| datetime.with_ordinal(ordinal)) } + /// Makes a new `DateTime` with the month number (starting from 0) changed. + /// + /// See also the [`NaiveDate::with_ordinal0`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The resulting date does not exist. + /// - The value for `ordinal0` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_ordinal0(&self, ordinal0: u32) -> Option> { map_local(self, |datetime| datetime.with_ordinal0(ordinal0)) @@ -919,21 +1044,64 @@ impl Timelike for DateTime { self.naive_local().nanosecond() } + /// Makes a new `DateTime` with the hour number changed. + /// + /// See also the [`NaiveTime::with_hour`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The value for `hour` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_hour(&self, hour: u32) -> Option> { map_local(self, |datetime| datetime.with_hour(hour)) } + /// Makes a new `DateTime` with the minute number changed. + /// + /// See also the [`NaiveTime::with_minute`] method. + /// + /// # Errors + /// + /// - The value for `minute` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_minute(&self, min: u32) -> Option> { map_local(self, |datetime| datetime.with_minute(min)) } + /// Makes a new `DateTime` with the second number changed. + /// + /// As with the [`second`](#method.second) method, + /// the input range is restricted to 0 through 59. + /// + /// See also the [`NaiveTime::with_second`] method. + /// + /// # Errors + /// + /// Returns `None` if: + /// - The value for `second` is invalid. + /// - The local time at the resulting date does not exist or is ambiguous, for example during a + /// daylight saving time transition. #[inline] fn with_second(&self, sec: u32) -> Option> { map_local(self, |datetime| datetime.with_second(sec)) } + /// Makes a new `DateTime` with nanoseconds since the whole non-leap second changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// As with the [`NaiveDateTime::nanosecond`] method, + /// the input range can exceed 1,000,000,000 for leap seconds. + /// + /// See also the [`NaiveTime::with_nanosecond`] method. + /// + /// # Errors + /// + /// Returns `None` if `nanosecond >= 2,000,000,000`. #[inline] fn with_nanosecond(&self, nano: u32) -> Option> { map_local(self, |datetime| datetime.with_nanosecond(nano)) diff --git a/src/traits.rs b/src/traits.rs index a6199dc6..22174da2 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -53,7 +53,7 @@ pub trait Datelike: Sized { /// Returns the ISO week. fn iso_week(&self) -> IsoWeek; - /// Makes a new value with the year number changed. + /// Makes a new value with the year number changed, while keeping the same month and day. /// /// Returns `None` when the resulting value would be invalid. fn with_year(&self, year: i32) -> Option; From 7ebaed563db016484160dc33e4a95a72061678c6 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 07:25:35 +0200 Subject: [PATCH 14/48] Remove Makefile --- Makefile | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 63aef15a..00000000 --- a/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# this Makefile is mostly for the packaging convenience. -# casual users should use `cargo` to retrieve the appropriate version of Chrono. - -CHANNEL=stable - -.PHONY: all -all: - @echo 'Try `cargo build` instead.' - -.PHONY: authors -authors: - echo 'Chrono is mainly written by Kang Seonghoon ,' > AUTHORS.txt - echo 'and also the following people (in ascending order):' >> AUTHORS.txt - echo >> AUTHORS.txt - git log --format='%aN <%aE>' | grep -v 'Kang Seonghoon' | sort -u >> AUTHORS.txt - -.PHONY: readme README.md -readme: README.md - -.PHONY: test -test: - CHANNEL=$(CHANNEL) ./ci/travis.sh - -.PHONY: doc -doc: authors readme - cargo doc --features 'serde rustc-serialize bincode' From 751e442e599cfdee5bb3529efadcd897d0ea2f37 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 18 May 2023 19:11:41 +0200 Subject: [PATCH 15/48] Make `NaiveDateDaysIterator` and `NaiveDateWeeksIterator` public --- src/naive/date.rs | 1 + src/naive/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 9b43ba8b..7e018538 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2045,6 +2045,7 @@ impl DoubleEndedIterator for NaiveDateDaysIterator { } } +/// Iterator over `NaiveDate` with a step size of one week. #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct NaiveDateWeeksIterator { value: NaiveDate, diff --git a/src/naive/mod.rs b/src/naive/mod.rs index c41acba8..d3d69196 100644 --- a/src/naive/mod.rs +++ b/src/naive/mod.rs @@ -10,8 +10,9 @@ mod internals; mod isoweek; mod time; +pub use self::date::{Days, NaiveDate, NaiveDateDaysIterator, NaiveDateWeeksIterator, NaiveWeek}; #[allow(deprecated)] -pub use self::date::{Days, NaiveDate, NaiveWeek, MAX_DATE, MIN_DATE}; +pub use self::date::{MAX_DATE, MIN_DATE}; #[cfg(feature = "rustc-serialize")] #[allow(deprecated)] pub use self::datetime::rustc_serialize::TsSeconds; From 249e649a1a868434b49bb89f8d93471b98ddb2ba Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 09:11:24 +0200 Subject: [PATCH 16/48] Implement `FusedIterator` --- src/naive/date.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/naive/date.rs b/src/naive/date.rs index 7e018538..1cc3515b 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -5,6 +5,7 @@ #[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; +use core::iter::FusedIterator; use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign}; use core::{fmt, str}; @@ -2045,6 +2046,8 @@ impl DoubleEndedIterator for NaiveDateDaysIterator { } } +impl FusedIterator for NaiveDateDaysIterator {} + /// Iterator over `NaiveDate` with a step size of one week. #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct NaiveDateWeeksIterator { @@ -2082,6 +2085,8 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { } } +impl FusedIterator for NaiveDateWeeksIterator {} + // TODO: NaiveDateDaysIterator and NaiveDateWeeksIterator should implement FusedIterator, // TrustedLen, and Step once they becomes stable. // See: https://github.com/chronotope/chrono/issues/208 From ece804bc06596d68022b56fb4f27a2000835b98a Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 09:12:17 +0200 Subject: [PATCH 17/48] Simplify iterators implementation --- src/naive/date.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 1cc3515b..11626849 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2017,13 +2017,10 @@ impl Iterator for NaiveDateDaysIterator { type Item = NaiveDate; fn next(&mut self) -> Option { - if self.value == NaiveDate::MAX { - return None; - } - // current < NaiveDate::MAX from here on: + // We return the current value, and have no way to return `NaiveDate::MAX`. let current = self.value; // This can't panic because current is < NaiveDate::MAX: - self.value = current.succ_opt().unwrap(); + self.value = current.succ_opt()?; Some(current) } @@ -2037,11 +2034,9 @@ impl ExactSizeIterator for NaiveDateDaysIterator {} impl DoubleEndedIterator for NaiveDateDaysIterator { fn next_back(&mut self) -> Option { - if self.value == NaiveDate::MIN { - return None; - } + // We return the current value, and have no way to return `NaiveDate::MIN`. let current = self.value; - self.value = current.pred_opt().unwrap(); + self.value = current.pred_opt()?; Some(current) } } @@ -2058,11 +2053,8 @@ impl Iterator for NaiveDateWeeksIterator { type Item = NaiveDate; fn next(&mut self) -> Option { - if NaiveDate::MAX - self.value < OldDuration::weeks(1) { - return None; - } let current = self.value; - self.value = current + OldDuration::weeks(1); + self.value = current.checked_add_signed(OldDuration::weeks(1))?; Some(current) } @@ -2076,11 +2068,8 @@ impl ExactSizeIterator for NaiveDateWeeksIterator {} impl DoubleEndedIterator for NaiveDateWeeksIterator { fn next_back(&mut self) -> Option { - if self.value - NaiveDate::MIN < OldDuration::weeks(1) { - return None; - } let current = self.value; - self.value = current - OldDuration::weeks(1); + self.value = current.checked_sub_signed(OldDuration::weeks(1))?; Some(current) } } From 0d2c9338f98b06418c843826e6f3f9c8dd4dba1f Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 09:20:33 +0200 Subject: [PATCH 18/48] Remove TODO --- src/naive/date.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 11626849..9745e080 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2076,10 +2076,6 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator { impl FusedIterator for NaiveDateWeeksIterator {} -// TODO: NaiveDateDaysIterator and NaiveDateWeeksIterator should implement FusedIterator, -// TrustedLen, and Step once they becomes stable. -// See: https://github.com/chronotope/chrono/issues/208 - /// The `Debug` output of the naive date `d` is the same as /// [`d.format("%Y-%m-%d")`](../format/strftime/index.html). /// From 4ca58b74f6affc75757c277735bc710954051345 Mon Sep 17 00:00:00 2001 From: LingMan Date: Thu, 15 Dec 2022 19:05:46 +0100 Subject: [PATCH 19/48] Specify licenses in SPDX format The use of `/` as a separator is deprecated. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2745c67e..c5ba2eaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/chronotope/chrono" keywords = ["date", "time", "calendar"] categories = ["date-and-time"] readme = "README.md" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" exclude = ["/ci/*"] edition = "2021" rust-version = "1.56.0" From afb1f1f2148a4034e4b0fa40ea7f6576d4551bcc Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 6 Jun 2023 14:02:25 +0200 Subject: [PATCH 20/48] Remove unnecessary wasm-specific code --- src/offset/local/mod.rs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 372fd497..04f92214 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -95,33 +95,9 @@ impl Local { } /// Returns a `DateTime` which corresponds to the current date and time. - #[cfg(not(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - )))] - #[must_use] pub fn now() -> DateTime { Utc::now().with_timezone(&Local) } - - /// Returns a `DateTime` which corresponds to the current date and time. - #[cfg(all( - target_arch = "wasm32", - feature = "wasmbind", - not(any(target_os = "emscripten", target_os = "wasi")) - ))] - #[must_use] - pub fn now() -> DateTime { - use super::Utc; - let now: DateTime = super::Utc::now(); - - // Workaround missing timezone logic in `time` crate - let offset = - FixedOffset::west_opt((js_sys::Date::new_0().get_timezone_offset() as i32) * 60) - .unwrap(); - DateTime::from_utc(now.naive_utc(), offset) - } } impl TimeZone for Local { From 4dceb645e9275f7e1d8e55ab5f5922bd509249e2 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 6 Jun 2023 14:17:19 +0200 Subject: [PATCH 21/48] Fixes to wasm test --- tests/wasm.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/wasm.rs b/tests/wasm.rs index f003d4db..3cc3dc03 100644 --- a/tests/wasm.rs +++ b/tests/wasm.rs @@ -1,11 +1,18 @@ +//! Run this test with: +//! `env TZ="$(date +%z)" NOW="$(date +%s)" wasm-pack test --node -- --features wasmbind` +//! +//! The `TZ` and `NOW` variables are used to compare the results inside the WASM environment with +//! the host system. +//! The check will fail if the local timezone does not match one of the timezones defined below. + #![cfg(all( target_arch = "wasm32", feature = "wasmbind", not(any(target_os = "emscripten", target_os = "wasi")) ))] -use self::chrono::prelude::*; -use self::wasm_bindgen_test::*; +use chrono::prelude::*; +use wasm_bindgen_test::*; #[wasm_bindgen_test] fn now() { @@ -52,7 +59,7 @@ fn from_is_exact() { let dt = DateTime::::from(now.clone()); - assert_eq!(now.get_time() as i64, dt.timestamp_millis_opt().unwrap()); + assert_eq!(now.get_time() as i64, dt.timestamp_millis()); } #[wasm_bindgen_test] @@ -72,7 +79,7 @@ fn convert_all_parts_with_milliseconds() { let js_date = js_sys::Date::from(time); assert_eq!(js_date.get_utc_full_year(), 2020); - assert_eq!(js_date.get_utc_month(), 12); + assert_eq!(js_date.get_utc_month(), 11); // months are numbered 0..=11 assert_eq!(js_date.get_utc_date(), 1); assert_eq!(js_date.get_utc_hours(), 3); assert_eq!(js_date.get_utc_minutes(), 1); From 582d2aa554cdb35d0570fbce82bcfff3d13013b3 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 6 Jun 2023 14:35:53 +0200 Subject: [PATCH 22/48] [CI] Test wamsbind --- .github/workflows/test.yml | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c97c0b16..a485fbe9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -117,7 +117,6 @@ jobs: os: [ubuntu-latest] target: [ - wasm32-unknown-unknown, wasm32-wasi, wasm32-unknown-emscripten, aarch64-apple-ios, @@ -130,19 +129,11 @@ jobs: with: targets: ${{ matrix.target }} - uses: Swatinem/rust-cache@v2 - - uses: actions/setup-node@v3 with: node-version: "12" - - run: | - set -euxo pipefail - export RUST_BACKTRACE=1 - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf \ - | bash --noprofile --norc - wasm-pack --version - shell: bash - run: cargo build --target ${{ matrix.target }} --color=always - features_check_wasm: + test_wasm: strategy: matrix: os: [ubuntu-latest] @@ -154,10 +145,11 @@ jobs: targets: wasm32-unknown-unknown - uses: taiki-e/install-action@cargo-hack - uses: Swatinem/rust-cache@v2 - - run: | - cargo hack check --feature-powerset --optional-deps serde,rkyv \ - --skip default --skip __internal_bench --skip __doctest \ - --skip iana-time-zone --skip pure-rust-locales + - uses: actions/setup-node@v3 + - uses: jetli/wasm-pack-action@v0.4.0 + # The `TZ` and `NOW` variables are used to compare the results inside the WASM environment + # with the host system. + - run: TZ="$(date +%z)" NOW="$(date +%s)" wasm-pack test --node -- --features wasmbind cross-targets: strategy: From 15f81167bceaf86dfb8c59697612f08f66bd52e2 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 6 Jun 2023 16:28:10 +0200 Subject: [PATCH 23/48] Correct offset calculation on wasm_bindgen --- src/offset/local/mod.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/offset/local/mod.rs b/src/offset/local/mod.rs index 04f92214..9e7d3033 100644 --- a/src/offset/local/mod.rs +++ b/src/offset/local/mod.rs @@ -50,15 +50,34 @@ mod inner { not(any(target_os = "emscripten", target_os = "wasi")) ))] mod inner { - use crate::{FixedOffset, LocalResult, NaiveDateTime}; + use crate::{Datelike, FixedOffset, LocalResult, NaiveDateTime, Timelike}; - pub(super) fn offset_from_utc_datetime(_utc: &NaiveDateTime) -> LocalResult { - let offset = js_sys::Date::new_0().get_timezone_offset(); + pub(super) fn offset_from_utc_datetime(utc: &NaiveDateTime) -> LocalResult { + let offset = js_sys::Date::from(utc.and_utc()).get_timezone_offset(); LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap()) } pub(super) fn offset_from_local_datetime(local: &NaiveDateTime) -> LocalResult { - offset_from_utc_datetime(local) + let mut year = local.year(); + if year < 100 { + // The API in `js_sys` does not let us create a `Date` with negative years. + // And values for years from `0` to `99` map to the years `1900` to `1999`. + // Shift the value by a multiple of 400 years until it is `>= 100`. + let shift_cycles = (year - 100).div_euclid(400); + year -= shift_cycles * 400; + } + let js_date = js_sys::Date::new_with_year_month_day_hr_min_sec( + year as u32, + local.month0() as i32, + local.day() as i32, + local.hour() as i32, + local.minute() as i32, + local.second() as i32, + // ignore milliseconds, our representation of leap seconds may be problematic + ); + let offset = js_date.get_timezone_offset(); + // We always get a result, even if this time does not exist or is ambiguous. + LocalResult::Single(FixedOffset::west_opt((offset as i32) * 60).unwrap()) } } From e1bbab007a3328181ebf0a00b7da57511327488b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 17:05:11 +0200 Subject: [PATCH 24/48] Remove old comment from `DateTime::from_utc` and `Date::from_utc` --- src/date.rs | 2 -- src/datetime/mod.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/date.rs b/src/date.rs index 96255565..aba0cbee 100644 --- a/src/date.rs +++ b/src/date.rs @@ -74,8 +74,6 @@ pub const MAX_DATE: Date = Date::::MAX_UTC; impl Date { /// Makes a new `Date` with given *UTC* date and offset. /// The local date should be constructed via the `TimeZone` trait. - // - // note: this constructor is purposely not named to `new` to discourage the direct usage. #[inline] #[must_use] pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date { diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 23a5cde8..44a89da6 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -109,8 +109,6 @@ impl DateTime { /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp_opt(61, 0).unwrap(), Utc); /// assert_eq!(Utc.timestamp_opt(61, 0).unwrap(), dt); /// ``` - // - // note: this constructor is purposely not named to `new` to discourage the direct usage. #[inline] #[must_use] pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { From cbdc9f786a180495f5a8f24eb08ac73fd12f8edf Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 17:29:31 +0200 Subject: [PATCH 25/48] Correct documentation of `Date::and_time` --- src/date.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/date.rs b/src/date.rs index aba0cbee..d831745a 100644 --- a/src/date.rs +++ b/src/date.rs @@ -83,7 +83,7 @@ impl Date { /// Makes a new `DateTime` from the current date and given `NaiveTime`. /// The offset in the current date is preserved. /// - /// Panics on invalid datetime. + /// Returns `None` on invalid datetime. #[inline] #[must_use] pub fn and_time(&self, time: NaiveTime) -> Option> { From 90a9af029c46fcfb87012e3a2b0660ab9be22007 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Wed, 7 Jun 2023 18:51:38 +0200 Subject: [PATCH 26/48] Consider `%s` to have be a timestamp in UTC --- src/datetime/tests.rs | 4 ++++ src/format/parsed.rs | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 7b3c1644..a8bc90c8 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -603,6 +603,10 @@ 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!( + DateTime::parse_from_str("0", "%s").unwrap(), + NaiveDateTime::from_timestamp_opt(0, 0).unwrap().and_utc().fixed_offset() + ); } #[test] diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 9526785e..809a5ae7 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -627,7 +627,12 @@ impl Parsed { /// plus a time zone offset. /// Either way those fields have to be consistent to each other. pub fn to_datetime(&self) -> ParseResult> { - let offset = self.offset.ok_or(NOT_ENOUGH)?; + // If there is no explicit offset, consider a timestamp value as indication of a UTC value. + let offset = match (self.offset, self.timestamp) { + (Some(off), _) => off, + (None, Some(_)) => 0, // UNIX timestamp may assume 0 offset + (None, None) => return Err(NOT_ENOUGH), + }; let datetime = self.to_naive_datetime_with_offset(offset)?; let offset = FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)?; From 2c7a24067cc7f13d6d66e10f23bb708dc11b6f40 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 12:50:28 +0200 Subject: [PATCH 27/48] Fix clippy warnings in tests --- src/datetime/tests.rs | 1 + tests/dateutils.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index a8bc90c8..42d1b470 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -314,6 +314,7 @@ fn test_datetime_offset() { } #[test] +#[allow(clippy::needless_borrow, clippy::op_ref)] fn signed_duration_since_autoref() { let dt1 = Utc.with_ymd_and_hms(2014, 5, 6, 7, 8, 9).unwrap(); let dt2 = Utc.with_ymd_and_hms(2014, 3, 4, 5, 6, 7).unwrap(); diff --git a/tests/dateutils.rs b/tests/dateutils.rs index f49659d2..36784ac1 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -58,10 +58,10 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) { /// for testing only #[allow(dead_code)] #[cfg(not(target_os = "aix"))] -const DATE_PATH: &'static str = "/usr/bin/date"; +const DATE_PATH: &str = "/usr/bin/date"; #[allow(dead_code)] #[cfg(target_os = "aix")] -const DATE_PATH: &'static str = "/opt/freeware/bin/date"; +const DATE_PATH: &str = "/opt/freeware/bin/date"; #[cfg(test)] #[cfg(unix)] From 6a7ef9fb823ca82c49a8b8d76c2c95ef76c2c308 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:20:59 +0200 Subject: [PATCH 28/48] Elide lifetime in format_item_localized --- src/format/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/format/mod.rs b/src/format/mod.rs index 93c9f86d..c8bb1e3a 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -994,12 +994,12 @@ impl FromStr for Weekday { /// Formats single formatting item #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] -pub fn format_item_localized<'a>( +pub fn format_item_localized( w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveTime>, off: Option<&(String, FixedOffset)>, - item: &Item<'a>, + item: &Item<'_>, locale: Locale, ) -> fmt::Result { let mut result = String::new(); From 52a46c728a097c75cf76cea2261b8472c9bc022d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:27:23 +0200 Subject: [PATCH 29/48] Don't use deprecated methods in `test_strftime_docs_localized` --- src/format/strftime.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 24bae20c..7c1174e9 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -671,14 +671,14 @@ fn test_strftime_docs() { #[cfg(feature = "unstable-locales")] #[test] fn test_strftime_docs_localized() { - use crate::{FixedOffset, NaiveDate, TimeZone}; + use crate::{FixedOffset, NaiveDate, TimeZone, Timelike}; - let dt = FixedOffset::east_opt(34200).unwrap().ymd_opt(2001, 7, 8).unwrap().and_hms_nano( - 0, - 34, - 59, - 1_026_490_708, - ); + let dt = FixedOffset::east_opt(34200) + .unwrap() + .with_ymd_and_hms(2001, 7, 8, 0, 34, 59) + .unwrap() + .with_nanosecond(1_026_490_708) + .unwrap(); // date specifiers assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); From 0c3ffe4320e0d8792a822cbf872942c91ff961aa Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:19:45 +0200 Subject: [PATCH 30/48] Remove `#[must_use]` from serialize methods --- src/datetime/serde.rs | 16 ---------------- src/naive/datetime/serde.rs | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index 72ada0cc..cead01fd 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -174,7 +174,6 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &DateTime, serializer: S) -> Result where S: ser::Serializer, @@ -202,7 +201,6 @@ pub mod ts_nanoseconds { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -299,7 +297,6 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option>, serializer: S) -> Result where S: ser::Serializer, @@ -330,7 +327,6 @@ pub mod ts_nanoseconds_option { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where D: de::Deserializer<'de>, @@ -431,7 +427,6 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &DateTime, serializer: S) -> Result where S: ser::Serializer, @@ -459,7 +454,6 @@ pub mod ts_microseconds { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -555,7 +549,6 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option>, serializer: S) -> Result where S: ser::Serializer, @@ -586,7 +579,6 @@ pub mod ts_microseconds_option { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where D: de::Deserializer<'de>, @@ -687,7 +679,6 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &DateTime, serializer: S) -> Result where S: ser::Serializer, @@ -715,7 +706,6 @@ pub mod ts_milliseconds { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918000000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -808,7 +798,6 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option>, serializer: S) -> Result where S: ser::Serializer, @@ -850,7 +839,6 @@ pub mod ts_milliseconds_option { /// assert_eq!(t, E::V(S { time: None })); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where D: de::Deserializer<'de>, @@ -952,7 +940,6 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &DateTime, serializer: S) -> Result where S: ser::Serializer, @@ -980,7 +967,6 @@ pub mod ts_seconds { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -1070,7 +1056,6 @@ pub mod ts_seconds_option { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option>, serializer: S) -> Result where S: ser::Serializer, @@ -1101,7 +1086,6 @@ pub mod ts_seconds_option { /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result>, D::Error> where D: de::Deserializer<'de>, diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 8107f384..6d75c9df 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -110,7 +110,6 @@ pub mod ts_nanoseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where S: ser::Serializer, @@ -138,7 +137,6 @@ pub mod ts_nanoseconds { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result where D: de::Deserializer<'de>, @@ -233,7 +231,6 @@ pub mod ts_nanoseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option, serializer: S) -> Result where S: ser::Serializer, @@ -264,7 +261,6 @@ pub mod ts_nanoseconds_option { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355733) }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -362,7 +358,6 @@ pub mod ts_microseconds { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where S: ser::Serializer, @@ -390,7 +385,6 @@ pub mod ts_microseconds { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result where D: de::Deserializer<'de>, @@ -488,7 +482,6 @@ pub mod ts_microseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option, serializer: S) -> Result where S: ser::Serializer, @@ -519,7 +512,6 @@ pub mod ts_microseconds_option { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918355000) }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -617,7 +609,6 @@ pub mod ts_milliseconds { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where S: ser::Serializer, @@ -645,7 +636,6 @@ pub mod ts_milliseconds { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result where D: de::Deserializer<'de>, @@ -740,7 +730,6 @@ pub mod ts_milliseconds_option { /// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option, serializer: S) -> Result where S: ser::Serializer, @@ -771,7 +760,6 @@ pub mod ts_milliseconds_option { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1526522699, 918000000) }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -869,7 +857,6 @@ pub mod ts_seconds { /// assert_eq!(as_string, r#"{"time":1431684000}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result where S: ser::Serializer, @@ -897,7 +884,6 @@ pub mod ts_seconds { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0).unwrap() }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result where D: de::Deserializer<'de>, @@ -989,7 +975,6 @@ pub mod ts_seconds_option { /// assert_eq!(as_string, r#"{"time":1526522699}"#); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn serialize(opt: &Option, serializer: S) -> Result where S: ser::Serializer, @@ -1020,7 +1005,6 @@ pub mod ts_seconds_option { /// assert_eq!(my_s, S { time: NaiveDateTime::from_timestamp_opt(1431684000, 0) }); /// # Ok::<(), serde_json::Error>(()) /// ``` - #[must_use] pub fn deserialize<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, From 2a22e1edf6657f38d9f2c9828de24a5fef8a074b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 12:55:39 +0200 Subject: [PATCH 31/48] Move tests in `datetime` to `test` module --- src/datetime/mod.rs | 28 ---------------------------- src/datetime/tests.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 44a89da6..bf9c16ad 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -1423,34 +1423,6 @@ where } } -#[test] -fn test_add_sub_months() { - let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0).unwrap()); - - let utc_dt = Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap(); - assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); - assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap()); - - let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0).unwrap()); - - let utc_dt = Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap(); - assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); - assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap()); -} - -#[test] -fn test_auto_conversion() { - let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); - let cdt_dt = FixedOffset::west_opt(5 * 60 * 60) - .unwrap() - .with_ymd_and_hms(2018, 9, 5, 18, 58, 0) - .unwrap(); - let utc_dt2: DateTime = cdt_dt.into(); - assert_eq!(utc_dt, utc_dt2); -} - #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] fn test_encodable_json(to_string_utc: FUtc, to_string_fixed: FFixed) where diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 42d1b470..3aeed665 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1027,3 +1027,31 @@ fn test_datetime_fixed_offset() { let datetime_fixed = fixed_offset.from_local_datetime(&naivedatetime).unwrap(); assert_eq!(datetime_fixed.fixed_offset(), datetime_fixed); } + +#[test] +fn test_add_sub_months() { + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); + assert_eq!(utc_dt + Months::new(15), Utc.with_ymd_and_hms(2019, 12, 5, 23, 58, 0).unwrap()); + + let utc_dt = Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap(); + assert_eq!(utc_dt + Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); + assert_eq!(utc_dt + Months::new(2), Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap()); + + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); + assert_eq!(utc_dt - Months::new(15), Utc.with_ymd_and_hms(2017, 6, 5, 23, 58, 0).unwrap()); + + let utc_dt = Utc.with_ymd_and_hms(2020, 3, 31, 23, 58, 0).unwrap(); + assert_eq!(utc_dt - Months::new(1), Utc.with_ymd_and_hms(2020, 2, 29, 23, 58, 0).unwrap()); + assert_eq!(utc_dt - Months::new(2), Utc.with_ymd_and_hms(2020, 1, 31, 23, 58, 0).unwrap()); +} + +#[test] +fn test_auto_conversion() { + let utc_dt = Utc.with_ymd_and_hms(2018, 9, 5, 23, 58, 0).unwrap(); + let cdt_dt = FixedOffset::west_opt(5 * 60 * 60) + .unwrap() + .with_ymd_and_hms(2018, 9, 5, 18, 58, 0) + .unwrap(); + let utc_dt2: DateTime = cdt_dt.into(); + assert_eq!(utc_dt, utc_dt2); +} From 5759abf959a5c40402cd7e9bf6e97a5d9acb691b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:16:42 +0200 Subject: [PATCH 32/48] Move tests in `datetime::serde` to `test` module --- src/datetime/serde.rs | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/datetime/serde.rs b/src/datetime/serde.rs index cead01fd..002ded0c 100644 --- a/src/datetime/serde.rs +++ b/src/datetime/serde.rs @@ -1128,30 +1128,36 @@ pub mod ts_seconds_option { } } -#[test] -fn test_serde_serialize() { - super::test_encodable_json(serde_json::to_string, serde_json::to_string); -} +#[cfg(test)] +mod tests { + use crate::datetime::{test_decodable_json, test_encodable_json}; + use crate::{DateTime, TimeZone, Utc}; -#[cfg(feature = "clock")] -#[test] -fn test_serde_deserialize() { - super::test_decodable_json( - |input| serde_json::from_str(input), - |input| serde_json::from_str(input), - |input| serde_json::from_str(input), - ); -} + #[test] + fn test_serde_serialize() { + test_encodable_json(serde_json::to_string, serde_json::to_string); + } -#[test] -fn test_serde_bincode() { - // Bincode is relevant to test separately from JSON because - // it is not self-describing. - use bincode::{deserialize, serialize}; + #[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), + ); + } - let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap(); - let encoded = serialize(&dt).unwrap(); - let decoded: DateTime = deserialize(&encoded).unwrap(); - assert_eq!(dt, decoded); - assert_eq!(dt.offset(), decoded.offset()); + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use bincode::{deserialize, serialize}; + + let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap(); + let encoded = serialize(&dt).unwrap(); + let decoded: DateTime = deserialize(&encoded).unwrap(); + assert_eq!(dt, decoded); + assert_eq!(dt.offset(), decoded.offset()); + } } From 98a54574b0007c75805f90180776830376edaf4a Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 12:56:15 +0200 Subject: [PATCH 33/48] Move test and related constants in `naive::date` to `test` module --- src/naive/date.rs | 104 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 9745e080..208ea2cb 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -33,29 +33,6 @@ use super::isoweek; const MAX_YEAR: i32 = internals::MAX_YEAR; const MIN_YEAR: i32 = internals::MIN_YEAR; -// MAX_YEAR-12-31 minus 0000-01-01 -// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + (0001-01-01 minus 0000-01-01) - 1 day -// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + 365 days -// = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 days -#[cfg(test)] // only used for testing -const MAX_DAYS_FROM_YEAR_0: i32 = - MAX_YEAR * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400 + 365; - -// MIN_YEAR-01-01 minus 0000-01-01 -// = (MIN_YEAR+400n+1)-01-01 minus (400n+1)-01-01 -// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - ((400n+1)-01-01 minus 0001-01-01) -// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - 146097n days -// -// n is set to 1000 for convenience. -#[cfg(test)] // only used for testing -const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + (MIN_YEAR + 400_000) / 4 - - (MIN_YEAR + 400_000) / 100 - + (MIN_YEAR + 400_000) / 400 - - 146_097_000; - -#[cfg(test)] // only used for testing, but duplicated in naive::datetime -const MAX_BITS: usize = 44; - /// A week represented by a [`NaiveDate`] and a [`Weekday`] which is the first /// day of the week. #[derive(Debug)] @@ -235,34 +212,6 @@ impl arbitrary::Arbitrary<'_> for NaiveDate { } } -// as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, -// we use a separate run-time test. -#[test] -fn test_date_bounds() { - let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap(); - let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap(); - assert!( - NaiveDate::MIN == calculated_min, - "`NaiveDate::MIN` should have a year flag {:?}", - calculated_min.of().flags() - ); - assert!( - NaiveDate::MAX == calculated_max, - "`NaiveDate::MAX` should have a year flag {:?}", - calculated_max.of().flags() - ); - - // let's also check that the entire range do not exceed 2^44 seconds - // (sometimes used for bounding `Duration` against overflow) - let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds(); - let maxsecs = maxsecs + 86401; // also take care of DateTime - assert!( - maxsecs < (1 << MAX_BITS), - "The entire `NaiveDate` range somehow exceeds 2^{} seconds", - MAX_BITS - ); -} - impl NaiveDate { pub(crate) fn weeks_from(&self, day: Weekday) -> i32 { (self.ordinal() as i32 - self.weekday().num_days_from(day) as i32 + 6) / 7 @@ -2389,13 +2338,39 @@ mod serde { #[cfg(test)] mod tests { - use super::{ - Days, Months, NaiveDate, MAX_DAYS_FROM_YEAR_0, MAX_YEAR, MIN_DAYS_FROM_YEAR_0, MIN_YEAR, - }; + use super::{Days, Months, NaiveDate, MAX_YEAR, MIN_YEAR}; use crate::oldtime::Duration; use crate::{Datelike, Weekday}; use std::{i32, u32}; + // as it is hard to verify year flags in `NaiveDate::MIN` and `NaiveDate::MAX`, + // we use a separate run-time test. + #[test] + fn test_date_bounds() { + let calculated_min = NaiveDate::from_ymd_opt(MIN_YEAR, 1, 1).unwrap(); + let calculated_max = NaiveDate::from_ymd_opt(MAX_YEAR, 12, 31).unwrap(); + assert!( + NaiveDate::MIN == calculated_min, + "`NaiveDate::MIN` should have a year flag {:?}", + calculated_min.of().flags() + ); + assert!( + NaiveDate::MAX == calculated_max, + "`NaiveDate::MAX` should have a year flag {:?}", + calculated_max.of().flags() + ); + + // let's also check that the entire range do not exceed 2^44 seconds + // (sometimes used for bounding `Duration` against overflow) + let maxsecs = NaiveDate::MAX.signed_duration_since(NaiveDate::MIN).num_seconds(); + let maxsecs = maxsecs + 86401; // also take care of DateTime + assert!( + maxsecs < (1 << MAX_BITS), + "The entire `NaiveDate` range somehow exceeds 2^{} seconds", + MAX_BITS + ); + } + #[test] fn diff_months() { // identity @@ -3219,4 +3194,25 @@ mod tests { assert!(dt.with_day0(4294967295).is_none()); assert!(dt.with_ordinal0(4294967295).is_none()); } + + // MAX_YEAR-12-31 minus 0000-01-01 + // = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + (0001-01-01 minus 0000-01-01) - 1 day + // = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + 365 days + // = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 days + const MAX_DAYS_FROM_YEAR_0: i32 = + MAX_YEAR * 365 + MAX_YEAR / 4 - MAX_YEAR / 100 + MAX_YEAR / 400 + 365; + + // MIN_YEAR-01-01 minus 0000-01-01 + // = (MIN_YEAR+400n+1)-01-01 minus (400n+1)-01-01 + // = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - ((400n+1)-01-01 minus 0001-01-01) + // = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - 146097n days + // + // n is set to 1000 for convenience. + const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + (MIN_YEAR + 400_000) / 4 + - (MIN_YEAR + 400_000) / 100 + + (MIN_YEAR + 400_000) / 400 + - 146_097_000; + + // only used for testing, but duplicated in naive::datetime + const MAX_BITS: usize = 44; } From ed21cadd36cdeaadd6bdffd21ef1bbd7008cdaac Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:33:59 +0200 Subject: [PATCH 34/48] Move tests in `format::strftime` to `test` module --- src/format/strftime.rs | 413 +++++++++++++++++++++-------------------- 1 file changed, 207 insertions(+), 206 deletions(-) diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 7c1174e9..b4275573 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -509,212 +509,213 @@ impl<'a> Iterator for StrftimeItems<'a> { } #[cfg(test)] -#[test] -fn test_strftime_items() { - fn parse_and_collect(s: &str) -> Vec> { - // map any error into `[Item::Error]`. useful for easy testing. - let items = StrftimeItems::new(s); - let items = items.map(|spec| if spec == Item::Error { None } else { Some(spec) }); - items.collect::>>().unwrap_or_else(|| vec![Item::Error]) +mod tests { + #[cfg(feature = "unstable-locales")] + use super::Locale; + use super::{Fixed, InternalFixed, InternalInternal, Item, Numeric, Pad, StrftimeItems}; + use crate::{DateTime, FixedOffset, NaiveDate, TimeZone, Timelike, Utc}; + + #[test] + fn test_strftime_items() { + fn parse_and_collect(s: &str) -> Vec> { + // map any error into `[Item::Error]`. useful for easy testing. + let items = StrftimeItems::new(s); + let items = items.map(|spec| if spec == Item::Error { None } else { Some(spec) }); + items.collect::>>().unwrap_or_else(|| vec![Item::Error]) + } + + assert_eq!(parse_and_collect(""), []); + assert_eq!(parse_and_collect(" \t\n\r "), [sp!(" \t\n\r ")]); + assert_eq!(parse_and_collect("hello?"), [lit!("hello?")]); + assert_eq!( + parse_and_collect("a b\t\nc"), + [lit!("a"), sp!(" "), lit!("b"), sp!("\t\n"), lit!("c")] + ); + assert_eq!(parse_and_collect("100%%"), [lit!("100"), lit!("%")]); + assert_eq!(parse_and_collect("100%% ok"), [lit!("100"), lit!("%"), sp!(" "), lit!("ok")]); + assert_eq!(parse_and_collect("%%PDF-1.0"), [lit!("%"), lit!("PDF-1.0")]); + assert_eq!( + parse_and_collect("%Y-%m-%d"), + [num0!(Year), lit!("-"), num0!(Month), lit!("-"), num0!(Day)] + ); + assert_eq!(parse_and_collect("[%F]"), parse_and_collect("[%Y-%m-%d]")); + 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("%%%%"), [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]); + assert_eq!(parse_and_collect("%.Z"), [Item::Error]); + assert_eq!(parse_and_collect("%:Z"), [Item::Error]); + assert_eq!(parse_and_collect("%-Z"), [Item::Error]); + assert_eq!(parse_and_collect("%0Z"), [Item::Error]); + assert_eq!(parse_and_collect("%_Z"), [Item::Error]); + assert_eq!(parse_and_collect("%.j"), [Item::Error]); + assert_eq!(parse_and_collect("%:j"), [Item::Error]); + assert_eq!(parse_and_collect("%-j"), [num!(Ordinal)]); + assert_eq!(parse_and_collect("%0j"), [num0!(Ordinal)]); + assert_eq!(parse_and_collect("%_j"), [nums!(Ordinal)]); + assert_eq!(parse_and_collect("%.e"), [Item::Error]); + assert_eq!(parse_and_collect("%:e"), [Item::Error]); + assert_eq!(parse_and_collect("%-e"), [num!(Day)]); + 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"), [internal_fix!(TimezoneOffsetPermissive)]); + assert_eq!(parse_and_collect("%#m"), [Item::Error]); } - assert_eq!(parse_and_collect(""), []); - assert_eq!(parse_and_collect(" \t\n\r "), [sp!(" \t\n\r ")]); - assert_eq!(parse_and_collect("hello?"), [lit!("hello?")]); - assert_eq!( - parse_and_collect("a b\t\nc"), - [lit!("a"), sp!(" "), lit!("b"), sp!("\t\n"), lit!("c")] - ); - assert_eq!(parse_and_collect("100%%"), [lit!("100"), lit!("%")]); - assert_eq!(parse_and_collect("100%% ok"), [lit!("100"), lit!("%"), sp!(" "), lit!("ok")]); - assert_eq!(parse_and_collect("%%PDF-1.0"), [lit!("%"), lit!("PDF-1.0")]); - assert_eq!( - parse_and_collect("%Y-%m-%d"), - [num0!(Year), lit!("-"), num0!(Month), lit!("-"), num0!(Day)] - ); - assert_eq!(parse_and_collect("[%F]"), parse_and_collect("[%Y-%m-%d]")); - 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("%%%%"), [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]); - assert_eq!(parse_and_collect("%.Z"), [Item::Error]); - assert_eq!(parse_and_collect("%:Z"), [Item::Error]); - assert_eq!(parse_and_collect("%-Z"), [Item::Error]); - assert_eq!(parse_and_collect("%0Z"), [Item::Error]); - assert_eq!(parse_and_collect("%_Z"), [Item::Error]); - assert_eq!(parse_and_collect("%.j"), [Item::Error]); - assert_eq!(parse_and_collect("%:j"), [Item::Error]); - assert_eq!(parse_and_collect("%-j"), [num!(Ordinal)]); - assert_eq!(parse_and_collect("%0j"), [num0!(Ordinal)]); - assert_eq!(parse_and_collect("%_j"), [nums!(Ordinal)]); - assert_eq!(parse_and_collect("%.e"), [Item::Error]); - assert_eq!(parse_and_collect("%:e"), [Item::Error]); - assert_eq!(parse_and_collect("%-e"), [num!(Day)]); - 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"), [internal_fix!(TimezoneOffsetPermissive)]); - assert_eq!(parse_and_collect("%#m"), [Item::Error]); -} - -#[cfg(test)] -#[test] -fn test_strftime_docs() { - use crate::NaiveDate; - use crate::{DateTime, FixedOffset, TimeZone, Timelike, Utc}; - - let dt = FixedOffset::east_opt(34200) - .unwrap() - .from_local_datetime( - &NaiveDate::from_ymd_opt(2001, 7, 8) - .unwrap() - .and_hms_nano_opt(0, 34, 59, 1_026_490_708) - .unwrap(), - ) - .unwrap(); - - // date specifiers - assert_eq!(dt.format("%Y").to_string(), "2001"); - assert_eq!(dt.format("%C").to_string(), "20"); - assert_eq!(dt.format("%y").to_string(), "01"); - assert_eq!(dt.format("%m").to_string(), "07"); - assert_eq!(dt.format("%b").to_string(), "Jul"); - assert_eq!(dt.format("%B").to_string(), "July"); - assert_eq!(dt.format("%h").to_string(), "Jul"); - assert_eq!(dt.format("%d").to_string(), "08"); - assert_eq!(dt.format("%e").to_string(), " 8"); - assert_eq!(dt.format("%e").to_string(), dt.format("%_d").to_string()); - assert_eq!(dt.format("%a").to_string(), "Sun"); - assert_eq!(dt.format("%A").to_string(), "Sunday"); - assert_eq!(dt.format("%w").to_string(), "0"); - assert_eq!(dt.format("%u").to_string(), "7"); - assert_eq!(dt.format("%U").to_string(), "27"); - assert_eq!(dt.format("%W").to_string(), "27"); - assert_eq!(dt.format("%G").to_string(), "2001"); - assert_eq!(dt.format("%g").to_string(), "01"); - assert_eq!(dt.format("%V").to_string(), "27"); - assert_eq!(dt.format("%j").to_string(), "189"); - assert_eq!(dt.format("%D").to_string(), "07/08/01"); - assert_eq!(dt.format("%x").to_string(), "07/08/01"); - assert_eq!(dt.format("%F").to_string(), "2001-07-08"); - assert_eq!(dt.format("%v").to_string(), " 8-Jul-2001"); - - // time specifiers - assert_eq!(dt.format("%H").to_string(), "00"); - assert_eq!(dt.format("%k").to_string(), " 0"); - assert_eq!(dt.format("%k").to_string(), dt.format("%_H").to_string()); - assert_eq!(dt.format("%I").to_string(), "12"); - assert_eq!(dt.format("%l").to_string(), "12"); - assert_eq!(dt.format("%l").to_string(), dt.format("%_I").to_string()); - assert_eq!(dt.format("%P").to_string(), "am"); - assert_eq!(dt.format("%p").to_string(), "AM"); - assert_eq!(dt.format("%M").to_string(), "34"); - assert_eq!(dt.format("%S").to_string(), "60"); - assert_eq!(dt.format("%f").to_string(), "026490708"); - assert_eq!(dt.format("%.f").to_string(), ".026490708"); - assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").to_string(), ".026490"); - assert_eq!(dt.format("%.3f").to_string(), ".026"); - assert_eq!(dt.format("%.6f").to_string(), ".026490"); - assert_eq!(dt.format("%.9f").to_string(), ".026490708"); - assert_eq!(dt.format("%3f").to_string(), "026"); - assert_eq!(dt.format("%6f").to_string(), "026490"); - assert_eq!(dt.format("%9f").to_string(), "026490708"); - assert_eq!(dt.format("%R").to_string(), "00:34"); - assert_eq!(dt.format("%T").to_string(), "00:34:60"); - assert_eq!(dt.format("%X").to_string(), "00:34:60"); - assert_eq!(dt.format("%r").to_string(), "12:34:60 AM"); - - // time zone specifiers - //assert_eq!(dt.format("%Z").to_string(), "ACST"); - assert_eq!(dt.format("%z").to_string(), "+0930"); - assert_eq!(dt.format("%:z").to_string(), "+09:30"); - assert_eq!(dt.format("%::z").to_string(), "+09:30:00"); - assert_eq!(dt.format("%:::z").to_string(), "+09"); - - // date & time specifiers - assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001"); - assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30"); - - assert_eq!( - dt.with_timezone(&Utc).format("%+").to_string(), - "2001-07-07T15:04:60.026490708+00:00" - ); - assert_eq!( - dt.with_timezone(&Utc), - DateTime::parse_from_str("2001-07-07T15:04:60.026490708Z", "%+").unwrap() - ); - assert_eq!( - dt.with_timezone(&Utc), - DateTime::parse_from_str("2001-07-07T15:04:60.026490708UTC", "%+").unwrap() - ); - assert_eq!( - dt.with_timezone(&Utc), - DateTime::parse_from_str("2001-07-07t15:04:60.026490708utc", "%+").unwrap() - ); - - assert_eq!( - dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(), - "2001-07-08T00:34:60.026490+09:30" - ); - assert_eq!(dt.format("%s").to_string(), "994518299"); - - // special specifiers - assert_eq!(dt.format("%t").to_string(), "\t"); - assert_eq!(dt.format("%n").to_string(), "\n"); - assert_eq!(dt.format("%%").to_string(), "%"); -} - -#[cfg(feature = "unstable-locales")] -#[test] -fn test_strftime_docs_localized() { - use crate::{FixedOffset, NaiveDate, TimeZone, Timelike}; - - let dt = FixedOffset::east_opt(34200) - .unwrap() - .with_ymd_and_hms(2001, 7, 8, 0, 34, 59) - .unwrap() - .with_nanosecond(1_026_490_708) - .unwrap(); - - // date specifiers - assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); - assert_eq!(dt.format_localized("%B", Locale::fr_BE).to_string(), "juillet"); - assert_eq!(dt.format_localized("%h", Locale::fr_BE).to_string(), "jui"); - assert_eq!(dt.format_localized("%a", Locale::fr_BE).to_string(), "dim"); - assert_eq!(dt.format_localized("%A", Locale::fr_BE).to_string(), "dimanche"); - assert_eq!(dt.format_localized("%D", Locale::fr_BE).to_string(), "07/08/01"); - assert_eq!(dt.format_localized("%x", Locale::fr_BE).to_string(), "08/07/01"); - assert_eq!(dt.format_localized("%F", Locale::fr_BE).to_string(), "2001-07-08"); - assert_eq!(dt.format_localized("%v", Locale::fr_BE).to_string(), " 8-jui-2001"); - - // time specifiers - assert_eq!(dt.format_localized("%P", Locale::fr_BE).to_string(), ""); - assert_eq!(dt.format_localized("%p", Locale::fr_BE).to_string(), ""); - assert_eq!(dt.format_localized("%R", Locale::fr_BE).to_string(), "00:34"); - assert_eq!(dt.format_localized("%T", Locale::fr_BE).to_string(), "00:34:60"); - assert_eq!(dt.format_localized("%X", Locale::fr_BE).to_string(), "00:34:60"); - assert_eq!(dt.format_localized("%r", Locale::fr_BE).to_string(), "12:34:60 "); - - // date & time specifiers - assert_eq!( - dt.format_localized("%c", Locale::fr_BE).to_string(), - "dim 08 jui 2001 00:34:60 +09:30" - ); - - let nd = NaiveDate::from_ymd_opt(2001, 7, 8).unwrap(); - - // date specifiers - assert_eq!(nd.format_localized("%b", Locale::de_DE).to_string(), "Jul"); - assert_eq!(nd.format_localized("%B", Locale::de_DE).to_string(), "Juli"); - assert_eq!(nd.format_localized("%h", Locale::de_DE).to_string(), "Jul"); - assert_eq!(nd.format_localized("%a", Locale::de_DE).to_string(), "So"); - assert_eq!(nd.format_localized("%A", Locale::de_DE).to_string(), "Sonntag"); - assert_eq!(nd.format_localized("%D", Locale::de_DE).to_string(), "07/08/01"); - assert_eq!(nd.format_localized("%x", Locale::de_DE).to_string(), "08.07.2001"); - assert_eq!(nd.format_localized("%F", Locale::de_DE).to_string(), "2001-07-08"); - assert_eq!(nd.format_localized("%v", Locale::de_DE).to_string(), " 8-Jul-2001"); + #[test] + fn test_strftime_docs() { + let dt = FixedOffset::east_opt(34200) + .unwrap() + .from_local_datetime( + &NaiveDate::from_ymd_opt(2001, 7, 8) + .unwrap() + .and_hms_nano_opt(0, 34, 59, 1_026_490_708) + .unwrap(), + ) + .unwrap(); + + // date specifiers + assert_eq!(dt.format("%Y").to_string(), "2001"); + assert_eq!(dt.format("%C").to_string(), "20"); + assert_eq!(dt.format("%y").to_string(), "01"); + assert_eq!(dt.format("%m").to_string(), "07"); + assert_eq!(dt.format("%b").to_string(), "Jul"); + assert_eq!(dt.format("%B").to_string(), "July"); + assert_eq!(dt.format("%h").to_string(), "Jul"); + assert_eq!(dt.format("%d").to_string(), "08"); + assert_eq!(dt.format("%e").to_string(), " 8"); + assert_eq!(dt.format("%e").to_string(), dt.format("%_d").to_string()); + assert_eq!(dt.format("%a").to_string(), "Sun"); + assert_eq!(dt.format("%A").to_string(), "Sunday"); + assert_eq!(dt.format("%w").to_string(), "0"); + assert_eq!(dt.format("%u").to_string(), "7"); + assert_eq!(dt.format("%U").to_string(), "27"); + assert_eq!(dt.format("%W").to_string(), "27"); + assert_eq!(dt.format("%G").to_string(), "2001"); + assert_eq!(dt.format("%g").to_string(), "01"); + assert_eq!(dt.format("%V").to_string(), "27"); + assert_eq!(dt.format("%j").to_string(), "189"); + assert_eq!(dt.format("%D").to_string(), "07/08/01"); + assert_eq!(dt.format("%x").to_string(), "07/08/01"); + assert_eq!(dt.format("%F").to_string(), "2001-07-08"); + assert_eq!(dt.format("%v").to_string(), " 8-Jul-2001"); + + // time specifiers + assert_eq!(dt.format("%H").to_string(), "00"); + assert_eq!(dt.format("%k").to_string(), " 0"); + assert_eq!(dt.format("%k").to_string(), dt.format("%_H").to_string()); + assert_eq!(dt.format("%I").to_string(), "12"); + assert_eq!(dt.format("%l").to_string(), "12"); + assert_eq!(dt.format("%l").to_string(), dt.format("%_I").to_string()); + assert_eq!(dt.format("%P").to_string(), "am"); + assert_eq!(dt.format("%p").to_string(), "AM"); + assert_eq!(dt.format("%M").to_string(), "34"); + assert_eq!(dt.format("%S").to_string(), "60"); + assert_eq!(dt.format("%f").to_string(), "026490708"); + assert_eq!(dt.format("%.f").to_string(), ".026490708"); + assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").to_string(), ".026490"); + assert_eq!(dt.format("%.3f").to_string(), ".026"); + assert_eq!(dt.format("%.6f").to_string(), ".026490"); + assert_eq!(dt.format("%.9f").to_string(), ".026490708"); + assert_eq!(dt.format("%3f").to_string(), "026"); + assert_eq!(dt.format("%6f").to_string(), "026490"); + assert_eq!(dt.format("%9f").to_string(), "026490708"); + assert_eq!(dt.format("%R").to_string(), "00:34"); + assert_eq!(dt.format("%T").to_string(), "00:34:60"); + assert_eq!(dt.format("%X").to_string(), "00:34:60"); + assert_eq!(dt.format("%r").to_string(), "12:34:60 AM"); + + // time zone specifiers + //assert_eq!(dt.format("%Z").to_string(), "ACST"); + assert_eq!(dt.format("%z").to_string(), "+0930"); + assert_eq!(dt.format("%:z").to_string(), "+09:30"); + assert_eq!(dt.format("%::z").to_string(), "+09:30:00"); + assert_eq!(dt.format("%:::z").to_string(), "+09"); + + // date & time specifiers + assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001"); + assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30"); + + assert_eq!( + dt.with_timezone(&Utc).format("%+").to_string(), + "2001-07-07T15:04:60.026490708+00:00" + ); + assert_eq!( + dt.with_timezone(&Utc), + DateTime::parse_from_str("2001-07-07T15:04:60.026490708Z", "%+").unwrap() + ); + assert_eq!( + dt.with_timezone(&Utc), + DateTime::parse_from_str("2001-07-07T15:04:60.026490708UTC", "%+").unwrap() + ); + assert_eq!( + dt.with_timezone(&Utc), + DateTime::parse_from_str("2001-07-07t15:04:60.026490708utc", "%+").unwrap() + ); + + assert_eq!( + dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(), + "2001-07-08T00:34:60.026490+09:30" + ); + assert_eq!(dt.format("%s").to_string(), "994518299"); + + // special specifiers + assert_eq!(dt.format("%t").to_string(), "\t"); + assert_eq!(dt.format("%n").to_string(), "\n"); + assert_eq!(dt.format("%%").to_string(), "%"); + } + + #[cfg(feature = "unstable-locales")] + #[test] + fn test_strftime_docs_localized() { + let dt = FixedOffset::east_opt(34200) + .unwrap() + .with_ymd_and_hms(2001, 7, 8, 0, 34, 59) + .unwrap() + .with_nanosecond(1_026_490_708) + .unwrap(); + + // date specifiers + assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); + assert_eq!(dt.format_localized("%B", Locale::fr_BE).to_string(), "juillet"); + assert_eq!(dt.format_localized("%h", Locale::fr_BE).to_string(), "jui"); + assert_eq!(dt.format_localized("%a", Locale::fr_BE).to_string(), "dim"); + assert_eq!(dt.format_localized("%A", Locale::fr_BE).to_string(), "dimanche"); + assert_eq!(dt.format_localized("%D", Locale::fr_BE).to_string(), "07/08/01"); + assert_eq!(dt.format_localized("%x", Locale::fr_BE).to_string(), "08/07/01"); + assert_eq!(dt.format_localized("%F", Locale::fr_BE).to_string(), "2001-07-08"); + assert_eq!(dt.format_localized("%v", Locale::fr_BE).to_string(), " 8-jui-2001"); + + // time specifiers + assert_eq!(dt.format_localized("%P", Locale::fr_BE).to_string(), ""); + assert_eq!(dt.format_localized("%p", Locale::fr_BE).to_string(), ""); + assert_eq!(dt.format_localized("%R", Locale::fr_BE).to_string(), "00:34"); + assert_eq!(dt.format_localized("%T", Locale::fr_BE).to_string(), "00:34:60"); + assert_eq!(dt.format_localized("%X", Locale::fr_BE).to_string(), "00:34:60"); + assert_eq!(dt.format_localized("%r", Locale::fr_BE).to_string(), "12:34:60 "); + + // date & time specifiers + assert_eq!( + dt.format_localized("%c", Locale::fr_BE).to_string(), + "dim 08 jui 2001 00:34:60 +09:30" + ); + + let nd = NaiveDate::from_ymd_opt(2001, 7, 8).unwrap(); + + // date specifiers + assert_eq!(nd.format_localized("%b", Locale::de_DE).to_string(), "Jul"); + assert_eq!(nd.format_localized("%B", Locale::de_DE).to_string(), "Juli"); + assert_eq!(nd.format_localized("%h", Locale::de_DE).to_string(), "Jul"); + assert_eq!(nd.format_localized("%a", Locale::de_DE).to_string(), "So"); + assert_eq!(nd.format_localized("%A", Locale::de_DE).to_string(), "Sonntag"); + assert_eq!(nd.format_localized("%D", Locale::de_DE).to_string(), "07/08/01"); + assert_eq!(nd.format_localized("%x", Locale::de_DE).to_string(), "08.07.2001"); + assert_eq!(nd.format_localized("%F", Locale::de_DE).to_string(), "2001-07-08"); + assert_eq!(nd.format_localized("%v", Locale::de_DE).to_string(), " 8-Jul-2001"); + } } From 9e735110b253bbbc152dc8287ea944544c55d6b3 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:40:47 +0200 Subject: [PATCH 35/48] Move tests in `naive::datetime::serde` to `test` module --- src/naive/datetime/serde.rs | 93 +++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/naive/datetime/serde.rs b/src/naive/datetime/serde.rs index 6d75c9df..1a97fb23 100644 --- a/src/naive/datetime/serde.rs +++ b/src/naive/datetime/serde.rs @@ -1047,51 +1047,6 @@ pub mod ts_seconds_option { } } -#[test] -fn test_serde_serialize() { - super::test_encodable_json(serde_json::to_string); -} - -#[test] -fn test_serde_deserialize() { - super::test_decodable_json(|input| serde_json::from_str(input)); -} - -// Bincode is relevant to test separately from JSON because -// it is not self-describing. -#[test] -fn test_serde_bincode() { - use crate::NaiveDate; - use bincode::{deserialize, serialize}; - - let dt = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap(); - let encoded = serialize(&dt).unwrap(); - let decoded: NaiveDateTime = deserialize(&encoded).unwrap(); - assert_eq!(dt, decoded); -} - -#[test] -fn test_serde_bincode_optional() { - use crate::prelude::*; - use crate::serde::ts_nanoseconds_option; - use bincode::{deserialize, serialize}; - use serde_derive::{Deserialize, Serialize}; - - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Test { - one: Option, - #[serde(with = "ts_nanoseconds_option")] - two: Option>, - } - - let expected = - Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap()) }; - let bytes: Vec = serialize(&expected).unwrap(); - let actual = deserialize::(&(bytes)).unwrap(); - - assert_eq!(expected, actual); -} - // lik? function to convert a LocalResult into a serde-ish Result pub(crate) fn serde_from(me: LocalResult, ts: &V) -> Result where @@ -1139,3 +1094,51 @@ impl fmt::Display for SerdeError { } } } + +#[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}; + + use bincode::{deserialize, serialize}; + use serde_derive::{Deserialize, Serialize}; + + #[test] + fn test_serde_serialize() { + test_encodable_json(serde_json::to_string); + } + + #[test] + fn test_serde_deserialize() { + test_decodable_json(|input| serde_json::from_str(input)); + } + + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + #[test] + fn test_serde_bincode() { + let dt = + NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_milli_opt(9, 10, 48, 90).unwrap(); + let encoded = serialize(&dt).unwrap(); + let decoded: NaiveDateTime = deserialize(&encoded).unwrap(); + assert_eq!(dt, decoded); + } + + #[test] + fn test_serde_bincode_optional() { + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Test { + one: Option, + #[serde(with = "ts_nanoseconds_option")] + two: Option>, + } + + let expected = + Test { one: Some(1), two: Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 1, 1).unwrap()) }; + let bytes: Vec = serialize(&expected).unwrap(); + let actual = deserialize::(&(bytes)).unwrap(); + + assert_eq!(expected, actual); + } +} From d1c5266126aef230fc17717cd07af3905f848c37 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:43:37 +0200 Subject: [PATCH 36/48] Move tests in `month::serde` to `test` module --- src/month.rs | 124 ++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/src/month.rs b/src/month.rs index 4c6321e1..161c43c8 100644 --- a/src/month.rs +++ b/src/month.rs @@ -283,67 +283,6 @@ mod month_serde { deserializer.deserialize_str(MonthVisitor) } } - - #[test] - fn test_serde_serialize() { - use serde_json::to_string; - use Month::*; - - let cases: Vec<(Month, &str)> = vec![ - (January, "\"January\""), - (February, "\"February\""), - (March, "\"March\""), - (April, "\"April\""), - (May, "\"May\""), - (June, "\"June\""), - (July, "\"July\""), - (August, "\"August\""), - (September, "\"September\""), - (October, "\"October\""), - (November, "\"November\""), - (December, "\"December\""), - ]; - - for (month, expected_str) in cases { - let string = to_string(&month).unwrap(); - assert_eq!(string, expected_str); - } - } - - #[test] - fn test_serde_deserialize() { - use serde_json::from_str; - use Month::*; - - let cases: Vec<(&str, Month)> = vec![ - ("\"january\"", January), - ("\"jan\"", January), - ("\"FeB\"", February), - ("\"MAR\"", March), - ("\"mar\"", March), - ("\"april\"", April), - ("\"may\"", May), - ("\"june\"", June), - ("\"JULY\"", July), - ("\"august\"", August), - ("\"september\"", September), - ("\"October\"", October), - ("\"November\"", November), - ("\"DECEmbEr\"", December), - ]; - - for (string, expected_month) in cases { - let month = from_str::(string).unwrap(); - assert_eq!(month, expected_month); - } - - let errors: Vec<&str> = - vec!["\"not a month\"", "\"ja\"", "\"Dece\"", "Dec", "\"Augustin\""]; - - for string in errors { - from_str::(string).unwrap_err(); - } - } } #[cfg(test)] @@ -403,4 +342,67 @@ mod tests { assert!(Month::July >= Month::May); assert!(Month::September > Month::March); } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_serialize() { + use serde_json::to_string; + use Month::*; + + let cases: Vec<(Month, &str)> = vec![ + (January, "\"January\""), + (February, "\"February\""), + (March, "\"March\""), + (April, "\"April\""), + (May, "\"May\""), + (June, "\"June\""), + (July, "\"July\""), + (August, "\"August\""), + (September, "\"September\""), + (October, "\"October\""), + (November, "\"November\""), + (December, "\"December\""), + ]; + + for (month, expected_str) in cases { + let string = to_string(&month).unwrap(); + assert_eq!(string, expected_str); + } + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_deserialize() { + use serde_json::from_str; + use Month::*; + + let cases: Vec<(&str, Month)> = vec![ + ("\"january\"", January), + ("\"jan\"", January), + ("\"FeB\"", February), + ("\"MAR\"", March), + ("\"mar\"", March), + ("\"april\"", April), + ("\"may\"", May), + ("\"june\"", June), + ("\"JULY\"", July), + ("\"august\"", August), + ("\"september\"", September), + ("\"October\"", October), + ("\"November\"", November), + ("\"DECEmbEr\"", December), + ]; + + for (string, expected_month) in cases { + let month = from_str::(string).unwrap(); + assert_eq!(month, expected_month); + } + + let errors: Vec<&str> = + vec!["\"not a month\"", "\"ja\"", "\"Dece\"", "Dec", "\"Augustin\""]; + + for string in errors { + from_str::(string).unwrap_err(); + } + } } From be93cf2d6fdc9c75fc7ce132c2f63dbb048ecd4f Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:44:36 +0200 Subject: [PATCH 37/48] Move test module to end of file --- src/weekday.rs | 74 +++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/weekday.rs b/src/weekday.rs index e2973cf7..890273b5 100644 --- a/src/weekday.rs +++ b/src/weekday.rs @@ -229,43 +229,6 @@ impl fmt::Debug for ParseWeekdayError { } } -#[cfg(test)] -mod tests { - use super::Weekday; - - #[test] - fn test_num_days_from() { - for i in 0..7 { - let base_day = Weekday::try_from(i).unwrap(); - - assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon)); - assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun)); - - assert_eq!(base_day.num_days_from(base_day), 0); - - assert_eq!(base_day.num_days_from(base_day.pred()), 1); - assert_eq!(base_day.num_days_from(base_day.pred().pred()), 2); - assert_eq!(base_day.num_days_from(base_day.pred().pred().pred()), 3); - assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred()), 4); - assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred().pred()), 5); - assert_eq!( - base_day.num_days_from(base_day.pred().pred().pred().pred().pred().pred()), - 6 - ); - - assert_eq!(base_day.num_days_from(base_day.succ()), 6); - assert_eq!(base_day.num_days_from(base_day.succ().succ()), 5); - assert_eq!(base_day.num_days_from(base_day.succ().succ().succ()), 4); - assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ()), 3); - assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ().succ()), 2); - assert_eq!( - base_day.num_days_from(base_day.succ().succ().succ().succ().succ().succ()), - 1 - ); - } - } -} - // the actual `FromStr` implementation is in the `format` module to leverage the existing code #[cfg(feature = "serde")] @@ -368,3 +331,40 @@ mod weekday_serde { } } } + +#[cfg(test)] +mod tests { + use super::Weekday; + + #[test] + fn test_num_days_from() { + for i in 0..7 { + let base_day = Weekday::try_from(i).unwrap(); + + assert_eq!(base_day.num_days_from_monday(), base_day.num_days_from(Weekday::Mon)); + assert_eq!(base_day.num_days_from_sunday(), base_day.num_days_from(Weekday::Sun)); + + assert_eq!(base_day.num_days_from(base_day), 0); + + assert_eq!(base_day.num_days_from(base_day.pred()), 1); + assert_eq!(base_day.num_days_from(base_day.pred().pred()), 2); + assert_eq!(base_day.num_days_from(base_day.pred().pred().pred()), 3); + assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred()), 4); + assert_eq!(base_day.num_days_from(base_day.pred().pred().pred().pred().pred()), 5); + assert_eq!( + base_day.num_days_from(base_day.pred().pred().pred().pred().pred().pred()), + 6 + ); + + assert_eq!(base_day.num_days_from(base_day.succ()), 6); + assert_eq!(base_day.num_days_from(base_day.succ().succ()), 5); + assert_eq!(base_day.num_days_from(base_day.succ().succ().succ()), 4); + assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ()), 3); + assert_eq!(base_day.num_days_from(base_day.succ().succ().succ().succ().succ()), 2); + assert_eq!( + base_day.num_days_from(base_day.succ().succ().succ().succ().succ().succ()), + 1 + ); + } + } +} From 76fc03737a693d4126ba02ec49f34debba05aae9 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:46:00 +0200 Subject: [PATCH 38/48] Move tests in `weekday::serde` to `test` module --- src/weekday.rs | 118 +++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/src/weekday.rs b/src/weekday.rs index 890273b5..f51e2178 100644 --- a/src/weekday.rs +++ b/src/weekday.rs @@ -272,64 +272,6 @@ mod weekday_serde { deserializer.deserialize_str(WeekdayVisitor) } } - - #[test] - fn test_serde_serialize() { - use serde_json::to_string; - use Weekday::*; - - let cases: Vec<(Weekday, &str)> = vec![ - (Mon, "\"Mon\""), - (Tue, "\"Tue\""), - (Wed, "\"Wed\""), - (Thu, "\"Thu\""), - (Fri, "\"Fri\""), - (Sat, "\"Sat\""), - (Sun, "\"Sun\""), - ]; - - for (weekday, expected_str) in cases { - let string = to_string(&weekday).unwrap(); - assert_eq!(string, expected_str); - } - } - - #[test] - fn test_serde_deserialize() { - use serde_json::from_str; - use Weekday::*; - - let cases: Vec<(&str, Weekday)> = vec![ - ("\"mon\"", Mon), - ("\"MONDAY\"", Mon), - ("\"MonDay\"", Mon), - ("\"mOn\"", Mon), - ("\"tue\"", Tue), - ("\"tuesday\"", Tue), - ("\"wed\"", Wed), - ("\"wednesday\"", Wed), - ("\"thu\"", Thu), - ("\"thursday\"", Thu), - ("\"fri\"", Fri), - ("\"friday\"", Fri), - ("\"sat\"", Sat), - ("\"saturday\"", Sat), - ("\"sun\"", Sun), - ("\"sunday\"", Sun), - ]; - - for (str, expected_weekday) in cases { - let weekday = from_str::(str).unwrap(); - assert_eq!(weekday, expected_weekday); - } - - let errors: Vec<&str> = - vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""]; - - for str in errors { - from_str::(str).unwrap_err(); - } - } } #[cfg(test)] @@ -367,4 +309,64 @@ mod tests { ); } } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_serialize() { + use serde_json::to_string; + use Weekday::*; + + let cases: Vec<(Weekday, &str)> = vec![ + (Mon, "\"Mon\""), + (Tue, "\"Tue\""), + (Wed, "\"Wed\""), + (Thu, "\"Thu\""), + (Fri, "\"Fri\""), + (Sat, "\"Sat\""), + (Sun, "\"Sun\""), + ]; + + for (weekday, expected_str) in cases { + let string = to_string(&weekday).unwrap(); + assert_eq!(string, expected_str); + } + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_deserialize() { + use serde_json::from_str; + use Weekday::*; + + let cases: Vec<(&str, Weekday)> = vec![ + ("\"mon\"", Mon), + ("\"MONDAY\"", Mon), + ("\"MonDay\"", Mon), + ("\"mOn\"", Mon), + ("\"tue\"", Tue), + ("\"tuesday\"", Tue), + ("\"wed\"", Wed), + ("\"wednesday\"", Wed), + ("\"thu\"", Thu), + ("\"thursday\"", Thu), + ("\"fri\"", Fri), + ("\"friday\"", Fri), + ("\"sat\"", Sat), + ("\"saturday\"", Sat), + ("\"sun\"", Sun), + ("\"sunday\"", Sun), + ]; + + for (str, expected_weekday) in cases { + let weekday = from_str::(str).unwrap(); + assert_eq!(weekday, expected_weekday); + } + + let errors: Vec<&str> = + vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""]; + + for str in errors { + from_str::(str).unwrap_err(); + } + } } From 70df5134418f26883c0944518e9c0c9a94bce440 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:56:17 +0200 Subject: [PATCH 39/48] Move tests in `naive::time::serde` to `test` module --- src/naive/time/serde.rs | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/naive/time/serde.rs b/src/naive/time/serde.rs index c7394fb5..cf3c4e3d 100644 --- a/src/naive/time/serde.rs +++ b/src/naive/time/serde.rs @@ -42,24 +42,30 @@ impl<'de> de::Deserialize<'de> for NaiveTime { } } -#[test] -fn test_serde_serialize() { - super::test_encodable_json(serde_json::to_string); -} +#[cfg(test)] +mod tests { + use crate::naive::time::{test_decodable_json, test_encodable_json}; + use crate::NaiveTime; -#[test] -fn test_serde_deserialize() { - super::test_decodable_json(|input| serde_json::from_str(input)); -} + #[test] + fn test_serde_serialize() { + test_encodable_json(serde_json::to_string); + } -#[test] -fn test_serde_bincode() { - // Bincode is relevant to test separately from JSON because - // it is not self-describing. - use bincode::{deserialize, serialize}; + #[test] + fn test_serde_deserialize() { + test_decodable_json(|input| serde_json::from_str(input)); + } - let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap(); - let encoded = serialize(&t).unwrap(); - let decoded: NaiveTime = deserialize(&encoded).unwrap(); - assert_eq!(t, decoded); + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use bincode::{deserialize, serialize}; + + let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap(); + let encoded = serialize(&t).unwrap(); + let decoded: NaiveTime = deserialize(&encoded).unwrap(); + assert_eq!(t, decoded); + } } From 33bf2fce57e68b8c62e2313cbdd59a1855ae1f38 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:59:29 +0200 Subject: [PATCH 40/48] Move tests in `naive::date::serde` to `test` module --- src/naive/date.rs | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 208ea2cb..43cb4363 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2313,26 +2313,32 @@ mod serde { } } - #[test] - fn test_serde_serialize() { - super::test_encodable_json(serde_json::to_string); - } + #[cfg(test)] + mod tests { + use crate::naive::date::{test_decodable_json, test_encodable_json}; + use crate::NaiveDate; - #[test] - fn test_serde_deserialize() { - super::test_decodable_json(|input| serde_json::from_str(input)); - } + #[test] + fn test_serde_serialize() { + test_encodable_json(serde_json::to_string); + } - #[test] - fn test_serde_bincode() { - // Bincode is relevant to test separately from JSON because - // it is not self-describing. - use bincode::{deserialize, serialize}; + #[test] + fn test_serde_deserialize() { + test_decodable_json(|input| serde_json::from_str(input)); + } - let d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap(); - let encoded = serialize(&d).unwrap(); - let decoded: NaiveDate = deserialize(&encoded).unwrap(); - assert_eq!(d, decoded); + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use bincode::{deserialize, serialize}; + + let d = NaiveDate::from_ymd_opt(2014, 7, 24).unwrap(); + let encoded = serialize(&d).unwrap(); + let decoded: NaiveDate = deserialize(&encoded).unwrap(); + assert_eq!(d, decoded); + } } } From 06440840c17a4888ad20dbab3d90f3069b447fb4 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 15:02:41 +0200 Subject: [PATCH 41/48] Move tests in `naive::date::rustc_serialize` to `test` module --- src/naive/date.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/naive/date.rs b/src/naive/date.rs index 43cb4363..f34d855a 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -2237,16 +2237,19 @@ mod rustc_serialize { } #[cfg(test)] - use rustc_serialize::json; + mod tests { + use crate::naive::date::{test_decodable_json, test_encodable_json}; + use rustc_serialize::json; - #[test] - fn test_encodable() { - super::test_encodable_json(json::encode); - } + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } - #[test] - fn test_decodable() { - super::test_decodable_json(json::decode); + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } } } From 4aa6c9a99530e0541dc589a51ba367651453530f Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 14:07:37 +0200 Subject: [PATCH 42/48] Move tests in `datetime::rustc_serialize` to `test` module --- src/datetime/rustc_serialize.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/datetime/rustc_serialize.rs b/src/datetime/rustc_serialize.rs index 18a67d62..8e75350d 100644 --- a/src/datetime/rustc_serialize.rs +++ b/src/datetime/rustc_serialize.rs @@ -103,21 +103,25 @@ impl Decodable for TsSeconds { } #[cfg(test)] -use rustc_serialize::json; +mod tests { + use crate::datetime::test_encodable_json; + use crate::datetime::{test_decodable_json, test_decodable_json_timestamps}; + use rustc_serialize::json; -#[test] -fn test_encodable() { - super::test_encodable_json(json::encode, json::encode); -} + #[test] + fn test_encodable() { + test_encodable_json(json::encode, json::encode); + } -#[cfg(feature = "clock")] -#[test] -fn test_decodable() { - super::test_decodable_json(json::decode, json::decode, json::decode); -} + #[cfg(feature = "clock")] + #[test] + fn test_decodable() { + test_decodable_json(json::decode, json::decode, json::decode); + } -#[cfg(feature = "clock")] -#[test] -fn test_decodable_timestamps() { - super::test_decodable_json_timestamps(json::decode, json::decode, json::decode); + #[cfg(feature = "clock")] + #[test] + fn test_decodable_timestamps() { + test_decodable_json_timestamps(json::decode, json::decode, json::decode); + } } From e0bc28c7992d5a459cde8b581a6821467de3955a Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 14:09:26 +0200 Subject: [PATCH 43/48] Move tests in `naive::datetime::rustc_serialize` to `test` module --- src/naive/datetime/rustc_serialize.rs | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/naive/datetime/rustc_serialize.rs b/src/naive/datetime/rustc_serialize.rs index 6e33829e..201fe7aa 100644 --- a/src/naive/datetime/rustc_serialize.rs +++ b/src/naive/datetime/rustc_serialize.rs @@ -55,19 +55,23 @@ impl Decodable for TsSeconds { } #[cfg(test)] -use rustc_serialize::json; +mod tests { + use crate::naive::datetime::test_encodable_json; + use crate::naive::datetime::{test_decodable_json, test_decodable_json_timestamp}; + use rustc_serialize::json; -#[test] -fn test_encodable() { - super::test_encodable_json(json::encode); -} + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } -#[test] -fn test_decodable() { - super::test_decodable_json(json::decode); -} + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } -#[test] -fn test_decodable_timestamps() { - super::test_decodable_json_timestamp(json::decode); + #[test] + fn test_decodable_timestamps() { + test_decodable_json_timestamp(json::decode); + } } From 4b4e694f2442e1ad799a7211c2b9404df8fa7da0 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 14:14:31 +0200 Subject: [PATCH 44/48] Move tests in `naive::time::rustc_serialize` to `test` module --- src/naive/time/rustc_serialize.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/naive/time/rustc_serialize.rs b/src/naive/time/rustc_serialize.rs index 9eaf6821..128fcec8 100644 --- a/src/naive/time/rustc_serialize.rs +++ b/src/naive/time/rustc_serialize.rs @@ -16,14 +16,17 @@ impl Decodable for NaiveTime { } #[cfg(test)] -use rustc_serialize::json; +mod tests { + use crate::naive::time::{test_decodable_json, test_encodable_json}; + use rustc_serialize::json; -#[test] -fn test_encodable() { - super::test_encodable_json(json::encode); -} + #[test] + fn test_encodable() { + test_encodable_json(json::encode); + } -#[test] -fn test_decodable() { - super::test_decodable_json(json::decode); + #[test] + fn test_decodable() { + test_decodable_json(json::decode); + } } From 03dd894a7ffd9a7cb2e805c3476067041fb88f1f Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 11:51:28 +0200 Subject: [PATCH 45/48] Deny tests outside `test` module --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 3737d1a9..2eb1a010 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -388,6 +388,7 @@ #![deny(missing_debug_implementations)] #![warn(unreachable_pub)] #![deny(dead_code)] +#![deny(clippy::tests_outside_test_module)] #![cfg_attr(not(any(feature = "std", test)), no_std)] // can remove this if/when rustc-serialize support is removed // keeps clippy happy in the meantime From 2665e3091dd3eee2427e74d83ca85e70d839c13a Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 13:14:45 +0200 Subject: [PATCH 46/48] [CI] Run clippy on all features and targets --- .github/workflows/lint.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a0cf75d9..6209a0ea 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,9 +17,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo fmt --check -- --color=always - run: cargo fmt --check --manifest-path fuzz/Cargo.toml - - run: cargo clippy --color=always -- -D warnings - run: | - cargo clippy --color=always --target x86_64-pc-windows-msvc \ + cargo clippy --all-features --all-targets --color=always \ -- -D warnings - run: | cargo clippy --manifest-path fuzz/Cargo.toml --color=always \ From c0dcbe7f9b2f3790497f2dd6f1c1075bcb767342 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 16:50:32 +0200 Subject: [PATCH 47/48] Move tests in `format::scan` to `test` module --- src/format/scan.rs | 189 +++++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 92 deletions(-) diff --git a/src/format/scan.rs b/src/format/scan.rs index 50315fef..29fa70d4 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -414,98 +414,103 @@ enum CommentState { } #[cfg(test)] -#[test] -fn test_rfc2822_comments() { - let testdata = [ - ("", Err(TOO_SHORT)), - (" ", Err(TOO_SHORT)), - ("x", Err(INVALID)), - ("(", Err(TOO_SHORT)), - ("()", Ok("")), - (" \r\n\t()", Ok("")), - ("() ", Ok(" ")), - ("()z", Ok("z")), - ("(x)", Ok("")), - ("(())", Ok("")), - ("((()))", Ok("")), - ("(x(x(x)x)x)", Ok("")), - ("( x ( x ( x ) x ) x )", Ok("")), - (r"(\)", Err(TOO_SHORT)), - (r"(\()", Ok("")), - (r"(\))", Ok("")), - (r"(\\)", Ok("")), - ("(()())", Ok("")), - ("( x ( x ) x ( x ) x )", Ok("")), - ]; +mod tests { + use super::{comment_2822, consume_colon_maybe, s_next, space, trim1}; + use crate::format::{INVALID, TOO_SHORT}; - for (test_in, expected) in testdata.iter() { - let actual = comment_2822(test_in).map(|(s, _)| s); - assert_eq!( - *expected, actual, - "{:?} expected to produce {:?}, but produced {:?}.", - test_in, expected, actual - ); + #[test] + fn test_rfc2822_comments() { + let testdata = [ + ("", Err(TOO_SHORT)), + (" ", Err(TOO_SHORT)), + ("x", Err(INVALID)), + ("(", Err(TOO_SHORT)), + ("()", Ok("")), + (" \r\n\t()", Ok("")), + ("() ", Ok(" ")), + ("()z", Ok("z")), + ("(x)", Ok("")), + ("(())", Ok("")), + ("((()))", Ok("")), + ("(x(x(x)x)x)", Ok("")), + ("( x ( x ( x ) x ) x )", Ok("")), + (r"(\)", Err(TOO_SHORT)), + (r"(\()", Ok("")), + (r"(\))", Ok("")), + (r"(\\)", Ok("")), + ("(()())", Ok("")), + ("( x ( x ) x ( x ) x )", Ok("")), + ]; + + for (test_in, expected) in testdata.iter() { + let actual = comment_2822(test_in).map(|(s, _)| s); + assert_eq!( + *expected, actual, + "{:?} expected to produce {:?}, but produced {:?}.", + test_in, expected, actual + ); + } + } + + #[test] + fn test_space() { + assert_eq!(space(""), Err(TOO_SHORT)); + assert_eq!(space(" "), Ok("")); + assert_eq!(space(" \t"), Ok("")); + assert_eq!(space(" \ta"), Ok("a")); + assert_eq!(space(" \ta "), Ok("a ")); + assert_eq!(space("a"), Err(INVALID)); + assert_eq!(space("a "), Err(INVALID)); + } + + #[test] + fn test_s_next() { + assert_eq!(s_next(""), ""); + assert_eq!(s_next(" "), ""); + assert_eq!(s_next("a"), ""); + assert_eq!(s_next("ab"), "b"); + assert_eq!(s_next("abc"), "bc"); + assert_eq!(s_next("😾b"), "b"); + assert_eq!(s_next("a😾"), "😾"); + assert_eq!(s_next("😾bc"), "bc"); + assert_eq!(s_next("a😾c"), "😾c"); + } + + #[test] + fn test_trim1() { + assert_eq!(trim1(""), ""); + assert_eq!(trim1(" "), ""); + assert_eq!(trim1("\t"), ""); + assert_eq!(trim1("\t\t"), "\t"); + assert_eq!(trim1(" "), " "); + assert_eq!(trim1("a"), "a"); + assert_eq!(trim1("a "), "a "); + assert_eq!(trim1("ab"), "ab"); + assert_eq!(trim1("😼"), "😼"); + assert_eq!(trim1("😼b"), "😼b"); + } + + #[test] + 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(" :😸")); } } - -#[test] -fn test_space() { - assert_eq!(space(""), Err(TOO_SHORT)); - assert_eq!(space(" "), Ok("")); - assert_eq!(space(" \t"), Ok("")); - assert_eq!(space(" \ta"), Ok("a")); - assert_eq!(space(" \ta "), Ok("a ")); - assert_eq!(space("a"), Err(INVALID)); - assert_eq!(space("a "), Err(INVALID)); -} - -#[test] -fn test_s_next() { - assert_eq!(s_next(""), ""); - assert_eq!(s_next(" "), ""); - assert_eq!(s_next("a"), ""); - assert_eq!(s_next("ab"), "b"); - assert_eq!(s_next("abc"), "bc"); - assert_eq!(s_next("😾b"), "b"); - assert_eq!(s_next("a😾"), "😾"); - assert_eq!(s_next("😾bc"), "bc"); - assert_eq!(s_next("a😾c"), "😾c"); -} - -#[test] -fn test_trim1() { - assert_eq!(trim1(""), ""); - assert_eq!(trim1(" "), ""); - assert_eq!(trim1("\t"), ""); - assert_eq!(trim1("\t\t"), "\t"); - assert_eq!(trim1(" "), " "); - assert_eq!(trim1("a"), "a"); - assert_eq!(trim1("a "), "a "); - assert_eq!(trim1("ab"), "ab"); - assert_eq!(trim1("😼"), "😼"); - assert_eq!(trim1("😼b"), "😼b"); -} - -#[test] -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(" :😸")); -} From 0ffb1a3b4007cb26416b5427460bb97f4117b3bd Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Thu, 8 Jun 2023 16:52:45 +0200 Subject: [PATCH 48/48] Fix clippy warnings --- src/datetime/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 29e1aa09..4517bb9b 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -240,6 +240,7 @@ fn test_datetime_sub_months() { } // local helper function to easily create a DateTime +#[allow(clippy::too_many_arguments)] fn ymdhms( fixedoffset: &FixedOffset, year: i32, @@ -253,6 +254,7 @@ fn ymdhms( } // local helper function to easily create a DateTime +#[allow(clippy::too_many_arguments)] fn ymdhms_milli( fixedoffset: &FixedOffset, year: i32, @@ -271,6 +273,7 @@ fn ymdhms_milli( } // local helper function to easily create a DateTime +#[allow(clippy::too_many_arguments)] fn ymdhms_micro( fixedoffset: &FixedOffset, year: i32, @@ -289,6 +292,7 @@ fn ymdhms_micro( } // local helper function to easily create a DateTime +#[allow(clippy::too_many_arguments)] fn ymdhms_nano( fixedoffset: &FixedOffset, year: i32,