#![allow(clippy::expect_used)]
use bitemporal_runtime::{temporal_snapshot, BitemporalRecord};
use chrono::{TimeZone, Utc};
fn make_record(id: &str, valid_time: i64, recorded_time: i64) -> BitemporalRecord<String> {
BitemporalRecord {
id: id.to_string(),
valid_time: Utc.timestamp_opt(valid_time, 0).unwrap(),
recorded_time: Utc.timestamp_opt(recorded_time, 0).unwrap(),
value: format!("value-of-{id}"),
}
}
#[test]
fn temporal_snapshot_returns_one_record_per_id_at_as_of_time() {
let records = vec![
make_record("alpha", 500, 1000), make_record("alpha", 500, 1500), make_record("alpha", 500, 2000), make_record("beta", 700, 1200), ];
let as_of = Utc.timestamp_opt(1500, 0).unwrap();
let snapshot = temporal_snapshot(&records, as_of);
assert_eq!(snapshot.len(), 2, "one record per unique id");
let alpha = snapshot
.iter()
.find(|r| r.id == "alpha")
.expect("alpha must be in the snapshot");
let beta = snapshot
.iter()
.find(|r| r.id == "beta")
.expect("beta must be in the snapshot");
assert_eq!(
alpha.recorded_time,
Utc.timestamp_opt(1500, 0).unwrap(),
"as-of-1500 must return the version of alpha that was current at T=1500"
);
assert_eq!(beta.recorded_time, Utc.timestamp_opt(1200, 0).unwrap());
}
#[test]
fn temporal_snapshot_returns_empty_for_time_before_any_recording() {
let records = vec![
make_record("alpha", 100, 1000),
make_record("beta", 200, 1200),
];
let as_of = Utc.timestamp_opt(400, 0).unwrap();
let snapshot = temporal_snapshot(&records, as_of);
assert!(
snapshot.is_empty(),
"no records were recorded before T=500, so T=400 returns empty"
);
}
#[test]
fn temporal_snapshot_preserves_valid_time_through_query() {
let records = vec![make_record("alpha", 500, 1000)];
let as_of = Utc.timestamp_opt(2000, 0).unwrap();
let snapshot = temporal_snapshot(&records, as_of);
assert_eq!(snapshot.len(), 1);
let alpha = &snapshot[0];
assert_eq!(alpha.valid_time, Utc.timestamp_opt(500, 0).unwrap());
assert_eq!(alpha.recorded_time, Utc.timestamp_opt(1000, 0).unwrap());
assert_eq!(alpha.value, "value-of-alpha");
}
#[test]
fn temporal_snapshot_handles_duplicate_id_with_advancing_recorded_times() {
let records = vec![
make_record("fact", 100, 1000), make_record("fact", 100, 1500), make_record("fact", 100, 2000), ];
let as_of_1200 = temporal_snapshot(&records, Utc.timestamp_opt(1200, 0).unwrap());
assert_eq!(as_of_1200.len(), 1);
assert_eq!(
as_of_1200[0].recorded_time,
Utc.timestamp_opt(1000, 0).unwrap(),
"as of T=1200, only the T=1000 recording was known"
);
let as_of_1700 = temporal_snapshot(&records, Utc.timestamp_opt(1700, 0).unwrap());
assert_eq!(as_of_1700[0].recorded_time, Utc.timestamp_opt(1500, 0).unwrap());
let as_of_2500 = temporal_snapshot(&records, Utc.timestamp_opt(2500, 0).unwrap());
assert_eq!(as_of_2500[0].recorded_time, Utc.timestamp_opt(2000, 0).unwrap());
}