use super::handle;
use crate::bin_cli::args::Commands;
use crate::bin_cli::dispatch::DispatchContext;
use crate::test_support::CwdGuard as E2eDeferCwdGuard;
const E2E_DEFER_FIXTURE_SOURCE: &str = r#"
pub struct Metadata {
pub document_title: String,
}
pub struct CompletionResult {
pub id: String,
pub metadata: Metadata,
}
pub fn complete(prompt: String) -> Result<CompletionResult, String> {
let _ = prompt;
Err("unimplemented".to_string())
}
"#;
const E2E_DEFER_FIXTURE_CARGO_TOML: &str = "[package]\nname = \"deferlib\"\nversion = \"0.1.0\"\nedition = \"2024\"\n";
const E2E_DEFER_FIXTURE_ALEF_TOML: &str = r#"
[workspace]
languages = ["python"]
[[crates]]
name = "deferlib"
sources = ["src/lib.rs"]
version_from = "Cargo.toml"
[crates.e2e]
fixtures = "fixtures"
output = "e2e"
languages = ["c", "rust"]
[crates.e2e.call]
function = "complete"
module = "deferlib"
result_var = "result"
[[crates.e2e.call.args]]
name = "prompt"
field = "input.prompt"
type = "string"
"#;
fn e2e_defer_fixture_json(field: &str) -> String {
format!(
"{{\n \"id\": \"complete_basic\",\n \"description\": \"a completion asserting a field on \
the nested Metadata type\",\n \"category\": \"smoke\",\n \"tags\": [\"smoke\"],\n \
\"call\": \"_default\",\n \"input\": {{ \"prompt\": \"hello\" }},\n \"assertions\": [\n \
{{ \"type\": \"not_error\" }},\n {{ \"type\": \"equals\", \"field\": \"{field}\", \"value\": \"irrelevant\" }}\n \
]\n}}\n"
)
}
fn write_e2e_defer_fixture_workspace(root: &std::path::Path, field: &str) {
std::fs::create_dir_all(root.join("src")).expect("create fixture src directory");
std::fs::create_dir_all(root.join("fixtures")).expect("create fixture fixtures directory");
std::fs::write(root.join("src/lib.rs"), E2E_DEFER_FIXTURE_SOURCE).expect("write fixture source");
std::fs::write(root.join("Cargo.toml"), E2E_DEFER_FIXTURE_CARGO_TOML).expect("write fixture Cargo.toml");
std::fs::write(root.join("fixtures/complete_basic.json"), e2e_defer_fixture_json(field))
.expect("write fixture json");
std::fs::write(root.join("alef.toml"), E2E_DEFER_FIXTURE_ALEF_TOML).expect("write fixture alef.toml");
}
fn e2e_defer_all_command() -> Commands {
Commands::All {
clean: false,
clobber_create_once_seeds: false,
strict: false,
skip_frb: false,
skip_snippet_validation: false,
}
}
fn expect_e2e_defer_err(result: anyhow::Result<Option<Commands>>, message: &str) -> anyhow::Error {
match result {
Err(error) => error,
Ok(_) => panic!("{message}"),
}
}
#[test]
fn all_defers_an_e2e_generator_failure_so_sibling_backends_still_write_and_the_run_fails() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path().canonicalize().unwrap_or_else(|_| temp.path().to_path_buf());
write_e2e_defer_fixture_workspace(&root, "metadata.title");
let _cwd = E2eDeferCwdGuard::enter(&root);
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
let error = expect_e2e_defer_err(
handle(e2e_defer_all_command(), &context),
"a C-backend e2e codegen failure must still fail the run -- writing sibling files must \
not silently turn this into a healthy exit code",
);
let message = format!("{error:#}");
assert!(
message.contains("e2e codegen failed") && message.contains("[c]"),
"the propagated error must be the deferred e2e generator failure naming the `c` backend, \
not something else: {message}"
);
assert!(
message.contains("Metadata") && message.contains("title"),
"the failure must carry `ensure_leaf_field_exists`'s own diagnostic verbatim: {message}"
);
let rust_cargo_toml = root.join("e2e").join("rust").join("Cargo.toml");
assert!(
rust_cargo_toml.is_file(),
"the `rust` sibling backend must still have written its e2e suite even though the `c` \
backend's codegen failed: {} is missing",
rust_cargo_toml.display()
);
let c_makefile = root.join("e2e").join("c").join("Makefile");
assert!(
!c_makefile.is_file(),
"the failing `c` backend itself must not have produced output -- `run_generators` \
treats a backend's `Err` as zero files for that backend, not a partial write: {}",
c_makefile.display()
);
}
#[test]
fn all_gates_e2e_stage_hash_and_orphan_sweep_on_a_deferred_generator_failure() {
let temp = tempfile::tempdir().expect("tempdir");
let root = temp.path().canonicalize().unwrap_or_else(|_| temp.path().to_path_buf());
write_e2e_defer_fixture_workspace(&root, "metadata.document_title");
let _cwd = E2eDeferCwdGuard::enter(&root);
let context = DispatchContext {
config_path: root.join("alef.toml"),
crate_filter: Vec::new(),
};
handle(e2e_defer_all_command(), &context).expect("the baseline run with a valid field path must succeed");
let c_makefile = root.join("e2e").join("c").join("Makefile");
assert!(
c_makefile.is_file(),
"the baseline run must have produced `c` e2e output at {}",
c_makefile.display()
);
std::fs::write(
root.join("fixtures/complete_basic.json"),
e2e_defer_fixture_json("metadata.title"),
)
.expect("rewrite fixture with a field Metadata does not have");
expect_e2e_defer_err(
handle(e2e_defer_all_command(), &context),
"a run whose fixture trips ensure_leaf_field_exists must still fail",
);
assert!(
c_makefile.is_file(),
"the previously-good `c` output must survive a run whose `c` backend failed -- \
sweep_manifest_orphans must not run on a deferred generator failure, or it deletes the \
last known-good backend output: {}",
c_makefile.display()
);
expect_e2e_defer_err(
handle(e2e_defer_all_command(), &context),
"a repeat run over the same broken fixture must still fail -- a stage hash written on \
the previous failed attempt would silently cache the failure away",
);
}