use assert_cmd::Command;
use std::collections::BTreeMap;
fn sdivi() -> Command {
Command::cargo_bin("sdivi").expect("sdivi binary must be built")
}
fn minimal_snapshot_json(path_partition: &BTreeMap<&str, u32>) -> String {
let pp_entries: Vec<String> = path_partition
.iter()
.map(|(k, v)| format!("\"{}\":{}", k, v))
.collect();
let pp_json = format!("{{{}}}", pp_entries.join(","));
format!(
r#"{{
"snapshot_version": "1.0",
"timestamp": "2026-04-29T00:00:00Z",
"graph": {{
"node_count": 2,
"edge_count": 1,
"density": 0.5,
"cycle_count": 0,
"top_hubs": [],
"component_count": 1
}},
"partition": {{
"assignments": {{"0": 0, "1": 0}},
"stability": {{"0": 1.0}},
"modularity": 0.5,
"seed": 42
}},
"catalog": {{"entries": {{}}}},
"pattern_metrics": {{
"entropy_per_category": {{}},
"total_entropy": 0.0,
"convention_drift": 0.0
}},
"path_partition": {pp_json}
}}"#
)
}
fn write_stable_snapshots(repo: &std::path::Path, n: usize) {
let snap_dir = repo.join(".sdivi").join("snapshots");
std::fs::create_dir_all(&snap_dir).unwrap();
let pp: BTreeMap<&str, u32> = [("a.rs", 0), ("b.rs", 0)].into();
let json = minimal_snapshot_json(&pp);
for i in 0..n {
let name = format!("snapshot_{i:04}.json");
std::fs::write(snap_dir.join(&name), &json).unwrap();
}
}
#[test]
fn ratify_emits_comment_loss_warning_when_spec_has_yaml_hash_comment() {
let repo = tempfile::tempdir().unwrap();
write_stable_snapshots(repo.path(), 4);
let sdivi_dir = repo.path().join(".sdivi");
let boundary_path = sdivi_dir.join("boundaries.yaml");
std::fs::write(
&boundary_path,
"# Hand-crafted spec — this comment will be lost on ratify\n\
boundaries:\n\
- name: old_community\n\
modules: []\n\
allow_imports_from: []\n",
)
.unwrap();
let out = sdivi()
.arg("--repo")
.arg(repo.path())
.arg("boundaries")
.arg("ratify")
.output()
.unwrap();
assert!(
out.status.success(),
"ratify must exit 0 even when overwriting a file with comments"
);
let stderr = String::from_utf8(out.stderr).unwrap();
assert!(
stderr.contains("comments will be lost"),
"stderr must contain the comment-loss warning; got: {stderr:?}"
);
assert!(
stderr.contains("boundaries.yaml") || stderr.contains(".sdivi"),
"warning must mention the spec file path; got: {stderr:?}"
);
}
#[test]
fn ratify_no_warning_when_spec_has_no_comments() {
let repo = tempfile::tempdir().unwrap();
write_stable_snapshots(repo.path(), 4);
let sdivi_dir = repo.path().join(".sdivi");
let boundary_path = sdivi_dir.join("boundaries.yaml");
std::fs::write(
&boundary_path,
"boundaries:\n\
- name: old_community\n\
modules: []\n\
allow_imports_from: []\n",
)
.unwrap();
let out = sdivi()
.arg("--repo")
.arg(repo.path())
.arg("boundaries")
.arg("ratify")
.output()
.unwrap();
assert!(out.status.success());
let stderr = String::from_utf8(out.stderr).unwrap();
assert!(
!stderr.contains("comments will be lost"),
"no comment-loss warning expected when file has no comments; got: {stderr:?}"
);
}
#[test]
fn ratify_no_warning_when_no_pre_existing_spec() {
let repo = tempfile::tempdir().unwrap();
write_stable_snapshots(repo.path(), 4);
let out = sdivi()
.arg("--repo")
.arg(repo.path())
.arg("boundaries")
.arg("ratify")
.output()
.unwrap();
assert!(out.status.success());
let stderr = String::from_utf8(out.stderr).unwrap();
assert!(
!stderr.contains("comments will be lost"),
"no comment-loss warning expected for first-time ratify; got: {stderr:?}"
);
}