#[path = "common/harness.rs"]
mod harness;
use harness::TestHarness;
use macrame::prelude::*;
use macrame::temporal::{reconstruct, save_snapshot, MaterializedState};
const TS: &str = "2026-01-01T00:00:00.000000Z";
const OPEN: &str = "9999-12-31T23:59:59.999999Z";
const LATER: &str = "2099-01-01T00:00:00.000000Z";
async fn seeded(harness: &TestHarness) -> Database {
let db = Database::open_with_cadence(&harness.db_path, None)
.await
.unwrap();
db.write_concepts(
(0..20)
.map(|i| {
ConceptUpsert::new(format!("c{i:03}"), format!("Concept {i}"))
.content(format!("body {i}"))
.valid_from(TS)
})
.collect(),
)
.await
.unwrap();
db.bulk_import(
(1..20)
.map(|i| {
EdgeAssertion::new("c000", format!("c{i:03}"), "LINKS")
.valid_from(TS)
.valid_to(OPEN)
})
.collect(),
)
.await
.unwrap();
db
}
#[tokio::test]
async fn an_empty_snapshot_directory_agrees_with_itself() {
let harness = TestHarness::new();
let db = seeded(&harness).await;
let check = db.verify_snapshot_chain(LATER).await.unwrap();
assert!(!check.diverged(), "{check}");
assert_eq!(check.composed_concepts, check.folded_concepts);
assert_eq!(check.composed_edges, check.folded_edges);
assert!(check.folded_concepts >= 20);
db.close().await.unwrap();
}
#[tokio::test]
async fn an_honest_snapshot_agrees_with_a_genesis_fold() {
let harness = TestHarness::new();
let db = seeded(&harness).await;
macrame::temporal::write_final(db.read_conn(), db.snapshots_dir(), LATER, None)
.await
.unwrap();
db.write_concepts(vec![ConceptUpsert::new("c000", "Renamed")
.content("new body")
.valid_from(TS)])
.await
.unwrap();
db.write_concepts(vec![ConceptUpsert::new("c999", "Late")
.content("late body")
.valid_from(TS)])
.await
.unwrap();
let check = db.verify_snapshot_chain(LATER).await.unwrap();
assert!(!check.diverged(), "{check}");
assert!(
check.composed_anchor > 0,
"the composed answer did not use a snapshot, so this test proved nothing: {check}"
);
db.close().await.unwrap();
}
#[tokio::test]
async fn a_tampered_snapshot_is_caught() {
let harness = TestHarness::new();
let db = seeded(&harness).await;
macrame::temporal::write_final(db.read_conn(), db.snapshots_dir(), LATER, None)
.await
.unwrap();
let mut state: MaterializedState = reconstruct(db.read_conn(), LATER, None, None)
.await
.unwrap();
let anchor = state.seq_anchor;
assert!(anchor > 0);
state
.concepts
.get_mut("c001")
.expect("c001 must be in the fold")
.title = "WRONG".to_string();
state.concepts.remove("c002");
let dropped = state.edges.pop().expect("there must be edges to drop");
save_snapshot(db.snapshots_dir(), &state).unwrap();
let check = db.verify_snapshot_chain(LATER).await.unwrap();
assert!(
check.diverged(),
"a snapshot with a renamed concept, a missing concept and a missing \
edge was certified as agreeing with the log: {check}"
);
assert!(
check.concept_disagreements.contains(&"c001".to_string()),
"the altered title was not reported: {check}"
);
assert!(
check.concept_disagreements.contains(&"c002".to_string()),
"the removed concept was not reported: {check}"
);
assert_eq!(
check.edge_disagreements.len(),
1,
"expected exactly the dropped edge: {check}"
);
assert!(
check.edge_disagreements[0].contains(&dropped.0)
&& check.edge_disagreements[0].contains(&dropped.1),
"the reported edge is not the one dropped ({dropped:?}): {check}"
);
let text = check.to_string();
assert!(text.contains("DIVERGED"), "{text}");
assert!(
text.contains("Doctrine VI") || text.contains("deleting the snapshot"),
"the report does not say the snapshots are disposable: {text}"
);
db.close().await.unwrap();
}
#[tokio::test]
async fn deleting_the_snapshots_restores_agreement() {
let harness = TestHarness::new();
let db = seeded(&harness).await;
macrame::temporal::write_final(db.read_conn(), db.snapshots_dir(), LATER, None)
.await
.unwrap();
let mut state: MaterializedState = reconstruct(db.read_conn(), LATER, None, None)
.await
.unwrap();
state.concepts.remove("c003");
save_snapshot(db.snapshots_dir(), &state).unwrap();
assert!(db.verify_snapshot_chain(LATER).await.unwrap().diverged());
for entry in std::fs::read_dir(db.snapshots_dir()).unwrap().flatten() {
std::fs::remove_file(entry.path()).unwrap();
}
let check = db.verify_snapshot_chain(LATER).await.unwrap();
assert!(
!check.diverged(),
"deleting the snapshots did not repair it: {check}"
);
db.close().await.unwrap();
}
#[tokio::test]
async fn the_report_is_bounded() {
use macrame::temporal::ChainCheck;
let harness = TestHarness::new();
let db = Database::open_with_cadence(&harness.db_path, None)
.await
.unwrap();
let n = ChainCheck::SAMPLE_LIMIT * 3;
db.write_concepts(
(0..n)
.map(|i| {
ConceptUpsert::new(format!("c{i:04}"), format!("C{i}"))
.content("body")
.valid_from(TS)
})
.collect(),
)
.await
.unwrap();
macrame::temporal::write_final(db.read_conn(), db.snapshots_dir(), LATER, None)
.await
.unwrap();
let mut state: MaterializedState = reconstruct(db.read_conn(), LATER, None, None)
.await
.unwrap();
state.concepts.clear();
save_snapshot(db.snapshots_dir(), &state).unwrap();
let check = db.verify_snapshot_chain(LATER).await.unwrap();
assert!(check.diverged());
assert_eq!(check.concept_disagreements.len(), ChainCheck::SAMPLE_LIMIT);
assert!(check.truncated, "a truncated report must say so: {check}");
db.close().await.unwrap();
}