From e95ea6d25141862e459be35356de6e768d58c255 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 22 Mar 2022 02:53:20 -0400 Subject: [PATCH] Add tests for size, alignment, trait impls This ensures that nothing will regress without knowing. As it turns out, there was a missing implementation that was caught during this. As such, `impl AddAssign for `StdDuration` was added in this commit as well. --- src/duration.rs | 11 +- tests/integration/duration.rs | 11 + tests/integration/main.rs | 8 +- tests/integration/meta.rs | 997 ++++++++++++++++++++++++++++++++++ 4 files changed, 1025 insertions(+), 2 deletions(-) create mode 100644 tests/integration/meta.rs diff --git a/src/duration.rs b/src/duration.rs index 7cb26d362..ee7af639b 100644 --- a/src/duration.rs +++ b/src/duration.rs @@ -4,7 +4,7 @@ use core::cmp::Ordering; use core::convert::{TryFrom, TryInto}; use core::fmt; use core::iter::Sum; -use core::ops::{Add, Div, Mul, Neg, Sub, SubAssign}; +use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; use core::time::Duration as StdDuration; use crate::error; @@ -837,6 +837,15 @@ impl Add for StdDuration { impl_add_assign!(Duration: Self, StdDuration); +impl AddAssign for StdDuration { + fn add_assign(&mut self, rhs: Duration) { + *self = (*self + rhs).try_into().expect( + "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \ + change the type.", + ); + } +} + impl Neg for Duration { type Output = Self; diff --git a/tests/integration/duration.rs b/tests/integration/duration.rs index 9fb4a2a4a..d20eb9a7f 100644 --- a/tests/integration/duration.rs +++ b/tests/integration/duration.rs @@ -471,6 +471,17 @@ fn add_assign_std() { assert_eq!(duration, 0.seconds()); } +#[test] +fn std_add_assign() { + let mut duration = 1.std_seconds(); + duration += 1.seconds(); + assert_eq!(duration, 2.seconds()); + + let mut duration = 500.std_milliseconds(); + duration += 500.milliseconds(); + assert_eq!(duration, 1.seconds()); +} + #[test] fn neg() { assert_eq!(-(1.seconds()), (-1).seconds()); diff --git a/tests/integration/main.rs b/tests/integration/main.rs index 3fe04d90c..ce4bd724b 100644 --- a/tests/integration/main.rs +++ b/tests/integration/main.rs @@ -28,7 +28,12 @@ unused_qualifications, variant_size_differences )] -#![allow(clippy::cognitive_complexity, clippy::clone_on_copy, clippy::cmp_owned)] +#![allow( + clippy::clone_on_copy, + clippy::cmp_owned, + clippy::cognitive_complexity, + clippy::missing_const_for_fn +)] extern crate quickcheck_dep as quickcheck; @@ -55,6 +60,7 @@ mod format_description; mod formatting; mod instant; mod macros; +mod meta; mod month; mod offset_date_time; mod parse_format_description; diff --git a/tests/integration/meta.rs b/tests/integration/meta.rs new file mode 100644 index 000000000..beb7d2881 --- /dev/null +++ b/tests/integration/meta.rs @@ -0,0 +1,997 @@ +// Prefer runtime checks if possible, as otherwise tests can't be run at all if something is +// changed. + +use std::borrow::Borrow; +use std::convert::TryFrom; +use std::error::Error as StdError; +use std::fmt::{Debug, Display}; +use std::hash::Hash; +use std::iter::Sum; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::time::{Duration as StdDuration, Instant as StdInstant, SystemTime}; + +use quickcheck_dep::Arbitrary; +use rand::distributions::{Distribution, Standard}; +use serde::{Deserialize, Serialize}; +use time::format_description::{modifier, well_known, Component, FormatItem}; +use time::formatting::Formattable; +use time::parsing::{Parsable, Parsed}; +use time::{ + error, ext, Date, Duration, Error, Instant, Month, OffsetDateTime, PrimitiveDateTime, Time, + UtcOffset, Weekday, +}; + +#[test] +fn alignment() { + macro_rules! assert_alignment { + ($t:ty, $alignment:literal, $opt_alignment:literal) => { + assert_eq!( + ::core::mem::align_of::<$t>(), + $alignment, + concat!("alignment of `", stringify!($t), "` was ", $alignment) + ); + assert_eq!( + ::core::mem::align_of::>(), + $opt_alignment, + concat!( + "alignment of `Option<", + stringify!($t), + ">` was ", + $opt_alignment + ) + ); + }; + } + + assert_alignment!(Date, 4, 4); + assert_alignment!(Duration, 8, 8); + assert_alignment!(OffsetDateTime, 4, 4); + assert_alignment!(PrimitiveDateTime, 4, 4); + assert_alignment!(Time, 4, 4); + assert_alignment!(UtcOffset, 1, 1); + assert_alignment!(error::ComponentRange, 8, 8); + assert_alignment!(error::ConversionRange, 1, 1); + assert_alignment!(error::DifferentVariant, 1, 1); + assert_alignment!(error::IndeterminateOffset, 1, 1); + assert_alignment!(modifier::Day, 1, 1); + assert_alignment!(modifier::Hour, 1, 1); + assert_alignment!(modifier::Minute, 1, 1); + assert_alignment!(modifier::Month, 1, 1); + assert_alignment!(modifier::OffsetHour, 1, 1); + assert_alignment!(modifier::OffsetMinute, 1, 1); + assert_alignment!(modifier::OffsetSecond, 1, 1); + assert_alignment!(modifier::Ordinal, 1, 1); + assert_alignment!(modifier::Period, 1, 1); + assert_alignment!(modifier::Second, 1, 1); + assert_alignment!(modifier::Subsecond, 1, 1); + assert_alignment!(modifier::WeekNumber, 1, 1); + assert_alignment!(modifier::Weekday, 1, 1); + assert_alignment!(modifier::Year, 1, 1); + assert_alignment!(well_known::Rfc2822, 1, 1); + assert_alignment!(well_known::Rfc3339, 1, 1); + assert_alignment!(Parsed, 4, 4); + assert_alignment!(Month, 1, 1); + assert_alignment!(Weekday, 1, 1); + assert_alignment!(Error, 8, 8); + assert_alignment!(error::Format, 8, 8); + assert_alignment!(error::InvalidFormatDescription, 8, 8); + assert_alignment!(error::Parse, 8, 8); + assert_alignment!(error::ParseFromDescription, 8, 8); + assert_alignment!(error::TryFromParsed, 8, 8); + assert_alignment!(Component, 1, 1); + assert_alignment!(FormatItem<'_>, 8, 8); + assert_alignment!(modifier::MonthRepr, 1, 1); + assert_alignment!(modifier::Padding, 1, 1); + assert_alignment!(modifier::SubsecondDigits, 1, 1); + assert_alignment!(modifier::WeekNumberRepr, 1, 1); + assert_alignment!(modifier::WeekdayRepr, 1, 1); + assert_alignment!(modifier::YearRepr, 1, 1); +} + +#[test] +fn size() { + macro_rules! assert_size { + ($t:ty, $size:literal, $opt_size:literal) => { + assert_eq!( + ::core::mem::size_of::<$t>(), + $size, + concat!("size of `", stringify!($t), "` was ", $size) + ); + assert_eq!( + ::core::mem::size_of::>(), + $opt_size, + concat!("size of `Option<", stringify!($t), ">` was ", $opt_size) + ); + }; + } + + assert_size!(Date, 4, 8); + assert_size!(Duration, 16, 16); + assert_size!(OffsetDateTime, 16, 16); + assert_size!(PrimitiveDateTime, 12, 12); + assert_size!(Time, 8, 8); + assert_size!(UtcOffset, 3, 4); + assert_size!(error::ComponentRange, 48, 48); + assert_size!(error::ConversionRange, 0, 1); + assert_size!(error::DifferentVariant, 0, 1); + assert_size!(error::IndeterminateOffset, 0, 1); + assert_size!(modifier::Day, 1, 1); + assert_size!(modifier::Hour, 2, 2); + assert_size!(modifier::Minute, 1, 1); + assert_size!(modifier::Month, 3, 3); + assert_size!(modifier::OffsetHour, 2, 2); + assert_size!(modifier::OffsetMinute, 1, 1); + assert_size!(modifier::OffsetSecond, 1, 1); + assert_size!(modifier::Ordinal, 1, 1); + assert_size!(modifier::Period, 2, 2); + assert_size!(modifier::Second, 1, 1); + assert_size!(modifier::Subsecond, 1, 1); + assert_size!(modifier::WeekNumber, 2, 2); + assert_size!(modifier::Weekday, 3, 3); + assert_size!(modifier::Year, 4, 4); + assert_size!(well_known::Rfc2822, 0, 1); + assert_size!(well_known::Rfc3339, 0, 1); + assert_size!(Parsed, 56, 56); + assert_size!(Month, 1, 1); + assert_size!(Weekday, 1, 1); + assert_size!(Error, 56, 56); + assert_size!(error::Format, 24, 24); + assert_size!(error::InvalidFormatDescription, 40, 40); + assert_size!(error::Parse, 56, 56); + assert_size!(error::ParseFromDescription, 16, 24); + assert_size!(error::TryFromParsed, 48, 48); + assert_size!(Component, 5, 5); + assert_size!(FormatItem<'_>, 24, 24); + assert_size!(modifier::MonthRepr, 1, 1); + assert_size!(modifier::Padding, 1, 1); + assert_size!(modifier::SubsecondDigits, 1, 1); + assert_size!(modifier::WeekNumberRepr, 1, 1); + assert_size!(modifier::WeekdayRepr, 1, 1); + assert_size!(modifier::YearRepr, 1, 1); +} + +macro_rules! assert_obj_safe { + ($($xs:path),+ $(,)?) => { + $(const _: Option<&dyn $xs> = None;)+ + }; +} + +assert_obj_safe!(ext::NumericalDuration); +assert_obj_safe!(ext::NumericalStdDuration); +assert_obj_safe!(Parsable); +// `Formattable` is not object safe. + +macro_rules! assert_impl { + ($($(@$lifetimes:lifetime),+ ;)? $type:ty: $($trait:path),+ $(,)?) => { + const _: fn() = || { + fn assert_impl_all<$($($lifetimes,)+)? T: ?Sized $(+ $trait)+>() {} + assert_impl_all::<$type>(); + }; + }; +} + +assert_impl! { @'a; Date: + Add, + Add, + AddAssign, + AddAssign, + Arbitrary, + Clone, + Debug, + Deserialize<'a>, + Display, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize, + Sub, + Sub, + Sub, + SubAssign, + SubAssign, + TryFrom, + Copy, + Eq, + RefUnwindSafe, + Send, + Sync, + Unpin, + UnwindSafe, +} +assert_impl! { @'a; Duration: + Add, + Add, + AddAssign, + AddAssign, + Arbitrary, + Clone, + Debug, + Default, + Deserialize<'a>, + Div, + Div, + Div, + Div, + Div, + Div, + Div, + Div, + Div, + Div, + DivAssign, + DivAssign, + DivAssign, + DivAssign, + DivAssign, + DivAssign, + DivAssign, + DivAssign, + Hash, + Mul, + Mul, + Mul, + Mul, + Mul, + Mul, + Mul, + Mul, + MulAssign, + MulAssign, + MulAssign, + MulAssign, + MulAssign, + MulAssign, + MulAssign, + MulAssign, + Neg, + Ord, + PartialEq, + PartialEq, + PartialOrd, + PartialOrd, + Serialize, + Sub, + Sub, + SubAssign, + SubAssign, + Sum<&'a Duration>, + Sum, + TryFrom, + Copy, + Eq, + RefUnwindSafe, + Send, + Sync, + Unpin, + UnwindSafe, +} +assert_impl! { Instant: + Add, + Add, + AddAssign, + AddAssign, + AsRef, + Borrow, + Clone, + Debug, + From, + Hash, + Ord, + PartialEq, + PartialEq, + PartialOrd, + PartialOrd, + Sub, + Sub, + Sub, + Sub, + SubAssign, + SubAssign, + Copy, + Eq, + RefUnwindSafe, + Send, + Sync, + Unpin, + UnwindSafe, +} +assert_impl! { @'a; OffsetDateTime: + Add, + Add, + AddAssign, + AddAssign, + Arbitrary, + Clone, + Debug, + Deserialize<'a>, + Display, + From, + Hash, + Ord, + PartialEq, + PartialEq, + PartialOrd, + PartialOrd, + Serialize, + Sub, + Sub, + Sub, + Sub, + SubAssign, + SubAssign, + TryFrom, + Copy, + Eq, + RefUnwindSafe, + Send, + Sync, + Unpin, + UnwindSafe, +} +assert_impl! { @'a; PrimitiveDateTime: + Add, + Add, + AddAssign, + AddAssign, + Arbitrary, + Clone, + Debug, + Deserialize<'a>, + Display, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize, + Sub, + Sub, + Sub, + SubAssign, + SubAssign, + TryFrom, + Copy, + Eq, + RefUnwindSafe, + Send, + Sync, + Unpin, + UnwindSafe, +} +assert_impl! { @'a; Time: + Add, + Add, + AddAssign, + AddAssign, + Arbitrary, + Clone, + Debug, + Deserialize<'a>, + Display, + Hash, + Ord, + PartialEq