diff --git a/packages/native-core/tests/called_minimally_on_build.rs b/packages/native-core/tests/called_minimally_on_build.rs new file mode 100644 index 000000000..da0675688 --- /dev/null +++ b/packages/native-core/tests/called_minimally_on_build.rs @@ -0,0 +1,242 @@ +use dioxus::prelude::*; +use dioxus_core::*; +use dioxus_native_core::prelude::*; +use dioxus_native_core::{ + dioxus::DioxusState, + node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView}, + real_dom::RealDom, + Dependancy, Pass, SendAnyMap, +}; +use rustc_hash::{FxHashMap, FxHashSet}; +use std::any::TypeId; +use std::sync::{Arc, Mutex}; + +macro_rules! dep { + ( child( $name:ty, $dep:ty ) ) => { + impl Pass for $name { + type ParentDependencies = (); + type ChildDependencies = $dep; + type NodeDependencies = (); + + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::ALL; + + fn pass<'a>( + &mut self, + _: NodeView, + _: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _: Option::ElementBorrowed<'a>>>, + _: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + }; + + ( parent( $name:ty, $dep:ty ) ) => { + impl Pass for $name { + type ParentDependencies = $dep; + type ChildDependencies = (); + type NodeDependencies = (); + + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::ALL; + + fn pass<'a>( + &mut self, + _: NodeView, + _: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _: Option::ElementBorrowed<'a>>>, + _: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + }; + + ( node( $name:ty, $dep:ty ) ) => { + impl Pass for $name { + type ParentDependencies = $dep; + type ChildDependencies = (); + type NodeDependencies = (); + + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::ALL; + + fn pass<'a>( + &mut self, + _: NodeView, + _: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + _: Option::ElementBorrowed<'a>>>, + _: &SendAnyMap, + ) -> bool { + self.0 += 1; + true + } + + fn create<'a>( + node_view: NodeView<()>, + node: ::ElementBorrowed<'a>, + parent: Option<::ElementBorrowed<'a>>, + children: Option::ElementBorrowed<'a>>>, + context: &SendAnyMap, + ) -> Self { + let mut myself = Self::default(); + myself.pass(node_view, node, parent, children, context); + myself + } + } + }; +} + +macro_rules! test_state{ + ( state: ( $( $state:ty ),* ) ) => { + #[test] + fn state_reduce_initally_called_minimally() { + #[allow(non_snake_case)] + fn Base(cx: Scope) -> Element { + render!{ + div { + div{ + div{ + p{} + } + p{ + "hello" + } + div{ + h1{} + } + p{ + "world" + } + } + } + } + } + + let mut vdom = VirtualDom::new(Base); + + let mutations = vdom.rebuild(); + + let mut dom: RealDom = RealDom::new(Box::new([$( <$state>::to_type_erased() ),*])); + let mut dioxus_state = DioxusState::create(&mut dom); + + dioxus_state.apply_mutations(&mut dom, mutations); + dom.update_state(SendAnyMap::new(), false); + + dom.traverse_depth_first(|n| { + $( + assert_eq!(n.get::<$state>().unwrap().0, 1); + )* + }); + } + } +} + +mod node_depends_on_child_and_parent { + use super::*; + #[derive(Debug, Clone, Default, PartialEq)] + struct Node(i32); + dep!(node(Node, (Child, Parent))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Child(i32); + dep!(child(Child, (Child,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Parent(i32); + dep!(parent(Parent, (Parent,))); + + test_state!(state: (Child, Node, Parent)); +} + +mod child_depends_on_node_that_depends_on_parent { + use super::*; + #[derive(Debug, Clone, Default, PartialEq)] + struct Node(i32); + dep!(node(Node, (Parent,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Child(i32); + dep!(child(Child, (Node,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Parent(i32); + dep!(parent(Parent, (Parent,))); + + test_state!(state: (Child, Node, Parent)); +} + +mod parent_depends_on_node_that_depends_on_child { + use super::*; + #[derive(Debug, Clone, Default, PartialEq)] + struct Node(i32); + dep!(node(Node, (Child,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Child(i32); + dep!(child(Child, (Child,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Parent(i32); + dep!(parent(Parent, (Node,))); + + test_state!(state: (Child, Node, Parent)); +} + +mod node_depends_on_other_node_state { + use super::*; + #[derive(Debug, Clone, Default, PartialEq)] + struct Node1(i32); + dep!(node(Node1, (Node2,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Node2(i32); + dep!(node(Node2, ())); + + test_state!(state: (Node1, Node2)); +} + +mod node_child_and_parent_state_depends_on_self { + use super::*; + #[derive(Debug, Clone, Default, PartialEq)] + struct Node(i32); + dep!(node(Node, ())); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Child(i32); + dep!(child(Child, (Child,))); + + #[derive(Debug, Clone, Default, PartialEq)] + struct Parent(i32); + dep!(parent(Parent, (Parent,))); + + test_state!(state: (Child, Node, Parent)); +}