diff --git a/Cargo.toml b/Cargo.toml index 381122f79..8c8eb0df9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ time-macros = { path = "time-macros", version = "=0.2.14" } criterion = { version = "0.5.1", default-features = false } deranged = { version = "0.3.7", default-features = false } +itertools = "0.11.0" itoa = "1.0.1" js-sys = "0.3.58" libc = "0.2.98" @@ -16,6 +17,7 @@ num_threads = "0.1.2" quickcheck = { version = "1.0.3", default-features = false } quickcheck_macros = "1.0.0" rand = { version = "0.8.4", default-features = false } +rstest = { version = "0.18.2", default-features = false } # ^1.0.184 due to serde-rs/serde#2538 serde = { version = "1.0.184", default-features = false } serde_json = "1.0.68" diff --git a/tests/duration.rs b/tests/duration.rs index 74a9dd165..194b67e3f 100644 --- a/tests/duration.rs +++ b/tests/duration.rs @@ -1,470 +1,533 @@ use core::u64; use std::cmp::Ordering; +use std::cmp::Ordering::{Equal, Greater, Less}; use std::time::Duration as StdDuration; +use rstest::rstest; use time::ext::{NumericalDuration, NumericalStdDuration}; use time::{error, Duration}; -#[test] -fn unit_values() { - assert_eq!(Duration::ZERO, 0.seconds()); - assert_eq!(Duration::NANOSECOND, 1.nanoseconds()); - assert_eq!(Duration::MICROSECOND, 1.microseconds()); - assert_eq!(Duration::MILLISECOND, 1.milliseconds()); - assert_eq!(Duration::SECOND, 1.seconds()); - assert_eq!(Duration::MINUTE, 60.seconds()); - assert_eq!(Duration::HOUR, 3_600.seconds()); - assert_eq!(Duration::DAY, 86_400.seconds()); - assert_eq!(Duration::WEEK, 604_800.seconds()); -} - -#[test] +#[rstest] +#[case(Duration::ZERO, 0.seconds())] +#[case(Duration::NANOSECOND, 1.nanoseconds())] +#[case(Duration::MICROSECOND, 1.microseconds())] +#[case(Duration::MILLISECOND, 1.milliseconds())] +#[case(Duration::SECOND, 1.seconds())] +#[case(Duration::MINUTE, 60.seconds())] +#[case(Duration::HOUR, 3_600.seconds())] +#[case(Duration::DAY, 86_400.seconds())] +#[case(Duration::WEEK, 604_800.seconds())] +fn unit_values(#[case] input: Duration, #[case] expected: Duration) { + assert_eq!(input, expected); +} + +#[rstest] fn default() { assert_eq!(Duration::default(), Duration::ZERO); } -#[test] -fn is_zero() { - assert!(!(-1).nanoseconds().is_zero()); - assert!(0.seconds().is_zero()); - assert!(!1.nanoseconds().is_zero()); +#[rstest] +#[case((-1).seconds(), false)] +#[case(0.seconds(), true)] +#[case(1.seconds(), false)] +fn is_zero(#[case] input: Duration, #[case] expected: bool) { + assert_eq!(input.is_zero(), expected); +} + +#[rstest] +#[case((-1).seconds(), true)] +#[case(0.seconds(), false)] +#[case(1.seconds(), false)] +fn is_negative(#[case] input: Duration, #[case] expected: bool) { + assert_eq!(input.is_negative(), expected); +} + +#[rstest] +#[case((-1).seconds(), false)] +#[case(0.seconds(), false)] +#[case(1.seconds(), true)] +fn is_positive(#[case] input: Duration, #[case] expected: bool) { + assert_eq!(input.is_positive(), expected); +} + +#[rstest] +#[case(1.seconds(), 1.seconds())] +#[case(0.seconds(), 0.seconds())] +#[case((-1).seconds(), 1.seconds())] +#[case(Duration::new(i64::MIN, 0), Duration::MAX)] +fn abs(#[case] input: Duration, #[case] expected: Duration) { + assert_eq!(input.abs(), expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds())] +#[case(0.seconds(), 0.std_seconds())] +#[case((-1).seconds(), 1.std_seconds())] +fn unsigned_abs(#[case] input: Duration, #[case] expected: StdDuration) { + assert_eq!(input.unsigned_abs(), expected); +} + +#[rstest] +#[case(1, 0, 1.seconds())] +#[case(-1, 0, (-1).seconds())] +#[case(1, 2_000_000_000, 3.seconds())] +#[case(0, 0, 0.seconds())] +#[case(0, 1_000_000_000, 1.seconds())] +#[case(-1, 1_000_000_000, 0.seconds())] +#[case(-2, 1_000_000_000, (-1).seconds())] +#[case(1, -1, 999_999_999.nanoseconds())] +#[case(-1, 1, (-999_999_999).nanoseconds())] +#[case(1, 1, 1_000_000_001.nanoseconds())] +#[case(-1, -1, (-1_000_000_001).nanoseconds())] +#[case(0, 1, 1.nanoseconds())] +#[case(0, -1, (-1).nanoseconds())] +#[case(-1, 1_400_000_000, 400.milliseconds())] +#[case(-2, 1_400_000_000, (-600).milliseconds())] +#[case(-3, 1_400_000_000, (-1_600).milliseconds())] +#[case(1, -1_400_000_000, (-400).milliseconds())] +#[case(2, -1_400_000_000, 600.milliseconds())] +#[case(3, -1_400_000_000, 1_600.milliseconds())] +fn new(#[case] secs: i64, #[case] nanos: i32, #[case] expected: Duration) { + assert_eq!(Duration::new(secs, nanos), expected); +} + +#[rstest] +#[case(i64::MAX, 1_000_000_000)] +#[case(i64::MIN, -1_000_000_000)] +#[should_panic] +fn new_panic(#[case] secs: i64, #[case] nanos: i32) { + let _ = Duration::new(secs, nanos); } -#[test] -fn is_negative() { - assert!((-1).seconds().is_negative()); - assert!(!0.seconds().is_negative()); - assert!(!1.seconds().is_negative()); +#[rstest] +#[case(1, 604_800)] +#[case(2, 2 * 604_800)] +#[case(-1, -604_800)] +#[case(-2, -2 * 604_800)] +fn weeks(#[case] weeks_: i64, #[case] expected: i64) { + assert_eq!(Duration::weeks(weeks_), expected.seconds()); } -#[test] -fn is_positive() { - assert!(!(-1).seconds().is_positive()); - assert!(!0.seconds().is_positive()); - assert!(1.seconds().is_positive()); +#[rstest] +#[case(i64::MAX)] +#[case(i64::MIN)] +#[should_panic] +fn weeks_panic(#[case] weeks: i64) { + let _ = Duration::weeks(weeks); } -#[test] -fn abs() { - assert_eq!(1.seconds().abs(), 1.seconds()); - assert_eq!(0.seconds().abs(), 0.seconds()); - assert_eq!((-1).seconds().abs(), 1.seconds()); - assert_eq!(Duration::new(i64::MIN, 0).abs(), Duration::MAX); +#[rstest] +#[case(7, 1)] +#[case(-7, -1)] +#[case(6, 0)] +#[case(-6, 0)] +fn whole_weeks(#[case] days: i64, #[case] expected: i64) { + assert_eq!(Duration::days(days).whole_weeks(), expected); } -#[test] -fn unsigned_abs() { - assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds()); - assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds()); - assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds()); +#[rstest] +#[case(1, 86_400)] +#[case(2, 2 * 86_400)] +#[case(-1, -86_400)] +#[case(-2, -2 * 86_400)] +fn days(#[case] days_: i64, #[case] expected: i64) { + assert_eq!(Duration::days(days_), expected.seconds()); } -#[test] -fn new() { - assert_eq!(Duration::new(1, 0), 1.seconds()); - assert_eq!(Duration::new(-1, 0), (-1).seconds()); - assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds()); - - assert_eq!(Duration::new(0, 0), 0.seconds()); - assert_eq!(Duration::new(0, 1_000_000_000), 1.seconds()); - assert_eq!(Duration::new(-1, 1_000_000_000), 0.seconds()); - assert_eq!(Duration::new(-2, 1_000_000_000), (-1).seconds()); - - assert_eq!(Duration::new(1, -1), 999_999_999.nanoseconds()); - assert_eq!(Duration::new(-1, 1), (-999_999_999).nanoseconds()); - assert_eq!(Duration::new(1, 1), 1_000_000_001.nanoseconds()); - assert_eq!(Duration::new(-1, -1), (-1_000_000_001).nanoseconds()); - assert_eq!(Duration::new(0, 1), 1.nanoseconds()); - assert_eq!(Duration::new(0, -1), (-1).nanoseconds()); - - assert_eq!(Duration::new(-1, 1_400_000_000), 400.milliseconds()); - assert_eq!(Duration::new(-2, 1_400_000_000), (-600).milliseconds()); - assert_eq!(Duration::new(-3, 1_400_000_000), (-1_600).milliseconds()); - assert_eq!(Duration::new(1, -1_400_000_000), (-400).milliseconds()); - assert_eq!(Duration::new(2, -1_400_000_000), 600.milliseconds()); - assert_eq!(Duration::new(3, -1_400_000_000), 1_600.milliseconds()); - - assert_panic!(Duration::new(i64::MAX, 1_000_000_000)); - assert_panic!(Duration::new(i64::MIN, -1_000_000_000)); -} - -#[test] -fn weeks() { - assert_eq!(Duration::weeks(1), 604_800.seconds()); - assert_eq!(Duration::weeks(2), (2 * 604_800).seconds()); - assert_eq!(Duration::weeks(-1), (-604_800).seconds()); - assert_eq!(Duration::weeks(-2), (2 * -604_800).seconds()); - - assert_panic!(Duration::weeks(i64::MAX)); - assert_panic!(Duration::weeks(i64::MIN)); -} - -#[test] -fn whole_weeks() { - assert_eq!(Duration::weeks(1).whole_weeks(), 1); - assert_eq!(Duration::weeks(-1).whole_weeks(), -1); - assert_eq!(Duration::days(6).whole_weeks(), 0); - assert_eq!(Duration::days(-6).whole_weeks(), 0); +#[rstest] +#[case(i64::MAX)] +#[case(i64::MIN)] +#[should_panic] +fn days_panic(#[case] days: i64) { + let _ = Duration::days(days); } -#[test] -fn days() { - assert_eq!(Duration::days(1), 86_400.seconds()); - assert_eq!(Duration::days(2), (2 * 86_400).seconds()); - assert_eq!(Duration::days(-1), (-86_400).seconds()); - assert_eq!(Duration::days(-2), (2 * -86_400).seconds()); - - assert_panic!(Duration::days(i64::MAX)); - assert_panic!(Duration::days(i64::MIN)); +#[rstest] +#[case(24, 1)] +#[case(-24, -1)] +#[case(23, 0)] +#[case(-23, 0)] +fn whole_days(#[case] hours: i64, #[case] expected: i64) { + assert_eq!(Duration::hours(hours).whole_days(), expected); } -#[test] -fn whole_days() { - assert_eq!(Duration::days(1).whole_days(), 1); - assert_eq!(Duration::days(-1).whole_days(), -1); - assert_eq!(Duration::hours(23).whole_days(), 0); - assert_eq!(Duration::hours(-23).whole_days(), 0); +#[rstest] +#[case(1, 3_600)] +#[case(2, 2 * 3_600)] +#[case(-1, -3_600)] +#[case(-2, -2 * 3_600)] +fn hours(#[case] hours_: i64, #[case] expected: i64) { + assert_eq!(Duration::hours(hours_), expected.seconds()); } -#[test] -fn hours() { - assert_eq!(Duration::hours(1), 3_600.seconds()); - assert_eq!(Duration::hours(2), (2 * 3_600).seconds()); - assert_eq!(Duration::hours(-1), (-3_600).seconds()); - assert_eq!(Duration::hours(-2), (2 * -3_600).seconds()); - - assert_panic!(Duration::hours(i64::MAX)); - assert_panic!(Duration::hours(i64::MIN)); +#[rstest] +#[case(i64::MAX)] +#[case(i64::MIN)] +#[should_panic] +fn hours_panic(#[case] hours: i64) { + let _ = Duration::hours(hours); } -#[test] -fn whole_hours() { - assert_eq!(Duration::hours(1).whole_hours(), 1); - assert_eq!(Duration::hours(-1).whole_hours(), -1); - assert_eq!(Duration::minutes(59).whole_hours(), 0); - assert_eq!(Duration::minutes(-59).whole_hours(), 0); +#[rstest] +#[case(60, 1)] +#[case(-60, -1)] +#[case(59, 0)] +#[case(-59, 0)] +fn whole_hours(#[case] minutes: i64, #[case] expected: i64) { + assert_eq!(Duration::minutes(minutes).whole_hours(), expected); } -#[test] -fn minutes() { - assert_eq!(Duration::minutes(1), 60.seconds()); - assert_eq!(Duration::minutes(2), (2 * 60).seconds()); - assert_eq!(Duration::minutes(-1), (-60).seconds()); - assert_eq!(Duration::minutes(-2), (2 * -60).seconds()); - - assert_panic!(Duration::minutes(i64::MAX)); - assert_panic!(Duration::minutes(i64::MIN)); +#[rstest] +#[case(1, 60)] +#[case(2, 2 * 60)] +#[case(-1, -60)] +#[case(-2, -2 * 60)] +fn minutes(#[case] minutes_: i64, #[case] expected: i64) { + assert_eq!(Duration::minutes(minutes_), expected.seconds()); } -#[test] -fn whole_minutes() { - assert_eq!(1.minutes().whole_minutes(), 1); - assert_eq!((-1).minutes().whole_minutes(), -1); - assert_eq!(59.seconds().whole_minutes(), 0); - assert_eq!((-59).seconds().whole_minutes(), 0); +#[rstest] +#[case(i64::MAX)] +#[case(i64::MIN)] +#[should_panic] +fn minutes_panic(#[case] minutes: i64) { + let _ = Duration::minutes(minutes); +} + +#[rstest] +#[case(60, 1)] +#[case(-60, -1)] +#[case(59, 0)] +#[case(-59, 0)] +fn whole_minutes(#[case] seconds: i64, #[case] expected: i64) { + assert_eq!(Duration::seconds(seconds).whole_minutes(), expected); +} + +#[rstest] +#[case(1, 1_000)] +#[case(2, 2 * 1_000)] +#[case(-1, -1_000)] +#[case(-2, -2 * 1_000)] +fn seconds(#[case] seconds_: i64, #[case] expected: i64) { + assert_eq!(Duration::seconds(seconds_), expected.milliseconds()); +} + +#[rstest] +#[case(1)] +#[case(-1)] +#[case(60)] +#[case(-60)] +fn whole_seconds(#[case] seconds: i64) { + assert_eq!(Duration::seconds(seconds).whole_seconds(), seconds); +} + +#[rstest] +#[case(0.5, Duration::milliseconds(500))] +#[case(-0.5, Duration::milliseconds(-500))] +#[case(123.250, Duration::milliseconds(123_250))] +#[case(0.000_000_000_012, Duration::ZERO)] +fn seconds_f64(#[case] seconds: f64, #[case] expected: Duration) { + assert_eq!(Duration::seconds_f64(seconds), expected); +} + +#[rstest] +#[case(f64::MAX)] +#[case(f64::MIN)] +#[case(f64::NAN)] +#[should_panic] +fn seconds_f64_panic(#[case] seconds: f64) { + let _ = Duration::seconds_f64(seconds); +} + +#[rstest] +#[case(0.5, Duration::milliseconds(500))] +#[case(-0.5, Duration::milliseconds(-500))] +#[case(123.250, Duration::milliseconds(123_250))] +#[case(0.000_000_000_012, Duration::ZERO)] +#[case(f64::MAX, Duration::MAX)] +#[case(f64::MIN, Duration::MIN)] +#[case(f64::NAN, Duration::ZERO)] +fn saturating_seconds_f64(#[case] seconds: f64, #[case] expected: Duration) { + assert_eq!(Duration::saturating_seconds_f64(seconds), expected); +} + +#[rstest] +#[case(0.5, 0.5)] +#[case(-0.5, -0.5)] +#[case(123.250, 123.250)] +#[case(0.000_000_000_012, 0.)] +fn checked_seconds_f64_success(#[case] seconds: f64, #[case] expected: f64) { + assert_eq!( + Duration::checked_seconds_f64(seconds), + Some(expected.seconds()) + ); } -#[test] -fn seconds() { - assert_eq!(Duration::seconds(1), 1_000.milliseconds()); - assert_eq!(Duration::seconds(2), (2 * 1_000).milliseconds()); - assert_eq!(Duration::seconds(-1), (-1_000).milliseconds()); - assert_eq!(Duration::seconds(-2), (2 * -1_000).milliseconds()); +#[rstest] +#[case(f64::MAX)] +#[case(f64::MIN)] +#[case(f64::NAN)] +fn checked_seconds_f64_edge_cases(#[case] seconds: f64) { + assert_eq!(Duration::checked_seconds_f64(seconds), None); } -#[test] -fn whole_seconds() { - assert_eq!(1.seconds().whole_seconds(), 1); - assert_eq!((-1).seconds().whole_seconds(), -1); - assert_eq!(1.minutes().whole_seconds(), 60); - assert_eq!((-1).minutes().whole_seconds(), -60); +#[rstest] +#[case(1.)] +#[case(-1.)] +#[case(60.)] +#[case(-60.)] +#[case(1.5)] +#[case(-1.5)] +fn as_seconds_f64(#[case] seconds: f64) { + assert_eq!(Duration::seconds_f64(seconds).as_seconds_f64(), seconds); } -#[test] -fn seconds_f64() { - assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds()); - assert_eq!(Duration::seconds_f64(-0.5), (-0.5).seconds()); - assert_eq!(Duration::seconds_f64(123.250), 123.250.seconds()); - assert_eq!(Duration::seconds_f64(0.000_000_000_012), Duration::ZERO); - - assert_panic!(Duration::seconds_f64(f64::MAX)); - assert_panic!(Duration::seconds_f64(f64::MIN)); - assert_panic!(Duration::seconds_f64(f64::NAN)); +#[rstest] +#[case(0.5, Duration::milliseconds(500))] +#[case(-0.5, Duration::milliseconds(-500))] +#[case(123.250, Duration::milliseconds(123_250))] +#[case(0.000_000_000_012, Duration::ZERO)] +fn seconds_f32_success(#[case] seconds: f32, #[case] expected: Duration) { + assert_eq!(Duration::seconds_f32(seconds), expected); } -#[test] -fn saturating_seconds_f64() { - assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds()); - assert_eq!(Duration::saturating_seconds_f64(-0.5), (-0.5).seconds()); - assert_eq!(Duration::saturating_seconds_f64(123.250), 123.250.seconds()); +#[rstest] +#[case(f32::MAX)] +#[case(f32::MIN)] +#[case(f32::NAN)] +#[should_panic] +fn seconds_f32_panic(#[case] seconds: f32) { + let _ = Duration::seconds_f32(seconds); +} + +#[rstest] +#[case(0.5, Duration::milliseconds(500))] +#[case(-0.5, Duration::milliseconds(-500))] +#[case(123.250, Duration::milliseconds(123_250))] +#[case(0.000_000_000_012, Duration::ZERO)] +#[case(f32::MAX, Duration::MAX)] +#[case(f32::MIN, Duration::MIN)] +#[case(f32::NAN, Duration::ZERO)] +fn saturating_seconds_f32(#[case] seconds: f32, #[case] expected: Duration) { + assert_eq!(Duration::saturating_seconds_f32(seconds), expected); +} + +#[rstest] +#[case(0.5, 0.5)] +#[case(-0.5, -0.5)] +#[case(123.250, 123.250)] +#[case(0.000_000_000_012, 0.0)] +fn checked_seconds_f32_success(#[case] seconds: f32, #[case] expected: f64) { assert_eq!( - Duration::saturating_seconds_f64(0.000_000_000_012), - Duration::ZERO + Duration::checked_seconds_f32(seconds), + Some(expected.seconds()) ); - - assert_eq!(Duration::saturating_seconds_f64(f64::MAX), Duration::MAX); - assert_eq!(Duration::saturating_seconds_f64(f64::MIN), Duration::MIN); - assert_eq!(Duration::saturating_seconds_f64(f64::NAN), Duration::ZERO); } -#[test] -fn checked_seconds_f64() { - assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds())); - assert_eq!(Duration::checked_seconds_f64(-0.5), Some((-0.5).seconds())); - assert_eq!( - Duration::checked_seconds_f64(123.250), - Some(123.250.seconds()) - ); - assert_eq!( - Duration::checked_seconds_f64(0.000_000_000_012), - Some(Duration::ZERO) - ); - - assert_eq!(Duration::checked_seconds_f64(f64::MAX), None); - assert_eq!(Duration::checked_seconds_f64(f64::MIN), None); - assert_eq!(Duration::checked_seconds_f64(f64::NAN), None); +#[rstest] +#[case(f32::MAX)] +#[case(f32::MIN)] +#[case(f32::NAN)] +fn checked_seconds_f32_none(#[case] seconds: f32) { + assert_eq!(Duration::checked_seconds_f32(seconds), None); } -#[test] -#[allow(clippy::float_cmp)] -fn as_seconds_f64() { - assert_eq!(1.seconds().as_seconds_f64(), 1.0); - assert_eq!((-1).seconds().as_seconds_f64(), -1.0); - assert_eq!(1.minutes().as_seconds_f64(), 60.0); - assert_eq!((-1).minutes().as_seconds_f64(), -60.0); - assert_eq!(1.5.seconds().as_seconds_f64(), 1.5); - assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5); -} - -#[test] -fn seconds_f32() { - assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds()); - assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds()); - assert_eq!(Duration::seconds_f32(123.250), 123.250.seconds()); - assert_eq!(Duration::seconds_f32(0.000_000_000_012), Duration::ZERO); - - assert_panic!(Duration::seconds_f32(f32::MAX)); - assert_panic!(Duration::seconds_f32(f32::MIN)); - assert_panic!(Duration::seconds_f32(f32::NAN)); -} - -#[test] -fn saturating_seconds_f32() { - assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds()); - assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds()); - assert_eq!(Duration::saturating_seconds_f32(123.250), 123.250.seconds()); - assert_eq!( - Duration::saturating_seconds_f32(0.000_000_000_012), - Duration::ZERO - ); +#[rstest] +#[case(1.0, 1.0)] +#[case(-1.0, -1.0)] +#[case(60.0, 60.0)] +#[case(-60.0, -60.0)] +#[case(1.5, 1.5)] +#[case(-1.5, -1.5)] +fn as_seconds_f32(#[case] seconds: f32, #[case] expected: f32) { + assert_eq!(Duration::seconds_f32(seconds).as_seconds_f32(), expected); +} - assert_eq!(Duration::saturating_seconds_f32(f32::MAX), Duration::MAX); - assert_eq!(Duration::saturating_seconds_f32(f32::MIN), Duration::MIN); - assert_eq!(Duration::saturating_seconds_f32(f32::NAN), Duration::ZERO); +#[rstest] +#[case(1, 1_000)] +#[case(-1, -1_000)] +fn milliseconds(#[case] input: i64, #[case] expected: i64) { + assert_eq!(Duration::milliseconds(input), expected.microseconds()); } -#[test] -fn checked_seconds_f32() { - assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds())); - assert_eq!(Duration::checked_seconds_f32(-0.5), Some((-0.5).seconds())); - assert_eq!( - Duration::checked_seconds_f32(123.250), - Some(123.250.seconds()) - ); - assert_eq!( - Duration::checked_seconds_f32(0.000_000_000_012), - Some(Duration::ZERO) - ); +#[rstest] +#[case(1.seconds(), 1_000)] +#[case((-1).seconds(), -1_000)] +#[case(1.milliseconds(), 1)] +#[case((-1).milliseconds(), -1)] +fn whole_milliseconds(#[case] input: Duration, #[case] expected: i128) { + assert_eq!(input.whole_milliseconds(), expected); +} - assert_eq!(Duration::checked_seconds_f32(f32::MAX), None); - assert_eq!(Duration::checked_seconds_f32(f32::MIN), None); - assert_eq!(Duration::checked_seconds_f32(f32::NAN), None); +#[rstest] +#[case(1.4.seconds(), 400)] +#[case((-1.4).seconds(), -400)] +fn subsec_milliseconds(#[case] duration: Duration, #[case] expected: i16) { + assert_eq!(duration.subsec_milliseconds(), expected); } -#[test] -#[allow(clippy::float_cmp)] -fn as_seconds_f32() { - assert_eq!(1.seconds().as_seconds_f32(), 1.0); - assert_eq!((-1).seconds().as_seconds_f32(), -1.0); - assert_eq!(1.minutes().as_seconds_f32(), 60.0); - assert_eq!((-1).minutes().as_seconds_f32(), -60.0); - assert_eq!(1.5.seconds().as_seconds_f32(), 1.5); - assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5); +#[rstest] +#[case(1, 1_000)] +#[case(-1, -1_000)] +fn microseconds(#[case] input: i64, #[case] expected: i64) { + assert_eq!(Duration::microseconds(input), expected.nanoseconds()); } -#[test] -fn milliseconds() { - assert_eq!(Duration::milliseconds(1), 1_000.microseconds()); - assert_eq!(Duration::milliseconds(-1), (-1000).microseconds()); +#[rstest] +#[case(1.milliseconds(), 1_000)] +#[case((-1).milliseconds(), -1_000)] +#[case(1.microseconds(), 1)] +#[case((-1).microseconds(), -1)] +fn whole_microseconds(#[case] input: Duration, #[case] expected: i128) { + assert_eq!(input.whole_microseconds(), expected); } -#[test] -fn whole_milliseconds() { - assert_eq!(1.seconds().whole_milliseconds(), 1_000); - assert_eq!((-1).seconds().whole_milliseconds(), -1_000); - assert_eq!(1.milliseconds().whole_milliseconds(), 1); - assert_eq!((-1).milliseconds().whole_milliseconds(), -1); +#[rstest] +#[case(1.0004.seconds(), 400)] +#[case((-1.0004).seconds(), -400)] +fn subsec_microseconds(#[case] duration: Duration, #[case] expected: i32) { + assert_eq!(duration.subsec_microseconds(), expected); } -#[test] -fn subsec_milliseconds() { - assert_eq!(1.4.seconds().subsec_milliseconds(), 400); - assert_eq!((-1.4).seconds().subsec_milliseconds(), -400); +#[rstest] +#[case(1, 1.microseconds() / 1_000)] +#[case(-1, (-1).microseconds() / 1_000)] +fn nanoseconds(#[case] input: i64, #[case] expected: Duration) { + assert_eq!(Duration::nanoseconds(input), expected); } -#[test] -fn microseconds() { - assert_eq!(Duration::microseconds(1), 1_000.nanoseconds()); - assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds()); +#[rstest] +#[case(1.microseconds(), 1_000)] +#[case((-1).microseconds(), -1_000)] +#[case(1.nanoseconds(), 1)] +#[case((-1).nanoseconds(), -1)] +fn whole_nanoseconds(#[case] input: Duration, #[case] expected: i128) { + assert_eq!(input.whole_nanoseconds(), expected); } -#[test] -fn whole_microseconds() { - assert_eq!(1.milliseconds().whole_microseconds(), 1_000); - assert_eq!((-1).milliseconds().whole_microseconds(), -1_000); - assert_eq!(1.microseconds().whole_microseconds(), 1); - assert_eq!((-1).microseconds().whole_microseconds(), -1); +#[rstest] +#[case(1.000_000_4.seconds(), 400)] +#[case((-1.000_000_4).seconds(), -400)] +fn subsec_nanoseconds(#[case] duration: Duration, #[case] expected: i32) { + assert_eq!(duration.subsec_nanoseconds(), expected); } -#[test] -fn subsec_microseconds() { - assert_eq!(1.0004.seconds().subsec_microseconds(), 400); - assert_eq!((-1.0004).seconds().subsec_microseconds(), -400); +#[rstest] +#[case(5.seconds(), 5.seconds(), 10.seconds())] +#[case((-5).seconds(), 5.seconds(), 0.seconds())] +#[case(1.seconds(), (-1).milliseconds(), 999.milliseconds())] +fn checked_add_some(#[case] a: Duration, #[case] b: Duration, #[case] expected: Duration) { + assert_eq!(a.checked_add(b), Some(expected)); } -#[test] -fn nanoseconds() { - assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000); - assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000); +#[rstest] +#[case(Duration::MAX, 1.nanoseconds())] +#[case(5.seconds(), Duration::MAX)] +#[case(Duration::MIN, Duration::MIN)] +fn checked_add_none(#[case] a: Duration, #[case] b: Duration) { + assert_eq!(a.checked_add(b), None); } -#[test] -fn whole_nanoseconds() { - assert_eq!(1.microseconds().whole_nanoseconds(), 1_000); - assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000); - assert_eq!(1.nanoseconds().whole_nanoseconds(), 1); - assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1); +#[rstest] +#[case(5.seconds(), 5.seconds(), 0.seconds())] +#[case(5.seconds(), 10.seconds(), (-5).seconds())] +fn checked_sub_some(#[case] a: Duration, #[case] b: Duration, #[case] expected: Duration) { + assert_eq!(a.checked_sub(b), Some(expected)); } -#[test] -fn subsec_nanoseconds() { - assert_eq!(1.000_000_4.seconds().subsec_nanoseconds(), 400); - assert_eq!((-1.000_000_4).seconds().subsec_nanoseconds(), -400); +#[rstest] +#[case(Duration::MIN, 1.nanoseconds())] +#[case(5.seconds(), Duration::MIN)] +#[case(Duration::MAX, Duration::MIN)] +fn checked_sub_none(#[case] a: Duration, #[case] b: Duration) { + assert_eq!(a.checked_sub(b), None); } -#[test] -fn checked_add() { - assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds())); - assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None); - assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds())); - assert_eq!( - 1.seconds().checked_add((-1).milliseconds()), - Some(999.milliseconds()) - ); +#[rstest] +#[case(5.seconds(), 2, 10.seconds())] +#[case(5.seconds(), -2, (-10).seconds())] +#[case(5.seconds(), 0, Duration::ZERO)] +fn checked_mul_some(#[case] duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + assert_eq!(duration.checked_mul(rhs), Some(expected)); } -#[test] -fn checked_sub() { - assert_eq!(5.seconds().checked_sub(5.seconds()), Some(0.seconds())); - assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None); - assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds())); - assert_eq!(Duration::MIN.checked_sub(Duration::MIN), Some(0.seconds())); +#[rstest] +#[case(Duration::MIN, -1)] +#[case(Duration::MAX, 2)] +#[case(Duration::MIN, 2)] +fn checked_mul_none(#[case] duration: Duration, #[case] rhs: i32) { + assert_eq!(duration.checked_mul(rhs), None); } -#[test] -fn checked_mul() { - assert_eq!(5.seconds().checked_mul(2), Some(10.seconds())); - assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds())); - assert_eq!(5.seconds().checked_mul(0), Some(Duration::ZERO)); - assert_eq!(Duration::MAX.checked_mul(2), None); - assert_eq!(Duration::MIN.checked_mul(2), None); +#[rstest] +#[case(10.seconds(), 2, 5.seconds())] +#[case(10.seconds(), -2, (-5).seconds())] +fn checked_div_some(#[case] duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + assert_eq!(duration.checked_div(rhs), Some(expected)); } -#[test] -fn checked_div() { - assert_eq!(10.seconds().checked_div(2), Some(5.seconds())); - assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds())); - assert_eq!(1.seconds().checked_div(0), None); - assert_eq!(Duration::MIN.checked_div(-1), None); +#[rstest] +#[case(1.seconds(), 0)] +#[case(Duration::MIN, -1)] +fn checked_div_none(#[case] duration: Duration, #[case] rhs: i32) { + assert_eq!(duration.checked_div(rhs), None); } -#[test] +#[rstest] fn checked_div_regression() { assert_eq!( Duration::new(1, 1).checked_div(7), Some(Duration::new(0, 142_857_143)) // manually verified ); } - -#[test] -fn saturating_add() { - assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds()); - assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX); - assert_eq!(Duration::MAX.saturating_add(1.seconds()), Duration::MAX); - assert_eq!( - Duration::MIN.saturating_add((-1).nanoseconds()), - Duration::MIN - ); - assert_eq!(Duration::MIN.saturating_add((-1).seconds()), Duration::MIN); - assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO); - assert_eq!( - 1_600.milliseconds().saturating_add(1_600.milliseconds()), - 3_200.milliseconds() - ); - assert_eq!( - 1.seconds().saturating_add((-1).milliseconds()), - (999).milliseconds() - ); -} - -#[test] -fn saturating_sub() { - assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO); - assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN); - assert_eq!( - Duration::MAX.saturating_sub((-1).nanoseconds()), - Duration::MAX - ); - assert_eq!(Duration::MAX.saturating_sub((-1).seconds()), Duration::MAX); - assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds()); - assert_eq!( - (-1_600).milliseconds().saturating_sub(1_600.milliseconds()), - (-3_200).milliseconds() - ); - assert_eq!(0.seconds().saturating_sub(Duration::MIN), Duration::MIN); - assert_eq!(Duration::MIN.saturating_sub(5.seconds()), Duration::MIN); - assert_eq!( - 1_200.milliseconds().saturating_sub(600.milliseconds()), - 600.milliseconds() - ); - assert_eq!( - (-1_200) - .milliseconds() - .saturating_sub((-600).milliseconds()), - (-600).milliseconds() - ); -} - -#[test] -fn saturating_mul() { - assert_eq!(5.seconds().saturating_mul(2), 10.seconds()); - assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds()); - assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO); - assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX); - assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN); - assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN); - assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX); - assert_eq!( - Duration::new(1_844_674_407_370_955_161, 600_000_000).saturating_mul(5), - Duration::MAX - ); - assert_eq!( - Duration::new(1_844_674_407_370_955_161, 800_000_000).saturating_mul(-5), - Duration::MIN - ); -} - -#[test] +#[rstest] +#[case(5.seconds(), 5.seconds(), 10.seconds())] +#[case(Duration::MAX, 1.nanoseconds(), Duration::MAX)] +#[case(Duration::MAX, 1.seconds(), Duration::MAX)] +#[case(Duration::MIN, (-1).nanoseconds(), Duration::MIN)] +#[case(Duration::MIN, (-1).seconds(), Duration::MIN)] +#[case((-5).seconds(), 5.seconds(), Duration::ZERO)] +#[case(1_600.milliseconds(), 1_600.milliseconds(), 3_200.milliseconds())] +#[case(1.seconds(), (-1).milliseconds(), 999.milliseconds())] +fn saturating_add(#[case] a: Duration, #[case] b: Duration, #[case] expected: Duration) { + assert_eq!(a.saturating_add(b), expected); +} + +#[rstest] +#[case(5.seconds(), 5.seconds(), Duration::ZERO)] +#[case(Duration::MIN, 1.nanoseconds(), Duration::MIN)] +#[case(Duration::MAX, (-1).nanoseconds(), Duration::MAX)] +#[case(Duration::MAX, (-1).seconds(), Duration::MAX)] +#[case(5.seconds(), 10.seconds(), (-5).seconds())] +#[case((-1_600).milliseconds(), 1_600.milliseconds(), (-3_200).milliseconds())] +#[case(0.seconds(), Duration::MIN, Duration::MIN)] +#[case(Duration::MIN, 5.seconds(), Duration::MIN)] +#[case(1_200.milliseconds(), 600.milliseconds(), 600.milliseconds())] +#[case((-1_200).milliseconds(), (-600).milliseconds(), (-600).milliseconds())] +fn saturating_sub(#[case] a: Duration, #[case] b: Duration, #[case] expected: Duration) { + assert_eq!(a.saturating_sub(b), expected); +} + +#[rstest] +#[case(5.seconds(), 2, 10.seconds())] +#[case(5.seconds(), -2, (-10).seconds())] +#[case(5.seconds(), 0, Duration::ZERO)] +#[case(Duration::MAX, 2, Duration::MAX)] +#[case(Duration::MIN, 2, Duration::MIN)] +#[case(Duration::MAX, -2, Duration::MIN)] +#[case(Duration::MIN, -2, Duration::MAX)] +#[case( + Duration::new(1_844_674_407_370_955_161, 600_000_000), + 5, + Duration::MAX +)] +#[case(Duration::new(1_844_674_407_370_955_161, 800_000_000), -5, Duration::MIN)] +fn saturating_mul(#[case] duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + assert_eq!(duration.saturating_mul(rhs), expected); +} + +#[rstest] +#[timeout(StdDuration::from_millis(100))] fn time_fn() { let (time, value) = Duration::time_fn(|| { std::thread::sleep(1.std_milliseconds()); @@ -475,463 +538,484 @@ fn time_fn() { assert_eq!(value, 0); } -#[allow(clippy::cognitive_complexity)] // all test the same thing -#[test] -fn display() { - assert_eq!(0.seconds().to_string(), "0s"); - assert_eq!(60.days().to_string(), "60d"); - assert_eq!((-48).hours().to_string(), "-2d"); - assert_eq!(48.hours().to_string(), "2d"); - assert_eq!(1.minutes().to_string(), "1m"); - assert_eq!(10.minutes().to_string(), "10m"); - assert_eq!(1.seconds().to_string(), "1s"); - assert_eq!(10.seconds().to_string(), "10s"); - assert_eq!(1.milliseconds().to_string(), "1ms"); - assert_eq!(10.milliseconds().to_string(), "10ms"); - assert_eq!(100.milliseconds().to_string(), "100ms"); - assert_eq!(1.microseconds().to_string(), "1µs"); - assert_eq!(10.microseconds().to_string(), "10µs"); - assert_eq!(100.microseconds().to_string(), "100µs"); - assert_eq!(1.nanoseconds().to_string(), "1ns"); - assert_eq!(10.nanoseconds().to_string(), "10ns"); - assert_eq!(100.nanoseconds().to_string(), "100ns"); - - assert_eq!(1.days().to_string(), "1d"); - assert_eq!(26.hours().to_string(), "1d2h"); - assert_eq!(1_563.minutes().to_string(), "1d2h3m"); - assert_eq!(93_784.seconds().to_string(), "1d2h3m4s"); - assert_eq!(93_784_005.milliseconds().to_string(), "1d2h3m4s5ms"); - assert_eq!(93_784_005_006.microseconds().to_string(), "1d2h3m4s5ms6µs"); - assert_eq!( - 93_784_005_006_007.nanoseconds().to_string(), - "1d2h3m4s5ms6µs7ns" - ); - - assert_eq!(format!("{:.3}", 0.seconds()), "0.000s"); - assert_eq!(format!("{:.3}", 60.days()), "60.000d"); - assert_eq!(format!("{:.3}", (-48).hours()), "-2.000d"); - assert_eq!(format!("{:.3}", 48.hours()), "2.000d"); - assert_eq!(format!("{:.3}", 1.minutes()), "1.000m"); - assert_eq!(format!("{:.3}", 10.minutes()), "10.000m"); - assert_eq!(format!("{:.3}", 1.seconds()), "1.000s"); - assert_eq!(format!("{:.3}", 10.seconds()), "10.000s"); - assert_eq!(format!("{:.3}", 1.milliseconds()), "1.000ms"); - assert_eq!(format!("{:.3}", 10.milliseconds()), "10.000ms"); - assert_eq!(format!("{:.3}", 100.milliseconds()), "100.000ms"); - assert_eq!(format!("{:.3}", 1.microseconds()), "1.000µs"); - assert_eq!(format!("{:.3}", 10.microseconds()), "10.000µs"); - assert_eq!(format!("{:.3}", 100.microseconds()), "100.000µs"); - assert_eq!(format!("{:.3}", 1.nanoseconds()), "1.000ns"); - assert_eq!(format!("{:.3}", 10.nanoseconds()), "10.000ns"); - assert_eq!(format!("{:.3}", 100.nanoseconds()), "100.000ns"); - - assert_eq!(format!("{:.3}", 1.days()), "1.000d"); - assert_eq!(format!("{:.3}", 26.hours()), "1.083d"); - assert_eq!(format!("{:.4}", 1_563.minutes()), "1.0854d"); - assert_eq!(format!("{:.5}", 93_784.seconds()), "1.08546d"); - assert_eq!(format!("{:.6}", 93_784_005.milliseconds()), "1.085463d"); - assert_eq!( - format!("{:.9}", 93_784_005_006.microseconds()), - "1.085463021d" - ); - assert_eq!( - format!("{:.12}", 93_784_005_006_007.nanoseconds()), - "1.085463020903d" - ); -} - -#[test] -fn try_from_std_duration() { - assert_eq!(Duration::try_from(0.std_seconds()), Ok(0.seconds())); - assert_eq!(Duration::try_from(1.std_seconds()), Ok(1.seconds())); - assert_eq!( - Duration::try_from(u64::MAX.std_seconds()), - Err(error::ConversionRange) - ); -} - -#[test] -fn try_to_std_duration() { - assert_eq!(StdDuration::try_from(0.seconds()), Ok(0.std_seconds())); - assert_eq!(StdDuration::try_from(1.seconds()), Ok(1.std_seconds())); - assert!(StdDuration::try_from((-1).seconds()).is_err()); - assert_eq!( - StdDuration::try_from((-500).milliseconds()), - Err(error::ConversionRange) - ); -} - -#[test] -fn add() { - assert_eq!(1.seconds() + 1.seconds(), 2.seconds()); - assert_eq!(500.milliseconds() + 500.milliseconds(), 1.seconds()); - assert_eq!(1.seconds() + (-1).seconds(), 0.seconds()); -} - -#[test] -fn add_std() { - assert_eq!(1.seconds() + 1.std_seconds(), 2.seconds()); - assert_eq!(500.milliseconds() + 500.std_milliseconds(), 1.seconds()); - assert_eq!((-1).seconds() + 1.std_seconds(), 0.seconds()); -} - -#[test] -fn std_add() { - assert_eq!(1.std_seconds() + 1.seconds(), 2.seconds()); - assert_eq!(500.std_milliseconds() + 500.milliseconds(), 1.seconds()); - assert_eq!(1.std_seconds() + (-1).seconds(), 0.seconds()); -} - -#[test] -fn add_assign() { - let mut duration = 1.seconds(); - duration += 1.seconds(); - assert_eq!(duration, 2.seconds()); - - let mut duration = 500.milliseconds(); - duration += 500.milliseconds(); - assert_eq!(duration, 1.seconds()); - - let mut duration = 1.seconds(); - duration += (-1).seconds(); - assert_eq!(duration, 0.seconds()); -} - -#[test] -fn add_assign_std() { - let mut duration = 1.seconds(); - duration += 1.std_seconds(); - assert_eq!(duration, 2.seconds()); - - let mut duration = 500.milliseconds(); - duration += 500.std_milliseconds(); - assert_eq!(duration, 1.seconds()); - - let mut duration = (-1).seconds(); - duration += 1.std_seconds(); - 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()); - assert_eq!(-(-1).seconds(), 1.seconds()); - assert_eq!(-(0.seconds()), 0.seconds()); -} - -#[test] -fn sub() { - assert_eq!(1.seconds() - 1.seconds(), 0.seconds()); - assert_eq!(1_500.milliseconds() - 500.milliseconds(), 1.seconds()); - assert_eq!(1.seconds() - (-1).seconds(), 2.seconds()); -} - -#[test] -fn sub_std() { - assert_eq!(1.seconds() - 1.std_seconds(), 0.seconds()); - assert_eq!(1_500.milliseconds() - 500.std_milliseconds(), 1.seconds()); - assert_eq!((-1).seconds() - 1.std_seconds(), (-2).seconds()); -} - -#[test] -fn std_sub() { - assert_eq!(1.std_seconds() - 1.seconds(), 0.seconds()); - assert_eq!(1_500.std_milliseconds() - 500.milliseconds(), 1.seconds()); - assert_eq!(1.std_seconds() - (-1).seconds(), 2.seconds()); -} - -#[test] -fn sub_assign() { - let mut duration = 1.seconds(); - duration -= 1.seconds(); - assert_eq!(duration, 0.seconds()); - - let mut duration = 1_500.milliseconds(); - duration -= 500.milliseconds(); - assert_eq!(duration, 1.seconds()); - - let mut duration = 1.seconds(); - duration -= (-1).seconds(); - assert_eq!(duration, 2.seconds()); -} - -#[test] -fn sub_assign_std() { - let mut duration = 1.seconds(); - duration -= 1.std_seconds(); - assert_eq!(duration, 0.seconds()); - - let mut duration = 1_500.milliseconds(); - duration -= 500.std_milliseconds(); - assert_eq!(duration, 1.seconds()); - - let mut duration = (-1).seconds(); - duration -= 1.std_seconds(); - assert_eq!(duration, (-2).seconds()); -} - -#[test] -fn std_sub_assign() { - let mut duration = 1.std_seconds(); - duration -= 1.seconds(); - assert_eq!(duration, 0.seconds()); - - let mut duration = 1_500.std_milliseconds(); - duration -= 500.milliseconds(); - assert_eq!(duration, 1.seconds()); -} - -#[test] +#[rstest] +#[case(0.seconds(), "0s")] +#[case(60.days(), "60d")] +#[case((-48).hours(), "-2d")] +#[case(48.hours(), "2d")] +#[case(1.minutes(), "1m")] +#[case(10.minutes(), "10m")] +#[case(1.seconds(), "1s")] +#[case(10.seconds(), "10s")] +#[case(1.milliseconds(), "1ms")] +#[case(10.milliseconds(), "10ms")] +#[case(100.milliseconds(), "100ms")] +#[case(1.microseconds(), "1µs")] +#[case(10.microseconds(), "10µs")] +#[case(100.microseconds(), "100µs")] +#[case(1.nanoseconds(), "1ns")] +#[case(10.nanoseconds(), "10ns")] +#[case(100.nanoseconds(), "100ns")] +fn display_basic(#[case] duration: Duration, #[case] expected: &str) { + assert_eq!(duration.to_string(), expected); +} + +#[rstest] +#[case(1.days(), "1d")] +#[case(26.hours(), "1d2h")] +#[case(1_563.minutes(), "1d2h3m")] +#[case(93_784.seconds(), "1d2h3m4s")] +#[case(93_784_005.milliseconds(), "1d2h3m4s5ms")] +#[case(93_784_005_006.microseconds(), "1d2h3m4s5ms6µs")] +#[case(93_784_005_006_007.nanoseconds(), "1d2h3m4s5ms6µs7ns")] +fn display_compound(#[case] duration: Duration, #[case] expected: &str) { + assert_eq!(duration.to_string(), expected); +} + +#[rstest] +#[case(0.seconds(), 3, "0.000s")] +#[case(60.days(), 3, "60.000d")] +#[case((-48).hours(), 3, "-2.000d")] +#[case(48.hours(), 3, "2.000d")] +#[case(1.minutes(), 3, "1.000m")] +#[case(10.minutes(), 3, "10.000m")] +#[case(1.seconds(), 3, "1.000s")] +#[case(10.seconds(), 3, "10.000s")] +#[case(1.milliseconds(), 3, "1.000ms")] +#[case(10.milliseconds(), 3, "10.000ms")] +#[case(100.milliseconds(), 3, "100.000ms")] +#[case(1.microseconds(), 3, "1.000µs")] +#[case(10.microseconds(), 3, "10.000µs")] +#[case(100.microseconds(), 3, "100.000µs")] +#[case(1.nanoseconds(), 3, "1.000ns")] +#[case(10.nanoseconds(), 3, "10.000ns")] +#[case(100.nanoseconds(), 3, "100.000ns")] +#[case(1.days(), 3, "1.000d")] +#[case(26.hours(), 3, "1.083d")] +#[case(1_563.minutes(), 4, "1.0854d")] +#[case(93_784.seconds(), 5, "1.08546d")] +#[case(93_784_005.milliseconds(), 6, "1.085463d")] +#[case(93_784_005_006.microseconds(), 9, "1.085463021d")] +#[case(93_784_005_006_007.nanoseconds(), 12, "1.085463020903d")] +fn display_precision(#[case] duration: Duration, #[case] precision: usize, #[case] expected: &str) { + assert_eq!(format!("{duration:.precision$}"), expected); +} + +#[rstest] +#[case(0.std_seconds(), 0.seconds())] +#[case(1.std_seconds(), 1.seconds())] +fn try_from_std_duration_success(#[case] std_duration: StdDuration, #[case] expected: Duration) { + assert_eq!(Duration::try_from(std_duration), Ok(expected)); +} + +#[rstest] +#[case(u64::MAX.std_seconds(), error::ConversionRange)] +fn try_from_std_duration_error( + #[case] std_duration: StdDuration, + #[case] expected: error::ConversionRange, +) { + assert_eq!(Duration::try_from(std_duration), Err(expected)); +} + +#[rstest] +#[case(0.seconds(), 0.std_seconds())] +#[case(1.seconds(), 1.std_seconds())] +fn try_to_std_duration_success(#[case] duration: Duration, #[case] expected: StdDuration) { + assert_eq!(StdDuration::try_from(duration), Ok(expected)); +} + +#[rstest] +#[case((-1).seconds())] +#[case((-500).milliseconds())] +fn try_to_std_duration_error(#[case] duration: Duration) { + assert_eq!(StdDuration::try_from(duration), Err(error::ConversionRange)); +} + +#[rstest] +#[case(1.seconds(), 1.seconds(), 2.seconds())] +#[case(500.milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.seconds(), (-1).seconds(), 0.seconds())] +fn add(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: Duration) { + assert_eq!(lhs + rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds(), 2.seconds())] +#[case(500.milliseconds(), 500.std_milliseconds(), 1.seconds())] +#[case((-1).seconds(), 1.std_seconds(), 0.seconds())] +fn add_std(#[case] lhs: Duration, #[case] rhs: StdDuration, #[case] expected: Duration) { + assert_eq!(lhs + rhs, expected); +} + +#[rstest] +#[case(1.std_seconds(), 1.seconds(), 2.seconds())] +#[case(500.std_milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.std_seconds(), (-1).seconds(), 0.seconds())] +fn std_add(#[case] lhs: StdDuration, #[case] rhs: Duration, #[case] expected: Duration) { + assert_eq!(lhs + rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.seconds(), 2.seconds())] +#[case(500.milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.seconds(), (-1).seconds(), 0.seconds())] +fn add_assign(#[case] mut duration: Duration, #[case] other: Duration, #[case] expected: Duration) { + duration += other; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds(), 2.seconds())] +#[case(500.milliseconds(), 500.std_milliseconds(), 1.seconds())] +#[case((-1).seconds(), 1.std_seconds(), 0.seconds())] +fn add_assign_std( + #[case] mut duration: Duration, + #[case] other: StdDuration, + #[case] expected: Duration, +) { + duration += other; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.std_seconds(), 1.seconds(), 2.seconds())] +#[case(500.std_milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.std_seconds(), (-1).seconds(), 0.seconds())] +fn std_add_assign( + #[case] mut duration: StdDuration, + #[case] other: Duration, + #[case] expected: Duration, +) { + duration += other; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), (-1).seconds())] +#[case((-1).seconds(), 1.seconds())] +#[case(0.seconds(), 0.seconds())] +fn neg(#[case] duration: Duration, #[case] expected: Duration) { + assert_eq!(-duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.seconds(), 0.seconds())] +#[case(1_500.milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.seconds(), (-1).seconds(), 2.seconds())] +fn sub(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: Duration) { + assert_eq!(lhs - rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds(), 0.seconds())] +#[case(1_500.milliseconds(), 500.std_milliseconds(), 1.seconds())] +#[case((-1).seconds(), 1.std_seconds(), -(2.seconds()))] +fn sub_std(#[case] lhs: Duration, #[case] rhs: StdDuration, #[case] expected: Duration) { + assert_eq!(lhs - rhs, expected); +} + +#[rstest] +#[case(1.std_seconds(), 1.seconds(), 0.seconds())] +#[case(1_500.std_milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.std_seconds(), (-1).seconds(), 2.seconds())] +fn std_sub(#[case] lhs: StdDuration, #[case] rhs: Duration, #[case] expected: Duration) { + assert_eq!(lhs - rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.seconds(), 0.seconds())] +#[case(1_500.milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.seconds(), (-1).seconds(), 2.seconds())] +fn sub_assign(#[case] mut duration: Duration, #[case] other: Duration, #[case] expected: Duration) { + duration -= other; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds(), 0.seconds())] +#[case(1_500.milliseconds(), 500.std_milliseconds(), 1.seconds())] +#[case((-1).seconds(), 1.std_seconds(), -(2.seconds()))] +fn sub_assign_std( + #[case] mut duration: Duration, + #[case] other: StdDuration, + #[case] expected: Duration, +) { + duration -= other; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.std_seconds(), 1.seconds(), 0.seconds())] +#[case(1_500.std_milliseconds(), 500.milliseconds(), 1.seconds())] +#[case(1.std_seconds(), (-1).seconds(), 2.seconds())] +fn std_sub_assign( + #[case] mut duration: StdDuration, + #[case] other: Duration, + #[case] expected: Duration, +) { + duration -= other; + assert_eq!(duration, expected); +} + +#[rstest] #[should_panic] fn std_sub_assign_overflow() { let mut duration = 1.std_seconds(); duration -= 2.seconds(); } -#[test] -fn mul_int() { - assert_eq!(1.seconds() * 2, 2.seconds()); - assert_eq!(1.seconds() * -2, (-2).seconds()); - - assert_panic!(Duration::MAX * 2); - assert_panic!(Duration::MIN * 2); -} - -#[test] -fn mul_int_assign() { - let mut duration = 1.seconds(); - duration *= 2; - assert_eq!(duration, 2.seconds()); - - let mut duration = 1.seconds(); - duration *= -2; - assert_eq!(duration, (-2).seconds()); +#[rstest] +#[case(1.seconds(), 2, 2.seconds())] +#[case(1.seconds(), -2, (-2).seconds())] +fn mul_int_success(#[case] duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + assert_eq!(duration * rhs, expected); } -#[test] -fn int_mul() { - assert_eq!(2 * 1.seconds(), 2.seconds()); - assert_eq!(-2 * 1.seconds(), (-2).seconds()); +#[rstest] +#[case(Duration::MAX, 2)] +#[case(Duration::MIN, 2)] +#[should_panic] +fn mul_int_panic(#[case] duration: Duration, #[case] rhs: i32) { + let _ = duration * rhs; } -#[test] -fn div_int() { - assert_eq!(1.seconds() / 2, 500.milliseconds()); - assert_eq!(1.seconds() / -2, (-500).milliseconds()); +#[rstest] +#[case(1.seconds(), 2, 2.seconds())] +#[case(1.seconds(), -2, (-2).seconds())] +fn mul_int_assign(#[case] mut duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + duration *= rhs; + assert_eq!(duration, expected); } -#[test] -fn div_int_assign() { - let mut duration = 1.seconds(); - duration /= 2; - assert_eq!(duration, 500.milliseconds()); - - let mut duration = 1.seconds(); - duration /= -2; - assert_eq!(duration, (-500).milliseconds()); +#[rstest] +#[case(2, 1.seconds(), 2.seconds())] +#[case(-2, 1.seconds(), (-2).seconds())] +fn int_mul(#[case] lhs: i32, #[case] duration: Duration, #[case] expected: Duration) { + assert_eq!(lhs * duration, expected); } -#[test] -#[allow(clippy::float_cmp)] -fn div() { - assert_eq!(1.seconds() / 0.5.seconds(), 2.); - assert_eq!(1.std_seconds() / 0.5.seconds(), 2.); - assert_eq!(1.seconds() / 0.5.std_seconds(), 2.); +#[rstest] +#[case(1.seconds(), 2, 500.milliseconds())] +#[case(1.seconds(), -2, (-500).milliseconds())] +fn div_int(#[case] duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + assert_eq!(duration / rhs, expected); } -#[test] -fn mul_float() { - assert_eq!(1.seconds() * 1.5_f32, 1_500.milliseconds()); - assert_eq!(1.seconds() * 2.5_f32, 2_500.milliseconds()); - assert_eq!(1.seconds() * -1.5_f32, (-1_500).milliseconds()); - assert_eq!(1.seconds() * 0_f32, 0.seconds()); - - assert_eq!(1.seconds() * 1.5_f64, 1_500.milliseconds()); - assert_eq!(1.seconds() * 2.5_f64, 2_500.milliseconds()); - assert_eq!(1.seconds() * -1.5_f64, (-1_500).milliseconds()); - assert_eq!(1.seconds() * 0_f64, 0.seconds()); +#[rstest] +#[case(1.seconds(), 2, 500.milliseconds())] +#[case(1.seconds(), -2, (-500).milliseconds())] +fn div_int_assign(#[case] mut duration: Duration, #[case] rhs: i32, #[case] expected: Duration) { + duration /= rhs; + assert_eq!(duration, expected); } -#[test] -fn float_mul() { - assert_eq!(1.5_f32 * 1.seconds(), 1_500.milliseconds()); - assert_eq!(2.5_f32 * 1.seconds(), 2_500.milliseconds()); - assert_eq!(-1.5_f32 * 1.seconds(), (-1_500).milliseconds()); - assert_eq!(0_f32 * 1.seconds(), 0.seconds()); - - assert_eq!(1.5_f64 * 1.seconds(), 1_500.milliseconds()); - assert_eq!(2.5_f64 * 1.seconds(), 2_500.milliseconds()); - assert_eq!(-1.5_f64 * 1.seconds(), (-1_500).milliseconds()); - assert_eq!(0_f64 * 1.seconds(), 0.seconds()); +#[rstest] +#[case(1.seconds(), 0.5.seconds(), 2.)] +#[case(2.seconds(), 0.25.seconds(), 8.)] +#[allow(clippy::float_cmp)] +fn div(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: f64) { + assert_eq!(lhs / rhs, expected); } -#[test] -fn mul_float_assign() { - let mut duration = 1.seconds(); - duration *= 1.5_f32; - assert_eq!(duration, 1_500.milliseconds()); - - let mut duration = 1.seconds(); - duration *= 2.5_f32; - assert_eq!(duration, 2_500.milliseconds()); - - let mut duration = 1.seconds(); - duration *= -1.5_f32; - assert_eq!(duration, (-1_500).milliseconds()); - - let mut duration = 1.seconds(); - duration *= 0_f32; - assert_eq!(duration, 0.seconds()); - - let mut duration = 1.seconds(); - duration *= 1.5_f64; - assert_eq!(duration, 1_500.milliseconds()); - - let mut duration = 1.seconds(); - duration *= 2.5_f64; - assert_eq!(duration, 2_500.milliseconds()); - - let mut duration = 1.seconds(); - duration *= -1.5_f64; - assert_eq!(duration, (-1_500).milliseconds()); - - let mut duration = 1.seconds(); - duration *= 0_f64; - assert_eq!(duration, 0.seconds()); -} - -#[test] -fn div_float() { - assert_eq!(1.seconds() / 1_f32, 1.seconds()); - assert_eq!(1.seconds() / 2_f32, 500.milliseconds()); - assert_eq!(1.seconds() / -1_f32, (-1).seconds()); - - assert_eq!(1.seconds() / 1_f64, 1.seconds()); - assert_eq!(1.seconds() / 2_f64, 500.milliseconds()); - assert_eq!(1.seconds() / -1_f64, (-1).seconds()); -} - -#[test] -fn div_float_assign() { - let mut duration = 1.seconds(); - duration /= 1_f32; - assert_eq!(duration, 1.seconds()); - - let mut duration = 1.seconds(); - duration /= 2_f32; - assert_eq!(duration, 500.milliseconds()); - - let mut duration = 1.seconds(); - duration /= -1_f32; - assert_eq!(duration, (-1).seconds()); - - let mut duration = 1.seconds(); - duration /= 1_f64; - assert_eq!(duration, 1.seconds()); - - let mut duration = 1.seconds(); - duration /= 2_f64; - assert_eq!(duration, 500.milliseconds()); - - let mut duration = 1.seconds(); - duration /= -1_f64; - assert_eq!(duration, (-1).seconds()); -} - -#[test] -fn partial_eq() { - assert_eq!(1.seconds(), 1.seconds()); - assert_eq!(0.seconds(), 0.seconds()); - assert_eq!((-1).seconds(), (-1).seconds()); - assert_ne!(1.minutes(), (-1).minutes()); - assert_ne!(40.seconds(), 1.minutes()); -} - -#[test] -fn partial_eq_std() { - assert_eq!(1.seconds(), 1.std_seconds()); - assert_eq!(0.seconds(), 0.std_seconds()); - assert_ne!((-1).seconds(), 1.std_seconds()); - assert_ne!((-1).minutes(), 1.std_minutes()); - assert_ne!(40.seconds(), 1.std_minutes()); -} - -#[test] -fn std_partial_eq() { - assert_eq!(1.std_seconds(), 1.seconds()); - assert_eq!(0.std_seconds(), 0.seconds()); - assert_ne!(1.std_seconds(), (-1).seconds()); - assert_ne!(1.std_minutes(), (-1).minutes()); - assert_ne!(40.std_seconds(), 1.minutes()); -} - -#[test] -fn partial_ord() { - use Ordering::*; - assert_eq!(0.seconds().partial_cmp(&0.seconds()), Some(Equal)); - assert_eq!(1.seconds().partial_cmp(&0.seconds()), Some(Greater)); - assert_eq!(1.seconds().partial_cmp(&(-1).seconds()), Some(Greater)); - assert_eq!((-1).seconds().partial_cmp(&1.seconds()), Some(Less)); - assert_eq!(0.seconds().partial_cmp(&(-1).seconds()), Some(Greater)); - assert_eq!(0.seconds().partial_cmp(&1.seconds()), Some(Less)); - assert_eq!((-1).seconds().partial_cmp(&0.seconds()), Some(Less)); - assert_eq!(1.minutes().partial_cmp(&1.seconds()), Some(Greater)); - assert_eq!((-1).minutes().partial_cmp(&(-1).seconds()), Some(Less)); -} - -#[test] -fn partial_ord_std() { - use Ordering::*; - assert_eq!(0.seconds().partial_cmp(&0.std_seconds()), Some(Equal)); - assert_eq!(1.seconds().partial_cmp(&0.std_seconds()), Some(Greater)); - assert_eq!((-1).seconds().partial_cmp(&1.std_seconds()), Some(Less)); - assert_eq!(0.seconds().partial_cmp(&1.std_seconds()), Some(Less)); - assert_eq!((-1).seconds().partial_cmp(&0.std_seconds()), Some(Less)); - assert_eq!(1.minutes().partial_cmp(&1.std_seconds()), Some(Greater)); - assert_eq!(0.seconds().partial_cmp(&u64::MAX.std_seconds()), Some(Less)); -} - -#[test] -fn std_partial_ord() { - use Ordering::*; - assert_eq!(0.std_seconds().partial_cmp(&0.seconds()), Some(Equal)); - assert_eq!(1.std_seconds().partial_cmp(&0.seconds()), Some(Greater)); - assert_eq!(1.std_seconds().partial_cmp(&(-1).seconds()), Some(Greater)); - assert_eq!(0.std_seconds().partial_cmp(&(-1).seconds()), Some(Greater)); - assert_eq!(0.std_seconds().partial_cmp(&1.seconds()), Some(Less)); - assert_eq!(1.std_minutes().partial_cmp(&1.seconds()), Some(Greater)); -} - -#[test] -fn ord() { - assert_eq!(0.seconds().cmp(&0.seconds()), Ordering::Equal); - assert_eq!(1.seconds().cmp(&0.seconds()), Ordering::Greater); - assert_eq!(1.seconds().cmp(&(-1).seconds()), Ordering::Greater); - assert_eq!((-1).seconds().cmp(&1.seconds()), Ordering::Less); - assert_eq!(0.seconds().cmp(&(-1).seconds()), Ordering::Greater); - assert_eq!(0.seconds().cmp(&1.seconds()), Ordering::Less); - assert_eq!((-1).seconds().cmp(&0.seconds()), Ordering::Less); - assert_eq!(1.minutes().cmp(&1.seconds()), Ordering::Greater); - assert_eq!((-1).minutes().cmp(&(-1).seconds()), Ordering::Less); - assert_eq!(100.nanoseconds().cmp(&200.nanoseconds()), Ordering::Less); - assert_eq!( - (-100).nanoseconds().cmp(&(-200).nanoseconds()), - Ordering::Greater - ); +#[rstest] +#[case(1.seconds(), 0.5.std_seconds(), 2.)] +#[case(2.seconds(), 0.25.std_seconds(), 8.)] +#[allow(clippy::float_cmp)] +fn div_std(#[case] lhs: Duration, #[case] rhs: StdDuration, #[case] expected: f64) { + assert_eq!(lhs / rhs, expected); } -#[test] +#[rstest] +#[case(1.std_seconds(), 0.5.seconds(), 2.)] +#[case(2.std_seconds(), 0.25.seconds(), 8.)] +#[allow(clippy::float_cmp)] +fn std_div(#[case] lhs: StdDuration, #[case] rhs: Duration, #[case] expected: f64) { + assert_eq!(lhs / rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.5, 1_500.milliseconds())] +#[case(1.seconds(), 2.5, 2_500.milliseconds())] +#[case(1.seconds(), -1.5, (-1_500).milliseconds())] +#[case(1.seconds(), 0., 0.seconds())] +fn mul_f32(#[case] duration: Duration, #[case] rhs: f32, #[case] expected: Duration) { + assert_eq!(duration * rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.5, 1_500.milliseconds())] +#[case(1.seconds(), 2.5, 2_500.milliseconds())] +#[case(1.seconds(), -1.5, (-1_500).milliseconds())] +#[case(1.seconds(), 0., 0.seconds())] +fn mul_f64(#[case] duration: Duration, #[case] rhs: f64, #[case] expected: Duration) { + assert_eq!(duration * rhs, expected); +} + +#[rstest] +#[case(1.5, 1.seconds(), 1_500.milliseconds())] +#[case(2.5, 1.seconds(), 2_500.milliseconds())] +#[case(-1.5, 1.seconds(), (-1_500).milliseconds())] +#[case(0., 1.seconds(), 0.seconds())] +fn f32_mul(#[case] lhs: f32, #[case] duration: Duration, #[case] expected: Duration) { + assert_eq!(lhs * duration, expected); +} + +#[rstest] +#[case(1.5, 1.seconds(), 1_500.milliseconds())] +#[case(2.5, 1.seconds(), 2_500.milliseconds())] +#[case(-1.5, 1.seconds(), (-1_500).milliseconds())] +#[case(0., 1.seconds(), 0.seconds())] +fn f64_mul(#[case] lhs: f64, #[case] duration: Duration, #[case] expected: Duration) { + assert_eq!(lhs * duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.5, 1_500.milliseconds())] +#[case(1.seconds(), 2.5, 2_500.milliseconds())] +#[case(1.seconds(), -1.5, (-1_500).milliseconds())] +#[case(1.seconds(), 0., 0.seconds())] +fn mul_f32_assign(#[case] mut duration: Duration, #[case] rhs: f32, #[case] expected: Duration) { + duration *= rhs; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.5, 1_500.milliseconds())] +#[case(1.seconds(), 2.5, 2_500.milliseconds())] +#[case(1.seconds(), -1.5, (-1_500).milliseconds())] +#[case(1.seconds(), 0., 0.seconds())] +fn mul_f64_assign(#[case] mut duration: Duration, #[case] rhs: f64, #[case] expected: Duration) { + duration *= rhs; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1., 1.seconds())] +#[case(1.seconds(), 2., 500.milliseconds())] +#[case(1.seconds(), 4., 250.milliseconds())] +#[case(1.seconds(), 0.25, 4.seconds())] +#[case(1.seconds(), -1., (-1).seconds())] +fn div_f32(#[case] duration: Duration, #[case] rhs: f32, #[case] expected: Duration) { + assert_eq!(duration / rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1., 1.seconds())] +#[case(1.seconds(), 2., 500.milliseconds())] +#[case(1.seconds(), 4., 250.milliseconds())] +#[case(1.seconds(), 0.25, 4.seconds())] +#[case(1.seconds(), -1., (-1).seconds())] +fn div_f64(#[case] duration: Duration, #[case] rhs: f64, #[case] expected: Duration) { + assert_eq!(duration / rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1., 1.seconds())] +#[case(1.seconds(), 2., 500.milliseconds())] +#[case(1.seconds(), 4., 250.milliseconds())] +#[case(1.seconds(), 0.25, 4.seconds())] +#[case(1.seconds(), -1., (-1).seconds())] +fn div_f32_assign(#[case] mut duration: Duration, #[case] rhs: f32, #[case] expected: Duration) { + duration /= rhs; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1., 1.seconds())] +#[case(1.seconds(), 2., 500.milliseconds())] +#[case(1.seconds(), 4., 250.milliseconds())] +#[case(1.seconds(), 0.25, 4.seconds())] +#[case(1.seconds(), -1., (-1).seconds())] +fn div_f64_assign(#[case] mut duration: Duration, #[case] rhs: f64, #[case] expected: Duration) { + duration /= rhs; + assert_eq!(duration, expected); +} + +#[rstest] +#[case(1.seconds(), 1.seconds(), true)] +#[case(0.seconds(), 0.seconds(), true)] +#[case(1.seconds(), 2.seconds(), false)] +#[case(1.seconds(), (-1).seconds(), false)] +#[case((-1).seconds(), (-1).seconds(), true)] +#[case(40.seconds(), 1.minutes(), false)] +fn partial_eq(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: bool) { + assert_eq_ne!(lhs, rhs, expected); +} + +#[rstest] +#[case(1.seconds(), 1.std_seconds(), true)] +#[case(0.seconds(), 0.std_seconds(), true)] +#[case(1.seconds(), 2.std_seconds(), false)] +#[case((-1).seconds(), 1.std_seconds(), false)] +#[case(40.seconds(), 1.std_minutes(), false)] +fn partial_eq_std(#[case] lhs: Duration, #[case] rhs: StdDuration, #[case] expected: bool) { + assert_eq_ne!(lhs, rhs, expected); +} + +#[rstest] +#[case(1.std_seconds(), 1.seconds(), true)] +#[case(0.std_seconds(), 0.seconds(), true)] +#[case(2.std_seconds(), 1.seconds(), false)] +#[case(1.std_seconds(), (-1).seconds(), false)] +#[case(1.std_minutes(), 40.seconds(), false)] +fn std_partial_eq(#[case] lhs: StdDuration, #[case] rhs: Duration, #[case] expected: bool) { + assert_eq_ne!(lhs, rhs, expected); +} + +#[rstest] +#[case(0.seconds(), 0.seconds(), Equal)] +#[case(1.seconds(), 0.seconds(), Greater)] +#[case(1.seconds(), (-1).seconds(), Greater)] +#[case((-1).seconds(), 1.seconds(), Less)] +#[case(0.seconds(), (-1).seconds(), Greater)] +#[case(0.seconds(), 1.seconds(), Less)] +#[case((-1).seconds(), 0.seconds(), Less)] +#[case(1.minutes(), 1.seconds(), Greater)] +#[case((-1).minutes(), (-1).seconds(), Less)] +fn partial_ord(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: Ordering) { + assert_eq!(lhs.partial_cmp(&rhs), Some(expected)); +} + +#[rstest] +#[case(0.seconds(), 0.std_seconds(), Equal)] +#[case(1.seconds(), 0.std_seconds(), Greater)] +#[case((-1).seconds(), 1.std_seconds(), Less)] +#[case(0.seconds(), 1.std_seconds(), Less)] +#[case((-1).seconds(), 0.std_seconds(), Less)] +#[case(1.minutes(), 1.std_seconds(), Greater)] +#[case(0.seconds(), u64::MAX.std_seconds(), Less)] +fn partial_ord_std(#[case] lhs: Duration, #[case] rhs: StdDuration, #[case] expected: Ordering) { + assert_eq!(lhs.partial_cmp(&rhs), Some(expected)); +} + +#[rstest] +#[case(0.std_seconds(), 0.seconds(), Equal)] +#[case(1.std_seconds(), 0.seconds(), Greater)] +#[case(1.std_seconds(), (-1).seconds(), Greater)] +#[case(0.std_seconds(), (-1).seconds(), Greater)] +#[case(0.std_seconds(), 1.seconds(), Less)] +#[case(1.std_minutes(), 1.seconds(), Greater)] +fn std_partial_ord(#[case] lhs: StdDuration, #[case] rhs: Duration, #[case] expected: Ordering) { + assert_eq!(lhs.partial_cmp(&rhs), Some(expected)); +} + +#[rstest] +#[case(0.seconds(), 0.seconds(), Equal)] +#[case(1.seconds(), 0.seconds(), Greater)] +#[case(1.seconds(), (-1).seconds(), Greater)] +#[case((-1).seconds(), 1.seconds(), Less)] +#[case(0.seconds(), (-1).seconds(), Greater)] +#[case(0.seconds(), 1.seconds(), Less)] +#[case((-1).seconds(), 0.seconds(), Less)] +#[case(1.minutes(), 1.seconds(), Greater)] +#[case((-1).minutes(), (-1).seconds(), Less)] +#[case(100.nanoseconds(), 200.nanoseconds(), Less)] +#[case((-100).nanoseconds(), (-200).nanoseconds(), Greater)] +fn ord(#[case] lhs: Duration, #[case] rhs: Duration, #[case] expected: Ordering) { + assert_eq!(lhs.cmp(&rhs), expected); +} + +#[rstest] fn arithmetic_regression() { let added = 1.6.seconds() + 1.6.seconds(); assert_eq!(added.whole_seconds(), 3); @@ -942,14 +1026,14 @@ fn arithmetic_regression() { assert_eq!(subtracted.subsec_milliseconds(), 200); } -#[test] +#[rstest] fn sum_iter_ref() { let i = [1.6.seconds(), 1.6.seconds()]; let sum = i.iter().sum::(); assert_eq!(sum, 3.2.seconds()); } -#[test] +#[rstest] fn sum_iter() { let i = [1.6.seconds(), 1.6.seconds()]; let sum = i.into_iter().sum::(); diff --git a/tests/macros.rs b/tests/macros.rs index 75c5e11be..cc0103e6f 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,11 +1,12 @@ use core::num::NonZeroU16; +use rstest::rstest; use time::format_description::modifier::*; use time::format_description::{Component, FormatItem}; use time::macros::{date, format_description, time}; use time::{Date, Time}; -#[test] +#[rstest] fn nontrivial_string() { assert!(format_description!(r"").is_empty()); assert!(format_description!(r###""###).is_empty()); @@ -26,7 +27,7 @@ fn nontrivial_string() { ); } -#[test] +#[rstest] fn format_description_version() { assert_eq!( format_description!(version = 1, "[["), @@ -42,7 +43,7 @@ fn format_description_version() { ); } -#[test] +#[rstest] fn nested_v1() { assert_eq!( format_description!(version = 1, "[optional [[[]]"), @@ -65,7 +66,7 @@ fn nested_v1() { ); } -#[test] +#[rstest] fn optional() { assert_eq!( format_description!(version = 2, "[optional [:[year]]]"), @@ -94,7 +95,7 @@ fn optional() { ); } -#[test] +#[rstest] fn first() { assert_eq!( format_description!(version = 2, "[first [a]]"), @@ -146,7 +147,7 @@ fn first() { ); } -#[test] +#[rstest] fn backslash_escape() { assert_eq!( format_description!(version = 2, r"[optional [\]]]"), @@ -194,7 +195,7 @@ fn backslash_escape() { ); } -#[test] +#[rstest] fn format_description_coverage() { assert_eq!( format_description!("[day padding:space][day padding:zero][day padding:none]"), @@ -315,7 +316,7 @@ fn format_description_coverage() { ); } -#[test] +#[rstest] fn date_coverage() { assert_eq!(Ok(date!(2000 - 001)), Date::from_ordinal_date(2000, 1)); assert_eq!(Ok(date!(2019-W 01-1)), Date::from_ordinal_date(2018, 365)); @@ -323,7 +324,7 @@ fn date_coverage() { assert_eq!(Ok(date!(2021-W 34-5)), Date::from_ordinal_date(2021, 239)); } -#[test] +#[rstest] fn time_coverage() { assert_eq!(time!(12 AM), Time::MIDNIGHT); assert_eq!(Ok(time!(12 PM)), Time::from_hms(12, 0, 0)); diff --git a/tests/main.rs b/tests/main.rs index 365f8b228..978d87b51 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -103,6 +103,19 @@ require_all_features! { } } + /// `assert_eq!` or `assert_ne!` depending on the value of `$is_eq`. + /// + /// This provides better diagnostics than `assert_eq!($left == $right, $is_eq)`. + macro_rules! assert_eq_ne { + ($left:expr, $right:expr, $is_eq:expr $(, $($rest:tt)*)?) => {{ + if $is_eq { + assert_eq!($left, $right $(, $($rest)*)?); + } else { + assert_ne!($left, $right $(, $($rest)*)?); + } + }} + } + mod date; mod derives; mod duration; diff --git a/tests/month.rs b/tests/month.rs index 44cba6cdc..867241627 100644 --- a/tests/month.rs +++ b/tests/month.rs @@ -1,170 +1,178 @@ +use rstest::rstest; use time::Month::{self, *}; -#[test] -fn previous() { - assert_eq!(January.previous(), December); - assert_eq!(February.previous(), January); - assert_eq!(March.previous(), February); - assert_eq!(April.previous(), March); - assert_eq!(May.previous(), April); - assert_eq!(June.previous(), May); - assert_eq!(July.previous(), June); - assert_eq!(August.previous(), July); - assert_eq!(September.previous(), August); - assert_eq!(October.previous(), September); - assert_eq!(November.previous(), October); - assert_eq!(December.previous(), November); +#[rstest] +#[case(January, December)] +#[case(February, January)] +#[case(March, February)] +#[case(April, March)] +#[case(May, April)] +#[case(June, May)] +#[case(July, June)] +#[case(August, July)] +#[case(September, August)] +#[case(October, September)] +#[case(November, October)] +#[case(December, November)] +fn previous(#[case] month: Month, #[case] expected: Month) { + assert_eq!(month.previous(), expected); } -#[test] -fn next() { - assert_eq!(January.next(), February); - assert_eq!(February.next(), March); - assert_eq!(March.next(), April); - assert_eq!(April.next(), May); - assert_eq!(May.next(), June); - assert_eq!(June.next(), July); - assert_eq!(July.next(), August); - assert_eq!(August.next(), September); - assert_eq!(September.next(), October); - assert_eq!(October.next(), November); - assert_eq!(November.next(), December); - assert_eq!(December.next(), January); +#[rstest] +#[case(January, February)] +#[case(February, March)] +#[case(March, April)] +#[case(April, May)] +#[case(May, June)] +#[case(June, July)] +#[case(July, August)] +#[case(August, September)] +#[case(September, October)] +#[case(October, November)] +#[case(November, December)] +#[case(December, January)] +fn next(#[case] month: Month, #[case] expected: Month) { + assert_eq!(month.next(), expected); } -#[allow(clippy::cognitive_complexity)] // all test the same thing -#[test] -fn nth_next() { - assert_eq!(January.nth_next(0), January); - assert_eq!(January.nth_next(1), February); - assert_eq!(January.nth_next(2), March); - assert_eq!(January.nth_next(3), April); - assert_eq!(January.nth_next(4), May); - assert_eq!(January.nth_next(5), June); - assert_eq!(January.nth_next(6), July); - assert_eq!(January.nth_next(7), August); - assert_eq!(January.nth_next(8), September); - assert_eq!(January.nth_next(9), October); - assert_eq!(January.nth_next(10), November); - assert_eq!(January.nth_next(11), December); - - assert_eq!(December.nth_next(0), December); - assert_eq!(December.nth_next(1), January); - assert_eq!(December.nth_next(2), February); - assert_eq!(December.nth_next(3), March); - assert_eq!(December.nth_next(4), April); - assert_eq!(December.nth_next(5), May); - assert_eq!(December.nth_next(6), June); - assert_eq!(December.nth_next(7), July); - assert_eq!(December.nth_next(8), August); - assert_eq!(December.nth_next(9), September); - assert_eq!(December.nth_next(10), October); - assert_eq!(December.nth_next(11), November); - - assert_eq!(January.nth_next(12), January); - assert_eq!(January.nth_next(u8::MAX), April); - assert_eq!(December.nth_next(12), December); - assert_eq!(December.nth_next(u8::MAX), March); +#[rstest] +#[case(January, 0, January)] +#[case(January, 1, February)] +#[case(January, 2, March)] +#[case(January, 3, April)] +#[case(January, 4, May)] +#[case(January, 5, June)] +#[case(January, 6, July)] +#[case(January, 7, August)] +#[case(January, 8, September)] +#[case(January, 9, October)] +#[case(January, 10, November)] +#[case(January, 11, December)] +#[case(December, 0, December)] +#[case(December, 1, January)] +#[case(December, 2, February)] +#[case(December, 3, March)] +#[case(December, 4, April)] +#[case(December, 5, May)] +#[case(December, 6, June)] +#[case(December, 7, July)] +#[case(December, 8, August)] +#[case(December, 9, September)] +#[case(December, 10, October)] +#[case(December, 11, November)] +#[case(January, 12, January)] +#[case(January, u8::MAX, April)] +#[case(December, 12, December)] +#[case(December, u8::MAX, March)] +fn nth_next(#[case] month: Month, #[case] n: u8, #[case] expected: Month) { + assert_eq!(month.nth_next(n), expected); } -#[allow(clippy::cognitive_complexity)] // all test the same thing -#[test] -fn nth_prev() { - assert_eq!(January.nth_prev(0), January); - assert_eq!(January.nth_prev(1), December); - assert_eq!(January.nth_prev(2), November); - assert_eq!(January.nth_prev(3), October); - assert_eq!(January.nth_prev(4), September); - assert_eq!(January.nth_prev(5), August); - assert_eq!(January.nth_prev(6), July); - assert_eq!(January.nth_prev(7), June); - assert_eq!(January.nth_prev(8), May); - assert_eq!(January.nth_prev(9), April); - assert_eq!(January.nth_prev(10), March); - assert_eq!(January.nth_prev(11), February); - - assert_eq!(December.nth_prev(0), December); - assert_eq!(December.nth_prev(1), November); - assert_eq!(December.nth_prev(2), October); - assert_eq!(December.nth_prev(3), September); - assert_eq!(December.nth_prev(4), August); - assert_eq!(December.nth_prev(5), July); - assert_eq!(December.nth_prev(6), June); - assert_eq!(December.nth_prev(7), May); - assert_eq!(December.nth_prev(8), April); - assert_eq!(December.nth_prev(9), March); - assert_eq!(December.nth_prev(10), February); - assert_eq!(December.nth_prev(11), January); +#[rstest] +#[case(January, 0, January)] +#[case(January, 1, December)] +#[case(January, 2, November)] +#[case(January, 3, October)] +#[case(January, 4, September)] +#[case(January, 5, August)] +#[case(January, 6, July)] +#[case(January, 7, June)] +#[case(January, 8, May)] +#[case(January, 9, April)] +#[case(January, 10, March)] +#[case(January, 11, February)] +#[case(December, 0, December)] +#[case(December, 1, November)] +#[case(December, 2, October)] +#[case(December, 3, September)] +#[case(December, 4, August)] +#[case(December, 5, July)] +#[case(December, 6, June)] +#[case(December, 7, May)] +#[case(December, 8, April)] +#[case(December, 9, March)] +#[case(December, 10, February)] +#[case(December, 11, January)] +#[case(January, 12, January)] +#[case(January, u8::MAX, October)] +#[case(December, 12, December)] +#[case(December, u8::MAX, September)] +fn nth_prev(#[case] month: Month, #[case] n: u8, #[case] expected: Month) { + assert_eq!(month.nth_prev(n), expected); +} - assert_eq!(January.nth_prev(12), January); - assert_eq!(January.nth_prev(u8::MAX), October); - assert_eq!(December.nth_prev(12), December); - assert_eq!(December.nth_prev(u8::MAX), September); +#[rstest] +#[case(January, "January")] +#[case(February, "February")] +#[case(March, "March")] +#[case(April, "April")] +#[case(May, "May")] +#[case(June, "June")] +#[case(July, "July")] +#[case(August, "August")] +#[case(September, "September")] +#[case(October, "October")] +#[case(November, "November")] +#[case(December, "December")] +fn display(#[case] month: Month, #[case] expected: &str) { + assert_eq!(month.to_string(), expected); } -#[test] -fn display() { - assert_eq!(January.to_string(), "January"); - assert_eq!(February.to_string(), "February"); - assert_eq!(March.to_string(), "March"); - assert_eq!(April.to_string(), "April"); - assert_eq!(May.to_string(), "May"); - assert_eq!(June.to_string(), "June"); - assert_eq!(July.to_string(), "July"); - assert_eq!(August.to_string(), "August"); - assert_eq!(September.to_string(), "September"); - assert_eq!(October.to_string(), "October"); - assert_eq!(November.to_string(), "November"); - assert_eq!(December.to_string(), "December"); +#[rstest] +#[case("January", Ok(January))] +#[case("February", Ok(February))] +#[case("March", Ok(March))] +#[case("April", Ok(April))] +#[case("May", Ok(May))] +#[case("June", Ok(June))] +#[case("July", Ok(July))] +#[case("August", Ok(August))] +#[case("September", Ok(September))] +#[case("October", Ok(October))] +#[case("November", Ok(November))] +#[case("December", Ok(December))] +#[case("foo", Err(time::error::InvalidVariant))] +fn from_str(#[case] s: &str, #[case] expected: Result) { + assert_eq!(s.parse::(), expected); } -#[test] -fn from_str() { - assert_eq!("January".parse(), Ok(January)); - assert_eq!("February".parse(), Ok(February)); - assert_eq!("March".parse(), Ok(March)); - assert_eq!("April".parse(), Ok(April)); - assert_eq!("May".parse(), Ok(May)); - assert_eq!("June".parse(), Ok(June)); - assert_eq!("July".parse(), Ok(July)); - assert_eq!("August".parse(), Ok(August)); - assert_eq!("September".parse(), Ok(September)); - assert_eq!("October".parse(), Ok(October)); - assert_eq!("November".parse(), Ok(November)); - assert_eq!("December".parse(), Ok(December)); - assert_eq!("foo".parse::(), Err(time::error::InvalidVariant)); +#[rstest] +#[case(January, 1)] +#[case(February, 2)] +#[case(March, 3)] +#[case(April, 4)] +#[case(May, 5)] +#[case(June, 6)] +#[case(July, 7)] +#[case(August, 8)] +#[case(September, 9)] +#[case(October, 10)] +#[case(November, 11)] +#[case(December, 12)] +fn to_u8(#[case] month: Month, #[case] expected: u8) { + assert_eq!(u8::from(month), expected); } -#[test] -fn to_u8() { - assert_eq!(u8::from(January), 1); - assert_eq!(u8::from(February), 2); - assert_eq!(u8::from(March), 3); - assert_eq!(u8::from(April), 4); - assert_eq!(u8::from(May), 5); - assert_eq!(u8::from(June), 6); - assert_eq!(u8::from(July), 7); - assert_eq!(u8::from(August), 8); - assert_eq!(u8::from(September), 9); - assert_eq!(u8::from(October), 10); - assert_eq!(u8::from(November), 11); - assert_eq!(u8::from(December), 12); +#[rstest] +#[case(1, January)] +#[case(2, February)] +#[case(3, March)] +#[case(4, April)] +#[case(5, May)] +#[case(6, June)] +#[case(7, July)] +#[case(8, August)] +#[case(9, September)] +#[case(10, October)] +#[case(11, November)] +#[case(12, December)] +fn try_from_u8_success(#[case] input: u8, #[case] expected: Month) { + assert_eq!(Month::try_from(input), Ok(expected)); } -#[test] -fn try_from_u8() { - assert!(matches!(Month::try_from(0), Err(err) if err.name() == "month")); - assert_eq!(Month::try_from(1), Ok(January)); - assert_eq!(Month::try_from(2), Ok(February)); - assert_eq!(Month::try_from(3), Ok(March)); - assert_eq!(Month::try_from(4), Ok(April)); - assert_eq!(Month::try_from(5), Ok(May)); - assert_eq!(Month::try_from(6), Ok(June)); - assert_eq!(Month::try_from(7), Ok(July)); - assert_eq!(Month::try_from(8), Ok(August)); - assert_eq!(Month::try_from(9), Ok(September)); - assert_eq!(Month::try_from(10), Ok(October)); - assert_eq!(Month::try_from(11), Ok(November)); - assert_eq!(Month::try_from(12), Ok(December)); - assert!(matches!(Month::try_from(13), Err(err) if err.name() == "month")); +#[rstest] +#[case(0)] +#[case(13)] +fn try_from_u8_error(#[case] input: u8) { + assert!(matches!(Month::try_from(input), Err(err) if err.name() == "month")); } diff --git a/tests/parse_format_description.rs b/tests/parse_format_description.rs index f77839926..470086431 100644 --- a/tests/parse_format_description.rs +++ b/tests/parse_format_description.rs @@ -1,147 +1,147 @@ use core::num::NonZeroU16; +use itertools::iproduct; +use rstest::{fixture, rstest}; use time::error::InvalidFormatDescription; use time::format_description::modifier::*; use time::format_description::{self, Component, FormatItem, OwnedFormatItem}; -mod iterator { - use super::*; - - pub(super) fn padding() -> impl Iterator { - [ - (Padding::Space, "padding:space"), - (Padding::Zero, "padding:zero"), - (Padding::None, "padding:none"), - ] - .iter() - .copied() - } +// Use type aliases to avoid writing out the full type in every test. +type PaddingIter = [(Padding, &'static str); 3]; +type HourIs12HourClockIter = [(bool, &'static str); 2]; +type PeriodIsUppercaseIter = [(bool, &'static str); 2]; +type MonthReprIter = [(MonthRepr, &'static str); 3]; +type SubsecondDigitsIter = [(SubsecondDigits, &'static str); 10]; +type WeekdayReprIter = [(WeekdayRepr, &'static str); 4]; +type WeekNumberReprIter = [(WeekNumberRepr, &'static str); 3]; +type YearReprIter = [(YearRepr, &'static str); 2]; +type YearIsIsoWeekBasedIter = [(bool, &'static str); 2]; +type SignIsMandatoryIter = [(bool, &'static str); 2]; +type WeekdayIsOneIndexedIter = [(bool, &'static str); 2]; +type CaseSensitiveIter = [(bool, &'static str); 2]; +type IgnoreCountIter = [(NonZeroU16, &'static str); 6]; +type UnixTimestampPrecisionIter = [(UnixTimestampPrecision, &'static str); 4]; + +// region: fixtures +#[fixture] +fn padding() -> PaddingIter { + [ + (Padding::Space, "padding:space"), + (Padding::Zero, "padding:zero"), + (Padding::None, "padding:none"), + ] +} - pub(super) fn hour_is_12_hour_clock() -> impl Iterator { - [(false, "repr:24"), (true, "repr:12")].iter().copied() - } +#[fixture] +fn hour_is_12_hour_clock() -> HourIs12HourClockIter { + [(false, "repr:24"), (true, "repr:12")] +} - pub(super) fn period_is_uppercase() -> impl Iterator { - [(true, "case:upper"), (false, "case:lower")] - .iter() - .copied() - } +#[fixture] +fn period_is_uppercase() -> PeriodIsUppercaseIter { + [(true, "case:upper"), (false, "case:lower")] +} - pub(super) fn month_repr() -> impl Iterator { - [ - (MonthRepr::Numerical, "repr:numerical"), - (MonthRepr::Long, "repr:long"), - (MonthRepr::Short, "repr:short"), - ] - .iter() - .copied() - } +#[fixture] +fn month_repr() -> MonthReprIter { + [ + (MonthRepr::Numerical, "repr:numerical"), + (MonthRepr::Long, "repr:long"), + (MonthRepr::Short, "repr:short"), + ] +} - pub(super) fn subsecond_digits() -> impl Iterator { - [ - (SubsecondDigits::One, "digits:1"), - (SubsecondDigits::Two, "digits:2"), - (SubsecondDigits::Three, "digits:3"), - (SubsecondDigits::Four, "digits:4"), - (SubsecondDigits::Five, "digits:5"), - (SubsecondDigits::Six, "digits:6"), - (SubsecondDigits::Seven, "digits:7"), - (SubsecondDigits::Eight, "digits:8"), - (SubsecondDigits::Nine, "digits:9"), - (SubsecondDigits::OneOrMore, "digits:1+"), - ] - .iter() - .copied() - } +#[fixture] +fn subsecond_digits() -> SubsecondDigitsIter { + [ + (SubsecondDigits::One, "digits:1"), + (SubsecondDigits::Two, "digits:2"), + (SubsecondDigits::Three, "digits:3"), + (SubsecondDigits::Four, "digits:4"), + (SubsecondDigits::Five, "digits:5"), + (SubsecondDigits::Six, "digits:6"), + (SubsecondDigits::Seven, "digits:7"), + (SubsecondDigits::Eight, "digits:8"), + (SubsecondDigits::Nine, "digits:9"), + (SubsecondDigits::OneOrMore, "digits:1+"), + ] +} - pub(super) fn weekday_repr() -> impl Iterator { - [ - (WeekdayRepr::Short, "repr:short"), - (WeekdayRepr::Long, "repr:long"), - (WeekdayRepr::Sunday, "repr:sunday"), - (WeekdayRepr::Monday, "repr:monday"), - ] - .iter() - .copied() - } +#[fixture] +fn weekday_repr() -> WeekdayReprIter { + [ + (WeekdayRepr::Short, "repr:short"), + (WeekdayRepr::Long, "repr:long"), + (WeekdayRepr::Sunday, "repr:sunday"), + (WeekdayRepr::Monday, "repr:monday"), + ] +} - pub(super) fn week_number_repr() -> impl Iterator { - [ - (WeekNumberRepr::Iso, "repr:iso"), - (WeekNumberRepr::Sunday, "repr:sunday"), - (WeekNumberRepr::Monday, "repr:monday"), - ] - .iter() - .copied() - } +#[fixture] +fn week_number_repr() -> WeekNumberReprIter { + [ + (WeekNumberRepr::Iso, "repr:iso"), + (WeekNumberRepr::Sunday, "repr:sunday"), + (WeekNumberRepr::Monday, "repr:monday"), + ] +} - pub(super) fn year_repr() -> impl Iterator { - [ - (YearRepr::Full, "repr:full"), - (YearRepr::LastTwo, "repr:last_two"), - ] - .iter() - .copied() - } +#[fixture] +fn year_repr() -> YearReprIter { + [ + (YearRepr::Full, "repr:full"), + (YearRepr::LastTwo, "repr:last_two"), + ] +} - pub(super) fn year_is_iso_week_based() -> impl Iterator { - [(false, "base:calendar"), (true, "base:iso_week")] - .iter() - .copied() - } +#[fixture] +fn year_is_iso_week_based() -> YearIsIsoWeekBasedIter { + [(false, "base:calendar"), (true, "base:iso_week")] +} - pub(super) fn sign_is_mandatory() -> impl Iterator { - [(false, "sign:automatic"), (true, "sign:mandatory")] - .iter() - .copied() - } +#[fixture] +fn sign_is_mandatory() -> SignIsMandatoryIter { + [(false, "sign:automatic"), (true, "sign:mandatory")] +} - pub(super) fn weekday_is_one_indexed() -> impl Iterator { - [(true, "one_indexed:true"), (false, "one_indexed:false")] - .iter() - .copied() - } +#[fixture] +fn weekday_is_one_indexed() -> WeekdayIsOneIndexedIter { + [(true, "one_indexed:true"), (false, "one_indexed:false")] +} - pub(super) fn case_sensitive() -> impl Iterator { - [ - (true, "case_sensitive:true"), - (false, "case_sensitive:false"), - ] - .iter() - .copied() - } +#[fixture] +fn case_sensitive() -> CaseSensitiveIter { + [ + (true, "case_sensitive:true"), + (false, "case_sensitive:false"), + ] +} - pub(super) fn ignore_count() -> impl Iterator { - [ - (1, "count:1"), - (2, "count:2"), - (3, "count:3"), - (10, "count:10"), - (100, "count:100"), - (1_000, "count:1000"), - ] - .into_iter() - .map(|(count, name)| { - ( - NonZeroU16::new(count).expect("number should not be zero"), - name, - ) - }) - } +#[fixture] +#[allow(clippy::unwrap_used)] // all values are valid +fn ignore_count() -> IgnoreCountIter { + [ + (NonZeroU16::new(1).unwrap(), "count:1"), + (NonZeroU16::new(2).unwrap(), "count:2"), + (NonZeroU16::new(3).unwrap(), "count:3"), + (NonZeroU16::new(10).unwrap(), "count:10"), + (NonZeroU16::new(100).unwrap(), "count:100"), + (NonZeroU16::new(1_000).unwrap(), "count:1000"), + ] +} - pub(super) fn unix_timestamp_precision() - -> impl Iterator { - [ - (UnixTimestampPrecision::Second, "precision:second"), - (UnixTimestampPrecision::Millisecond, "precision:millisecond"), - (UnixTimestampPrecision::Microsecond, "precision:microsecond"), - (UnixTimestampPrecision::Nanosecond, "precision:nanosecond"), - ] - .into_iter() - } +#[fixture] +fn unix_timestamp_precision() -> UnixTimestampPrecisionIter { + [ + (UnixTimestampPrecision::Second, "precision:second"), + (UnixTimestampPrecision::Millisecond, "precision:millisecond"), + (UnixTimestampPrecision::Microsecond, "precision:microsecond"), + (UnixTimestampPrecision::Nanosecond, "precision:nanosecond"), + ] } +// endregion fixtures -#[test] +#[rstest] fn empty() { assert_eq!(format_description::parse_borrowed::<2>(""), Ok(vec![])); assert_eq!( @@ -150,175 +150,46 @@ fn empty() { ); } -#[test] -fn only_literal() { - assert_eq!( - format_description::parse("foo bar"), - Ok(vec![FormatItem::Literal(b"foo bar")]) - ); - assert_eq!( - format_description::parse(" leading spaces"), - Ok(vec![FormatItem::Literal(b" leading spaces")]) - ); - assert_eq!( - format_description::parse("trailing spaces "), - Ok(vec![FormatItem::Literal(b"trailing spaces ")]) - ); - assert_eq!( - format_description::parse(" "), - Ok(vec![FormatItem::Literal(b" ")]) - ); - assert_eq!( - format_description::parse("[["), - Ok(vec![FormatItem::Literal(b"[")]) - ); +#[rstest] +#[case("foo bar", [b"foo bar".as_slice()])] +#[case(" leading spaces", [b" leading spaces".as_slice()])] +#[case("trailing spaces ", [b"trailing spaces ".as_slice()])] +#[case(" ", [b" ".as_slice()])] +#[case("[[", [b"[".as_slice()])] +#[case("foo[[bar", [b"foo".as_slice(), b"[".as_slice(), b"bar".as_slice()])] +fn only_literal(#[case] format_description: &str, #[case] expected: [&[u8]; N]) { assert_eq!( - format_description::parse("foo[[bar"), - Ok(vec![ - FormatItem::Literal(b"foo"), - FormatItem::Literal(b"["), - FormatItem::Literal(b"bar") - ]) + format_description::parse(format_description), + Ok(expected.into_iter().map(FormatItem::Literal).collect()) ); } -#[test] -fn simple_component() { - assert_eq!( - format_description::parse("[day]"), - Ok(vec![FormatItem::Component(Component::Day(modifier!( - Day { - padding: Padding::Zero - } - )))]) - ); - assert_eq!( - format_description::parse("[end]"), - Ok(vec![FormatItem::Component(Component::End(modifier!(End)))]) - ); - assert_eq!( - format_description::parse("[hour]"), - Ok(vec![FormatItem::Component(Component::Hour(modifier!( - Hour { - padding: Padding::Zero, - is_12_hour_clock: false - } - )))]) - ); - assert_eq!( - format_description::parse("[minute]"), - Ok(vec![FormatItem::Component(Component::Minute(modifier!( - Minute { - padding: Padding::Zero - } - )))]) - ); - assert_eq!( - format_description::parse("[month]"), - Ok(vec![FormatItem::Component(Component::Month(modifier!( - Month { - padding: Padding::Zero, - repr: MonthRepr::Numerical - } - )))]) - ); - assert_eq!( - format_description::parse("[offset_hour]"), - Ok(vec![FormatItem::Component(Component::OffsetHour( - modifier!(OffsetHour { - sign_is_mandatory: false, - padding: Padding::Zero - }) - ))]) - ); - assert_eq!( - format_description::parse("[offset_minute]"), - Ok(vec![FormatItem::Component(Component::OffsetMinute( - modifier!(OffsetMinute { - padding: Padding::Zero - }) - ))]) - ); - assert_eq!( - format_description::parse("[offset_second]"), - Ok(vec![FormatItem::Component(Component::OffsetSecond( - modifier!(OffsetSecond { - padding: Padding::Zero - }) - ))]) - ); - assert_eq!( - format_description::parse("[ordinal]"), - Ok(vec![FormatItem::Component(Component::Ordinal(modifier!( - Ordinal { - padding: Padding::Zero - } - )))]) - ); - assert_eq!( - format_description::parse("[period]"), - Ok(vec![FormatItem::Component(Component::Period(modifier!( - Period { is_uppercase: true } - )))]) - ); - assert_eq!( - format_description::parse("[second]"), - Ok(vec![FormatItem::Component(Component::Second(modifier!( - Second { - padding: Padding::Zero - } - )))]) - ); - assert_eq!( - format_description::parse("[subsecond]"), - Ok(vec![FormatItem::Component(Component::Subsecond( - modifier!(Subsecond { - digits: SubsecondDigits::OneOrMore - }) - ))]) - ); - assert_eq!( - format_description::parse("[unix_timestamp]"), - Ok(vec![FormatItem::Component(Component::UnixTimestamp( - modifier!(UnixTimestamp { - precision: UnixTimestampPrecision::Second, - sign_is_mandatory: false, - }) - ))]) - ); - assert_eq!( - format_description::parse("[weekday]"), - Ok(vec![FormatItem::Component(Component::Weekday(modifier!( - Weekday { - repr: WeekdayRepr::Long, - one_indexed: true, - } - )))]) - ); - assert_eq!( - format_description::parse("[week_number]"), - Ok(vec![FormatItem::Component(Component::WeekNumber( - modifier!(WeekNumber { - padding: Padding::Zero, - repr: WeekNumberRepr::Iso - }) - ))]) - ); - assert_eq!( - format_description::parse("[year]"), - Ok(vec![FormatItem::Component(Component::Year(modifier!( - Year { - padding: Padding::Zero, - repr: YearRepr::Full, - iso_week_based: false, - sign_is_mandatory: false - } - )))]) +#[rstest] +#[case("[day]", Component::Day(modifier!(Day)))] +#[case("[end]", Component::End(modifier!(End)))] +#[case("[hour]", Component::Hour(modifier!(Hour)))] +#[case("[minute]", Component::Minute(modifier!(Minute)))] +#[case("[month]", Component::Month(modifier!(Month)))] +#[case("[offset_hour]", Component::OffsetHour(modifier!(OffsetHour)))] +#[case("[offset_minute]", Component::OffsetMinute(modifier!(OffsetMinute)))] +#[case("[offset_second]", Component::OffsetSecond(modifier!(OffsetSecond)))] +#[case("[ordinal]", Component::Ordinal(modifier!(Ordinal)))] +#[case("[period]", Component::Period(modifier!(Period)))] +#[case("[second]", Component::Second(modifier!(Second)))] +#[case("[subsecond]", Component::Subsecond(modifier!(Subsecond)))] +#[case("[unix_timestamp]", Component::UnixTimestamp(modifier!(UnixTimestamp)))] +#[case("[weekday]", Component::Weekday(modifier!(Weekday)))] +#[case("[week_number]", Component::WeekNumber(modifier!(WeekNumber)))] +#[case("[year]", Component::Year(modifier!(Year)))] +fn simple_component(#[case] format_description: &str, #[case] component: Component) { + assert_eq!( + format_description::parse(format_description), + Ok(vec![FormatItem::Component(component)]) ); } #[allow(clippy::cognitive_complexity)] // all test the same thing -#[test] +#[rstest] fn errors() { use InvalidFormatDescription::*; @@ -350,173 +221,265 @@ fn errors() { } } -#[allow(clippy::cognitive_complexity)] // all test the same thing -#[test] -fn component_with_modifiers() { - for (padding, padding_str) in iterator::padding() { +// region: individual components +#[rstest] +fn day_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[day {padding_str}]")), Ok(vec![FormatItem::Component(Component::Day(modifier!( Day { padding } )))]) ); + } +} + +#[rstest] +fn minute_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[minute {padding_str}]")), Ok(vec![FormatItem::Component(Component::Minute(modifier!( Minute { padding } )))]) ); + } +} + +#[rstest] +fn offset_minute_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[offset_minute {padding_str}]")), Ok(vec![FormatItem::Component(Component::OffsetMinute( modifier!(OffsetMinute { padding }) ))]) ); + } +} + +#[rstest] +fn offset_second_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[offset_second {padding_str}]")), Ok(vec![FormatItem::Component(Component::OffsetSecond( modifier!(OffsetSecond { padding }) ))]) ); + } +} + +#[rstest] +fn ordinal_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[ordinal {padding_str}]")), Ok(vec![FormatItem::Component(Component::Ordinal(modifier!( Ordinal { padding } )))]) ); + } +} + +#[rstest] +fn second_component(padding: PaddingIter) { + for (padding, padding_str) in padding { assert_eq!( format_description::parse(&format!("[second {padding_str}]")), Ok(vec![FormatItem::Component(Component::Second(modifier!( Second { padding } )))]) ); + } +} + +#[rstest] +fn hour_component(padding: PaddingIter, hour_is_12_hour_clock: HourIs12HourClockIter) { + for ((padding, padding_str), (is_12_hour_clock, is_12_hour_clock_str)) in + iproduct!(padding, hour_is_12_hour_clock) + { + assert_eq!( + format_description::parse(&format!("[hour {padding_str} {is_12_hour_clock_str}]")), + Ok(vec![FormatItem::Component(Component::Hour(modifier!( + Hour { + padding, + is_12_hour_clock + } + )))]) + ); + } +} + +#[rstest] +fn month_component( + padding: PaddingIter, + case_sensitive: CaseSensitiveIter, + month_repr: MonthReprIter, +) { + for ((padding, padding_str), (repr, repr_str), (case_sensitive, case_sensitive_str)) in + iproduct!(padding, month_repr, case_sensitive) + { + assert_eq!( + format_description::parse(&format!( + "[month {padding_str} {case_sensitive_str} {repr_str}]" + )), + Ok(vec![FormatItem::Component(Component::Month(modifier!( + Month { + padding, + repr, + case_sensitive + } + )))]) + ); + } +} + +#[rstest] +fn period_component(case_sensitive: CaseSensitiveIter, period_is_uppercase: PeriodIsUppercaseIter) { + for ((case_sensitive, case_sensitive_repr), (is_uppercase, is_uppercase_str)) in + iproduct!(case_sensitive, period_is_uppercase) + { + assert_eq!( + format_description::parse(&format!( + "[period {is_uppercase_str} {case_sensitive_repr}]" + )), + Ok(vec![FormatItem::Component(Component::Period(modifier!( + Period { + is_uppercase, + case_sensitive + } + )))]) + ); + } +} - for (is_12_hour_clock, is_12_hour_clock_str) in iterator::hour_is_12_hour_clock() { - assert_eq!( - format_description::parse(&format!("[hour {padding_str} {is_12_hour_clock_str}]")), - Ok(vec![FormatItem::Component(Component::Hour(modifier!( - Hour { - padding, - is_12_hour_clock - } - )))]) - ); - } - for (case_sensitive, case_sensitive_repr) in iterator::case_sensitive() { - for (repr, repr_str) in iterator::month_repr() { - assert_eq!( - format_description::parse(&format!( - "[month {padding_str} {case_sensitive_repr} {repr_str}]" - )), - Ok(vec![FormatItem::Component(Component::Month(modifier!( - Month { - padding, - repr, - case_sensitive - } - )))]) - ); - } - for (is_uppercase, is_uppercase_str) in iterator::period_is_uppercase() { - assert_eq!( - format_description::parse(&format!( - "[period {is_uppercase_str} {case_sensitive_repr}]" - )), - Ok(vec![FormatItem::Component(Component::Period(modifier!( - Period { - is_uppercase, - case_sensitive - } - )))]) - ); - } - for (repr, repr_str) in iterator::weekday_repr() { - for (one_indexed, one_indexed_str) in iterator::weekday_is_one_indexed() { - assert_eq!( - format_description::parse(&format!( - "[weekday {repr_str} {one_indexed_str} {case_sensitive_repr} ]" - )), - Ok(vec![FormatItem::Component(Component::Weekday(modifier!( - Weekday { - repr, - one_indexed, - case_sensitive - } - )))]) - ); +#[rstest] +fn weekday_component( + case_sensitive: CaseSensitiveIter, + weekday_is_one_indexed: WeekdayIsOneIndexedIter, + weekday_repr: WeekdayReprIter, +) { + for ((case_sensitive, case_sensitive_repr), (one_indexed, one_indexed_str), (repr, repr_str)) in + iproduct!(case_sensitive, weekday_is_one_indexed, weekday_repr) + { + assert_eq!( + format_description::parse(&format!( + "[weekday {repr_str} {one_indexed_str} {case_sensitive_repr} ]" + )), + Ok(vec![FormatItem::Component(Component::Weekday(modifier!( + Weekday { + repr, + one_indexed, + case_sensitive } - } - } - for (repr, repr_str) in iterator::week_number_repr() { - assert_eq!( - format_description::parse(&format!("[week_number {padding_str} {repr_str}]")), - Ok(vec![FormatItem::Component(Component::WeekNumber( - modifier!(WeekNumber { padding, repr }) - ))]) - ); - } - for (sign_is_mandatory, sign_is_mandatory_str) in iterator::sign_is_mandatory() { - assert_eq!( - format_description::parse(&format!( - "[offset_hour {padding_str} {sign_is_mandatory_str}]" - )), - Ok(vec![FormatItem::Component(Component::OffsetHour( - modifier!(OffsetHour { - sign_is_mandatory, - padding - }) - ))]) - ); - - for (repr, repr_str) in iterator::year_repr() { - for (iso_week_based, iso_week_based_str) in iterator::year_is_iso_week_based() { - assert_eq!( - format_description::parse(&format!( - "[year {padding_str} {repr_str} {iso_week_based_str} \ - \n{sign_is_mandatory_str}]", - )), - Ok(vec![FormatItem::Component(Component::Year(modifier!( - Year { - padding, - repr, - iso_week_based, - sign_is_mandatory - } - )))]) - ); + )))]) + ) + } +} + +#[rstest] +fn week_number_component(padding: PaddingIter, week_number_repr: WeekNumberReprIter) { + for ((padding, padding_str), (repr, repr_str)) in iproduct!(padding, week_number_repr) { + assert_eq!( + format_description::parse(&format!("[week_number {padding_str} {repr_str}]")), + Ok(vec![FormatItem::Component(Component::WeekNumber( + modifier!(WeekNumber { padding, repr }) + ))]) + ); + } +} + +#[rstest] +fn offset_hour_component(padding: PaddingIter, sign_is_mandatory: SignIsMandatoryIter) { + for ((padding, padding_str), (sign_is_mandatory, sign_is_mandatory_str)) in + iproduct!(padding, sign_is_mandatory) + { + assert_eq!( + format_description::parse(&format!( + "[offset_hour {padding_str} {sign_is_mandatory_str}]" + )), + Ok(vec![FormatItem::Component(Component::OffsetHour( + modifier!(OffsetHour { + padding, + sign_is_mandatory + }) + ))]) + ); + } +} + +#[rstest] +fn year_component( + padding: PaddingIter, + year_repr: YearReprIter, + year_is_iso_week_based: YearIsIsoWeekBasedIter, + sign_is_mandatory: SignIsMandatoryIter, +) { + for ( + (padding, padding_str), + (repr, repr_str), + (iso_week_based, iso_week_based_str), + (sign_is_mandatory, sign_is_mandatory_str), + ) in iproduct!( + padding, + year_repr, + year_is_iso_week_based, + sign_is_mandatory + ) { + assert_eq!( + format_description::parse(&format!( + "[year {padding_str} {repr_str} {iso_week_based_str} {sign_is_mandatory_str}]" + )), + Ok(vec![FormatItem::Component(Component::Year(modifier!( + Year { + padding, + repr, + iso_week_based, + sign_is_mandatory } - } - } + )))]) + ); } +} - for (sign_is_mandatory, sign_is_mandatory_str) in iterator::sign_is_mandatory() { - for (unix_timestamp_precision, unix_timestamp_precision_str) in - iterator::unix_timestamp_precision() - { - assert_eq!( - format_description::parse(&format!( - "[unix_timestamp {sign_is_mandatory_str} {unix_timestamp_precision_str}]" - )), - Ok(vec![FormatItem::Component(Component::UnixTimestamp( - modifier!(UnixTimestamp { - sign_is_mandatory, - precision: unix_timestamp_precision - }) - ))]) - ); - } +#[rstest] +fn unix_timestamp_component( + sign_is_mandatory: SignIsMandatoryIter, + unix_timestamp_precision: UnixTimestampPrecisionIter, +) { + for ((sign_is_mandatory, sign_is_mandatory_str), (precision, precision_str)) in + iproduct!(sign_is_mandatory, unix_timestamp_precision) + { + assert_eq!( + format_description::parse(&format!( + "[unix_timestamp {sign_is_mandatory_str} {precision_str}]" + )), + Ok(vec![FormatItem::Component(Component::UnixTimestamp( + modifier!(UnixTimestamp { + sign_is_mandatory, + precision + }) + ))]) + ); } +} - for (digits, digits_str) in iterator::subsecond_digits() { +#[rstest] +fn subsecond_component(subsecond_digits: SubsecondDigitsIter) { + for (digits, digits_str) in subsecond_digits { assert_eq!( format_description::parse(&format!("[subsecond {digits_str}]")), Ok(vec![FormatItem::Component(Component::Subsecond( modifier!(Subsecond { digits }) - ))]) + ))]), ); } +} - for (count, count_str) in iterator::ignore_count() { +#[rstest] +fn ignore_component(ignore_count: IgnoreCountIter) { + for (count, count_str) in ignore_count { assert_eq!( format_description::parse(&format!("[ignore {count_str}]")), Ok(vec![FormatItem::Component(Component::Ignore( @@ -525,8 +488,9 @@ fn component_with_modifiers() { ); } } +// endregion individual components -#[test] +#[rstest] fn optional() { assert_eq!( format_description::parse_owned::<2>("[optional [:[year]]]"), @@ -561,7 +525,7 @@ fn optional() { ); } -#[test] +#[rstest] fn first() { assert_eq!( format_description::parse_owned::<2>("[first [a]]"), @@ -617,7 +581,7 @@ fn first() { ); } -#[test] +#[rstest] fn backslash_escape() { assert_eq!( format_description::parse_owned::<2>(r"[optional [\]]]"), @@ -677,43 +641,29 @@ fn backslash_escape() { ); } -#[test] -fn backslash_escape_error() { - assert!(matches!( - format_description::parse_owned::<2>(r"\a"), - Err(InvalidFormatDescription::Expected { - what: "valid escape sequence", - index: 1, - .. - }) - )); - assert!(matches!( - format_description::parse_owned::<2>(r"\"), - Err(InvalidFormatDescription::Expected { - what: "valid escape sequence", - index: 0, - .. - }) - )); +#[rstest] +#[case(r"\a", 1)] +#[case(r"\", 0)] +fn backslash_escape_error(#[case] format_description: &str, #[case] expected_index: usize) { assert!(matches!( - format_description::parse_borrowed::<2>(r"\a"), + format_description::parse_owned::<2>(format_description), Err(InvalidFormatDescription::Expected { what: "valid escape sequence", - index: 1, + index, .. - }) + }) if index == expected_index )); assert!(matches!( - format_description::parse_borrowed::<2>(r"\"), + format_description::parse_borrowed::<2>(format_description), Err(InvalidFormatDescription::Expected { what: "valid escape sequence", - index: 0, + index, .. - }) + }) if index == expected_index )); } -#[test] +#[rstest] fn nested_v1_error() { assert!(matches!( format_description::parse_owned::<2>("[optional [[[]]"), @@ -729,7 +679,7 @@ fn nested_v1_error() { )); } -#[test] +#[rstest] fn nested_error() { use InvalidFormatDescription::*; @@ -797,52 +747,53 @@ fn nested_error() { )); } -#[allow(clippy::unwrap_used)] // It's the point of the test. -#[test] -fn error_display() { - assert_eq!( - format_description::parse("[").unwrap_err().to_string(), - "missing component name at byte index 0" - ); - assert_eq!( - format_description::parse("[foo").unwrap_err().to_string(), - "unclosed opening bracket at byte index 0" - ); - assert_eq!( - format_description::parse("[foo]").unwrap_err().to_string(), - "invalid component name `foo` at byte index 1" - ); - assert_eq!( - format_description::parse("[day bar]") - .unwrap_err() - .to_string(), - "invalid modifier `bar` at byte index 5" - ); - assert_eq!( - format_description::parse("[]").unwrap_err().to_string(), - "missing component name at byte index 0" - ); - assert_eq!( - format_description::parse_owned::<2>("[optional ") - .unwrap_err() - .to_string(), - "expected opening bracket at byte index 9" - ); - assert_eq!( - format_description::parse("[optional []]") - .unwrap_err() - .to_string(), - "optional item is not supported in runtime-parsed format descriptions at byte index 0" - ); - assert_eq!( - format_description::parse("[ignore]") - .unwrap_err() - .to_string(), - "missing required modifier `count` for component at byte index 1" - ); +#[rstest] +#[case("[", "missing component name at byte index 0")] +#[case("[foo", "unclosed opening bracket at byte index 0")] +#[case("[foo]", "invalid component name `foo` at byte index 1")] +#[case("[day bar]", "invalid modifier `bar` at byte index 5")] +#[case("[]", "missing component name at byte index 0")] +#[case( + "[optional []]", + "optional item is not supported in runtime-parsed format descriptions at byte index 0" +)] +#[case( + "[ignore]", + "missing required modifier `count` for component at byte index 1" +)] +fn error_display(#[case] format_description: &str, #[case] error: &str) { + // la10736/rstest#217 + #[allow(clippy::unwrap_used)] // It's the point of the test. + let test = || { + assert_eq!( + format_description::parse(format_description) + .unwrap_err() + .to_string(), + error + ); + }; + + test(); +} + +#[rstest] +#[case("[optional ", "expected opening bracket at byte index 9")] +fn error_display_owned(#[case] format_description: &str, #[case] error: &str) { + // la10736/rstest#217 + #[allow(clippy::unwrap_used)] // It's the point of the test. + let test = || { + assert_eq!( + format_description::parse_owned::<2>(format_description) + .unwrap_err() + .to_string(), + error + ) + }; + + test(); } -#[test] +#[rstest] fn rfc_3339() { assert_eq!( format_description::parse( diff --git a/tests/serde/macros.rs b/tests/serde/macros.rs index c96dd9810..3b38e5894 100644 --- a/tests/serde/macros.rs +++ b/tests/serde/macros.rs @@ -17,7 +17,8 @@ time::serde::format_description!(my_format, OffsetDateTime, ISO_FORMAT); serde::format_description!( offset_dt_format, OffsetDateTime, - "custom format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour]:[offset_minute]" + "custom format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \ + sign:mandatory]:[offset_minute]" ); serde::format_description!( primitive_dt_format, @@ -29,7 +30,7 @@ serde::format_description!(date_format, Date, "custom format: [year]-[month]-[da serde::format_description!( offset_format, UtcOffset, - "custom format: [offset_hour]:[offset_minute]" + "custom format: [offset_hour sign:mandatory]:[offset_minute]" ); const TIME_FORMAT_ALT: &[FormatItem<'_>] = time::macros::format_description!("[hour]:[minute]"); @@ -126,7 +127,8 @@ fn custom_serialize_error() { Token::Bool(false), ], "invalid type: boolean `false`, expected a(n) `OffsetDateTime` in the format \"custom \ - format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour]:[offset_minute]\"", + format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \ + sign:mandatory]:[offset_minute]\"", ); assert_de_tokens_error::( &[ diff --git a/tests/utc_offset.rs b/tests/utc_offset.rs index 4886f6577..d8054c333 100644 --- a/tests/utc_offset.rs +++ b/tests/utc_offset.rs @@ -1,147 +1,158 @@ +use rstest::rstest; use time::macros::offset; -use time::{OffsetDateTime, Result, UtcOffset}; +use time::{OffsetDateTime, UtcOffset}; #[test] fn utc_is_zero() { assert_eq!(offset!(UTC), offset!(+0)); } -#[test] -fn from_hms() -> Result<()> { - assert_eq!(UtcOffset::from_hms(0, 0, 0), Ok(offset!(UTC))); - assert_eq!(UtcOffset::from_hms(0, 0, 1), Ok(offset!(+0:00:01))); - assert_eq!(UtcOffset::from_hms(0, 0, -1), Ok(offset!(-0:00:01))); - assert_eq!(UtcOffset::from_hms(1, 0, 0), Ok(offset!(+1))); - assert_eq!(UtcOffset::from_hms(-1, 0, 0), Ok(offset!(-1))); - assert_eq!(UtcOffset::from_hms(23, 59, 0), Ok(offset!(+23:59))); - assert_eq!(UtcOffset::from_hms(-23, -59, 0), Ok(offset!(-23:59))); - assert_eq!(UtcOffset::from_hms(23, 59, 59), Ok(offset!(+23:59:59))); - assert_eq!(UtcOffset::from_hms(-23, -59, -59), Ok(offset!(-23:59:59))); - assert_eq!(UtcOffset::from_hms(1, 2, 3)?.as_hms(), (1, 2, 3)); - assert_eq!(UtcOffset::from_hms(1, -2, -3)?.as_hms(), (1, 2, 3)); - assert_eq!(UtcOffset::from_hms(0, 2, -3)?.as_hms(), (0, 2, 3)); - Ok(()) -} - -#[test] -fn from_whole_seconds() { - assert_eq!(UtcOffset::from_whole_seconds(0), Ok(offset!(UTC))); - assert_eq!(UtcOffset::from_whole_seconds(1), Ok(offset!(+0:00:01))); - assert_eq!(UtcOffset::from_whole_seconds(-1), Ok(offset!(-0:00:01))); - assert_eq!(UtcOffset::from_whole_seconds(3_600), Ok(offset!(+1))); - assert_eq!(UtcOffset::from_whole_seconds(-3_600), Ok(offset!(-1))); - assert_eq!(UtcOffset::from_whole_seconds(86_340), Ok(offset!(+23:59))); - assert_eq!(UtcOffset::from_whole_seconds(-86_340), Ok(offset!(-23:59))); - assert_eq!( - UtcOffset::from_whole_seconds(86_399), - Ok(offset!(+23:59:59)) - ); - assert_eq!( - UtcOffset::from_whole_seconds(-86_399), - Ok(offset!(-23:59:59)) - ); -} - -#[test] -fn as_hms() { - assert_eq!(offset!(UTC).as_hms(), (0, 0, 0)); - assert_eq!(offset!(+0:00:01).as_hms(), (0, 0, 1)); - assert_eq!(offset!(-0:00:01).as_hms(), (0, 0, -1)); - assert_eq!(offset!(+1).as_hms(), (1, 0, 0)); - assert_eq!(offset!(-1).as_hms(), (-1, 0, 0)); - assert_eq!(offset!(+23:59).as_hms(), (23, 59, 0)); - assert_eq!(offset!(-23:59).as_hms(), (-23, -59, 0)); - assert_eq!(offset!(+23:59:59).as_hms(), (23, 59, 59)); - assert_eq!(offset!(-23:59:59).as_hms(), (-23, -59, -59)); -} - -#[test] -fn whole_hours() { - assert_eq!(offset!(+1:02:03).whole_hours(), 1); - assert_eq!(offset!(-1:02:03).whole_hours(), -1); -} - -#[test] -fn whole_minutes() { - assert_eq!(offset!(+1:02:03).whole_minutes(), 62); - assert_eq!(offset!(-1:02:03).whole_minutes(), -62); -} - -#[test] -fn minutes_past_hour() { - assert_eq!(offset!(+1:02:03).minutes_past_hour(), 2); - assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2); -} - -#[test] -fn whole_seconds() { - assert_eq!(offset!(UTC).whole_seconds(), 0); - assert_eq!(offset!(+0:00:01).whole_seconds(), 1); - assert_eq!(offset!(-0:00:01).whole_seconds(), -1); - assert_eq!(offset!(+1).whole_seconds(), 3_600); - assert_eq!(offset!(-1).whole_seconds(), -3_600); - assert_eq!(offset!(+23:59).whole_seconds(), 86_340); - assert_eq!(offset!(-23:59).whole_seconds(), -86_340); - assert_eq!(offset!(+23:59:59).whole_seconds(), 86_399); - assert_eq!(offset!(-23:59:59).whole_seconds(), -86_399); -} - -#[test] -fn seconds_past_minute() { - assert_eq!(offset!(+1:02:03).seconds_past_minute(), 3); - assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3); -} - -#[test] -fn is_utc() { - assert!(offset!(UTC).is_utc()); - assert!(!offset!(+0:00:01).is_utc()); - assert!(!offset!(-0:00:01).is_utc()); - assert!(!offset!(+1).is_utc()); - assert!(!offset!(-1).is_utc()); - assert!(!offset!(+23:59).is_utc()); - assert!(!offset!(-23:59).is_utc()); - assert!(!offset!(+23:59:59).is_utc()); - assert!(!offset!(-23:59:59).is_utc()); -} - -#[test] -fn is_positive() { - assert!(!offset!(UTC).is_positive()); - assert!(offset!(+0:00:01).is_positive()); - assert!(!offset!(-0:00:01).is_positive()); - assert!(offset!(+1).is_positive()); - assert!(!offset!(-1).is_positive()); - assert!(offset!(+23:59).is_positive()); - assert!(!offset!(-23:59).is_positive()); - assert!(offset!(+23:59:59).is_positive()); - assert!(!offset!(-23:59:59).is_positive()); -} - -#[test] -fn is_negative() { - assert!(!offset!(UTC).is_negative()); - assert!(!offset!(+0:00:01).is_negative()); - assert!(offset!(-0:00:01).is_negative()); - assert!(!offset!(+1).is_negative()); - assert!(offset!(-1).is_negative()); - assert!(!offset!(+23:59).is_negative()); - assert!(offset!(-23:59).is_negative()); - assert!(!offset!(+23:59:59).is_negative()); - assert!(offset!(-23:59:59).is_negative()); -} - -#[test] -fn neg() { - assert_eq!(-offset!(UTC), offset!(UTC)); - assert_eq!(-offset!(+0:00:01), offset!(-0:00:01)); - assert_eq!(-offset!(-0:00:01), offset!(+0:00:01)); - assert_eq!(-offset!(+1), offset!(-1)); - assert_eq!(-offset!(-1), offset!(+1)); - assert_eq!(-offset!(+23:59), offset!(-23:59)); - assert_eq!(-offset!(-23:59), offset!(+23:59)); - assert_eq!(-offset!(+23:59:59), offset!(-23:59:59)); - assert_eq!(-offset!(-23:59:59), offset!(+23:59:59)); +#[rstest] +#[case(0, 0, 0, offset!(UTC))] +#[case(0, 0, 1, offset!(+0:00:01))] +#[case(0, 0, -1, offset!(-0:00:01))] +#[case(1, 0, 0, offset!(+1))] +#[case(-1, 0, 0, offset!(-1))] +#[case(23, 59, 0, offset!(+23:59))] +#[case(-23, -59, 0, offset!(-23:59))] +#[case(23, 59, 59, offset!(+23:59:59))] +#[case(-23, -59, -59, offset!(-23:59:59))] +#[case(1, 2, 3, offset!(+1:02:03))] +#[case(1, -2, -3, offset!(+1:02:03))] +#[case(0, 2, -3, offset!(+0:02:03))] +fn from_hms( + #[case] hours: i8, + #[case] minutes: i8, + #[case] seconds: i8, + #[case] expected: UtcOffset, +) { + assert_eq!(UtcOffset::from_hms(hours, minutes, seconds), Ok(expected)); +} + +#[rstest] +#[case(0, offset!(UTC))] +#[case(1, offset!(+0:00:01))] +#[case(-1, offset!(-0:00:01))] +#[case(3_600, offset!(+1))] +#[case(-3_600, offset!(-1))] +#[case(86_340, offset!(+23:59))] +#[case(-86_340, offset!(-23:59))] +#[case(86_399, offset!(+23:59:59))] +#[case(-86_399, offset!(-23:59:59))] +fn from_whole_seconds(#[case] seconds: i32, #[case] expected: UtcOffset) { + assert_eq!(UtcOffset::from_whole_seconds(seconds), Ok(expected)); +} + +#[rstest] +#[case(offset!(UTC), (0, 0, 0))] +#[case(offset!(+0:00:01), (0, 0, 1))] +#[case(offset!(-0:00:01), (0, 0, -1))] +#[case(offset!(+1), (1, 0, 0))] +#[case(offset!(-1), (-1, 0, 0))] +#[case(offset!(+23:59), (23, 59, 0))] +#[case(offset!(-23:59), (-23, -59, 0))] +#[case(offset!(+23:59:59), (23, 59, 59))] +#[case(offset!(-23:59:59), (-23, -59, -59))] +fn as_hms(#[case] offset: UtcOffset, #[case] expected: (i8, i8, i8)) { + assert_eq!(offset.as_hms(), expected); +} + +#[rstest] +#[case(offset!(+1:02:03), 1)] +#[case(offset!(-1:02:03), -1)] +fn whole_hours(#[case] offset: UtcOffset, #[case] expected: i8) { + assert_eq!(offset.whole_hours(), expected); +} + +#[rstest] +#[case(offset!(+1:02:03), 62)] +#[case(offset!(-1:02:03), -62)] +fn whole_minutes(#[case] offset: UtcOffset, #[case] expected: i16) { + assert_eq!(offset.whole_minutes(), expected); +} + +#[rstest] +#[case(offset!(+1:02:03), 2)] +#[case(offset!(-1:02:03), -2)] +fn minutes_past_hour(#[case] offset: UtcOffset, #[case] expected: i8) { + assert_eq!(offset.minutes_past_hour(), expected); +} + +#[rstest] +#[case(offset!(UTC), 0)] +#[case(offset!(+0:00:01), 1)] +#[case(offset!(-0:00:01), -1)] +#[case(offset!(+1), 3_600)] +#[case(offset!(-1), -3_600)] +#[case(offset!(+23:59), 86_340)] +#[case(offset!(-23:59), -86_340)] +#[case(offset!(+23:59:59), 86_399)] +#[case(offset!(-23:59:59), -86_399)] +fn whole_seconds(#[case] offset: UtcOffset, #[case] expected: i32) { + assert_eq!(offset.whole_seconds(), expected); +} + +#[rstest] +#[case(offset!(+1:02:03), 3)] +#[case(offset!(-1:02:03), -3)] +fn seconds_past_minute(#[case] offset: UtcOffset, #[case] expected: i8) { + assert_eq!(offset.seconds_past_minute(), expected); +} + +#[rstest] +#[case(offset!(UTC), true)] +#[case(offset!(+0:00:01), false)] +#[case(offset!(-0:00:01), false)] +#[case(offset!(+1), false)] +#[case(offset!(-1), false)] +#[case(offset!(+23:59), false)] +#[case(offset!(-23:59), false)] +#[case(offset!(+23:59:59), false)] +#[case(offset!(-23:59:59), false)] +fn is_utc(#[case] offset: UtcOffset, #[case] expected: bool) { + assert_eq!(offset.is_utc(), expected); +} + +#[rstest] +#[case(offset!(UTC), false)] +#[case(offset!(+0:00:01), true)] +#[case(offset!(-0:00:01), false)] +#[case(offset!(+1), true)] +#[case(offset!(-1), false)] +#[case(offset!(+23:59), true)] +#[case(offset!(-23:59), false)] +#[case(offset!(+23:59:59), true)] +#[case(offset!(-23:59:59), false)] +fn is_positive(#[case] offset: UtcOffset, #[case] expected: bool) { + assert_eq!(offset.is_positive(), expected); +} + +#[rstest] +#[case(offset!(UTC), false)] +#[case(offset!(+0:00:01), false)] +#[case(offset!(-0:00:01), true)] +#[case(offset!(+1), false)] +#[case(offset!(-1), true)] +#[case(offset!(+23:59), false)] +#[case(offset!(-23:59), true)] +#[case(offset!(+23:59:59), false)] +#[case(offset!(-23:59:59), true)] +fn is_negative(#[case] offset: UtcOffset, #[case] expected: bool) { + assert_eq!(offset.is_negative(), expected); +} + +#[rstest] +#[case(offset!(UTC), offset!(UTC))] +#[case(offset!(+0:00:01), offset!(-0:00:01))] +#[case(offset!(-0:00:01), offset!(+0:00:01))] +#[case(offset!(+1), offset!(-1))] +#[case(offset!(-1), offset!(+1))] +#[case(offset!(+23:59), offset!(-23:59))] +#[case(offset!(-23:59), offset!(+23:59))] +#[case(offset!(+23:59:59), offset!(-23:59:59))] +#[case(offset!(-23:59:59), offset!(+23:59:59))] +fn neg(#[case] offset: UtcOffset, #[case] expected: UtcOffset) { + assert_eq!(-offset, expected); } #[cfg_attr(miri, ignore)] diff --git a/tests/util.rs b/tests/util.rs index e934e9c7b..8f0f67cf7 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -1,57 +1,59 @@ +use rstest::rstest; +use time::Month::*; use time::{util, Month}; -#[test] -fn days_in_year_month() { - // Common year - assert_eq!(util::days_in_year_month(2019, Month::January), 31); - assert_eq!(util::days_in_year_month(2019, Month::February), 28); - assert_eq!(util::days_in_year_month(2019, Month::March), 31); - assert_eq!(util::days_in_year_month(2019, Month::April), 30); - assert_eq!(util::days_in_year_month(2019, Month::May), 31); - assert_eq!(util::days_in_year_month(2019, Month::June), 30); - assert_eq!(util::days_in_year_month(2019, Month::July), 31); - assert_eq!(util::days_in_year_month(2019, Month::August), 31); - assert_eq!(util::days_in_year_month(2019, Month::September), 30); - assert_eq!(util::days_in_year_month(2019, Month::October), 31); - assert_eq!(util::days_in_year_month(2019, Month::November), 30); - assert_eq!(util::days_in_year_month(2019, Month::December), 31); - - // Leap year - assert_eq!(util::days_in_year_month(2020, Month::January), 31); - assert_eq!(util::days_in_year_month(2020, Month::February), 29); - assert_eq!(util::days_in_year_month(2020, Month::March), 31); - assert_eq!(util::days_in_year_month(2020, Month::April), 30); - assert_eq!(util::days_in_year_month(2020, Month::May), 31); - assert_eq!(util::days_in_year_month(2020, Month::June), 30); - assert_eq!(util::days_in_year_month(2020, Month::July), 31); - assert_eq!(util::days_in_year_month(2020, Month::August), 31); - assert_eq!(util::days_in_year_month(2020, Month::September), 30); - assert_eq!(util::days_in_year_month(2020, Month::October), 31); - assert_eq!(util::days_in_year_month(2020, Month::November), 30); - assert_eq!(util::days_in_year_month(2020, Month::December), 31); +#[rstest] +#[case(2019, January, 31)] +#[case(2019, February, 28)] +#[case(2019, March, 31)] +#[case(2019, April, 30)] +#[case(2019, May, 31)] +#[case(2019, June, 30)] +#[case(2019, July, 31)] +#[case(2019, August, 31)] +#[case(2019, September, 30)] +#[case(2019, October, 31)] +#[case(2019, November, 30)] +#[case(2019, December, 31)] +#[case(2020, January, 31)] +#[case(2020, February, 29)] +#[case(2020, March, 31)] +#[case(2020, April, 30)] +#[case(2020, May, 31)] +#[case(2020, June, 30)] +#[case(2020, July, 31)] +#[case(2020, August, 31)] +#[case(2020, September, 30)] +#[case(2020, October, 31)] +#[case(2020, November, 30)] +#[case(2020, December, 31)] +fn days_in_year_month(#[case] year: i32, #[case] month: Month, #[case] expected: u8) { + assert_eq!(util::days_in_year_month(year, month), expected); } -#[test] -fn is_leap_year() { - assert!(!util::is_leap_year(1900)); - assert!(util::is_leap_year(2000)); - assert!(util::is_leap_year(2004)); - assert!(!util::is_leap_year(2005)); - assert!(!util::is_leap_year(2100)); +#[rstest] +#[case(1900, false)] +#[case(2000, true)] +#[case(2004, true)] +#[case(2005, false)] +#[case(2100, false)] +fn is_leap_year(#[case] year: i32, #[case] expected: bool) { + assert_eq!(util::is_leap_year(year), expected); } -#[test] -fn days_in_year() { - assert_eq!(util::days_in_year(1900), 365); - assert_eq!(util::days_in_year(2000), 366); - assert_eq!(util::days_in_year(2004), 366); - assert_eq!(util::days_in_year(2005), 365); - assert_eq!(util::days_in_year(2100), 365); +#[rstest] +#[case(1900, 365)] +#[case(2000, 366)] +#[case(2004, 366)] +#[case(2005, 365)] +#[case(2100, 365)] +fn days_in_year(#[case] year: i32, #[case] expected: u16) { + assert_eq!(util::days_in_year(year), expected); } -#[test] +#[rstest] fn weeks_in_year() { - let num_weeks_for_years = vec![ + let num_weeks_for_years = [ 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 53, 52, 52, 52, @@ -77,7 +79,7 @@ fn weeks_in_year() { } } -#[test] +#[rstest] fn local_offset_soundness() { use time::util::local_offset::*; diff --git a/tests/weekday.rs b/tests/weekday.rs index e6dd48a11..9b6ed54e0 100644 --- a/tests/weekday.rs +++ b/tests/weekday.rs @@ -1,138 +1,145 @@ +use rstest::rstest; use time::Weekday::{self, *}; -#[test] -fn previous() { - assert_eq!(Sunday.previous(), Saturday); - assert_eq!(Monday.previous(), Sunday); - assert_eq!(Tuesday.previous(), Monday); - assert_eq!(Wednesday.previous(), Tuesday); - assert_eq!(Thursday.previous(), Wednesday); - assert_eq!(Friday.previous(), Thursday); - assert_eq!(Saturday.previous(), Friday); +#[rstest] +#[case(Sunday, Saturday)] +#[case(Monday, Sunday)] +#[case(Tuesday, Monday)] +#[case(Wednesday, Tuesday)] +#[case(Thursday, Wednesday)] +#[case(Friday, Thursday)] +#[case(Saturday, Friday)] +fn previous(#[case] current: Weekday, #[case] expected: Weekday) { + assert_eq!(current.previous(), expected); } -#[test] -fn next() { - assert_eq!(Sunday.next(), Monday); - assert_eq!(Monday.next(), Tuesday); - assert_eq!(Tuesday.next(), Wednesday); - assert_eq!(Wednesday.next(), Thursday); - assert_eq!(Thursday.next(), Friday); - assert_eq!(Friday.next(), Saturday); - assert_eq!(Saturday.next(), Sunday); +#[rstest] +#[case(Sunday, Monday)] +#[case(Monday, Tuesday)] +#[case(Tuesday, Wednesday)] +#[case(Wednesday, Thursday)] +#[case(Thursday, Friday)] +#[case(Friday, Saturday)] +#[case(Saturday, Sunday)] +fn next(#[case] current: Weekday, #[case] expected: Weekday) { + assert_eq!(current.next(), expected); } -#[test] -fn nth_next() { - assert_eq!(Sunday.nth_next(0), Sunday); - assert_eq!(Sunday.nth_next(1), Monday); - assert_eq!(Sunday.nth_next(2), Tuesday); - assert_eq!(Sunday.nth_next(3), Wednesday); - assert_eq!(Sunday.nth_next(4), Thursday); - assert_eq!(Sunday.nth_next(5), Friday); - assert_eq!(Sunday.nth_next(6), Saturday); - - assert_eq!(Monday.nth_next(0), Monday); - assert_eq!(Monday.nth_next(1), Tuesday); - assert_eq!(Monday.nth_next(2), Wednesday); - assert_eq!(Monday.nth_next(3), Thursday); - assert_eq!(Monday.nth_next(4), Friday); - assert_eq!(Monday.nth_next(5), Saturday); - assert_eq!(Monday.nth_next(6), Sunday); - - assert_eq!(Sunday.nth_next(7), Sunday); - assert_eq!(Sunday.nth_next(u8::MAX), Wednesday); - assert_eq!(Monday.nth_next(7), Monday); - assert_eq!(Monday.nth_next(u8::MAX), Thursday); +#[rstest] +#[case(Sunday, 0, Sunday)] +#[case(Sunday, 1, Monday)] +#[case(Sunday, 2, Tuesday)] +#[case(Sunday, 3, Wednesday)] +#[case(Sunday, 4, Thursday)] +#[case(Sunday, 5, Friday)] +#[case(Sunday, 6, Saturday)] +#[case(Monday, 0, Monday)] +#[case(Monday, 1, Tuesday)] +#[case(Monday, 2, Wednesday)] +#[case(Monday, 3, Thursday)] +#[case(Monday, 4, Friday)] +#[case(Monday, 5, Saturday)] +#[case(Monday, 6, Sunday)] +#[case(Sunday, 7, Sunday)] +#[case(Sunday, u8::MAX, Wednesday)] +#[case(Monday, 7, Monday)] +#[case(Monday, u8::MAX, Thursday)] +fn nth_next(#[case] current: Weekday, #[case] n: u8, #[case] expected: Weekday) { + assert_eq!(current.nth_next(n), expected); } -#[test] -fn nth_prev() { - assert_eq!(Sunday.nth_prev(0), Sunday); - assert_eq!(Sunday.nth_prev(1), Saturday); - assert_eq!(Sunday.nth_prev(2), Friday); - assert_eq!(Sunday.nth_prev(3), Thursday); - assert_eq!(Sunday.nth_prev(4), Wednesday); - assert_eq!(Sunday.nth_prev(5), Tuesday); - assert_eq!(Sunday.nth_prev(6), Monday); - - assert_eq!(Monday.nth_prev(0), Monday); - assert_eq!(Monday.nth_prev(1), Sunday); - assert_eq!(Monday.nth_prev(2), Saturday); - assert_eq!(Monday.nth_prev(3), Friday); - assert_eq!(Monday.nth_prev(4), Thursday); - assert_eq!(Monday.nth_prev(5), Wednesday); - assert_eq!(Monday.nth_prev(6), Tuesday); - - assert_eq!(Sunday.nth_prev(7), Sunday); - assert_eq!(Sunday.nth_prev(u8::MAX), Thursday); - assert_eq!(Monday.nth_prev(7), Monday); - assert_eq!(Monday.nth_prev(u8::MAX), Friday); +#[rstest] +#[case(Sunday, 0, Sunday)] +#[case(Sunday, 1, Saturday)] +#[case(Sunday, 2, Friday)] +#[case(Sunday, 3, Thursday)] +#[case(Sunday, 4, Wednesday)] +#[case(Sunday, 5, Tuesday)] +#[case(Sunday, 6, Monday)] +#[case(Monday, 0, Monday)] +#[case(Monday, 1, Sunday)] +#[case(Monday, 2, Saturday)] +#[case(Monday, 3, Friday)] +#[case(Monday, 4, Thursday)] +#[case(Monday, 5, Wednesday)] +#[case(Monday, 6, Tuesday)] +#[case(Sunday, 7, Sunday)] +#[case(Sunday, u8::MAX, Thursday)] +#[case(Monday, 7, Monday)] +#[case(Monday, u8::MAX, Friday)] +fn nth_prev(#[case] current: Weekday, #[case] n: u8, #[case] expected: Weekday) { + assert_eq!(current.nth_prev(n), expected); } -#[test] -fn number_from_monday() { - assert_eq!(Monday.number_from_monday(), 1); - assert_eq!(Tuesday.number_from_monday(), 2); - assert_eq!(Wednesday.number_from_monday(), 3); - assert_eq!(Thursday.number_from_monday(), 4); - assert_eq!(Friday.number_from_monday(), 5); - assert_eq!(Saturday.number_from_monday(), 6); - assert_eq!(Sunday.number_from_monday(), 7); +#[rstest] +#[case(Monday, 1)] +#[case(Tuesday, 2)] +#[case(Wednesday, 3)] +#[case(Thursday, 4)] +#[case(Friday, 5)] +#[case(Saturday, 6)] +#[case(Sunday, 7)] +fn number_from_monday(#[case] weekday: Weekday, #[case] expected: u8) { + assert_eq!(weekday.number_from_monday(), expected); } -#[test] -fn number_from_sunday() { - assert_eq!(Sunday.number_from_sunday(), 1); - assert_eq!(Monday.number_from_sunday(), 2); - assert_eq!(Tuesday.number_from_sunday(), 3); - assert_eq!(Wednesday.number_from_sunday(), 4); - assert_eq!(Thursday.number_from_sunday(), 5); - assert_eq!(Friday.number_from_sunday(), 6); - assert_eq!(Saturday.number_from_sunday(), 7); +#[rstest] +#[case(Sunday, 1)] +#[case(Monday, 2)] +#[case(Tuesday, 3)] +#[case(Wednesday, 4)] +#[case(Thursday, 5)] +#[case(Friday, 6)] +#[case(Saturday, 7)] +fn number_from_sunday(#[case] weekday: Weekday, #[case] expected: u8) { + assert_eq!(weekday.number_from_sunday(), expected); } -#[test] -fn number_days_from_monday() { - assert_eq!(Monday.number_days_from_monday(), 0); - assert_eq!(Tuesday.number_days_from_monday(), 1); - assert_eq!(Wednesday.number_days_from_monday(), 2); - assert_eq!(Thursday.number_days_from_monday(), 3); - assert_eq!(Friday.number_days_from_monday(), 4); - assert_eq!(Saturday.number_days_from_monday(), 5); - assert_eq!(Sunday.number_days_from_monday(), 6); +#[rstest] +#[case(Monday, 0)] +#[case(Tuesday, 1)] +#[case(Wednesday, 2)] +#[case(Thursday, 3)] +#[case(Friday, 4)] +#[case(Saturday, 5)] +#[case(Sunday, 6)] +fn number_days_from_monday(#[case] weekday: Weekday, #[case] expected: u8) { + assert_eq!(weekday.number_days_from_monday(), expected); } -#[test] -fn number_days_from_sunday() { - assert_eq!(Sunday.number_days_from_sunday(), 0); - assert_eq!(Monday.number_days_from_sunday(), 1); - assert_eq!(Tuesday.number_days_from_sunday(), 2); - assert_eq!(Wednesday.number_days_from_sunday(), 3); - assert_eq!(Thursday.number_days_from_sunday(), 4); - assert_eq!(Friday.number_days_from_sunday(), 5); - assert_eq!(Saturday.number_days_from_sunday(), 6); +#[rstest] +#[case(Sunday, 0)] +#[case(Monday, 1)] +#[case(Tuesday, 2)] +#[case(Wednesday, 3)] +#[case(Thursday, 4)] +#[case(Friday, 5)] +#[case(Saturday, 6)] +fn number_days_from_sunday(#[case] weekday: Weekday, #[case] expected: u8) { + assert_eq!(weekday.number_days_from_sunday(), expected); } -#[test] -fn display() { - assert_eq!(Monday.to_string(), "Monday"); - assert_eq!(Tuesday.to_string(), "Tuesday"); - assert_eq!(Wednesday.to_string(), "Wednesday"); - assert_eq!(Thursday.to_string(), "Thursday"); - assert_eq!(Friday.to_string(), "Friday"); - assert_eq!(Saturday.to_string(), "Saturday"); - assert_eq!(Sunday.to_string(), "Sunday"); +#[rstest] +#[case(Monday, "Monday")] +#[case(Tuesday, "Tuesday")] +#[case(Wednesday, "Wednesday")] +#[case(Thursday, "Thursday")] +#[case(Friday, "Friday")] +#[case(Saturday, "Saturday")] +#[case(Sunday, "Sunday")] +fn display(#[case] weekday: Weekday, #[case] expected: &str) { + assert_eq!(weekday.to_string(), expected); } -#[test] -fn from_str() { - assert_eq!("Monday".parse(), Ok(Monday)); - assert_eq!("Tuesday".parse(), Ok(Tuesday)); - assert_eq!("Wednesday".parse(), Ok(Wednesday)); - assert_eq!("Thursday".parse(), Ok(Thursday)); - assert_eq!("Friday".parse(), Ok(Friday)); - assert_eq!("Saturday".parse(), Ok(Saturday)); - assert_eq!("Sunday".parse(), Ok(Sunday)); - assert_eq!("foo".parse::(), Err(time::error::InvalidVariant)); +#[rstest] +#[case("Monday", Ok(Monday))] +#[case("Tuesday", Ok(Tuesday))] +#[case("Wednesday", Ok(Wednesday))] +#[case("Thursday", Ok(Thursday))] +#[case("Friday", Ok(Friday))] +#[case("Saturday", Ok(Saturday))] +#[case("Sunday", Ok(Sunday))] +#[case("foo", Err(time::error::InvalidVariant))] +fn from_str(#[case] input: &str, #[case] expected: Result) { + assert_eq!(input.parse::(), expected); } diff --git a/time/Cargo.toml b/time/Cargo.toml index 696c6af26..9893a07f1 100644 --- a/time/Cargo.toml +++ b/time/Cargo.toml @@ -65,12 +65,14 @@ num_threads = { workspace = true, optional = true } js-sys = { workspace = true, optional = true } [dev-dependencies] +itertools = { workspace = true } rand = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_test = { workspace = true } quickcheck_macros = { workspace = true } time-macros = { workspace = true } +rstest = { workspace = true } [target.'cfg(__ui_tests)'.dev-dependencies] trybuild = { workspace = true }