use super::*;
fn gen_file(rel: &str, content: &str) -> crate::core::backend::GeneratedFile {
crate::core::backend::GeneratedFile {
path: std::path::PathBuf::from(rel),
content: content.to_string(),
generated_header: true,
}
}
fn gen_file_unheadered(rel: &str, content: &str) -> crate::core::backend::GeneratedFile {
crate::core::backend::GeneratedFile {
path: std::path::PathBuf::from(rel),
content: content.to_string(),
generated_header: false,
}
}
#[test]
fn frozen_managed_paths_reports_an_unmarked_pre_existing_file() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("SomeType.java"), "final class SomeType {}\n").unwrap();
let files = vec![gen_file("SomeType.java", "final class SomeType {}\n")];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1);
assert_eq!(frozen[0].path, dir.path().join("SomeType.java").display().to_string());
assert_eq!(
frozen[0].remedy.as_deref(),
Some("// This file is auto-generated by alef — DO NOT EDIT.")
);
assert_eq!(
frozen[0].near_miss, None,
"plain hand-written content has no near miss to report"
);
}
#[test]
fn frozen_managed_paths_reports_a_near_miss_when_one_is_present() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(
dir.path().join("SomeType.java"),
"// This alef-generated file should not be edited.\nfinal class SomeType {}\n",
)
.unwrap();
let files = vec![gen_file("SomeType.java", "final class SomeType {}\n")];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1);
assert_eq!(
frozen[0].near_miss.as_deref(),
Some("// This alef-generated file should not be edited.")
);
}
#[test]
fn frozen_managed_paths_reports_nothing_when_the_existing_file_already_carries_the_marker() {
let dir = tempfile::tempdir().expect("tempdir");
let marked = format!(
"{}final class SomeType {{}}\n",
crate::core::hash::header(crate::core::hash::CommentStyle::DoubleSlash)
);
std::fs::write(dir.path().join("SomeType.java"), &marked).unwrap();
let files = vec![gen_file("SomeType.java", "final class SomeType {}\n")];
assert!(frozen_managed_paths(&files, dir.path()).is_empty());
}
#[test]
fn frozen_managed_paths_reports_nothing_when_the_file_does_not_exist() {
let dir = tempfile::tempdir().expect("tempdir");
let files = vec![gen_file("SomeType.java", "final class SomeType {}\n")];
assert!(frozen_managed_paths(&files, dir.path()).is_empty());
}
#[test]
fn frozen_managed_paths_ignores_a_hand_written_scaffold_file() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("Cargo.toml"), "[package]\nname = \"demo\"\n").unwrap();
let files = vec![gen_file_unheadered("Cargo.toml", "[package]\nname = \"demo\"\n")];
assert!(frozen_managed_paths(&files, dir.path()).is_empty());
}
#[test]
fn frozen_managed_paths_reads_the_remedy_from_self_marked_content() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("Foo.swift"), "struct Foo {}\n").unwrap();
let files = vec![gen_file_unheadered(
"Foo.swift",
"// Generated by alef. Do not edit by hand.\nstruct Foo {}\n",
)];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1);
assert_eq!(
frozen[0].remedy.as_deref(),
Some("// Generated by alef. Do not edit by hand.")
);
}
#[test]
fn frozen_managed_paths_reports_no_remedy_for_an_unmarkable_extension() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("manifest.json"), "{}\n").unwrap();
let files = vec![gen_file("manifest.json", "{}\n")];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1);
assert_eq!(frozen[0].remedy, None);
}
#[test]
fn frozen_managed_paths_reports_nothing_for_an_unmarkable_extension_with_a_committed_ownership_record() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("manifest.json");
std::fs::write(&path, "{}\n").unwrap();
crate::cli::cache::record_scaffold_owned_path(dir.path(), &path).expect("record ownership");
let files = vec![gen_file("manifest.json", "{}\n")];
assert!(
frozen_managed_paths(&files, dir.path()).is_empty(),
"a path the committed ownership record already proves alef owns must agree with \
the write guard, which would happily overwrite it"
);
}
#[test]
fn frozen_managed_paths_offers_a_real_remedy_for_clang_format() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join(".clang-format"), "---\nBasedOnStyle: LLVM\n").unwrap();
let files = vec![gen_file(".clang-format", "---\nBasedOnStyle: LLVM\n")];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1);
assert_eq!(
frozen[0].remedy.as_deref(),
Some("# This file is auto-generated by alef — DO NOT EDIT.")
);
}
#[test]
fn frozen_managed_paths_reports_an_unmarkable_generated_header_false_file_with_no_ownership_record() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("config.m4"), "dnl old content\n").unwrap();
let files = vec![gen_file_unheadered(
"config.m4",
"dnl Configuration for Rust-based PHP extension via ext-php-rs.\n",
)];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(
frozen.len(),
1,
"an unmarkable, generated_header: false, unmarked-content file the write guard would \
refuse must be surfaced by alef verify too"
);
assert_eq!(frozen[0].path, dir.path().join("config.m4").display().to_string());
assert_eq!(
frozen[0].remedy, None,
"`.m4` has no comment syntax alef stamps, so there is no literal marker line to hand back"
);
}
#[test]
fn frozen_managed_paths_reports_nothing_for_an_unmarkable_generated_header_false_file_with_a_committed_ownership_record()
{
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.m4");
std::fs::write(&path, "dnl old content\n").unwrap();
crate::cli::cache::record_scaffold_owned_path(dir.path(), &path).expect("record ownership");
let files = vec![gen_file_unheadered(
"config.m4",
"dnl Configuration for Rust-based PHP extension via ext-php-rs.\n",
)];
assert!(
frozen_managed_paths(&files, dir.path()).is_empty(),
"a path the committed ownership record already proves alef owns must agree with the \
write guard, which would happily overwrite it"
);
}
#[test]
fn every_frozen_path_is_actually_accepted_by_the_adopt_invocation_its_create_once_flag_implies() {
let dir = tempfile::tempdir().expect("tempdir");
let base = dir.path();
std::fs::write(base.join("config.m4"), "dnl old content\n").unwrap();
let seed_file = gen_file_unheadered(
"config.m4",
"dnl Configuration for Rust-based PHP extension via ext-php-rs.\n",
);
std::fs::write(base.join("SomeType.java"), "final class SomeType {}\n").unwrap();
let marker_rail_file = gen_file("SomeType.java", "final class SomeType {}\n");
let files = vec![seed_file, marker_rail_file];
let frozen = frozen_managed_paths(&files, base);
assert_eq!(
frozen.len(),
2,
"fixture precondition: both paths must be reported frozen"
);
let seed = frozen
.iter()
.find(|f| f.path.ends_with("config.m4"))
.expect("config.m4 must be in the frozen report");
assert!(
seed.create_once,
"an unmarkable, unrecorded seed must classify as create-once"
);
let adoptable = frozen
.iter()
.find(|f| f.path.ends_with("SomeType.java"))
.expect("SomeType.java must be in the frozen report");
assert!(
!adoptable.create_once,
"a marker-rail file must never classify as create-once"
);
let managed = crate::cli::commands::adopt::managed_outputs(&files, base);
let plain_write = crate::cli::commands::adopt::AdoptOptions {
target: "config.m4".to_owned(),
base_dir: base.to_path_buf(),
write: true,
converged_only: false,
clobber_create_once_seeds: false,
};
assert!(
crate::cli::commands::adopt::run(&plain_write, &managed).is_err(),
"a plain `alef adopt --write` must still refuse a create-once seed -- if this ever \
passes, `is_create_once_seed` and this fixture's `config.m4` have drifted apart"
);
let clobbering = crate::cli::commands::adopt::AdoptOptions {
clobber_create_once_seeds: true,
..plain_write
};
let seed_report = crate::cli::commands::adopt::run(&clobbering, &managed)
.expect("the exact remedy `alef verify` prints for a create-once seed must be accepted");
assert_eq!(seed_report.adopted, vec![std::path::PathBuf::from("config.m4")]);
let adopt_marker_rail = crate::cli::commands::adopt::AdoptOptions {
target: "SomeType.java".to_owned(),
base_dir: base.to_path_buf(),
write: true,
converged_only: false,
clobber_create_once_seeds: false,
};
let adoptable_report = crate::cli::commands::adopt::run(&adopt_marker_rail, &managed).expect(
"the remedy `alef verify` prints for a genuinely adoptable frozen file must be accepted \
under a plain --write",
);
assert_eq!(
adoptable_report.adopted,
vec![std::path::PathBuf::from("SomeType.java")]
);
}
#[test]
fn has_adoptable_frozen_files_is_true_when_one_of_several_frozen_files_is_adoptable() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("seed.zzz"), "old seed content\n").unwrap();
std::fs::write(dir.path().join("SomeType.java"), "final class SomeType {}\n").unwrap();
let files = vec![
gen_file_unheadered("seed.zzz", "fresh seed content\n"),
gen_file("SomeType.java", "final class SomeType {}\n"),
];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 2, "fixture precondition: both paths must be frozen");
assert!(
has_adoptable_frozen_files(&frozen),
"a genuinely adoptable frozen file must still be detected even alongside a \
create-once seed that must not gate the exit code on its own"
);
}
#[test]
fn has_adoptable_frozen_files_is_false_for_an_empty_list() {
assert!(!super::has_adoptable_frozen_files(&[]));
}
#[test]
fn has_adoptable_frozen_files_is_false_when_every_frozen_file_is_a_create_once_seed() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("seed.zzz"), "old seed content\n").unwrap();
let files = vec![crate::core::backend::GeneratedFile {
path: std::path::PathBuf::from("seed.zzz"),
content: "fresh seed content\n".to_string(),
generated_header: false,
}];
let frozen = super::frozen_managed_paths(&files, dir.path());
assert_eq!(
frozen.len(),
1,
"fixture precondition: exactly one frozen create-once seed"
);
assert!(
frozen[0].create_once,
"fixture precondition: the seed must classify as create-once"
);
assert!(
!super::has_adoptable_frozen_files(&frozen),
"a frozen list of only create-once seeds has nothing `alef adopt --write` accepts, so \
verify must not gate its exit code on it"
);
}
#[test]
fn has_adoptable_frozen_files_is_true_when_a_real_adoptable_frozen_file_remains() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("binding.rs"), "fn hand_written() {}\n").unwrap();
let files = vec![crate::core::backend::GeneratedFile {
path: std::path::PathBuf::from("binding.rs"),
content: "fn generated() {}\n".to_string(),
generated_header: true,
}];
let frozen = super::frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1, "fixture precondition: exactly one frozen file");
assert!(
!frozen[0].create_once,
"fixture precondition: this one is on the marker rail"
);
assert!(super::has_adoptable_frozen_files(&frozen));
}
#[test]
fn report_lines_omits_a_create_once_seed_and_never_names_the_clobber_flag() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("LICENSE"), "Copyright the consumer\n").unwrap();
let files = vec![gen_file_unheadered("LICENSE", "Copyright <holder>\n")];
let frozen = frozen_managed_paths(&files, dir.path());
assert_eq!(frozen.len(), 1, "the seed is still classified");
assert!(
frozen[0].create_once,
"an unmarked seed with unmarked content is create-once"
);
let report = super::report_lines(&frozen);
assert!(
report.is_empty(),
"a create-once seed must not be reported as frozen: {report:?}"
);
assert_eq!(super::unmarked_create_once_seeds(&frozen).len(), 1);
}
#[test]
fn report_lines_still_reports_a_genuinely_adoptable_frozen_file() {
let dir = tempfile::tempdir().expect("tempdir");
std::fs::write(dir.path().join("SomeType.java"), "final class SomeType {}\n").unwrap();
let files = vec![gen_file("SomeType.java", "final class SomeType {}\n")];
let frozen = frozen_managed_paths(&files, dir.path());
let report = super::report_lines(&frozen).join("\n");
assert!(report.contains("Frozen generated files detected"), "{report}");
assert!(report.contains("SomeType.java"), "{report}");
assert!(report.contains("add marker:"), "{report}");
assert!(super::unmarked_create_once_seeds(&frozen).is_empty());
}