use crate::bin_cli::helpers::verify_walk;
use crate::core::hash;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
const SOURCES_HASH: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
const ALEF_TOML: &[u8] = b"[workspace]\nlanguages = [\"python\"]\n";
fn write_marked(root: &Path, relative: &str, body: &str) -> PathBuf {
let path = relative.split('/').fold(root.to_path_buf(), |acc, part| acc.join(part));
std::fs::create_dir_all(path.parent().expect("relative path has a parent")).expect("create parent dirs");
let content = format!("{}{body}", hash::header(hash::CommentStyle::DoubleSlash));
std::fs::write(&path, content).expect("write marked file");
path
}
const UNFORMATTED_BODY: &str = "pub fn build(alpha: u32, beta: u32, gamma: u32, delta: u32, epsilon: u32) -> u32 { alpha + beta + gamma + delta + epsilon }\n";
const FORMATTED_BODY: &str = "pub fn build(alpha: u32, beta: u32, gamma: u32, delta: u32, epsilon: u32) -> u32 {\n alpha + beta + gamma + delta + epsilon\n}\n";
struct Tree {
_dir: tempfile::TempDir,
root: PathBuf,
in_stamp_set: PathBuf,
outside_stamp_set: PathBuf,
}
fn tree() -> Tree {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path().to_path_buf();
let in_stamp_set = write_marked(&root, "packages/python/glue.rs", FORMATTED_BODY);
let outside_stamp_set = write_marked(&root, "crates/demo-py/src/lib.rs", UNFORMATTED_BODY);
Tree {
_dir: dir,
root,
in_stamp_set,
outside_stamp_set,
}
}
fn path_set(paths: &[&PathBuf]) -> HashSet<PathBuf> {
paths.iter().map(|p| (*p).clone()).collect()
}
fn stale_paths(root: &Path) -> Vec<String> {
verify_walk(root)
.expect("verify walk")
.into_iter()
.map(|mismatch| mismatch.path)
.collect()
}
#[test]
fn formatting_a_file_outside_the_stamp_set_makes_verify_report_it_stale() {
let tree = tree();
let all = path_set(&[&tree.in_stamp_set, &tree.outside_stamp_set]);
super::finalize_hashes(&all, SOURCES_HASH, ALEF_TOML).expect("initial stamp");
assert!(
stale_paths(&tree.root).is_empty(),
"the tree must start verify-clean, or this test proves nothing"
);
std::fs::write(
&tree.outside_stamp_set,
hash::inject_hash_line(
&format!("{}{FORMATTED_BODY}", hash::header(hash::CommentStyle::DoubleSlash)),
&hash::extract_hash(&std::fs::read_to_string(&tree.outside_stamp_set).expect("read"))
.expect("stamped file carries a hash line"),
),
)
.expect("simulate formatter rewrite");
super::finalize_hashes(&path_set(&[&tree.in_stamp_set]), SOURCES_HASH, ALEF_TOML).expect("narrow stamp");
assert_eq!(
stale_paths(&tree.root),
vec![tree.outside_stamp_set.display().to_string()],
"a formatter pass wider than the stamp set leaves exactly the untracked file stale"
);
}
#[test]
fn finalize_hashes_after_tree_format_keeps_verify_clean_for_files_outside_the_stamp_set() {
let tree = tree();
let all = path_set(&[&tree.in_stamp_set, &tree.outside_stamp_set]);
super::finalize_hashes(&all, SOURCES_HASH, ALEF_TOML).expect("initial stamp");
std::fs::write(
&tree.outside_stamp_set,
hash::inject_hash_line(
&format!("{}{FORMATTED_BODY}", hash::header(hash::CommentStyle::DoubleSlash)),
&hash::extract_hash(&std::fs::read_to_string(&tree.outside_stamp_set).expect("read"))
.expect("stamped file carries a hash line"),
),
)
.expect("simulate formatter rewrite");
super::finalize_hashes_after_tree_format(&path_set(&[&tree.in_stamp_set]), &tree.root, SOURCES_HASH, ALEF_TOML)
.expect("tree-scoped stamp");
assert!(
stale_paths(&tree.root).is_empty(),
"after a whole-tree format pass every alef-marked file under the formatted root must \
carry a stamp derived from its post-format bytes; still stale: {:?}",
stale_paths(&tree.root)
);
}