Files
pawctioneer-bot/src/test_utils.rs
Dylan Knutson cf02bfd6d7 Major refactor: restructure new listing command and update data models
- Refactor new_listing from single file to modular structure
- Add handler factory pattern for state management
- Improve keyboard utilities and validations
- Update database models for bid, listing, and user systems
- Add new types: listing_duration, user_row_id
- Remove deprecated user_id type
- Update Docker configuration
- Enhance test utilities and message handling
2025-08-29 06:31:19 +00:00

215 lines
6.8 KiB
Rust

//! Test utilities including timestamp comparison macros
/// Assert that two timestamps are approximately equal within a given epsilon tolerance.
///
/// This macro is useful for testing timestamps that may have small variations due to
/// execution timing. The epsilon is specified as a `Duration`.
///
/// # Examples
///
/// ```
/// use chrono::{Utc, Duration};
/// use crate::test_utils::assert_timestamps_approx_eq;
///
/// let now = Utc::now();
/// let nearly_now = now + Duration::milliseconds(50);
///
/// // This will pass - 50ms difference is within 100ms epsilon
/// assert_timestamps_approx_eq!(now, nearly_now, Duration::milliseconds(100));
///
/// // This will fail - 150ms difference exceeds 100ms epsilon
/// // assert_timestamps_approx_eq!(now, nearly_now, Duration::milliseconds(100));
/// ```
#[macro_export]
macro_rules! assert_timestamps_approx_eq {
($left:expr, $right:expr, $epsilon:expr) => {{
let left_val = $left;
let right_val = $right;
let epsilon_val = $epsilon;
let diff = if left_val > right_val {
left_val - right_val
} else {
right_val - left_val
};
if diff > epsilon_val {
panic!(
"Timestamp assertion failed: timestamps differ by {:?}, which exceeds epsilon {:?}\n left: {:?}\n right: {:?}",
diff, epsilon_val, left_val, right_val
);
}
}};
($left:expr, $right:expr, $epsilon:expr, $($arg:tt)+) => {{
let left_val = $left;
let right_val = $right;
let epsilon_val = $epsilon;
let diff = if left_val > right_val {
left_val - right_val
} else {
right_val - left_val
};
if diff > epsilon_val {
panic!(
"Timestamp assertion failed: timestamps differ by {:?}, which exceeds epsilon {:?}\n left: {:?}\n right: {:?}\n{}",
diff, epsilon_val, left_val, right_val, format_args!($($arg)+)
);
}
}};
}
/// Assert that two timestamps are approximately equal within a default epsilon of 1 second.
///
/// This is a convenience macro for common cases where a 1-second tolerance is sufficient.
/// For more control over the epsilon, use `assert_timestamps_approx_eq!`.
///
/// # Examples
///
/// ```
/// use chrono::Utc;
/// use crate::test_utils::assert_timestamps_approx_eq_default;
///
/// let now = Utc::now();
/// let nearly_now = now + chrono::Duration::milliseconds(500);
///
/// // This will pass - 500ms difference is within default 1s epsilon
/// assert_timestamps_approx_eq_default!(now, nearly_now);
/// ```
#[macro_export]
macro_rules! assert_timestamps_approx_eq_default {
($left:expr, $right:expr) => {
$crate::assert_timestamps_approx_eq!($left, $right, chrono::Duration::seconds(1))
};
($left:expr, $right:expr, $($arg:tt)+) => {
$crate::assert_timestamps_approx_eq!($left, $right, chrono::Duration::seconds(1), $($arg)+)
};
}
/// Assert that the `starts_at` and `ends_at` fields of two structs are approximately equal.
///
/// This macro is specifically designed for comparing listing timestamps where small
/// variations in timing are expected. Uses a default epsilon of 1 second.
///
/// # Examples
///
/// ```
/// use chrono::Utc;
/// use crate::test_utils::assert_listing_timestamps_approx_eq;
///
/// let original_listing = /* some listing */;
/// let reconstructed_listing = /* reconstructed from DB */;
///
/// // Compare both starts_at and ends_at with default 1s epsilon
/// assert_listing_timestamps_approx_eq!(
/// original_listing.base,
/// reconstructed_listing.base
/// );
/// ```
#[macro_export]
macro_rules! assert_listing_timestamps_approx_eq {
($left:expr, $right:expr) => {
$crate::assert_timestamps_approx_eq_default!(
$left.starts_at,
$right.starts_at,
"starts_at timestamps don't match"
);
$crate::assert_timestamps_approx_eq_default!(
$left.ends_at,
$right.ends_at,
"ends_at timestamps don't match"
);
};
($left:expr, $right:expr, $epsilon:expr) => {
$crate::assert_timestamps_approx_eq!(
$left.starts_at,
$right.starts_at,
$epsilon,
"starts_at timestamps don't match"
);
$crate::assert_timestamps_approx_eq!(
$left.ends_at,
$right.ends_at,
$epsilon,
"ends_at timestamps don't match"
);
};
}
#[cfg(test)]
mod tests {
use chrono::{Duration, Utc};
#[test]
fn test_assert_timestamps_approx_eq_success() {
let now = Utc::now();
let nearly_now = now + Duration::milliseconds(50);
// Should not panic - within epsilon
assert_timestamps_approx_eq!(now, nearly_now, Duration::milliseconds(100));
assert_timestamps_approx_eq!(nearly_now, now, Duration::milliseconds(100));
}
#[test]
fn test_assert_timestamps_approx_eq_exact() {
let now = Utc::now();
// Should not panic - exact match
assert_timestamps_approx_eq!(now, now, Duration::milliseconds(1));
}
#[test]
#[should_panic(expected = "Timestamp assertion failed")]
fn test_assert_timestamps_approx_eq_failure() {
let now = Utc::now();
let much_later = now + Duration::seconds(2);
// Should panic - exceeds epsilon
assert_timestamps_approx_eq!(now, much_later, Duration::milliseconds(100));
}
#[test]
fn test_assert_timestamps_approx_eq_default_success() {
let now = Utc::now();
let nearly_now = now + Duration::milliseconds(500);
// Should not panic - within default 1s epsilon
assert_timestamps_approx_eq_default!(now, nearly_now);
}
#[test]
#[should_panic(expected = "Timestamp assertion failed")]
fn test_assert_timestamps_approx_eq_default_failure() {
let now = Utc::now();
let much_later = now + Duration::seconds(2);
// Should panic - exceeds default 1s epsilon
assert_timestamps_approx_eq_default!(now, much_later);
}
#[test]
fn test_custom_error_message() {
let now = Utc::now();
let nearly_now = now + Duration::milliseconds(50);
// Should not panic - within epsilon, but test custom message format
assert_timestamps_approx_eq!(
now,
nearly_now,
Duration::milliseconds(100),
"Custom error message"
);
}
#[test]
fn test_negative_duration() {
let now = Utc::now();
let earlier = now - Duration::milliseconds(50);
// Should not panic - absolute difference is within epsilon
assert_timestamps_approx_eq!(now, earlier, Duration::milliseconds(100));
assert_timestamps_approx_eq!(earlier, now, Duration::milliseconds(100));
}
}