miri_stress.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. #![allow(non_snake_case)]
  2. /*
  3. Stress Miri as much as possible.
  4. Prove that we don't leak memory and that our methods are safe.
  5. Specifically:
  6. - [ ] VirtualDom drops memory safely
  7. - [ ] Borrowed components don't expose invalid pointers
  8. - [ ] Async isn't busted
  9. */
  10. use dioxus::prelude::*;
  11. /// This test ensures that if a component aborts early, it is replaced with a placeholder.
  12. /// In debug, this should also toss a warning.
  13. #[test]
  14. #[ignore]
  15. fn test_memory_leak() {
  16. fn app(cx: Scope) -> Element {
  17. let val = cx.use_hook(|| 0);
  18. *val += 1;
  19. if *val == 2 || *val == 4 {
  20. return cx.render(rsx!(()));
  21. }
  22. let name = cx.use_hook(|| String::from("asd"));
  23. cx.render(rsx!(
  24. div { "Hello, world!" }
  25. Child {}
  26. Child {}
  27. Child {}
  28. Child {}
  29. Child {}
  30. Child {}
  31. BorrowedChild { na: name }
  32. BorrowedChild { na: name }
  33. BorrowedChild { na: name }
  34. BorrowedChild { na: name }
  35. BorrowedChild { na: name }
  36. ))
  37. }
  38. #[derive(Props)]
  39. struct BorrowedProps<'a> {
  40. na: &'a str,
  41. }
  42. fn BorrowedChild<'a>(cx: Scope<'a, BorrowedProps<'a>>) -> Element {
  43. render!(div {
  44. "goodbye {cx.props.na}"
  45. Child {}
  46. Child {}
  47. })
  48. }
  49. fn Child(cx: Scope) -> Element {
  50. render!(div { "goodbye world" })
  51. }
  52. let mut dom = VirtualDom::new(app);
  53. dom.rebuild();
  54. dom.hard_diff(ScopeId(0));
  55. dom.hard_diff(ScopeId(0));
  56. dom.hard_diff(ScopeId(0));
  57. dom.hard_diff(ScopeId(0));
  58. dom.hard_diff(ScopeId(0));
  59. dom.hard_diff(ScopeId(0));
  60. }
  61. #[test]
  62. fn memo_works_properly() {
  63. fn app(cx: Scope) -> Element {
  64. let val = cx.use_hook(|| 0);
  65. *val += 1;
  66. if *val == 2 || *val == 4 {
  67. return None;
  68. }
  69. let name = cx.use_hook(|| String::from("asd"));
  70. cx.render(rsx!(
  71. div { "Hello, world! {name}" }
  72. Child { na: "asdfg".to_string() }
  73. ))
  74. }
  75. #[derive(PartialEq, Props)]
  76. struct ChildProps {
  77. na: String,
  78. }
  79. fn Child(cx: Scope<ChildProps>) -> Element {
  80. render!(div { "goodbye world" })
  81. }
  82. let mut dom = new_dom(app, ());
  83. dom.rebuild();
  84. dom.hard_diff(ScopeId(0));
  85. dom.hard_diff(ScopeId(0));
  86. dom.hard_diff(ScopeId(0));
  87. dom.hard_diff(ScopeId(0));
  88. dom.hard_diff(ScopeId(0));
  89. dom.hard_diff(ScopeId(0));
  90. dom.hard_diff(ScopeId(0));
  91. }
  92. #[test]
  93. fn free_works_on_root_props() {
  94. fn app(cx: Scope<Custom>) -> Element {
  95. cx.render(rsx! {
  96. Child { a: "alpha"}
  97. Child { a: "beta"}
  98. Child { a: "gamma"}
  99. Child { a: "delta"}
  100. })
  101. }
  102. #[derive(Props, PartialEq)]
  103. struct ChildProps {
  104. a: &'static str,
  105. }
  106. fn Child(cx: Scope<ChildProps>) -> Element {
  107. render!("child {cx.props.a}")
  108. }
  109. struct Custom {
  110. val: String,
  111. }
  112. impl Drop for Custom {
  113. fn drop(&mut self) {
  114. dbg!("dropped! {}", &self.val);
  115. }
  116. }
  117. let mut dom = new_dom(app, Custom { val: String::from("asd") });
  118. dom.rebuild();
  119. }
  120. #[test]
  121. fn free_works_on_borrowed() {
  122. fn app(cx: Scope) -> Element {
  123. cx.render(rsx! {
  124. Child { a: "alpha", b: "asd".to_string() }
  125. })
  126. }
  127. #[derive(Props)]
  128. struct ChildProps<'a> {
  129. a: &'a str,
  130. b: String,
  131. }
  132. fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
  133. dbg!("rendering child");
  134. render!("child {cx.props.a}, {cx.props.b}")
  135. }
  136. impl Drop for ChildProps<'_> {
  137. fn drop(&mut self) {
  138. dbg!("dropped child!");
  139. }
  140. }
  141. let mut dom = new_dom(app, ());
  142. let _ = dom.rebuild();
  143. }
  144. #[test]
  145. fn free_works_on_root_hooks() {
  146. /*
  147. On Drop, scopearena drops all the hook contents.
  148. */
  149. struct Droppable<T>(T);
  150. impl<T> Drop for Droppable<T> {
  151. fn drop(&mut self) {
  152. dbg!("dropping droppable");
  153. }
  154. }
  155. fn app(cx: Scope) -> Element {
  156. let name = cx.use_hook(|| Droppable(String::from("asd")));
  157. render!(div { "{name.0}" })
  158. }
  159. let mut dom = new_dom(app, ());
  160. let _ = dom.rebuild();
  161. }
  162. #[test]
  163. fn old_props_arent_stale() {
  164. fn app(cx: Scope) -> Element {
  165. dbg!("rendering parent");
  166. let cnt = cx.use_hook(|| 0);
  167. *cnt += 1;
  168. if *cnt == 1 {
  169. render!(div { Child { a: "abcdef".to_string() } })
  170. } else {
  171. render!(div { Child { a: "abcdef".to_string() } })
  172. }
  173. }
  174. #[derive(Props, PartialEq)]
  175. struct ChildProps {
  176. a: String,
  177. }
  178. fn Child(cx: Scope<ChildProps>) -> Element {
  179. dbg!("rendering child", &cx.props.a);
  180. render!(div { "child {cx.props.a}" })
  181. }
  182. let mut dom = new_dom(app, ());
  183. let _ = dom.rebuild();
  184. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  185. dom.work_with_deadline(|| false);
  186. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  187. dom.work_with_deadline(|| false);
  188. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  189. dom.work_with_deadline(|| false);
  190. dbg!("forcing update to child");
  191. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  192. dom.work_with_deadline(|| false);
  193. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  194. dom.work_with_deadline(|| false);
  195. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  196. dom.work_with_deadline(|| false);
  197. }
  198. #[test]
  199. fn basic() {
  200. fn app(cx: Scope) -> Element {
  201. render!(div {
  202. Child { a: "abcdef".to_string() }
  203. })
  204. }
  205. #[derive(Props, PartialEq)]
  206. struct ChildProps {
  207. a: String,
  208. }
  209. fn Child(cx: Scope<ChildProps>) -> Element {
  210. dbg!("rendering child", &cx.props.a);
  211. render!(div { "child {cx.props.a}" })
  212. }
  213. let mut dom = new_dom(app, ());
  214. let _ = dom.rebuild();
  215. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  216. dom.work_with_deadline(|| false);
  217. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  218. dom.work_with_deadline(|| false);
  219. }
  220. #[test]
  221. fn leak_thru_children() {
  222. fn app(cx: Scope) -> Element {
  223. cx.render(rsx! {
  224. Child {
  225. name: "asd".to_string(),
  226. }
  227. });
  228. cx.render(rsx! {
  229. div {}
  230. })
  231. }
  232. #[inline_props]
  233. fn Child(cx: Scope, name: String) -> Element {
  234. render!(div { "child {name}" })
  235. }
  236. let mut dom = new_dom(app, ());
  237. let _ = dom.rebuild();
  238. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  239. dom.work_with_deadline(|| false);
  240. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  241. dom.work_with_deadline(|| false);
  242. }
  243. #[test]
  244. fn test_pass_thru() {
  245. #[inline_props]
  246. fn NavContainer<'a>(cx: Scope, children: Element<'a>) -> Element {
  247. cx.render(rsx! {
  248. header {
  249. nav { children }
  250. }
  251. })
  252. }
  253. fn NavMenu(cx: Scope) -> Element {
  254. render!( NavBrand {}
  255. div {
  256. NavStart {}
  257. NavEnd {}
  258. }
  259. )
  260. }
  261. fn NavBrand(cx: Scope) -> Element {
  262. render!(div {})
  263. }
  264. fn NavStart(cx: Scope) -> Element {
  265. render!(div {})
  266. }
  267. fn NavEnd(cx: Scope) -> Element {
  268. render!(div {})
  269. }
  270. #[inline_props]
  271. fn MainContainer<'a>(
  272. cx: Scope,
  273. nav: Element<'a>,
  274. body: Element<'a>,
  275. footer: Element<'a>,
  276. ) -> Element {
  277. cx.render(rsx! {
  278. div {
  279. class: "columns is-mobile",
  280. div {
  281. class: "column is-full",
  282. nav,
  283. body,
  284. footer,
  285. }
  286. }
  287. })
  288. }
  289. fn app(cx: Scope) -> Element {
  290. let nav = cx.render(rsx! {
  291. NavContainer {
  292. NavMenu {}
  293. }
  294. });
  295. let body = cx.render(rsx! {
  296. div {}
  297. });
  298. let footer = cx.render(rsx! {
  299. div {}
  300. });
  301. cx.render(rsx! {
  302. MainContainer {
  303. nav: nav,
  304. body: body,
  305. footer: footer,
  306. }
  307. })
  308. }
  309. let mut dom = new_dom(app, ());
  310. let _ = dom.rebuild();
  311. for _ in 0..40 {
  312. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  313. dom.work_with_deadline(|| false);
  314. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  315. dom.work_with_deadline(|| false);
  316. dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
  317. dom.work_with_deadline(|| false);
  318. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  319. dom.work_with_deadline(|| false);
  320. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  321. dom.work_with_deadline(|| false);
  322. dom.handle_message(SchedulerMsg::Immediate(ScopeId(1)));
  323. dom.work_with_deadline(|| false);
  324. dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
  325. dom.work_with_deadline(|| false);
  326. dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
  327. dom.work_with_deadline(|| false);
  328. dom.handle_message(SchedulerMsg::Immediate(ScopeId(2)));
  329. dom.work_with_deadline(|| false);
  330. dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
  331. dom.work_with_deadline(|| false);
  332. dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
  333. dom.work_with_deadline(|| false);
  334. dom.handle_message(SchedulerMsg::Immediate(ScopeId(3)));
  335. dom.work_with_deadline(|| false);
  336. }
  337. }