#[cfg(any(feature = "chrono", feature = "jiff", feature = "time"))]
use super::ValidationError;
#[cfg(all(not(kani), any(feature = "chrono", feature = "jiff", feature = "time")))]
use crate::{ElicitCommunicator, ElicitResult, Elicitation, Prompt};
#[cfg(any(feature = "chrono", feature = "jiff", feature = "time"))]
use elicitation_macros::instrumented_impl;
#[cfg(feature = "chrono")]
use chrono::{DateTime, NaiveDateTime, Utc};
#[cfg(feature = "chrono")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct DateTimeUtcAfter {
value: DateTime<Utc>,
threshold: DateTime<Utc>,
}
#[cfg(all(feature = "chrono", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DateTimeUtcAfter(std::marker::PhantomData<()>);
#[cfg(feature = "chrono")]
#[cfg_attr(not(kani), instrumented_impl)]
impl DateTimeUtcAfter {
#[cfg(not(kani))]
pub fn new(value: DateTime<Utc>, threshold: DateTime<Utc>) -> Result<Self, ValidationError> {
if value > threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooEarly {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(_value: DateTime<Utc>, _threshold: DateTime<Utc>) -> Result<Self, ValidationError> {
let is_after: bool = kani::any();
if is_after {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooEarly {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> DateTime<Utc> {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> DateTime<Utc> {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> DateTime<Utc> {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> DateTime<Utc> {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> DateTime<Utc> {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> DateTime<Utc> {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for DateTimeUtcAfter {
fn prompt() -> Option<&'static str> {
Some("Please provide a datetime (UTC):")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for DateTimeUtcAfter {
type Style = <DateTime<Utc> as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting DateTimeUtcAfter");
let threshold = DateTime::UNIX_EPOCH;
loop {
let dt = DateTime::<Utc>::elicit(communicator).await?;
match Self::new(dt, threshold) {
Ok(valid) => {
tracing::debug!(datetime = %valid.value, "Valid datetime after threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(error = %e, "DateTime not after threshold, re-prompting");
continue;
}
}
}
}
}
#[cfg(feature = "chrono")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct DateTimeUtcBefore {
value: DateTime<Utc>,
threshold: DateTime<Utc>,
}
#[cfg(all(feature = "chrono", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DateTimeUtcBefore(std::marker::PhantomData<()>);
#[cfg(feature = "chrono")]
#[cfg_attr(not(kani), instrumented_impl)]
impl DateTimeUtcBefore {
#[cfg(not(kani))]
pub fn new(value: DateTime<Utc>, threshold: DateTime<Utc>) -> Result<Self, ValidationError> {
if value < threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooLate {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(_value: DateTime<Utc>, _threshold: DateTime<Utc>) -> Result<Self, ValidationError> {
let is_before: bool = kani::any();
if is_before {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooLate {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> DateTime<Utc> {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> DateTime<Utc> {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> DateTime<Utc> {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> DateTime<Utc> {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> DateTime<Utc> {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> DateTime<Utc> {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for DateTimeUtcBefore {
fn prompt() -> Option<&'static str> {
Some("Please provide a datetime (UTC):")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for DateTimeUtcBefore {
type Style = <DateTime<Utc> as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting DateTimeUtcBefore");
let threshold = Utc::now();
loop {
let dt = DateTime::<Utc>::elicit(communicator).await?;
match Self::new(dt, threshold) {
Ok(valid) => {
tracing::debug!(datetime = %valid.value, "Valid datetime before threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(error = %e, "DateTime not before threshold, re-prompting");
continue;
}
}
}
}
}
#[cfg(feature = "chrono")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct NaiveDateTimeAfter {
value: NaiveDateTime,
threshold: NaiveDateTime,
}
#[cfg(all(feature = "chrono", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NaiveDateTimeAfter(std::marker::PhantomData<()>);
#[cfg(feature = "chrono")]
#[cfg_attr(not(kani), instrumented_impl)]
impl NaiveDateTimeAfter {
#[cfg(not(kani))]
pub fn new(value: NaiveDateTime, threshold: NaiveDateTime) -> Result<Self, ValidationError> {
if value > threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooEarly {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(_value: NaiveDateTime, _threshold: NaiveDateTime) -> Result<Self, ValidationError> {
let is_after: bool = kani::any();
if is_after {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooEarly {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> NaiveDateTime {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> NaiveDateTime {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> NaiveDateTime {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> NaiveDateTime {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> NaiveDateTime {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> NaiveDateTime {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for NaiveDateTimeAfter {
fn prompt() -> Option<&'static str> {
Some("Please provide a datetime (no timezone):")
}
}
#[cfg(feature = "chrono")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for NaiveDateTimeAfter {
type Style = <NaiveDateTime as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting NaiveDateTimeAfter");
let threshold = DateTime::<Utc>::UNIX_EPOCH.naive_utc();
loop {
let dt = NaiveDateTime::elicit(communicator).await?;
match Self::new(dt, threshold) {
Ok(valid) => {
tracing::debug!(datetime = %valid.value, "Valid naive datetime after threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(error = %e, "NaiveDateTime not after threshold, re-prompting");
continue;
}
}
}
}
}
#[cfg(all(test, feature = "chrono"))]
mod tests {
use super::*;
use chrono::{Duration, Utc};
#[test]
fn test_datetime_utc_after_valid() {
let threshold = Utc::now();
let value = threshold + Duration::hours(1);
let result = DateTimeUtcAfter::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_datetime_utc_after_too_early() {
let threshold = Utc::now();
let value = threshold - Duration::hours(1);
let result = DateTimeUtcAfter::new(value, threshold);
assert!(result.is_err());
}
#[test]
fn test_datetime_utc_after_get() {
let threshold = Utc::now();
let value = threshold + Duration::hours(1);
let after = DateTimeUtcAfter::new(value, threshold).unwrap();
assert_eq!(after.get(), value);
assert_eq!(after.threshold(), threshold);
}
#[test]
fn test_datetime_utc_before_valid() {
let threshold = Utc::now();
let value = threshold - Duration::hours(1);
let result = DateTimeUtcBefore::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_datetime_utc_before_too_late() {
let threshold = Utc::now();
let value = threshold + Duration::hours(1);
let result = DateTimeUtcBefore::new(value, threshold);
assert!(result.is_err());
}
#[test]
fn test_naive_datetime_after_valid() {
let threshold = Utc::now().naive_utc();
let value = threshold + Duration::hours(1);
let result = NaiveDateTimeAfter::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_naive_datetime_after_too_early() {
let threshold = Utc::now().naive_utc();
let value = threshold - Duration::hours(1);
let result = NaiveDateTimeAfter::new(value, threshold);
assert!(result.is_err());
}
}
#[cfg(feature = "jiff")]
use jiff::Timestamp;
#[cfg(feature = "jiff")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct TimestampAfter {
value: Timestamp,
threshold: Timestamp,
}
#[cfg(all(feature = "jiff", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimestampAfter(std::marker::PhantomData<()>);
#[cfg(feature = "jiff")]
#[cfg_attr(not(kani), instrumented_impl)]
impl TimestampAfter {
#[cfg(not(kani))]
pub fn new(value: Timestamp, threshold: Timestamp) -> Result<Self, ValidationError> {
if value > threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooEarly {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(_value: Timestamp, _threshold: Timestamp) -> Result<Self, ValidationError> {
let is_after: bool = kani::any();
if is_after {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooEarly {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> Timestamp {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> Timestamp {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> Timestamp {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> Timestamp {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> Timestamp {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> Timestamp {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "jiff")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for TimestampAfter {
fn prompt() -> Option<&'static str> {
Some("Please provide a timestamp:")
}
}
#[cfg(feature = "jiff")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for TimestampAfter {
type Style = <Timestamp as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting TimestampAfter");
let threshold = Timestamp::UNIX_EPOCH;
loop {
let ts = Timestamp::elicit(communicator).await?;
match Self::new(ts, threshold) {
Ok(valid) => {
tracing::debug!(timestamp = %valid.value, "Valid timestamp after threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(error = %e, "Timestamp not after threshold, re-prompting");
continue;
}
}
}
}
}
#[cfg(feature = "jiff")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct TimestampBefore {
value: Timestamp,
threshold: Timestamp,
}
#[cfg(all(feature = "jiff", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TimestampBefore(std::marker::PhantomData<()>);
#[cfg(feature = "jiff")]
#[cfg_attr(not(kani), instrumented_impl)]
impl TimestampBefore {
#[cfg(not(kani))]
pub fn new(value: Timestamp, threshold: Timestamp) -> Result<Self, ValidationError> {
if value < threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooLate {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(_value: Timestamp, _threshold: Timestamp) -> Result<Self, ValidationError> {
let is_before: bool = kani::any();
if is_before {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooLate {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> Timestamp {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> Timestamp {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> Timestamp {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> Timestamp {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> Timestamp {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> Timestamp {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "jiff")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for TimestampBefore {
fn prompt() -> Option<&'static str> {
Some("Please provide a timestamp:")
}
}
#[cfg(feature = "jiff")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for TimestampBefore {
type Style = <Timestamp as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting TimestampBefore");
let threshold = Timestamp::now();
loop {
let ts = Timestamp::elicit(communicator).await?;
match Self::new(ts, threshold) {
Ok(valid) => {
tracing::debug!(timestamp = %valid.value, "Valid timestamp before threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(error = %e, "Timestamp not before threshold, re-prompting");
continue;
}
}
}
}
}
#[cfg(all(test, feature = "jiff"))]
mod jiff_tests {
use super::*;
use jiff::ToSpan;
#[test]
fn test_timestamp_after_valid() {
let threshold = Timestamp::now();
let value = threshold + 1.hour();
let result = TimestampAfter::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_timestamp_after_too_early() {
let threshold = Timestamp::now();
let value = threshold - 1.hour();
let result = TimestampAfter::new(value, threshold);
assert!(result.is_err());
}
#[test]
fn test_timestamp_before_valid() {
let threshold = Timestamp::now();
let value = threshold - 1.hour();
let result = TimestampBefore::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_timestamp_before_too_late() {
let threshold = Timestamp::now();
let value = threshold + 1.hour();
let result = TimestampBefore::new(value, threshold);
assert!(result.is_err());
}
}
#[cfg(feature = "time")]
use time::OffsetDateTime;
#[cfg(feature = "time")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct OffsetDateTimeAfter {
value: OffsetDateTime,
threshold: OffsetDateTime,
}
#[cfg(all(feature = "time", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OffsetDateTimeAfter(std::marker::PhantomData<()>);
#[cfg(feature = "time")]
#[cfg_attr(not(kani), instrumented_impl)]
impl OffsetDateTimeAfter {
#[cfg(not(kani))]
pub fn new(value: OffsetDateTime, threshold: OffsetDateTime) -> Result<Self, ValidationError> {
if value > threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooEarly {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(
_value: OffsetDateTime,
_threshold: OffsetDateTime,
) -> Result<Self, ValidationError> {
let is_after: bool = kani::any();
if is_after {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooEarly {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> OffsetDateTime {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> OffsetDateTime {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> OffsetDateTime {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> OffsetDateTime {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> OffsetDateTime {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> OffsetDateTime {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "time")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for OffsetDateTimeAfter {
fn prompt() -> Option<&'static str> {
Some("Please provide a datetime with timezone offset:")
}
}
#[cfg(feature = "time")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for OffsetDateTimeAfter {
type Style = <OffsetDateTime as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting OffsetDateTimeAfter");
let threshold = OffsetDateTime::UNIX_EPOCH;
loop {
let dt = OffsetDateTime::elicit(communicator).await?;
match Self::new(dt, threshold) {
Ok(valid) => {
tracing::debug!(datetime = %valid.value, "Valid offset datetime after threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(
error = %e,
"OffsetDateTime not after threshold, re-prompting"
);
continue;
}
}
}
}
}
#[cfg(feature = "time")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(not(kani))]
pub struct OffsetDateTimeBefore {
value: OffsetDateTime,
threshold: OffsetDateTime,
}
#[cfg(all(feature = "time", kani))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OffsetDateTimeBefore(std::marker::PhantomData<()>);
#[cfg(feature = "time")]
#[cfg_attr(not(kani), instrumented_impl)]
impl OffsetDateTimeBefore {
#[cfg(not(kani))]
pub fn new(value: OffsetDateTime, threshold: OffsetDateTime) -> Result<Self, ValidationError> {
if value < threshold {
Ok(Self { value, threshold })
} else {
Err(ValidationError::DateTimeTooLate {
value: value.to_string(),
threshold: threshold.to_string(),
})
}
}
#[cfg(kani)]
pub fn new(
_value: OffsetDateTime,
_threshold: OffsetDateTime,
) -> Result<Self, ValidationError> {
let is_before: bool = kani::any();
if is_before {
Ok(Self(std::marker::PhantomData))
} else {
Err(ValidationError::DateTimeTooLate {
value: "value".to_string(),
threshold: "threshold".to_string(),
})
}
}
#[cfg(not(kani))]
pub fn get(&self) -> OffsetDateTime {
self.value
}
#[cfg(kani)]
pub fn get(&self) -> OffsetDateTime {
panic!("get() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn threshold(&self) -> OffsetDateTime {
self.threshold
}
#[cfg(kani)]
pub fn threshold(&self) -> OffsetDateTime {
panic!("threshold() not supported in Kani verification")
}
#[cfg(not(kani))]
pub fn into_inner(self) -> OffsetDateTime {
self.value
}
#[cfg(kani)]
pub fn into_inner(self) -> OffsetDateTime {
panic!("into_inner() not supported in Kani verification")
}
}
#[cfg(feature = "time")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Prompt for OffsetDateTimeBefore {
fn prompt() -> Option<&'static str> {
Some("Please provide a datetime with timezone offset:")
}
}
#[cfg(feature = "time")]
#[cfg(not(kani))]
#[cfg_attr(not(kani), instrumented_impl)]
impl Elicitation for OffsetDateTimeBefore {
type Style = <OffsetDateTime as Elicitation>::Style;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: ElicitCommunicator>(communicator: &C) -> ElicitResult<Self> {
tracing::debug!("Eliciting OffsetDateTimeBefore");
let threshold = OffsetDateTime::now_utc();
loop {
let dt = OffsetDateTime::elicit(communicator).await?;
match Self::new(dt, threshold) {
Ok(valid) => {
tracing::debug!(datetime = %valid.value, "Valid offset datetime before threshold");
return Ok(valid);
}
Err(e) => {
tracing::warn!(
error = %e,
"OffsetDateTime not before threshold, re-prompting"
);
continue;
}
}
}
}
}
#[cfg(all(test, feature = "time"))]
mod time_tests {
use super::*;
use time::Duration;
#[test]
fn test_offset_datetime_after_valid() {
let threshold = OffsetDateTime::now_utc();
let value = threshold + Duration::hours(1);
let result = OffsetDateTimeAfter::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_offset_datetime_after_too_early() {
let threshold = OffsetDateTime::now_utc();
let value = threshold - Duration::hours(1);
let result = OffsetDateTimeAfter::new(value, threshold);
assert!(result.is_err());
}
#[test]
fn test_offset_datetime_before_valid() {
let threshold = OffsetDateTime::now_utc();
let value = threshold - Duration::hours(1);
let result = OffsetDateTimeBefore::new(value, threshold);
assert!(result.is_ok());
}
#[test]
fn test_offset_datetime_before_too_late() {
let threshold = OffsetDateTime::now_utc();
let value = threshold + Duration::hours(1);
let result = OffsetDateTimeBefore::new(value, threshold);
assert!(result.is_err());
}
}