use crate::core::backend::GeneratedFile;
use std::path::{Path, PathBuf};
use tracing_test::traced_test;
fn seed_config(base_dir: &Path, user_owned: &[&str]) {
let patterns = user_owned
.iter()
.map(|pattern| format!(" \"{pattern}\",\n"))
.collect::<String>();
let ownership = if user_owned.is_empty() {
String::new()
} else {
format!("[workspace.ownership]\nuser_owned = [\n{patterns}]\n\n")
};
std::fs::write(
base_dir.join("alef.toml"),
format!("{ownership}[[crates]]\nname = \"sample_core\"\nsources = [\"src/lib.rs\"]\n"),
)
.expect("write alef.toml");
}
fn seed_existing(base_dir: &Path, relative: &str, content: &str) -> PathBuf {
let full = base_dir.join(relative);
std::fs::create_dir_all(full.parent().expect("parent")).expect("create parent");
std::fs::write(&full, content).expect("seed existing file");
full
}
fn generated(relative: &str, content: &str, generated_header: bool) -> GeneratedFile {
GeneratedFile {
path: PathBuf::from(relative),
content: content.to_owned(),
generated_header,
}
}
#[test]
fn a_declared_user_owned_file_is_skipped_rather_than_refused_and_is_not_overwritten() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &["e2e/*/index.test.js"]);
let existing = seed_existing(base_dir, "e2e/node/index.test.js", "// hand-maintained by this repo\n");
let report = super::scaffold::write_scaffold_files_report(
&[generated("e2e/node/index.test.js", "// alef placeholder\n", false)],
base_dir,
true,
)
.expect("write");
assert_eq!(
std::fs::read_to_string(&existing).expect("read back"),
"// hand-maintained by this repo\n",
"a declared user-owned file must not be rewritten"
);
assert!(
report.refused_paths.is_empty(),
"a declared path is a disposition, not a failure; refused: {:?}",
report.refused_paths
);
assert_eq!(
report.user_owned_paths.iter().collect::<Vec<_>>(),
vec![&existing],
"the declared skip must be counted so the run can state it"
);
assert!(
report.expected_paths.contains(&existing),
"a declared path must stay in the expected set or the next orphan sweep deletes it"
);
}
#[test]
fn an_undeclared_create_once_seed_is_still_refused_exactly_as_before() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &[]);
let existing = seed_existing(base_dir, "e2e/node/index.test.js", "// hand-maintained by this repo\n");
let report = super::scaffold::write_scaffold_files_report(
&[generated("e2e/node/index.test.js", "// alef placeholder\n", false)],
base_dir,
true,
)
.expect("write");
assert_eq!(
std::fs::read_to_string(&existing).expect("read back"),
"// hand-maintained by this repo\n",
"the ownership guard must still leave an undeclared unmarked file alone"
);
assert_eq!(
report.refused_paths.iter().collect::<Vec<_>>(),
vec![&existing],
"an undeclared seed must still be reported as a refusal"
);
assert!(
report.user_owned_paths.is_empty(),
"nothing was declared, so nothing may be counted as a declared skip"
);
}
#[test]
fn a_declared_path_that_does_not_exist_is_seeded_once_and_left_unstamped() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &["e2e/*/index.test.js"]);
let target = base_dir.join("e2e/node/index.test.js");
let report = super::scaffold::write_scaffold_files_report(
&[generated("e2e/node/index.test.js", "// alef placeholder\n", true)],
base_dir,
true,
)
.expect("write");
let written = std::fs::read_to_string(&target).expect("the declared path must be seeded when absent");
assert!(
written.contains("// alef placeholder"),
"the seed must carry the generator's content: {written:?}"
);
assert!(
!crate::core::hash::content_has_alef_marker(&written),
"a declared user-owned seed must NOT be stamped -- a marker would let a later run's \
ownership guard authorise the overwrite the declaration forbids: {written:?}"
);
assert!(
report.changed_paths.contains(&target),
"the seeding write is an ordinary write and must be counted as one"
);
assert!(
report.user_owned_paths.is_empty(),
"nothing was skipped this run -- the path did not exist yet"
);
}
#[test]
fn a_seeded_declared_path_is_never_written_into_the_ownership_record() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &["e2e/*/package.json"]);
super::scaffold::write_scaffold_files_report(
&[generated(
"e2e/node/package.json",
"{\n \"name\": \"sample\"\n}\n",
false,
)],
base_dir,
true,
)
.expect("write");
let record = std::fs::read_to_string(base_dir.join(crate::cli::cache::OWNERSHIP_MANIFEST)).unwrap_or_default();
assert!(
!record.contains("package.json"),
"a declared user-owned seed must not be recorded as alef-owned: {record:?}"
);
}
#[test]
fn a_second_run_leaves_a_hand_edited_declared_seed_alone() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &["e2e/*/index.test.js"]);
let target = base_dir.join("e2e/node/index.test.js");
super::scaffold::write_scaffold_files_report(
&[generated("e2e/node/index.test.js", "// alef placeholder\n", true)],
base_dir,
true,
)
.expect("first write");
std::fs::write(&target, "// grown past the placeholder\n").expect("hand edit");
let second = super::scaffold::write_scaffold_files_report(
&[generated("e2e/node/index.test.js", "// alef placeholder v2\n", true)],
base_dir,
true,
)
.expect("second write");
assert_eq!(
std::fs::read_to_string(&target).expect("read back"),
"// grown past the placeholder\n",
"the consumer's edit must survive every later run"
);
assert!(second.refused_paths.is_empty(), "still a disposition, never a failure");
assert_eq!(second.user_owned_count(), 1, "the declared skip must be counted");
}
#[test]
fn the_binding_writer_honours_the_same_declaration() {
let temp = tempfile::tempdir().expect("tempdir");
let base_dir = temp.path();
seed_config(base_dir, &["packages/node/handwritten.ts"]);
let existing = seed_existing(base_dir, "packages/node/handwritten.ts", "// this repo's\n");
let report = super::write::write_files_report(
&[(
crate::core::config::Language::Node,
vec![generated("packages/node/handwritten.ts", "// alef output\n", true)],
)],
base_dir,
)
.expect("write");
assert_eq!(
std::fs::read_to_string(&existing).expect("read back"),
"// this repo's\n",
"the binding writer must honour the declaration too"
);
assert!(report.refused_paths.is_empty(), "declared, so not a refusal");
assert_eq!(report.user_owned_count(), 1, "declared skips must be counted here too");
}
#[test]
#[traced_test]
fn the_refusal_report_states_how_many_files_were_not_written() {
let report = super::write::WriteReport {
refused_paths: [PathBuf::from("/repo/a.rs"), PathBuf::from("/repo/b.rs")]
.into_iter()
.collect(),
..super::write::WriteReport::default()
};
super::write::report_refused_writes(&report);
assert!(
logs_contain("2 file(s) were NOT written"),
"the refusal report must state the count, not merely fire"
);
assert!(logs_contain("/repo/a.rs"), "and must name each refused path");
}
#[test]
#[traced_test]
fn the_declared_skip_report_states_a_count_without_calling_it_a_failure() {
let report = super::write::WriteReport {
user_owned_paths: ["a.json", "b.swift", "c.kt"]
.into_iter()
.map(|name| PathBuf::from("/repo").join(name))
.collect(),
..super::write::WriteReport::default()
};
super::write::report_user_owned_skips(&report);
assert!(
logs_contain("3 file(s) were not written because"),
"the declared-skip report must state its own count"
);
assert!(
logs_contain("workspace.ownership"),
"and must name the declaration a reader can go and audit"
);
assert!(
!logs_contain("were NOT written"),
"a declared skip must never be worded as the refusal tally -- the categories are the point"
);
}
#[test]
#[traced_test]
fn nothing_is_reported_when_no_path_is_declared() {
super::write::report_user_owned_skips(&super::write::WriteReport::default());
assert!(!logs_contain("workspace.ownership"));
}