use alef_core::config::NewAlefConfig;
use alef_e2e::codegen::E2eCodegen;
use alef_e2e::codegen::zig::ZigE2eCodegen;
use alef_e2e::fixture::{Assertion, Fixture, FixtureGroup};
fn not_error_assertion() -> Assertion {
Assertion {
assertion_type: "not_error".to_string(),
field: None,
value: None,
values: None,
method: None,
check: None,
args: None,
return_type: None,
}
}
fn is_empty_assertion() -> Assertion {
Assertion {
assertion_type: "is_empty".to_string(),
field: None,
value: None,
values: None,
method: None,
check: None,
args: None,
return_type: None,
}
}
fn config_toml() -> &'static str {
r#"
[workspace]
languages = ["zig"]
[[crates]]
name = "tree_sitter_language_pack"
sources = ["src/lib.rs"]
[crates.e2e]
fixtures = "fixtures"
output = "e2e"
[crates.e2e.call]
function = "process"
module = "tree_sitter_language_pack"
result_var = "result"
args = [{ name = "source", field = "source_code", type = "string" }]
[crates.e2e.calls.detect_content]
function = "detect_language_from_content"
module = "tree_sitter_language_pack"
result_var = "result"
result_is_simple = true
result_is_option = true
args = [{ name = "content", field = "content", type = "string" }]
"#
}
fn render(fixture: Fixture) -> String {
let cfg: NewAlefConfig = toml::from_str(config_toml()).expect("config parses");
let resolved = cfg.clone().resolve().expect("config resolves").remove(0);
let e2e = cfg.crates[0].e2e.clone().expect("e2e config present");
let groups = vec![FixtureGroup {
category: "error_handling".to_string(),
fixtures: vec![fixture],
}];
let files = ZigE2eCodegen
.generate(&groups, &e2e, &resolved, &[], &[])
.expect("generation succeeds");
files
.iter()
.find(|f| f.path.to_string_lossy().contains("error_handling_test.zig"))
.expect("error_handling_test.zig is emitted")
.content
.clone()
}
#[test]
fn not_error_alone_does_not_emit_not_null_check() {
let fixture = Fixture {
id: "error_detect_content_empty".to_string(),
category: Some("error_handling".to_string()),
description: "Detect language from empty content returns null".to_string(),
tags: Vec::new(),
skip: None,
env: None,
call: Some("detect_content".to_string()),
input: serde_json::json!({ "content": "" }),
mock_response: None,
visitor: None,
assertions: vec![not_error_assertion()],
source: "error_handling.json".to_string(),
http: None,
};
let rendered = render(fixture);
assert!(
!rendered.contains("try testing.expect(result != null);"),
"not_error must NOT emit `expect(result != null)` for Optional result. Rendered:\n{rendered}"
);
assert!(
rendered.contains("_ = try tree_sitter_language_pack.detect_language_from_content("),
"call must still be emitted and `try`-propagated. Rendered:\n{rendered}"
);
}
#[test]
fn not_error_with_is_empty_does_not_contradict() {
let fixture = Fixture {
id: "error_detect_content_empty_pair".to_string(),
category: Some("error_handling".to_string()),
description: "not_error + is_empty must not contradict".to_string(),
tags: Vec::new(),
skip: None,
env: None,
call: Some("detect_content".to_string()),
input: serde_json::json!({ "content": "" }),
mock_response: None,
visitor: None,
assertions: vec![not_error_assertion(), is_empty_assertion()],
source: "error_handling.json".to_string(),
http: None,
};
let rendered = render(fixture);
assert!(
!rendered.contains("try testing.expect(result != null);"),
"not_error + is_empty must NOT emit `expect(result != null)`. Rendered:\n{rendered}"
);
assert!(
rendered.contains("try testing.expect(result == null);"),
"is_empty must still emit `expect(result == null)`. Rendered:\n{rendered}"
);
assert!(
rendered.contains("// not_error: covered by try propagation"),
"not_error must emit a comment-only inert line. Rendered:\n{rendered}"
);
}