use super::ensure_required_records_tracked;
use crate::bin_cli::args::Commands;
use crate::bin_cli::dispatch::DispatchContext;
use crate::cli::cache;
use std::path::Path;
const OWNERSHIP_MANIFEST: &str = ".alef-ownership.toml";
fn init_git_work_tree(base_dir: &Path) -> Option<()> {
let status = crate::test_support::git_command(base_dir)
.args(["init", "--quiet"])
.status()
.ok()?;
status.success().then_some(())
}
fn git_add(base_dir: &Path, relative: &str) {
let status = crate::test_support::git_command(base_dir)
.args(["add", "--", relative])
.status()
.expect("git add");
assert!(status.success(), "git add {relative} failed");
}
#[test]
fn verify_fails_on_an_untracked_required_record_and_passes_once_it_is_staged() {
let dir = tempfile::tempdir().expect("tempdir");
let base = dir.path();
if init_git_work_tree(base).is_none() {
return;
}
cache::record_scaffold_owned_path(base, &base.join("packages/node/package.json")).expect("record");
let error = ensure_required_records_tracked(&cache::untracked_required_records(base), false)
.expect_err("an untracked required record must fail verification, not merely print");
let message = error.to_string();
assert!(
message.contains(OWNERSHIP_MANIFEST),
"the failure must name the offending record, got: {message}"
);
assert!(
message.contains(&format!("git add {OWNERSHIP_MANIFEST}")),
"the failure must carry the exact remedy command, got: {message}"
);
git_add(base, OWNERSHIP_MANIFEST);
ensure_required_records_tracked(&cache::untracked_required_records(base), false)
.expect("staging the record must make verification pass");
}
#[test]
fn verify_passes_outside_a_git_work_tree() {
let dir = tempfile::tempdir().expect("tempdir");
let base = dir.path();
cache::record_scaffold_owned_path(base, &base.join("packages/node/package.json")).expect("record");
assert!(base.join(OWNERSHIP_MANIFEST).is_file(), "sanity: the record exists");
ensure_required_records_tracked(&cache::untracked_required_records(base), false)
.expect("no repository to ask means no fault to report");
}
#[test]
fn report_only_downgrades_an_untracked_record_to_a_report() {
let dir = tempfile::tempdir().expect("tempdir");
let base = dir.path();
if init_git_work_tree(base).is_none() {
return;
}
cache::record_scaffold_owned_path(base, &base.join("packages/node/package.json")).expect("record");
let untracked = cache::untracked_required_records(base);
assert_eq!(
untracked,
vec![OWNERSHIP_MANIFEST],
"sanity: without this the report-only assertion below would examine nothing"
);
ensure_required_records_tracked(&untracked, true).expect("--report-only keeps a successful exit status");
}
const DIFF_FIXTURE_SOURCE: &str = "pub fn greet(name: String) -> String {\n name\n}\n";
const DIFF_FIXTURE_CARGO_TOML: &str = "[package]\nname = \"test-lib\"\nversion = \"0.1.0\"\nedition = \"2024\"\n";
const DIFF_FIXTURE_ALEF_TOML: &str = r#"
[workspace]
languages = ["python"]
[[crates]]
name = "test-lib"
sources = ["src/lib.rs"]
version_from = "Cargo.toml"
[crates.python]
module_name = "test_lib"
[crates.python.stubs]
output = "packages/python/test_lib"
"#;
fn write_diff_fixture_workspace(root: &Path) {
std::fs::create_dir_all(root.join("src")).expect("create fixture src directory");
std::fs::write(root.join("src/lib.rs"), DIFF_FIXTURE_SOURCE).expect("write fixture source");
std::fs::write(root.join("Cargo.toml"), DIFF_FIXTURE_CARGO_TOML).expect("write fixture Cargo.toml");
std::fs::write(root.join("alef.toml"), DIFF_FIXTURE_ALEF_TOML).expect("write fixture alef.toml");
}
#[test]
fn diff_does_not_regress_a_language_manifest_generate_already_reconciled() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
write_diff_fixture_workspace(&root);
let _cwd = crate::test_support::CwdGuard::enter(&root);
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
super::handle(
Commands::Generate {
lang: None,
clean: false,
skip_frb: false,
strict: false,
},
&context,
)
.expect("alef generate must succeed against the fixture");
let mut before = cache::read_lang_manifest("test-lib", "python");
before.sort();
let mut expected = vec![
root.join("crates/test-lib-py/src/lib.rs"),
root.join("packages/python/test_lib/test_lib.pyi"),
root.join("packages/python/test_lib/options.py"),
root.join("packages/python/test_lib/api.py"),
root.join("packages/python/test_lib/exceptions.py"),
root.join("packages/python/test_lib/__init__.py"),
];
expected.sort();
assert_eq!(
before, expected,
"sanity: alef generate must record all six alef-marked Python files before alef diff \
ever runs, or the assertion below would pass even if diff wiped the manifest clean"
);
super::handle(Commands::Diff { exit_code: false }, &context).expect("alef diff must succeed");
let mut after = cache::read_lang_manifest("test-lib", "python");
after.sort();
assert_eq!(
after, before,
"alef diff is documented as \"without writing\" and must not regress \
<lang>.manifest -- got {after:?}, expected the unchanged pre-diff set {before:?}"
);
}
fn verify_command() -> Commands {
Commands::Verify {
exit_code: false,
report_only: false,
compile: false,
lint: false,
lang: None,
}
}
#[test]
fn verify_command_reports_and_fails_on_a_real_orphaned_generated_file() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
write_diff_fixture_workspace(&root);
let _cwd = crate::test_support::CwdGuard::enter(&root);
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
crate::bin_cli::all_commands::handle(
Commands::All {
clean: false,
clobber_create_once_seeds: false,
strict: false,
skip_frb: true,
skip_snippet_validation: false,
},
&context,
)
.expect("alef all must succeed against the fixture");
super::handle(verify_command(), &context)
.expect("alef verify must pass on a tree alef all just produced, before any orphan is injected");
let current = root.join("packages/python/test_lib/api.py");
let stale = root.join("packages/python/test_lib/legacy_visitor.py");
std::fs::copy(¤t, &stale).expect("plant a stale alef-marked file");
let error = super::handle(verify_command(), &context)
.err()
.expect("alef verify must fail once an alef-marked file is orphaned on disk");
let message = error.to_string();
assert!(
message.contains("out of date"),
"alef verify's real failure path must be the one under test, got: {message}"
);
let report_only_error = super::handle(
Commands::Verify {
exit_code: false,
report_only: true,
compile: false,
lint: false,
lang: None,
},
&context,
)
.err();
assert!(
report_only_error.is_none(),
"--report-only must downgrade the same orphan finding to a non-fatal report, got: \
{report_only_error:?}"
);
std::fs::remove_file(&stale).expect("remove the planted orphan");
super::handle(verify_command(), &context)
.expect("alef verify must pass again once the orphaned file is removed from disk");
}
#[test]
fn verify_passes_with_zero_findings_despite_a_gitignored_dependency_cache_directory() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
write_diff_fixture_workspace(&root);
if init_git_work_tree(&root).is_none() {
return;
}
let _cwd = crate::test_support::CwdGuard::enter(&root);
std::fs::write(root.join(".gitignore"), "vendor-cache/\n").expect("write .gitignore");
let cache_dir = root.join("test_apps/native/vendor-cache/fetched-dep-9.9.9/src");
std::fs::create_dir_all(&cache_dir).expect("create the vendored dependency cache directory");
std::fs::write(
cache_dir.join("legacy.py"),
"# generated by alef\n# alef:hash:0000000000000000000000000000000000000000000000000000000000000000\n",
)
.expect("plant a foreign alef-marked file inside the gitignored cache");
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
crate::bin_cli::all_commands::handle(
Commands::All {
clean: false,
clobber_create_once_seeds: false,
strict: false,
skip_frb: true,
skip_snippet_validation: false,
},
&context,
)
.expect("alef all must succeed against the fixture");
git_add(&root, ".");
super::handle(verify_command(), &context).expect(
"alef verify must pass with zero findings on a freshly regenerated tree, even with a \
gitignored dependency-cache directory containing a stale, alef-marked file sitting \
alongside it",
);
}
#[test]
fn docs_skip_snippet_validation_flag_bypasses_the_real_validator() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
write_diff_fixture_workspace(&root);
std::fs::create_dir_all(root.join("docs/snippets/json")).expect("create snippet directory");
std::fs::write(
root.join("docs/snippets/json/example.md"),
"```json\n{ this is not valid json\n```\n",
)
.expect("write invalid JSON snippet");
std::fs::write(
root.join("alef.toml"),
format!(
"{DIFF_FIXTURE_ALEF_TOML}\n[workspace.docs.snippets]\ndirs = [\"docs/snippets\"]\nvalidation_level = \"syntax\"\n"
),
)
.expect("overwrite fixture alef.toml with a docs.snippets section");
let _cwd = crate::test_support::CwdGuard::enter(&root);
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
let validated_err = match super::handle(
Commands::Docs {
lang: None,
output: None,
skip_snippet_validation: false,
},
&context,
) {
Err(error) => error,
Ok(_) => panic!(
"the invalid JSON snippet must fail validation when `alef docs` runs it -- if this \
passes, the fixture never reaches the validator and the assertion below proves nothing"
),
};
assert!(
validated_err.to_string().contains("snippet validation failed"),
"expected a snippet-validation failure naming the invalid JSON, got: {validated_err:#}"
);
super::handle(
Commands::Docs {
lang: None,
output: None,
skip_snippet_validation: true,
},
&context,
)
.expect(
"`alef docs --skip-snippet-validation` must never invoke the same invalid-JSON \
snippet's validator -- its failure above proves this fixture reaches the validator \
when it runs, so success here can only mean the compile-validation step was skipped",
);
}