use std::collections::BTreeSet;
use oxgraph_snapshot::{
PendingSection, PlanError, Snapshot, SnapshotBuilder, SnapshotError, SnapshotPlan,
};
use proptest::{prelude::*, test_runner::TestCaseError};
fn prop_plan<T>(result: Result<T, PlanError>) -> Result<T, TestCaseError> {
result.map_err(|error| TestCaseError::fail(error.to_string()))
}
fn prop_open<T>(result: Result<T, SnapshotError>) -> Result<T, TestCaseError> {
result.map_err(|error| TestCaseError::fail(error.to_string()))
}
#[derive(Clone, Debug)]
struct GenSection {
kind: u32,
version: u32,
alignment_log2: u8,
payload: Vec<u8>,
}
prop_compose! {
fn gen_section()(
kind in 0u32..64,
version in 0u32..4,
alignment_log2 in 0u8..=4,
payload in proptest::collection::vec(any::<u8>(), 0..32),
) -> GenSection {
GenSection { kind, version, alignment_log2, payload }
}
}
proptest! {
#![proptest_config(ProptestConfig {
failure_persistence: None,
..ProptestConfig::default()
})]
#[test]
fn writer_and_builder_emit_identical_bytes(
sections in proptest::collection::vec(gen_section(), 0..8),
) {
let mut seen = BTreeSet::new();
let unique: Vec<GenSection> = sections
.into_iter()
.filter(|section| seen.insert(section.kind))
.collect();
let mut builder = SnapshotBuilder::new();
for section in &unique {
prop_plan(builder.add_section(
section.kind,
section.version,
section.alignment_log2,
section.payload.clone(),
).map(|_| ()))?;
}
let from_builder = prop_plan(builder.finish())?;
let pending: Vec<PendingSection<'_>> = unique
.iter()
.map(|section| PendingSection {
kind: section.kind,
version: section.version,
alignment_log2: section.alignment_log2,
payload: section.payload.as_slice(),
})
.collect();
let plan = prop_plan(SnapshotPlan::new(&pending))?;
let needed = prop_plan(plan.encoded_len())?;
let mut from_plan = vec![0u8; needed];
let written = prop_plan(plan.write_into(&mut from_plan))?;
prop_assert_eq!(written, needed);
prop_assert_eq!(&from_builder, &from_plan);
let snapshot = prop_open(Snapshot::open(&from_builder))?;
prop_assert_eq!(snapshot.section_count(), unique.len());
for section in &unique {
let Some(view) = snapshot.section(section.kind) else {
return Err(TestCaseError::fail("section missing after open"));
};
prop_assert_eq!(view.bytes(), section.payload.as_slice());
prop_assert_eq!(view.version(), section.version);
}
}
}