use std::path::{Path, PathBuf};
use super::support::*;
use prov_graph::exec::block_on;
#[test]
fn binned_bytes_are_not_newly_retained_by_a_routine_capture() {
let dir = seed("capture-bin");
write(
&dir,
"recyclebin/index.yaml",
"title: Recycle Bin\ndeleted: []\n",
);
write(&dir, "recyclebin/items/notes/old.md", "binned bytes\n");
write(
&dir,
"index.md",
"---\ntitle: Home\ncontents:\n- notes/a.md\n- notes/photo.jpg.yaml\n\
recycle_bin: recyclebin/index.yaml\n---\nroot\n",
);
let set = block_on(ws(&dir).history_capture_set(Path::new("index.md"))).unwrap();
assert!(
set.iter().all(|p| !p.starts_with("recyclebin/items")),
"binned bytes must not be captured: {set:?}"
);
assert!(
set.contains(&PathBuf::from("recyclebin/index.yaml")),
"the bin index is ordinary structural state: {set:?}"
);
}
#[test]
fn a_shard_index_never_answers_to_a_name_the_author_might_use() {
let dir = seed("titles-history");
capture(&dir, "2026-01-15T09:15:22.000000Z", Some("first"));
let w = ws(&dir);
let titles = block_on(w.title_index_scoped(Path::new("index.md"))).unwrap();
assert!(
matches!(titles.resolve("January 2026"), crate::TitleMatch::Unknown),
"a history shard answered to a month-and-year name"
);
assert!(
matches!(titles.resolve("History"), crate::TitleMatch::Unique(_)),
"the store index is part of the workspace and should still resolve"
);
assert!(
matches!(titles.resolve("A"), crate::TitleMatch::Unique(_)),
"an ordinary note stopped resolving"
);
}
#[test]
fn a_recycled_document_stops_answering_to_the_name_it_had() {
let dir = seed("titles-bin");
let mut w = ws(&dir);
block_on(w.recycle(Path::new("notes/a.md"), false, Some("2026-01-15T09:15:22Z"))).unwrap();
let titles = block_on(ws(&dir).title_index_scoped(Path::new("index.md"))).unwrap();
assert!(
matches!(titles.resolve("A"), crate::TitleMatch::Unknown),
"a binned document still answered to its title"
);
}
#[test]
fn a_cache_from_another_workspace_is_refused() {
let one = seed("cache-foreign-one");
let two = seed("cache-foreign-two");
let mut first = ws(&one);
first.set_fixity_cache(Some(crate::FixityCache::new(&one)));
block_on(first.history_capture(
Path::new("index.md"),
"2026-01-01T00:00:00Z",
crate::CaptureNote::default(),
))
.unwrap();
let bytes = first.take_fixity_cache().unwrap().encode();
assert!(
crate::FixityCache::decode(&bytes, &two).is_none(),
"one workspace's digests were offered to another"
);
assert!(crate::FixityCache::decode(&bytes, &one).is_some());
}
#[test]
fn uncaptured_names_what_nothing_links_and_excuses_what_prov_parks() {
let dir = seed("uncaptured");
write(
&dir,
"loose.md",
"---\ntitle: Loose\n---\nnobody links this\n",
);
write(
&dir,
"strays/deep.md",
"---\ntitle: Deep\n---\nnor this, a directory down\n",
);
write(&dir, ".hidden.md", "---\ntitle: Hidden\n---\nignored\n");
capture(&dir, "2026-07-31T09:00:00Z", None);
let found = block_on(ws(&dir).uncaptured(Path::new("index.md"))).unwrap();
let unreached: Vec<&Path> = found
.iter()
.filter(|u| u.reason == crate::Omission::Unreached)
.map(|u| u.path.as_path())
.collect();
assert_eq!(
unreached,
vec![Path::new("loose.md"), Path::new("strays/deep.md")],
"exactly the files a capture would silently leave behind"
);
let captured = block_on(ws(&dir).history_capture_set(Path::new("index.md"))).unwrap();
for path in &captured {
assert!(
!found.iter().any(|u| &u.path == path),
"{} is captured and must not be reported as left out",
path.display()
);
}
let bookkeeping: Vec<&Path> = found
.iter()
.filter(|u| u.reason == crate::Omission::Bookkeeping)
.map(|u| u.path.as_path())
.collect();
assert!(
bookkeeping.contains(&Path::new("history/index.md")),
"the store index is reachable and uncaptured, and is not a stray: {bookkeeping:?}"
);
assert!(bookkeeping.contains(&Path::new("history/blobs")));
assert!(
!bookkeeping
.iter()
.any(|p| *p != Path::new("history/blobs") && p.starts_with("history/blobs")),
"the parked interior is refused by not descending: {bookkeeping:?}"
);
}
#[test]
fn uncaptured_is_empty_when_the_graph_reaches_every_file() {
let dir = seed("uncaptured-clean");
capture(&dir, "2026-07-31T09:00:00Z", None);
let found = block_on(ws(&dir).uncaptured(Path::new("index.md"))).unwrap();
assert!(
!found.iter().any(|u| u.reason == crate::Omission::Unreached),
"the seed workspace links everything in it: {found:?}"
);
}