From c1fb5e986a7dfbabe5d0a603db2124311b9e461a Mon Sep 17 00:00:00 2001 From: slhx agent Date: Mon, 25 May 2026 23:27:16 +0200 Subject: [PATCH] test(build): cover form contract metadata Assert that slhx-build lowers Surface form controls into generated FormContract field metadata, including names, control kinds, required flags, and handle-to-form syms. req: codegen/004 req: form/001 --- slhx-build/src/lib.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/slhx-build/src/lib.rs b/slhx-build/src/lib.rs index 0e1657a..f785ae6 100644 --- a/slhx-build/src/lib.rs +++ b/slhx-build/src/lib.rs @@ -1036,6 +1036,49 @@ mod tests { let _ = std::fs::remove_dir_all(&base); } + #[test] + fn emits_form_contract_metadata_from_surface_controls() { + // req: codegen/004 req: form/001 + let base = test_dir("slhx-build-form-contract-test"); + let templates = base.join("templates"); + let out = base.join("out"); + let _ = std::fs::remove_dir_all(&base); + std::fs::create_dir_all(&templates).unwrap(); + std::fs::write( + templates.join("profile.heml"), + r#"
+ + + + +
"#, + ) + .unwrap(); + + app().template_dir(&templates).out_dir(&out).run().unwrap(); + + let generated = std::fs::read_to_string(out.join("slhx.generated.rs")).unwrap(); + assert!(generated.contains("pub const PROFILE_CONTRACT: ::slhx::FormContract")); + assert!(generated.contains("pub const PROFILE_FIELDS: &[::slhx::FormField]")); + assert!(generated.contains( + "::slhx::FormField { name: \"title\", kind: ::slhx::FormControlKind::Text, required: true }" + )); + assert!(generated.contains( + "::slhx::FormField { name: \"count\", kind: ::slhx::FormControlKind::Number { min: Some(\"1\"), max: Some(\"10\"), step: Some(\"1\") }, required: false }" + )); + assert!(generated.contains( + "::slhx::FormField { name: \"labels\", kind: ::slhx::FormControlKind::Select { multiple: true }, required: false }" + )); + assert!(generated.contains( + "::slhx::FormField { name: \"avatar\", kind: ::slhx::FormControlKind::File, required: false }" + )); + + let syms = std::fs::read_to_string(out.join("slhx.syms")).unwrap(); + assert!(syms.contains("handle_form\tsave\tprofile\n")); + + let _ = std::fs::remove_dir_all(&base); + } + #[test] fn emits_checked_css_class_tokens_from_templates_and_stylesheets() { // req: style/001, req: codegen/001