feat(v1): harden typed runtime boundaries
Elect one canonical EffectBatch codec, remove the parallel postcard API, and strengthen fail-closed host, form, sync, WASM, macro, generated-contract, and test-harness proofs with mutation-driven coverage. req: wire/008 req: wire/009 req: wire/010 req: push/008 req: client_local/015 req: client_local/016 req: client_local/017 req: client_local/018 req: client_local/019 req: sync/024 req: sync/025 req: sync/026 req: sync/027 req: sync/028 req: sync/029 req: test/020 req: test/021
This commit is contained in:
+63
-2
@@ -985,12 +985,73 @@ fn compile_error(message: &str) -> TokenStream {
|
||||
mod tests {
|
||||
use super::{
|
||||
add_app_registry_helper, add_component_register_helper, component_handler_names,
|
||||
form_model_type, handle_params, handle_requires_form, has_form_param, has_non_unit_return,
|
||||
missing_component_handlers, missing_handle_params, parser_type, syms_contains_handle,
|
||||
form_model_type, handle_params, handle_requires_form, handler_form_model_type,
|
||||
has_form_param, has_non_unit_return, missing_component_handlers, missing_handle_params,
|
||||
parser_type, returns_result, syms_contains_handle,
|
||||
};
|
||||
use quote::quote;
|
||||
use syn::{parse_quote, ItemFn, Type};
|
||||
|
||||
#[test]
|
||||
fn handler_type_helpers_recognize_only_the_public_form_and_result_shapes() {
|
||||
let bare: Type = parse_quote!(Form<String>);
|
||||
let qualified: Type = parse_quote!(hemx::Form<crate::Input>);
|
||||
let wrong_module: Type = parse_quote!(other::Form<String>);
|
||||
let missing_model: Type = parse_quote!(hemx::Form);
|
||||
let unrelated: Type = parse_quote!(String);
|
||||
assert_eq!(quote!(#bare).to_string(), "Form < String >");
|
||||
assert_eq!(
|
||||
quote!(#qualified).to_string(),
|
||||
"hemx :: Form < crate :: Input >"
|
||||
);
|
||||
assert!(form_model_type(&bare).is_some());
|
||||
assert!(form_model_type(&qualified).is_some());
|
||||
assert!(form_model_type(&wrong_module).is_none());
|
||||
assert!(form_model_type(&missing_model).is_none());
|
||||
assert!(form_model_type(&unrelated).is_none());
|
||||
|
||||
let function: ItemFn = parse_quote!(
|
||||
fn save(
|
||||
first: hemx::Form<crate::First>,
|
||||
value: String,
|
||||
last: Form<crate::Last>,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
quote!(#function)
|
||||
.to_string()
|
||||
.contains("last : Form < crate :: Last >"),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
quote!(#function)
|
||||
.to_string()
|
||||
.contains("first : hemx :: Form < crate :: First >"),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
handler_form_model_type(&function)
|
||||
.map(|ty| quote!(#ty).to_string())
|
||||
.as_deref(),
|
||||
Some("crate :: Last")
|
||||
);
|
||||
assert!(returns_result(&function.sig.output));
|
||||
|
||||
let no_result: ItemFn = parse_quote!(
|
||||
fn save() -> String {
|
||||
String::new()
|
||||
}
|
||||
);
|
||||
let no_return: ItemFn = parse_quote!(
|
||||
fn save() {}
|
||||
);
|
||||
assert!(!returns_result(&no_result.sig.output));
|
||||
assert!(!returns_result(&no_return.sig.output));
|
||||
// test req: derive_handler/001 req: derive_handler/005
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syms_lookup_matches_handle_ident() {
|
||||
let path = std::env::temp_dir().join("hemx-derive-syms-test.syms");
|
||||
|
||||
@@ -1031,6 +1031,45 @@ pub const MISSING: hemx::CssClass = ui::classes::missing;
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effect_batch_has_no_parallel_postcard_wire_api() {
|
||||
// req: wire/010 test
|
||||
let fixture = Fixture::new("hemx-effect-batch-postcard-api-fail");
|
||||
fixture.write(
|
||||
"Cargo.toml",
|
||||
&format!(
|
||||
r#"[package]
|
||||
name = "hemx-effect-batch-postcard-api-fail"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
hemx = {{ path = {:?} }}
|
||||
"#,
|
||||
repo_path("hemx")
|
||||
),
|
||||
);
|
||||
fixture.write(
|
||||
"src/lib.rs",
|
||||
r#"pub fn encode(batch: &hemx::advanced::EffectBatch) {
|
||||
let _ = batch.to_postcard();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let output = check_fixture(&fixture);
|
||||
|
||||
assert!(!output.status.success(), "fixture unexpectedly compiled");
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert!(
|
||||
stderr.contains("no method named `to_postcard`"),
|
||||
"missing sole-wire-API diagnostic in stderr:\n{stderr}"
|
||||
);
|
||||
}
|
||||
|
||||
fn check_fixture(fixture: &Fixture) -> std::process::Output {
|
||||
Command::new("cargo")
|
||||
.arg("check")
|
||||
|
||||
Reference in New Issue
Block a user