From 51441b44ca922961eb1ea798ecc50283e5d48fa7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 15 Jan 2024 10:52:30 -0600 Subject: [PATCH] fix diffing fuzz test --- packages/core/src/diff/node.rs | 13 +++-- packages/core/tests/fuzzing.rs | 92 ++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/packages/core/src/diff/node.rs b/packages/core/src/diff/node.rs index 347dbe2fa..48f33f17d 100644 --- a/packages/core/src/diff/node.rs +++ b/packages/core/src/diff/node.rs @@ -234,7 +234,7 @@ impl VNode { mount, dom, to, - idx, + id, dynamic_node, replace_with.filter(|_| last_node), gen_muts, @@ -296,9 +296,11 @@ impl VNode { } dom.reclaim(id) } - Fragment(nodes) => nodes - .iter() - .for_each(|_node| self.remove_node(dom, to, replace_with, gen_muts)), + Fragment(nodes) => { + for node in nodes { + node.remove_node(dom, to, replace_with, gen_muts) + } + } }; } @@ -315,7 +317,7 @@ impl VNode { dom: &mut VirtualDom, _to: &mut impl WriteMutations, ) { - let id = None; + let mut id = None; for (idx, path) in self.template.get().attr_paths.iter().enumerate() { let _attr = &self.dynamic_attrs[idx]; @@ -330,6 +332,7 @@ impl VNode { // only reclaim the new element if it's different from the previous one if id != Some(next_id) { dom.reclaim(next_id); + id = Some(next_id); } } } diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index ca92a8793..c454019a2 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -177,7 +177,7 @@ fn create_random_dynamic_node(depth: usize) -> DynamicNode { VNode::new( None, Template { - name: concat!(file!(), ":", line!(), ":", column!(), ":0"), + name: create_template_location(), roots: &[TemplateNode::Dynamic { id: 0 }], node_paths: &[&[0]], attr_paths: &[], @@ -225,6 +225,23 @@ fn create_random_dynamic_attr() -> Attribute { static mut TEMPLATE_COUNT: usize = 0; +fn create_template_location() -> &'static str { + Box::leak( + format!( + "{}{}", + concat!(file!(), ":", line!(), ":", column!(), ":"), + { + unsafe { + let old = TEMPLATE_COUNT; + TEMPLATE_COUNT += 1; + old + } + } + ) + .into_boxed_str(), + ) +} + #[derive(PartialEq, Props, Clone)] struct DepthProps { depth: usize, @@ -238,20 +255,7 @@ fn create_random_element(cx: DepthProps) -> Element { let range = if cx.root { 2 } else { 3 }; let node = match rand::random::() % range { 0 | 1 => { - let (template, dynamic_node_types) = create_random_template(Box::leak( - format!( - "{}{}", - concat!(file!(), ":", line!(), ":", column!(), ":"), - { - unsafe { - let old = TEMPLATE_COUNT; - TEMPLATE_COUNT += 1; - old - } - } - ) - .into_boxed_str(), - )); + let (template, dynamic_node_types) = create_random_template(create_template_location()); let node = VNode::new( None, template, @@ -310,14 +314,58 @@ fn diff() { ); } { - let muts = vdom.render_immediate_to_vec(); - for mut_ in muts.edits { - if let Mutation::NewEventListener { name, id } = mut_ { - println!("new event listener on {:?} for {:?}", id, name); - event_listeners.insert(id); - } - } + vdom.render_immediate(&mut InsertEventListenerMutationHandler( + &mut event_listeners, + )); } } } } + +struct InsertEventListenerMutationHandler<'a>(&'a mut HashSet); + +impl WriteMutations for InsertEventListenerMutationHandler<'_> { + fn register_template(&mut self, _: Template) {} + + fn append_children(&mut self, _: ElementId, _: usize) {} + + fn assign_node_id(&mut self, _: &'static [u8], _: ElementId) {} + + fn create_placeholder(&mut self, _: ElementId) {} + + fn create_text_node(&mut self, _: &str, _: ElementId) {} + + fn hydrate_text_node(&mut self, _: &'static [u8], _: &str, _: ElementId) {} + + fn load_template(&mut self, _: &'static str, _: usize, _: ElementId) {} + + fn replace_node_with(&mut self, _: ElementId, _: usize) {} + + fn replace_placeholder_with_nodes(&mut self, _: &'static [u8], _: usize) {} + + fn insert_nodes_after(&mut self, _: ElementId, _: usize) {} + + fn insert_nodes_before(&mut self, _: ElementId, _: usize) {} + + fn set_attribute( + &mut self, + _: &'static str, + _: Option<&'static str>, + _: &AttributeValue, + _: ElementId, + ) { + } + + fn set_node_text(&mut self, _: &str, _: ElementId) {} + + fn create_event_listener(&mut self, name: &'static str, id: ElementId) { + println!("new event listener on {:?} for {:?}", id, name); + self.0.insert(id); + } + + fn remove_event_listener(&mut self, _: &'static str, _: ElementId) {} + + fn remove_node(&mut self, _: ElementId) {} + + fn push_root(&mut self, _: ElementId) {} +}