use crate::core::config::ResolvedCrateConfig;
use crate::core::ir::{FieldDef, FunctionDef, TypeDef, TypeRef};
use crate::e2e::codegen::call_ir::CallIr;
use crate::e2e::config::E2eConfig;
use crate::e2e::fixture::{Assertion, Fixture};
use super::test_file::render_test_file;
fn response_type() -> TypeDef {
TypeDef {
name: "Response".to_string(),
has_serde: true,
fields: vec![FieldDef {
name: "summary".to_string(),
ty: TypeRef::String,
..FieldDef::default()
}],
..TypeDef::default()
}
}
fn opaque_tree_type() -> TypeDef {
TypeDef {
name: "Tree".to_string(),
is_opaque: true,
fields: vec![FieldDef {
name: "summary".to_string(),
ty: TypeRef::String,
..FieldDef::default()
}],
..TypeDef::default()
}
}
fn summary_fixture() -> Fixture {
Fixture {
id: "summary_smoke".to_string(),
description: "Summary smoke".to_string(),
assertions: vec![Assertion {
assertion_type: "equals".to_string(),
field: Some("summary".to_string()),
value: Some(serde_json::Value::String("hi".to_string())),
..Assertion::default()
}],
..Fixture::default()
}
}
#[test]
fn json_dto_return_with_no_config_routes_through_json_path_via_ir() {
let type_defs = vec![response_type()];
let functions = vec![FunctionDef {
name: "process".to_string(),
return_type: TypeRef::Named("Response".to_string()),
..FunctionDef::default()
}];
let ir = CallIr {
functions: &functions,
type_defs: &type_defs,
};
let fixture = summary_fixture();
let mut e2e = E2eConfig::default();
e2e.call.function = "process".to_string();
let rendered = render_test_file(
"smoke",
&[&fixture],
&e2e,
"process",
"result",
&[],
"sample",
"sample",
&ResolvedCrateConfig::default(),
&type_defs,
&[],
ir,
&[],
);
assert!(
rendered.contains("std.json.parseFromSlice"),
"a serde-JSON DTO return must route through the JSON path, got:\n{rendered}"
);
assert!(
!rendered.contains("result.summary"),
"must not emit direct field access against the []u8 the backend actually returns, got:\n{rendered}"
);
}
#[test]
fn opaque_handle_return_with_no_config_stays_on_the_typed_struct_path() {
let type_defs = vec![opaque_tree_type()];
let functions = vec![FunctionDef {
name: "parse".to_string(),
return_type: TypeRef::Named("Tree".to_string()),
..FunctionDef::default()
}];
let ir = CallIr {
functions: &functions,
type_defs: &type_defs,
};
let fixture = summary_fixture();
let mut e2e = E2eConfig::default();
e2e.call.function = "parse".to_string();
let rendered = render_test_file(
"smoke",
&[&fixture],
&e2e,
"parse",
"result",
&[],
"sample",
"sample",
&ResolvedCrateConfig::default(),
&type_defs,
&[],
ir,
&[],
);
assert!(
!rendered.contains("std.json.parseFromSlice"),
"an opaque-handle return must not be routed through the JSON path, got:\n{rendered}"
);
assert!(
rendered.contains("result.summary"),
"an opaque-handle return keeps direct typed-struct field access, got:\n{rendered}"
);
}
#[test]
fn an_explicit_override_still_forces_json_struct_without_ir_support() {
let fixture = summary_fixture();
let mut e2e = E2eConfig::default();
e2e.call.function = "mystery".to_string();
e2e.call.overrides.insert(
"zig".to_string(),
crate::e2e::config::CallOverride {
result_is_json_struct: true,
..Default::default()
},
);
let rendered = render_test_file(
"smoke",
&[&fixture],
&e2e,
"mystery",
"result",
&[],
"sample",
"sample",
&ResolvedCrateConfig::default(),
&[],
&[],
CallIr::default(),
&[],
);
assert!(
rendered.contains("std.json.parseFromSlice"),
"an explicit override must still force the JSON path, got:\n{rendered}"
);
}