use std::path::Path;
use std::process::Command;
use rto_graph::{IngestConfig, ObjectCache, Registry, Repo, Store};
fn git(dir: &Path, args: &[&str]) -> std::process::Output {
let out = Command::new("git")
.args([
"-c",
"user.name=Test",
"-c",
"user.email=t@t",
"-c",
"commit.gpgsign=false",
"-c",
"init.defaultBranch=main",
])
.args(args)
.current_dir(dir)
.output()
.expect("run git");
assert!(out.status.success(), "git {args:?} failed");
out
}
fn rev(dir: &Path, r: &str) -> String {
String::from_utf8(git(dir, &["rev-parse", r]).stdout)
.unwrap()
.trim()
.to_owned()
}
fn config_keys_at(repo: &Repo, cache: &ObjectCache, rev: &str) -> Vec<String> {
let reg = Registry::new(IngestConfig::default());
let mut store = Store::open_in_memory().expect("store");
rto_graph::sync_tree(&mut store, repo, cache, ®, rev).expect("sync_tree");
let mut keys: Vec<String> = store
.config_keys()
.expect("config_keys")
.into_iter()
.map(|c| c.key)
.collect();
keys.sort();
keys
}
#[test]
fn sync_tree_materialises_the_graph_at_a_pinned_commit() {
let base = std::env::temp_dir().join(format!("roteiro-synctree-{}", std::process::id()));
std::fs::remove_dir_all(&base).ok();
std::fs::create_dir_all(&base).expect("mkdir");
git(&base, &["init", "-q"]);
std::fs::write(base.join("README.md"), "# hub\n").expect("write");
std::fs::write(
base.join("config.toml"),
"[serve]\naddr = \"0.0.0.0\"\ntools = true\n",
)
.expect("write");
git(&base, &["add", "."]);
git(&base, &["commit", "-q", "-m", "v1"]);
let v1 = rev(&base, "HEAD");
std::fs::write(
base.join("config.toml"),
"[serve]\naddr = \"0.0.0.0\"\nfeatures = true\n",
)
.expect("write");
git(&base, &["add", "."]);
git(&base, &["commit", "-q", "-m", "v2"]);
let head = rev(&base, "HEAD");
let repo = Repo::discover(&base).expect("discover");
let cache =
ObjectCache::open(repo.common_dir().join("roteiro").join("objects")).expect("cache");
let at_pin = config_keys_at(&repo, &cache, &v1);
let at_head = config_keys_at(&repo, &cache, &head);
assert!(
at_pin.iter().any(|k| k == "serve.tools"),
"v1 has it: {at_pin:?}"
);
assert!(
!at_head.iter().any(|k| k == "serve.tools"),
"HEAD renamed it: {at_head:?}"
);
assert!(
at_head.iter().any(|k| k == "serve.features"),
"HEAD has features: {at_head:?}"
);
let readme = |r: &str| {
repo.blobs_at(r)
.unwrap()
.into_iter()
.find(|b| b.path == "README.md")
.unwrap()
.oid
};
assert_eq!(
readme(&v1),
readme(&head),
"unchanged blob keeps its oid → cache hit"
);
std::fs::remove_dir_all(&base).ok();
}