use crate::core::config::NewAlefConfig;
use crate::core::ir::{FieldDef, FunctionDef, TypeDef, TypeRef};
use crate::e2e::codegen::E2eCodegen;
use crate::e2e::codegen::rust::RustE2eCodegen;
use crate::e2e::fixture::Fixture;
fn ir() -> (Vec<TypeDef>, Vec<FunctionDef>) {
let table = TypeDef {
name: "Table".into(),
fields: vec![
FieldDef {
name: "name".into(),
ty: TypeRef::String,
optional: false,
..FieldDef::default()
},
FieldDef {
name: "cells".into(),
ty: TypeRef::Vec(Box::new(TypeRef::Vec(Box::new(TypeRef::String)))),
optional: false,
..FieldDef::default()
},
],
..TypeDef::default()
};
let sample_result = TypeDef {
name: "SampleResult".into(),
fields: vec![
FieldDef {
name: "tables".into(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Table".into()))),
optional: false,
..FieldDef::default()
},
FieldDef {
name: "maybe_tables".into(),
ty: TypeRef::Optional(Box::new(TypeRef::Vec(Box::new(TypeRef::Named("Table".into()))))),
optional: true,
..FieldDef::default()
},
],
..TypeDef::default()
};
(
vec![sample_result, table],
vec![FunctionDef {
name: "convert".into(),
return_type: TypeRef::Named("SampleResult".into()),
..FunctionDef::default()
}],
)
}
fn snippet_body(operations_json: serde_json::Value) -> String {
let config_text = r#"
[workspace]
languages = ["rust"]
[[crates]]
name = "example-core"
sources = ["src/lib.rs"]
[crates.e2e]
fixtures = "fixtures"
[crates.e2e.call]
function = "convert"
module = "example_core"
result_var = "result"
args = [{ name = "html", field = "html", type = "string" }]
"#;
let config: NewAlefConfig = toml::from_str(config_text).expect("config parses");
let e2e = config.crates[0].e2e.clone().expect("e2e config");
let resolved = config.resolve().expect("config resolves").remove(0);
let fixture: Fixture = serde_json::from_value(serde_json::json!({
"id": "sample_fixture",
"description": "Sample fixture",
"input": {"html": "<p>Hello</p>"},
"assertions": [],
"docs": {
"topic": "smoke",
"stem": "sample_fixture",
"presentation": {"operations": operations_json},
},
}))
.expect("fixture parses");
let (type_defs, functions) = ir();
RustE2eCodegen
.render_snippet_body_with_functions(&fixture, &e2e, &resolved, &type_defs, &[], &functions, &[])
.expect("rust snippet body renders")
}
#[test]
fn a_plain_collection_iterate_borrows_rather_than_moves() {
let body = snippet_body(serde_json::json!([{
"op": "iterate", "path": "tables", "item": "table", "fields": ["name"],
}]));
assert!(
body.contains("for table in result.tables.iter() {"),
"a plain Vec field must be borrowed with `.iter()`, not moved:\n{body}"
);
}
#[test]
fn an_optional_collection_iterate_keeps_iter_flatten_without_double_borrowing() {
let body = snippet_body(serde_json::json!([{
"op": "iterate", "path": "maybe_tables", "item": "table", "fields": ["name"],
}]));
assert!(
body.contains("for table in result.maybe_tables.iter().flatten() {"),
"an optional collection must keep exactly one `.iter().flatten()`, no extra adapter:\n{body}"
);
}
#[test]
fn a_non_display_safe_per_item_field_falls_back_to_debug_formatting() {
let body = snippet_body(serde_json::json!([{
"op": "iterate", "path": "tables", "item": "table", "fields": ["cells"], "display": true,
}]));
assert!(
body.contains("println!(\"{:?}\", table.cells);"),
"a `Vec<Vec<String>>` per-item field must fall back to `{{:?}}`:\n{body}"
);
assert!(
!body.contains("println!(\"{}\", table.cells);"),
"a `Vec<Vec<String>>` per-item field must never be formatted with `{{}}`:\n{body}"
);
}
#[test]
fn a_display_safe_per_item_field_keeps_display_formatting() {
let body = snippet_body(serde_json::json!([{
"op": "iterate", "path": "tables", "item": "table", "fields": ["name"], "display": true,
}]));
assert!(
body.contains("println!(\"{}\", table.name);"),
"a `String` per-item field must keep `{{}}` when `display: true`:\n{body}"
);
}
#[test]
fn a_plain_collection_with_mixed_display_safety_fields_compiles_shaped_output() {
let body = snippet_body(serde_json::json!([{
"op": "iterate", "path": "tables", "item": "table", "fields": ["name", "cells"], "display": true,
}]));
assert!(body.contains("for table in result.tables.iter() {"), "{body}");
assert!(body.contains("println!(\"{}\", table.name);"), "{body}");
assert!(body.contains("println!(\"{:?}\", table.cells);"), "{body}");
}