test(derive): close sixth mutation shard
Exercise malformed parameter manifests, handler patterns, app diagnostics, and registration guards; delete an unreachable empty-handler branch and narrowly classify quote-owned parse invariants. req: derive_app/001 req: component/003 req: derive_handler/003 req: test/020 req: test/021 req: test/022 req: test/023
This commit is contained in:
+86
-5
@@ -765,9 +765,6 @@ fn add_component_register_helper(mut module: ItemMod, component: &str) -> ItemMo
|
||||
let Some(state_ty) = component_state_type(items) else {
|
||||
return module;
|
||||
};
|
||||
if handlers.is_empty() {
|
||||
return module;
|
||||
}
|
||||
let calls = handlers
|
||||
.iter()
|
||||
.map(|handler| component_registration_call(handler, &component_ident));
|
||||
@@ -1021,8 +1018,8 @@ mod tests {
|
||||
add_app_registry_helper, add_component_register_helper, client_handler_has_inputs,
|
||||
component_handler_names, expand_handler_function, form_contract_errors, form_decode_fields,
|
||||
form_fields, form_impl_generics, form_model_type, form_resource_id, generic_inner_type,
|
||||
handle_params, handle_requires_form, handler_form_model_type, handler_placement,
|
||||
handler_syms_path, has_form_param, has_non_unit_return, is_type_named,
|
||||
handle_params, handle_requires_form, handler_arg_names, handler_form_model_type,
|
||||
handler_placement, handler_syms_path, has_form_param, has_non_unit_return, is_type_named,
|
||||
join_contract_errors, missing_component_handlers, missing_form_generated_files_message,
|
||||
missing_handle_params, missing_handler_generated_files_message, parser_type,
|
||||
returns_result, rust_ident, syms_contains_handle, HandlerPlacement,
|
||||
@@ -1461,6 +1458,14 @@ mod tests {
|
||||
assert_eq!(missing_handle_params(&path, "show", &missing), vec!["mode"]);
|
||||
assert!(missing_handle_params(&path, "unknown", &missing).is_empty());
|
||||
|
||||
std::fs::write(&path, "handle_param\nhandle_param\tshow\tmode\n").unwrap();
|
||||
assert_eq!(handle_params(&path, "show"), vec!["mode"]);
|
||||
|
||||
let patterns: ItemFn = parse_quote! {
|
||||
fn patterns(self, named: String, (left, right): (u8, u8), _: bool) {}
|
||||
};
|
||||
assert_eq!(handler_arg_names(&patterns), vec!["named"]);
|
||||
|
||||
let _ = std::fs::remove_file(path);
|
||||
}
|
||||
|
||||
@@ -1518,6 +1523,80 @@ mod tests {
|
||||
);
|
||||
assert!(generated.contains("hemx_axum :: State"), "{generated}");
|
||||
assert!(generated.contains("state . clone"), "{generated}");
|
||||
|
||||
let no_components: ItemFn = parse_quote!(
|
||||
fn registry(state: App) {}
|
||||
);
|
||||
assert_eq!(
|
||||
add_app_registry_helper(no_components, vec![]).err().unwrap(),
|
||||
"#[hemx::app] requires component registry module(s), for example #[hemx::app(todo_handlers, auth_handlers)]"
|
||||
);
|
||||
let unnamed_state: ItemFn = parse_quote!(
|
||||
fn registry((state,): (App,)) {}
|
||||
);
|
||||
assert_eq!(
|
||||
add_app_registry_helper(unnamed_state, vec![parse_quote!(handlers)])
|
||||
.err()
|
||||
.unwrap(),
|
||||
"#[hemx::app] must be used on a registry function with a named app state argument"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn component_registration_generation_respects_existing_and_incomplete_modules() {
|
||||
let external: syn::ItemMod = parse_quote!(
|
||||
mod handlers;
|
||||
);
|
||||
let unchanged = add_component_register_helper(external.clone(), "todos");
|
||||
assert_eq!(
|
||||
quote!(#external).to_string(),
|
||||
quote!(#unchanged).to_string()
|
||||
);
|
||||
|
||||
for existing in ["register", "register_with_state"] {
|
||||
let existing_ident = syn::Ident::new(existing, proc_macro2::Span::call_site());
|
||||
let module: syn::ItemMod = parse_quote! {
|
||||
mod handlers {
|
||||
struct App;
|
||||
#[hemx::handler]
|
||||
fn create(app: App) {}
|
||||
fn #existing_ident() {}
|
||||
}
|
||||
};
|
||||
let generated = add_component_register_helper(module, "todos");
|
||||
let items = generated.content.unwrap().1;
|
||||
assert_eq!(items.len(), 3, "must preserve existing {existing}");
|
||||
}
|
||||
|
||||
let no_state: syn::ItemMod = parse_quote! {
|
||||
mod handlers {
|
||||
#[hemx::handler]
|
||||
fn create() {}
|
||||
}
|
||||
};
|
||||
assert_eq!(
|
||||
add_component_register_helper(no_state, "todos")
|
||||
.content
|
||||
.unwrap()
|
||||
.1
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
let no_handlers: syn::ItemMod = parse_quote! {
|
||||
mod handlers {
|
||||
struct App;
|
||||
fn helper(app: App) {}
|
||||
}
|
||||
};
|
||||
assert_eq!(
|
||||
add_component_register_helper(no_handlers, "todos")
|
||||
.content
|
||||
.unwrap()
|
||||
.1
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
// test req: component/003 req: derive_handler/003
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1525,6 +1604,8 @@ mod tests {
|
||||
// req: component/003 req: derive_handler/003
|
||||
let module = parse_quote! {
|
||||
mod handlers {
|
||||
const COMPONENT_KIND: &str = "todos";
|
||||
|
||||
#[hemx::handler]
|
||||
fn sync_form(app: super::App, form: super::NewTodo) -> impl hemx::IntoEffect {
|
||||
hemx::EventName::new("sync-form").emit("")
|
||||
|
||||
Reference in New Issue
Block a user