#[must_use]
pub fn has_subsecond_precision(filetime: u64) -> bool {
filetime % 10_000_000 != 0
}
#[must_use]
pub fn is_low_precision_timestamp(filetime: u64) -> bool {
filetime != 0 && !has_subsecond_precision(filetime)
}
#[must_use]
pub fn is_all_macb_identical(m: i64, a: i64, c: i64, b: i64) -> bool {
m == a && a == c && c == b
}
#[must_use]
pub fn is_round_hour_timestamp(ts_ns: i64) -> bool {
ts_ns > 0 && ts_ns % 3_600_000_000_000 == 0
}
pub const MIN_PLAUSIBLE_INSTALL_DATE_SECS: u32 = 1_000_000_000;
#[must_use]
pub fn is_plausible_install_date(unix_secs: u32) -> bool {
unix_secs >= MIN_PLAUSIBLE_INSTALL_DATE_SECS
}
#[must_use]
pub fn is_foreign_file(born_ns: i64, modified_ns: i64) -> bool {
born_ns > modified_ns
}
pub const CLOCK_SKEW_TOLERANCE_NS: i64 = 1_000_000_000;
#[must_use]
pub fn is_future_timestamp_beyond_skew(ts_ns: i64, now_ns: i64) -> bool {
ts_ns > now_ns + CLOCK_SKEW_TOLERANCE_NS
}
#[must_use]
pub fn is_future_timestamp(ts_ns: i64, now_ns: i64) -> bool {
ts_ns > now_ns
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subsecond_precision_nonzero_sub_second() {
let filetime = 10_000_001u64; assert!(has_subsecond_precision(filetime));
}
#[test]
fn subsecond_precision_zero_sub_second() {
let filetime = 10_000_000u64; assert!(!has_subsecond_precision(filetime));
}
#[test]
fn low_precision_whole_second() {
let filetime = 10_000_000u64;
assert!(is_low_precision_timestamp(filetime));
}
#[test]
fn low_precision_zero_filetime_returns_false() {
assert!(!is_low_precision_timestamp(0));
}
#[test]
fn low_precision_with_sub_second_returns_false() {
let filetime = 10_000_001u64;
assert!(!is_low_precision_timestamp(filetime));
}
#[test]
fn macb_identical_all_same() {
assert!(is_all_macb_identical(100, 100, 100, 100));
}
#[test]
fn macb_not_identical_m_differs() {
assert!(!is_all_macb_identical(99, 100, 100, 100));
}
#[test]
fn macb_not_identical_a_differs() {
assert!(!is_all_macb_identical(100, 99, 100, 100));
}
#[test]
fn round_hour_on_exact_hour() {
assert!(is_round_hour_timestamp(3_600_000_000_000));
}
#[test]
fn round_hour_not_on_hour() {
assert!(!is_round_hour_timestamp(3_600_000_000_001));
}
#[test]
fn round_hour_zero_is_not_round() {
assert!(!is_round_hour_timestamp(0));
}
#[test]
fn round_hour_negative_is_not_round() {
assert!(!is_round_hour_timestamp(-3_600_000_000_000));
}
#[test]
fn plausible_install_date_above_threshold() {
assert!(is_plausible_install_date(1_100_000_000));
}
#[test]
fn plausible_install_date_at_threshold() {
assert!(is_plausible_install_date(MIN_PLAUSIBLE_INSTALL_DATE_SECS));
}
#[test]
fn plausible_install_date_below_threshold() {
assert!(!is_plausible_install_date(999_999_999));
}
#[test]
fn foreign_file_born_after_modified_is_foreign() {
let modified_ns = 1_577_836_800_000_000_000i64; let born_ns = 1_685_577_600_000_000_000i64; assert!(is_foreign_file(born_ns, modified_ns));
}
#[test]
fn foreign_file_born_before_modified_is_normal() {
let born_ns = 1_577_836_800_000_000_000i64; let modified_ns = 1_685_577_600_000_000_000i64; assert!(!is_foreign_file(born_ns, modified_ns));
}
#[test]
fn foreign_file_equal_timestamps_is_not_foreign() {
let ts = 1_600_000_000_000_000_000i64;
assert!(!is_foreign_file(ts, ts));
}
#[test]
fn foreign_file_born_one_ns_after_modified() {
assert!(is_foreign_file(101, 100));
}
#[test]
fn foreign_file_born_one_ns_before_modified() {
assert!(!is_foreign_file(100, 101));
}
#[test]
fn future_timestamp_strictly_greater_than_now() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + 1;
assert!(is_future_timestamp(ts_ns, now_ns));
}
#[test]
fn future_timestamp_equal_to_now_is_not_future() {
let now_ns = 1_700_000_000_000_000_000i64;
assert!(!is_future_timestamp(now_ns, now_ns));
}
#[test]
fn future_timestamp_in_past_is_not_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns - 1_000_000_000; assert!(!is_future_timestamp(ts_ns, now_ns));
}
#[test]
fn future_timestamp_far_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + 86_400_000_000_000i64; assert!(is_future_timestamp(ts_ns, now_ns));
}
#[test]
fn clock_skew_tolerance_is_one_second() {
assert_eq!(CLOCK_SKEW_TOLERANCE_NS, 1_000_000_000i64);
}
#[test]
fn beyond_skew_one_ns_over_tolerance_is_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + CLOCK_SKEW_TOLERANCE_NS + 1;
assert!(is_future_timestamp_beyond_skew(ts_ns, now_ns));
}
#[test]
fn beyond_skew_exactly_at_tolerance_is_not_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + CLOCK_SKEW_TOLERANCE_NS;
assert!(!is_future_timestamp_beyond_skew(ts_ns, now_ns));
}
#[test]
fn beyond_skew_one_ns_under_tolerance_is_not_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + CLOCK_SKEW_TOLERANCE_NS - 1;
assert!(!is_future_timestamp_beyond_skew(ts_ns, now_ns));
}
#[test]
fn beyond_skew_in_past_is_not_future() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns - 1_000_000_000; assert!(!is_future_timestamp_beyond_skew(ts_ns, now_ns));
}
#[test]
fn beyond_skew_five_seconds_ahead_is_flagged() {
let now_ns = 1_700_000_000_000_000_000i64;
let ts_ns = now_ns + 5_000_000_000i64;
assert!(is_future_timestamp_beyond_skew(ts_ns, now_ns));
}
}