use crate::AssertThat;
use crate::mode::Mode;
use crate::tracking::AssertionTracking;
use indoc::writedoc;
use jiff::SignedDuration;
use std::fmt::Write;
#[allow(clippy::return_self_not_must_use)]
#[cfg_attr(feature = "fluent", assertr_derive::fluent_aliases)]
pub trait SignedDurationAssertions {
fn is_zero(self) -> Self;
fn is_negative(self) -> Self;
fn is_positive(self) -> Self;
fn is_close_to(self, expected: SignedDuration, allowed_deviation: SignedDuration) -> Self;
}
impl<M: Mode> SignedDurationAssertions for AssertThat<'_, SignedDuration, M> {
#[track_caller]
fn is_zero(self) -> Self {
self.track_assertion();
if !self.actual().is_zero() {
self.add_detail_message("Actual was not zero.");
let expected = SignedDuration::ZERO;
self.fail(|w: &mut String| {
writedoc! {w, r"
Expected: {expected:#?}
Actual: {actual:#?}
", actual = self.actual()}
});
}
self
}
#[track_caller]
fn is_negative(self) -> Self {
self.track_assertion();
if !self.actual().is_negative() {
self.fail(|w: &mut String| {
writedoc! {w, r"
Expected: {actual:#?} to be negative,
Actual: {actual:#?},
", actual = self.actual()}
});
}
self
}
#[track_caller]
fn is_positive(self) -> Self {
self.track_assertion();
if !self.actual().is_positive() {
self.fail(|w: &mut String| {
writedoc! {w, r"
Expected: {actual:#?} to be positive,
Actual: {actual:#?},
", actual = self.actual()}
});
}
self
}
#[track_caller]
fn is_close_to(self, expected: SignedDuration, allowed_deviation: SignedDuration) -> Self {
self.track_assertion();
let actual = *self.actual();
let min = expected - allowed_deviation;
let max = expected + allowed_deviation;
if !(actual >= min && actual <= max) {
self.fail(|w: &mut String| {
writedoc! {w, r"
Expected value to be close to: {expected:?},
with allowed deviation being: {allowed_deviation:?},
but value was outside range: [{min:?}, {max:?}]
Actual: {actual:?}
", actual = self.actual()}
});
}
self
}
}
#[cfg(test)]
mod tests {
mod is_zero {
use crate::prelude::*;
use indoc::formatdoc;
use jiff::SignedDuration;
#[test]
fn succeeds_when_zero() {
assert_that!(SignedDuration::ZERO).is_zero();
}
#[test]
fn panics_when_not_zero() {
let duration: SignedDuration = "2h 30m".parse().unwrap();
assert_that_panic_by(|| {
assert_that!(duration).with_location(false).is_zero();
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected: 0s
Actual: 9000s
Details: [
Actual was not zero.,
]
-------- assertr --------
"#});
}
}
mod is_negative {
use crate::prelude::*;
use indoc::formatdoc;
use jiff::SignedDuration;
#[test]
fn succeeds_when_negative() {
assert_that!(SignedDuration::from_secs(-5)).is_negative();
}
#[test]
fn panics_when_zero() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::ZERO)
.with_location(false)
.is_negative();
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected: 0s to be negative,
Actual: 0s,
-------- assertr --------
"#});
}
#[test]
fn panics_when_positive() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::from_secs(5))
.with_location(false)
.is_negative();
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected: 5s to be negative,
Actual: 5s,
-------- assertr --------
"#});
}
}
mod is_positive {
use crate::prelude::*;
use indoc::formatdoc;
use jiff::SignedDuration;
#[test]
fn succeeds_when_positive() {
assert_that!(SignedDuration::from_secs(5)).is_positive();
}
#[test]
fn panics_when_zero() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::ZERO)
.with_location(false)
.is_positive();
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected: 0s to be positive,
Actual: 0s,
-------- assertr --------
"#});
}
#[test]
fn panics_when_negative() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::from_secs(-5))
.with_location(false)
.is_positive();
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected: -5s to be positive,
Actual: -5s,
-------- assertr --------
"#});
}
}
mod is_close_to {
use crate::prelude::*;
use indoc::formatdoc;
use jiff::SignedDuration;
#[test]
fn panics_when_below_allowed_range() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::from_secs_f32(0.3319))
.with_location(false)
.is_close_to(
SignedDuration::from_secs_f32(0.333),
SignedDuration::from_secs_f32(0.001),
);
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected value to be close to: 333ms,
with allowed deviation being: 1ms,
but value was outside range: [332ms, 334ms]
Actual: 331ms 900µs
-------- assertr --------
"#});
}
#[test]
fn succeeds_when_actual_is_in_allowed_range() {
assert_that!(SignedDuration::from_secs_f32(0.332)).is_close_to(
SignedDuration::from_secs_f32(0.333),
SignedDuration::from_secs_f32(0.001),
);
assert_that!(SignedDuration::from_secs_f32(0.333)).is_close_to(
SignedDuration::from_secs_f32(0.333),
SignedDuration::from_secs_f32(0.001),
);
assert_that!(SignedDuration::from_secs_f32(0.334)).is_close_to(
SignedDuration::from_secs_f32(0.333),
SignedDuration::from_secs_f32(0.001),
);
}
#[test]
fn panics_when_above_allowed_range() {
assert_that_panic_by(|| {
assert_that!(SignedDuration::from_secs_f32(0.3341))
.with_location(false)
.is_close_to(
SignedDuration::from_secs_f32(0.333),
SignedDuration::from_secs_f32(0.001),
);
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Expected value to be close to: 333ms,
with allowed deviation being: 1ms,
but value was outside range: [332ms, 334ms]
Actual: 334ms 100µs
-------- assertr --------
"#});
}
}
}