feat(derive): check form parser availability

Introduce FormValue as the parser-availability bound for #[slhx::form] models, blanket it for FromStr types, and add compile-fail coverage for a form field whose domain type lacks a parser.

req: form/004

req: form/006
This commit is contained in:
slhx agent
2026-05-25 23:48:56 +02:00
parent 274b8e9e55
commit 21716882ab
5 changed files with 117 additions and 4 deletions
+54
View File
@@ -325,6 +325,60 @@ struct Profile {
);
}
#[test]
fn form_struct_requires_field_parser() {
// req: form/004 req: form/006 req: test/003
let fixture = Fixture::new("slhx-derive-form-struct-parser-fail");
fixture.write(
"Cargo.toml",
&format!(
r#"[package]
name = "slhx-derive-form-struct-parser-fail"
version = "0.0.0"
edition = "2021"
[lib]
path = "src/lib.rs"
[dependencies]
slhx = {{ path = {:?} }}
"#,
repo_path("slhx")
),
);
fixture.write(
"build.rs",
r#"fn main() {
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
std::fs::write(
out.join("slhx.syms"),
"slhx-syms-v1\nform\ttemplates/app.heml::profile\tprofile\t1\nform_field\tprofile\temail\ttrue\tfalse\n",
)
.unwrap();
}
"#,
);
fixture.write(
"src/lib.rs",
r#"struct Email;
#[slhx::form("profile")]
struct Profile {
email: Email,
}
"#,
);
let output = check_fixture(&fixture);
assert!(!output.status.success(), "fixture unexpectedly compiled");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Email: FormValue") || stderr.contains("Email: slhx::FormValue"),
"missing parser availability diagnostic in stderr:\n{stderr}"
);
}
#[test]
fn form_handle_accepts_checked_form_model() {
// req: form/001 req: form/004 req: form/006