use std::fs::{self, OpenOptions};
use proptest::prelude::*;
use wal_db::Wal;
proptest! {
#[test]
fn truncation_at_any_offset_recovers_a_clean_prefix(
records in prop::collection::vec(prop::collection::vec(any::<u8>(), 0..64), 0..40),
cut in 0u64..8192,
) {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("torn.wal");
{
let wal = Wal::open(&path).unwrap();
for record in &records {
let _ = wal.append(record).unwrap();
}
}
let full_len = fs::metadata(&path).unwrap().len();
let cut_at = cut.min(full_len);
let file = OpenOptions::new().write(true).open(&path).unwrap();
file.set_len(cut_at).unwrap();
drop(file);
let wal = Wal::open(&path).unwrap();
let recovered: Vec<Vec<u8>> = {
let mut out = Vec::new();
for item in wal.iter().unwrap() {
out.push(item.expect("recovered records must all be complete").into_data());
}
out
};
prop_assert!(recovered.len() <= records.len());
for (got, original) in recovered.iter().zip(records.iter()) {
prop_assert_eq!(got, original);
}
if cut_at == full_len {
prop_assert_eq!(recovered.len(), records.len());
}
let expected_tail: u64 = recovered.iter().map(|r| (8 + r.len()) as u64).sum();
let next = wal.append(b"sentinel").unwrap();
prop_assert_eq!(next.get(), expected_tail);
}
}