fuzzing.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. use dioxus::prelude::Props;
  2. use dioxus_core::*;
  3. use dioxus_native_core::{
  4. dioxus::DioxusState,
  5. node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView},
  6. real_dom::RealDom,
  7. Dependancy, SendAnyMap, State,
  8. };
  9. use std::cell::Cell;
  10. fn random_ns() -> Option<&'static str> {
  11. let namespace = rand::random::<u8>() % 2;
  12. match namespace {
  13. 0 => None,
  14. 1 => Some(Box::leak(
  15. format!("ns{}", rand::random::<usize>()).into_boxed_str(),
  16. )),
  17. _ => unreachable!(),
  18. }
  19. }
  20. fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> {
  21. match rand::random::<u8>() % 2 {
  22. 0 => TemplateAttribute::Static {
  23. name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
  24. value: Box::leak(format!("value{}", rand::random::<usize>()).into_boxed_str()),
  25. namespace: random_ns(),
  26. },
  27. 1 => TemplateAttribute::Dynamic {
  28. id: {
  29. let old_idx = *attr_idx;
  30. *attr_idx += 1;
  31. old_idx
  32. },
  33. },
  34. _ => unreachable!(),
  35. }
  36. }
  37. fn create_random_template_node(
  38. dynamic_node_types: &mut Vec<DynamicNodeType>,
  39. template_idx: &mut usize,
  40. attr_idx: &mut usize,
  41. depth: usize,
  42. ) -> TemplateNode<'static> {
  43. match rand::random::<u8>() % 4 {
  44. 0 => {
  45. let attrs = {
  46. let attrs: Vec<_> = (0..(rand::random::<usize>() % 10))
  47. .map(|_| create_random_attribute(attr_idx))
  48. .collect();
  49. Box::leak(attrs.into_boxed_slice())
  50. };
  51. TemplateNode::Element {
  52. tag: Box::leak(format!("tag{}", rand::random::<usize>()).into_boxed_str()),
  53. namespace: random_ns(),
  54. attrs,
  55. children: {
  56. if depth > 4 {
  57. &[]
  58. } else {
  59. let children: Vec<_> = (0..(rand::random::<usize>() % 3))
  60. .map(|_| {
  61. create_random_template_node(
  62. dynamic_node_types,
  63. template_idx,
  64. attr_idx,
  65. depth + 1,
  66. )
  67. })
  68. .collect();
  69. Box::leak(children.into_boxed_slice())
  70. }
  71. },
  72. }
  73. }
  74. 1 => TemplateNode::Text {
  75. text: Box::leak(format!("{}", rand::random::<usize>()).into_boxed_str()),
  76. },
  77. 2 => TemplateNode::DynamicText {
  78. id: {
  79. let old_idx = *template_idx;
  80. *template_idx += 1;
  81. dynamic_node_types.push(DynamicNodeType::Text);
  82. old_idx
  83. },
  84. },
  85. 3 => TemplateNode::Dynamic {
  86. id: {
  87. let old_idx = *template_idx;
  88. *template_idx += 1;
  89. dynamic_node_types.push(DynamicNodeType::Other);
  90. old_idx
  91. },
  92. },
  93. _ => unreachable!(),
  94. }
  95. }
  96. fn generate_paths(
  97. node: &TemplateNode<'static>,
  98. current_path: &[u8],
  99. node_paths: &mut Vec<Vec<u8>>,
  100. attr_paths: &mut Vec<Vec<u8>>,
  101. ) {
  102. match node {
  103. TemplateNode::Element {
  104. children, attrs, ..
  105. } => {
  106. for attr in *attrs {
  107. match attr {
  108. TemplateAttribute::Static { .. } => {}
  109. TemplateAttribute::Dynamic { .. } => {
  110. attr_paths.push(current_path.to_vec());
  111. }
  112. }
  113. }
  114. for (i, child) in children.iter().enumerate() {
  115. let mut current_path = current_path.to_vec();
  116. current_path.push(i as u8);
  117. generate_paths(child, &current_path, node_paths, attr_paths);
  118. }
  119. }
  120. TemplateNode::Text { .. } => {}
  121. TemplateNode::DynamicText { .. } => {
  122. node_paths.push(current_path.to_vec());
  123. }
  124. TemplateNode::Dynamic { .. } => {
  125. node_paths.push(current_path.to_vec());
  126. }
  127. }
  128. }
  129. enum DynamicNodeType {
  130. Text,
  131. Other,
  132. }
  133. fn create_random_template(name: &'static str) -> (Template<'static>, Vec<DynamicNodeType>) {
  134. let mut dynamic_node_type = Vec::new();
  135. let mut template_idx = 0;
  136. let mut attr_idx = 0;
  137. let roots = (0..(1 + rand::random::<usize>() % 5))
  138. .map(|_| {
  139. create_random_template_node(&mut dynamic_node_type, &mut template_idx, &mut attr_idx, 0)
  140. })
  141. .collect::<Vec<_>>();
  142. assert!(!roots.is_empty());
  143. let roots = Box::leak(roots.into_boxed_slice());
  144. let mut node_paths = Vec::new();
  145. let mut attr_paths = Vec::new();
  146. for (i, root) in roots.iter().enumerate() {
  147. generate_paths(root, &[i as u8], &mut node_paths, &mut attr_paths);
  148. }
  149. let node_paths = Box::leak(
  150. node_paths
  151. .into_iter()
  152. .map(|v| &*Box::leak(v.into_boxed_slice()))
  153. .collect::<Vec<_>>()
  154. .into_boxed_slice(),
  155. );
  156. let attr_paths = Box::leak(
  157. attr_paths
  158. .into_iter()
  159. .map(|v| &*Box::leak(v.into_boxed_slice()))
  160. .collect::<Vec<_>>()
  161. .into_boxed_slice(),
  162. );
  163. (
  164. Template {
  165. name,
  166. roots,
  167. node_paths,
  168. attr_paths,
  169. },
  170. dynamic_node_type,
  171. )
  172. }
  173. fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
  174. let range = if depth > 3 { 1 } else { 3 };
  175. match rand::random::<u8>() % range {
  176. 0 => DynamicNode::Placeholder(Default::default()),
  177. 1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| VNode {
  178. key: None,
  179. parent: Default::default(),
  180. template: Cell::new(Template {
  181. name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
  182. roots: &[TemplateNode::Dynamic { id: 0 }],
  183. node_paths: &[&[0]],
  184. attr_paths: &[],
  185. }),
  186. root_ids: Default::default(),
  187. dynamic_nodes: cx.bump().alloc([cx.component(
  188. create_random_element,
  189. DepthProps { depth, root: false },
  190. "create_random_element",
  191. )]),
  192. dynamic_attrs: &[],
  193. })),
  194. 2 => cx.component(
  195. create_random_element,
  196. DepthProps { depth, root: false },
  197. "create_random_element",
  198. ),
  199. _ => unreachable!(),
  200. }
  201. }
  202. fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
  203. let value = match rand::random::<u8>() % 6 {
  204. 0 => AttributeValue::Text(Box::leak(
  205. format!("{}", rand::random::<usize>()).into_boxed_str(),
  206. )),
  207. 1 => AttributeValue::Float(rand::random()),
  208. 2 => AttributeValue::Int(rand::random()),
  209. 3 => AttributeValue::Bool(rand::random()),
  210. 4 => cx.any_value(rand::random::<usize>()),
  211. 5 => AttributeValue::None,
  212. // Listener(RefCell<Option<ListenerCb<'a>>>),
  213. _ => unreachable!(),
  214. };
  215. Attribute {
  216. name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
  217. value,
  218. namespace: random_ns(),
  219. mounted_element: Default::default(),
  220. volatile: rand::random(),
  221. }
  222. }
  223. static mut TEMPLATE_COUNT: usize = 0;
  224. #[derive(PartialEq, Props)]
  225. struct DepthProps {
  226. depth: usize,
  227. root: bool,
  228. }
  229. fn create_random_element(cx: Scope<DepthProps>) -> Element {
  230. cx.needs_update();
  231. let range = if cx.props.root { 2 } else { 3 };
  232. let node = match rand::random::<usize>() % range {
  233. 0 | 1 => {
  234. let (template, dynamic_node_types) = create_random_template(Box::leak(
  235. format!(
  236. "{}{}",
  237. concat!(file!(), ":", line!(), ":", column!(), ":"),
  238. {
  239. unsafe {
  240. let old = TEMPLATE_COUNT;
  241. TEMPLATE_COUNT += 1;
  242. old
  243. }
  244. }
  245. )
  246. .into_boxed_str(),
  247. ));
  248. println!("{template:#?}");
  249. let node = VNode {
  250. key: None,
  251. parent: None,
  252. template: Cell::new(template),
  253. root_ids: Default::default(),
  254. dynamic_nodes: {
  255. let dynamic_nodes: Vec<_> = dynamic_node_types
  256. .iter()
  257. .map(|ty| match ty {
  258. DynamicNodeType::Text => DynamicNode::Text(VText {
  259. value: Box::leak(
  260. format!("{}", rand::random::<usize>()).into_boxed_str(),
  261. ),
  262. id: Default::default(),
  263. }),
  264. DynamicNodeType::Other => {
  265. create_random_dynamic_node(cx, cx.props.depth + 1)
  266. }
  267. })
  268. .collect();
  269. cx.bump().alloc(dynamic_nodes)
  270. },
  271. dynamic_attrs: cx.bump().alloc(
  272. (0..template.attr_paths.len())
  273. .map(|_| create_random_dynamic_attr(cx))
  274. .collect::<Vec<_>>(),
  275. ),
  276. };
  277. Some(node)
  278. }
  279. _ => None,
  280. };
  281. println!("{node:#?}");
  282. node
  283. }
  284. #[derive(Debug, Clone, PartialEq, Eq, Default)]
  285. pub struct BlablaState {
  286. count: usize,
  287. }
  288. impl State for BlablaState {
  289. type ParentDependencies = (Self,);
  290. type ChildDependencies = ();
  291. type NodeDependencies = ();
  292. const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
  293. .with_attrs(AttributeMaskBuilder::Some(&["blabla"]))
  294. .with_element();
  295. fn update<'a>(
  296. &mut self,
  297. _: NodeView,
  298. _: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
  299. parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
  300. _: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
  301. _: &SendAnyMap,
  302. ) -> bool {
  303. if let Some((parent,)) = parent {
  304. if parent.count != 0 {
  305. self.count += 1;
  306. }
  307. }
  308. true
  309. }
  310. fn create<'a>(
  311. node_view: NodeView<()>,
  312. node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
  313. parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
  314. children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
  315. context: &SendAnyMap,
  316. ) -> Self {
  317. let mut myself = Self::default();
  318. myself.update(node_view, node, parent, children, context);
  319. myself
  320. }
  321. }
  322. // test for panics when creating random nodes and templates
  323. #[test]
  324. fn create() {
  325. for _ in 0..100 {
  326. let mut vdom = VirtualDom::new_with_props(
  327. create_random_element,
  328. DepthProps {
  329. depth: 0,
  330. root: true,
  331. },
  332. );
  333. let mutations = vdom.rebuild();
  334. let mut rdom: RealDom = RealDom::new(Box::new([BlablaState::to_type_erased()]));
  335. let mut dioxus_state = DioxusState::create(&mut rdom);
  336. dioxus_state.apply_mutations(&mut rdom, mutations);
  337. let ctx = SendAnyMap::new();
  338. rdom.update_state(ctx, false);
  339. }
  340. }
  341. // test for panics when diffing random nodes
  342. // This test will change the template every render which is not very realistic, but it helps stress the system
  343. #[test]
  344. fn diff() {
  345. for _ in 0..10 {
  346. let mut vdom = VirtualDom::new_with_props(
  347. create_random_element,
  348. DepthProps {
  349. depth: 0,
  350. root: true,
  351. },
  352. );
  353. let mutations = vdom.rebuild();
  354. let mut rdom: RealDom = RealDom::new(Box::new([BlablaState::to_type_erased()]));
  355. let mut dioxus_state = DioxusState::create(&mut rdom);
  356. dioxus_state.apply_mutations(&mut rdom, mutations);
  357. let ctx = SendAnyMap::new();
  358. rdom.update_state(ctx, false);
  359. for _ in 0..10 {
  360. let mutations = vdom.render_immediate();
  361. dioxus_state.apply_mutations(&mut rdom, mutations);
  362. let ctx = SendAnyMap::new();
  363. rdom.update_state(ctx, false);
  364. }
  365. }
  366. }