diffing.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. //! Diffing Tests
  2. use bumpalo::Bump;
  3. use dioxus::{
  4. arena::SharedResources, diff::DiffMachine, prelude::*, DiffInstruction, DomEdit, MountType,
  5. };
  6. use dioxus_core as dioxus;
  7. use dioxus_html as dioxus_elements;
  8. use futures_util::FutureExt;
  9. mod test_logging;
  10. use DomEdit::*;
  11. // logging is wired up to the test harness
  12. // feel free to enable while debugging
  13. const IS_LOGGING_ENABLED: bool = false;
  14. struct TestDom {
  15. bump: Bump,
  16. resources: SharedResources,
  17. }
  18. impl TestDom {
  19. fn new() -> TestDom {
  20. test_logging::set_up_logging(IS_LOGGING_ENABLED);
  21. let bump = Bump::new();
  22. let resources = SharedResources::new();
  23. TestDom { bump, resources }
  24. }
  25. fn new_factory<'a>(&'a self) -> NodeFactory<'a> {
  26. NodeFactory::new(&self.bump)
  27. }
  28. fn render<'a, F>(&'a self, lazy_nodes: LazyNodes<'a, F>) -> VNode<'a>
  29. where
  30. F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
  31. {
  32. use dioxus_core::nodes::{IntoVNode, IntoVNodeList};
  33. lazy_nodes.into_vnode(NodeFactory::new(&self.bump))
  34. }
  35. fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
  36. // let mut edits = Vec::new();
  37. let mut machine = DiffMachine::new_headless(&self.resources);
  38. machine.stack.push(DiffInstruction::DiffNode { new, old });
  39. machine.mutations
  40. }
  41. fn create<'a, F1>(&'a self, left: LazyNodes<'a, F1>) -> Mutations<'a>
  42. where
  43. F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
  44. {
  45. let old = self.bump.alloc(self.render(left));
  46. let mut machine = DiffMachine::new_headless(&self.resources);
  47. machine.stack.create_node(old, MountType::Append);
  48. work_sync(&mut machine);
  49. machine.mutations
  50. }
  51. fn lazy_diff<'a, F1, F2>(
  52. &'a self,
  53. left: LazyNodes<'a, F1>,
  54. right: LazyNodes<'a, F2>,
  55. ) -> (Mutations<'a>, Mutations<'a>)
  56. where
  57. F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
  58. F2: FnOnce(NodeFactory<'a>) -> VNode<'a>,
  59. {
  60. let old = self.bump.alloc(self.render(left));
  61. let new = self.bump.alloc(self.render(right));
  62. let mut machine = DiffMachine::new_headless(&self.resources);
  63. machine.stack.create_node(old, MountType::Append);
  64. work_sync(&mut machine);
  65. let create_edits = machine.mutations;
  66. let mut machine = DiffMachine::new_headless(&self.resources);
  67. machine.stack.push(DiffInstruction::DiffNode { old, new });
  68. work_sync(&mut machine);
  69. let edits = machine.mutations;
  70. (create_edits, edits)
  71. }
  72. }
  73. fn work_sync(machine: &mut DiffMachine) {
  74. let mut fut = machine.work().boxed_local();
  75. while let None = (&mut fut).now_or_never() {
  76. //
  77. }
  78. }
  79. #[test]
  80. fn diffing_works() {}
  81. /// Should push the text node onto the stack and modify it
  82. #[test]
  83. fn html_and_rsx_generate_the_same_output() {
  84. let dom = TestDom::new();
  85. let (create, change) = dom.lazy_diff(
  86. rsx! ( div { "Hello world" } ),
  87. rsx! ( div { "Goodbye world" } ),
  88. );
  89. assert_eq!(
  90. create.edits,
  91. [
  92. CreateElement { id: 0, tag: "div" },
  93. CreateTextNode {
  94. id: 1,
  95. text: "Hello world"
  96. },
  97. AppendChildren { many: 1 },
  98. AppendChildren { many: 1 },
  99. ]
  100. );
  101. assert_eq!(
  102. change.edits,
  103. [
  104. PushRoot { id: 1 },
  105. SetText {
  106. text: "Goodbye world"
  107. },
  108. PopRoot
  109. ]
  110. );
  111. }
  112. /// Should result in 3 elements on the stack
  113. #[test]
  114. fn fragments_create_properly() {
  115. let dom = TestDom::new();
  116. let create = dom.create(rsx! {
  117. div { "Hello a" }
  118. div { "Hello b" }
  119. div { "Hello c" }
  120. });
  121. assert_eq!(
  122. create.edits,
  123. [
  124. CreateElement { id: 0, tag: "div" },
  125. CreateTextNode {
  126. id: 1,
  127. text: "Hello a"
  128. },
  129. AppendChildren { many: 1 },
  130. CreateElement { id: 2, tag: "div" },
  131. CreateTextNode {
  132. id: 3,
  133. text: "Hello b"
  134. },
  135. AppendChildren { many: 1 },
  136. CreateElement { id: 4, tag: "div" },
  137. CreateTextNode {
  138. id: 5,
  139. text: "Hello c"
  140. },
  141. AppendChildren { many: 1 },
  142. AppendChildren { many: 3 },
  143. ]
  144. );
  145. }
  146. /// Should result in the creation of an anchor (placeholder) and then a replacewith
  147. #[test]
  148. fn empty_fragments_create_anchors() {
  149. let dom = TestDom::new();
  150. let left = rsx!({ (0..0).map(|f| rsx! { div {}}) });
  151. let right = rsx!({ (0..1).map(|f| rsx! { div {}}) });
  152. let (create, change) = dom.lazy_diff(left, right);
  153. assert_eq!(
  154. create.edits,
  155. [CreatePlaceholder { id: 0 }, AppendChildren { many: 1 }]
  156. );
  157. assert_eq!(
  158. change.edits,
  159. [
  160. CreateElement { id: 1, tag: "div" },
  161. ReplaceWith { m: 1, root: 0 }
  162. ]
  163. );
  164. }
  165. /// Should result in the creation of an anchor (placeholder) and then a replacewith m=5
  166. #[test]
  167. fn empty_fragments_create_many_anchors() {
  168. let dom = TestDom::new();
  169. let left = rsx!({ (0..0).map(|f| rsx! { div {}}) });
  170. let right = rsx!({ (0..5).map(|f| rsx! { div {}}) });
  171. let (create, change) = dom.lazy_diff(left, right);
  172. assert_eq!(
  173. create.edits,
  174. [CreatePlaceholder { id: 0 }, AppendChildren { many: 1 }]
  175. );
  176. assert_eq!(
  177. change.edits,
  178. [
  179. CreateElement { id: 1, tag: "div" },
  180. CreateElement { id: 2, tag: "div" },
  181. CreateElement { id: 3, tag: "div" },
  182. CreateElement { id: 4, tag: "div" },
  183. CreateElement { id: 5, tag: "div" },
  184. ReplaceWith { m: 5, root: 0 }
  185. ]
  186. );
  187. }
  188. /// Should result in the creation of an anchor (placeholder) and then a replacewith
  189. /// Includes child nodes inside the fragment
  190. #[test]
  191. fn empty_fragments_create_anchors_with_many_children() {
  192. let dom = TestDom::new();
  193. let left = rsx!({ (0..0).map(|f| rsx! { div {} }) });
  194. let right = rsx!({
  195. (0..3).map(|f| {
  196. rsx! { div { "hello: {f}" }}
  197. })
  198. });
  199. let (create, change) = dom.lazy_diff(left, right);
  200. assert_eq!(
  201. create.edits,
  202. [CreatePlaceholder { id: 0 }, AppendChildren { many: 1 }]
  203. );
  204. assert_eq!(
  205. change.edits,
  206. [
  207. CreateElement { id: 1, tag: "div" },
  208. CreateTextNode {
  209. text: "hello: 0",
  210. id: 2
  211. },
  212. AppendChildren { many: 1 },
  213. CreateElement { id: 3, tag: "div" },
  214. CreateTextNode {
  215. text: "hello: 1",
  216. id: 4
  217. },
  218. AppendChildren { many: 1 },
  219. CreateElement { id: 5, tag: "div" },
  220. CreateTextNode {
  221. text: "hello: 2",
  222. id: 6
  223. },
  224. AppendChildren { many: 1 },
  225. ReplaceWith { m: 3, root: 0 }
  226. ]
  227. );
  228. }
  229. /// Should result in every node being pushed and then replaced with an anchor
  230. #[test]
  231. fn many_items_become_fragment() {
  232. let dom = TestDom::new();
  233. let left = rsx!({
  234. (0..2).map(|f| {
  235. rsx! { div { "hello" }}
  236. })
  237. });
  238. let right = rsx!({ (0..0).map(|f| rsx! { div {} }) });
  239. let (create, change) = dom.lazy_diff(left, right);
  240. assert_eq!(
  241. create.edits,
  242. [
  243. CreateElement { id: 0, tag: "div" },
  244. CreateTextNode {
  245. text: "hello",
  246. id: 1
  247. },
  248. AppendChildren { many: 1 },
  249. CreateElement { id: 2, tag: "div" },
  250. CreateTextNode {
  251. text: "hello",
  252. id: 3
  253. },
  254. AppendChildren { many: 1 },
  255. AppendChildren { many: 2 },
  256. ]
  257. );
  258. // hmmmmmmmmm worried about reusing IDs that we shouldnt be
  259. assert_eq!(
  260. change.edits,
  261. [
  262. Remove { root: 2 },
  263. CreatePlaceholder { id: 4 },
  264. ReplaceWith { root: 0, m: 1 },
  265. ]
  266. );
  267. }
  268. /// Should result in no edits
  269. #[test]
  270. fn two_equal_fragments_are_equal() {
  271. let dom = TestDom::new();
  272. let left = rsx!({
  273. (0..2).map(|f| {
  274. rsx! { div { "hello" }}
  275. })
  276. });
  277. let right = rsx!({
  278. (0..2).map(|f| {
  279. rsx! { div { "hello" }}
  280. })
  281. });
  282. let (create, change) = dom.lazy_diff(left, right);
  283. assert!(change.edits.is_empty());
  284. }
  285. /// Should result the creation of more nodes appended after the old last node
  286. #[test]
  287. fn two_fragments_with_differrent_elements_are_differet() {
  288. let dom = TestDom::new();
  289. let left = rsx!(
  290. { (0..2).map(|_| rsx! { div { }} ) }
  291. p {}
  292. );
  293. let right = rsx!(
  294. { (0..5).map(|_| rsx! (h1 { }) ) }
  295. p {}
  296. );
  297. let (create, changes) = dom.lazy_diff(left, right);
  298. log::debug!("{:#?}", &changes);
  299. assert_eq!(
  300. changes.edits,
  301. [
  302. // create the new h1s
  303. CreateElement { tag: "h1", id: 3 },
  304. CreateElement { tag: "h1", id: 4 },
  305. CreateElement { tag: "h1", id: 5 },
  306. InsertAfter { root: 1, n: 3 },
  307. // replace the divs with new h1s
  308. CreateElement { tag: "h1", id: 6 },
  309. ReplaceWith { root: 0, m: 1 },
  310. CreateElement { tag: "h1", id: 7 },
  311. ReplaceWith { root: 1, m: 1 },
  312. ]
  313. );
  314. }
  315. /// Should result in multiple nodes destroyed - with changes to the first nodes
  316. #[test]
  317. fn two_fragments_with_differrent_elements_are_differet_shorter() {
  318. let dom = TestDom::new();
  319. let left = rsx!(
  320. {(0..5).map(|f| {rsx! { div { }}})}
  321. p {}
  322. );
  323. let right = rsx!(
  324. {(0..2).map(|f| {rsx! { h1 { }}})}
  325. p {}
  326. );
  327. let (create, change) = dom.lazy_diff(left, right);
  328. assert_eq!(
  329. create.edits,
  330. [
  331. CreateElement { id: 0, tag: "div" },
  332. CreateElement { id: 1, tag: "div" },
  333. CreateElement { id: 2, tag: "div" },
  334. CreateElement { id: 3, tag: "div" },
  335. CreateElement { id: 4, tag: "div" },
  336. CreateElement { id: 5, tag: "p" },
  337. AppendChildren { many: 6 },
  338. ]
  339. );
  340. assert_eq!(
  341. change.edits,
  342. [
  343. Remove { root: 2 },
  344. Remove { root: 3 },
  345. Remove { root: 4 },
  346. CreateElement { id: 6, tag: "h1" },
  347. ReplaceWith { root: 0, m: 1 },
  348. CreateElement { id: 7, tag: "h1" },
  349. ReplaceWith { root: 1, m: 1 },
  350. ]
  351. );
  352. }
  353. /// Should result in multiple nodes destroyed - with no changes
  354. #[test]
  355. fn two_fragments_with_same_elements_are_differet() {
  356. let dom = TestDom::new();
  357. let left = rsx!(
  358. {(0..2).map(|f| {rsx! { div { }}})}
  359. p {}
  360. );
  361. let right = rsx!(
  362. {(0..5).map(|f| {rsx! { div { }}})}
  363. p {}
  364. );
  365. let (create, change) = dom.lazy_diff(left, right);
  366. assert_eq!(
  367. create.edits,
  368. [
  369. CreateElement { id: 0, tag: "div" },
  370. CreateElement { id: 1, tag: "div" },
  371. CreateElement { id: 2, tag: "p" },
  372. AppendChildren { many: 3 },
  373. ]
  374. );
  375. assert_eq!(
  376. change.edits,
  377. [
  378. CreateElement { id: 3, tag: "div" },
  379. CreateElement { id: 4, tag: "div" },
  380. CreateElement { id: 5, tag: "div" },
  381. InsertAfter { root: 1, n: 3 },
  382. ]
  383. );
  384. }
  385. /// should result in the removal of elements
  386. #[test]
  387. fn keyed_diffing_order() {
  388. let dom = TestDom::new();
  389. let left = rsx!(
  390. {(0..5).map(|f| {rsx! { div { key: "{f}" }}})}
  391. p {"e"}
  392. );
  393. let right = rsx!(
  394. {(0..2).map(|f| {rsx! { div { key: "{f}" }}})}
  395. p {"e"}
  396. );
  397. let (create, change) = dom.lazy_diff(left, right);
  398. assert_eq!(
  399. change.edits,
  400. [Remove { root: 2 }, Remove { root: 3 }, Remove { root: 4 },]
  401. );
  402. }
  403. /// Should result in moves, but not removals or additions
  404. #[test]
  405. fn keyed_diffing_out_of_order() {
  406. let dom = TestDom::new();
  407. let left = rsx!({
  408. [0, 1, 2, 3, /**/ 4, 5, 6, /**/ 7, 8, 9].iter().map(|f| {
  409. rsx! { div { key: "{f}" }}
  410. })
  411. });
  412. let right = rsx!({
  413. [0, 1, 2, 3, /**/ 6, 4, 5, /**/ 7, 8, 9].iter().map(|f| {
  414. rsx! { div { key: "{f}" }}
  415. })
  416. });
  417. let (_, changes) = dom.lazy_diff(left, right);
  418. log::debug!("{:?}", &changes);
  419. assert_eq!(
  420. changes.edits,
  421. [PushRoot { id: 6 }, InsertBefore { root: 4, n: 1 }]
  422. );
  423. }
  424. /// Should result in moves only
  425. #[test]
  426. fn keyed_diffing_out_of_order_adds() {
  427. let dom = TestDom::new();
  428. let left = rsx!({
  429. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  430. rsx! { div { key: "{f}" }}
  431. })
  432. });
  433. let right = rsx!({
  434. [/**/ 8, 7, 4, 5, 6 /**/].iter().map(|f| {
  435. rsx! { div { key: "{f}" }}
  436. })
  437. });
  438. let (_, change) = dom.lazy_diff(left, right);
  439. assert_eq!(
  440. change.edits,
  441. [
  442. PushRoot { id: 4 },
  443. PushRoot { id: 3 },
  444. InsertBefore { n: 2, root: 0 }
  445. ]
  446. );
  447. }
  448. /// Should result in moves onl
  449. #[test]
  450. fn keyed_diffing_out_of_order_adds_2() {
  451. let dom = TestDom::new();
  452. let left = rsx!({
  453. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  454. rsx! { div { key: "{f}" }}
  455. })
  456. });
  457. let right = rsx!({
  458. [/**/ 7, 8, 4, 5, 6 /**/].iter().map(|f| {
  459. rsx! { div { key: "{f}" }}
  460. })
  461. });
  462. let (_, change) = dom.lazy_diff(left, right);
  463. assert_eq!(
  464. change.edits,
  465. [
  466. PushRoot { id: 3 },
  467. PushRoot { id: 4 },
  468. InsertBefore { n: 2, root: 0 }
  469. ]
  470. );
  471. }
  472. /// Should result in moves onl
  473. #[test]
  474. fn keyed_diffing_out_of_order_adds_3() {
  475. let dom = TestDom::new();
  476. let left = rsx!({
  477. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  478. rsx! { div { key: "{f}" }}
  479. })
  480. });
  481. let right = rsx!({
  482. [/**/ 4, 8, 7, 5, 6 /**/].iter().map(|f| {
  483. rsx! { div { key: "{f}" }}
  484. })
  485. });
  486. let (_, change) = dom.lazy_diff(left, right);
  487. assert_eq!(
  488. change.edits,
  489. [
  490. PushRoot { id: 4 },
  491. PushRoot { id: 3 },
  492. InsertBefore { n: 2, root: 1 }
  493. ]
  494. );
  495. }
  496. /// Should result in moves onl
  497. #[test]
  498. fn keyed_diffing_out_of_order_adds_4() {
  499. let dom = TestDom::new();
  500. let left = rsx!({
  501. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  502. rsx! { div { key: "{f}" }}
  503. })
  504. });
  505. let right = rsx!({
  506. [/**/ 4, 5, 8, 7, 6 /**/].iter().map(|f| {
  507. rsx! { div { key: "{f}" }}
  508. })
  509. });
  510. let (_, change) = dom.lazy_diff(left, right);
  511. assert_eq!(
  512. change.edits,
  513. [
  514. PushRoot { id: 4 },
  515. PushRoot { id: 3 },
  516. InsertBefore { n: 2, root: 2 }
  517. ]
  518. );
  519. }
  520. /// Should result in moves onl
  521. #[test]
  522. fn keyed_diffing_out_of_order_adds_5() {
  523. let dom = TestDom::new();
  524. let left = rsx!({
  525. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  526. rsx! { div { key: "{f}" }}
  527. })
  528. });
  529. let right = rsx!({
  530. [/**/ 4, 5, 6, 8, 7 /**/].iter().map(|f| {
  531. rsx! { div { key: "{f}" }}
  532. })
  533. });
  534. let (_, change) = dom.lazy_diff(left, right);
  535. assert_eq!(
  536. change.edits,
  537. [PushRoot { id: 4 }, InsertBefore { n: 1, root: 3 }]
  538. );
  539. }
  540. #[test]
  541. fn keyed_diffing_additions() {
  542. let dom = TestDom::new();
  543. let left = rsx!({
  544. [/**/ 4, 5, 6, 7, 8 /**/].iter().map(|f| {
  545. rsx! { div { key: "{f}" }}
  546. })
  547. });
  548. let right = rsx!({
  549. [/**/ 4, 5, 6, 7, 8, 9, 10 /**/].iter().map(|f| {
  550. rsx! { div { key: "{f}" }}
  551. })
  552. });
  553. let (_, change) = dom.lazy_diff(left, right);
  554. assert_eq!(
  555. change.edits,
  556. [
  557. CreateElement { id: 5, tag: "div" },
  558. CreateElement { id: 6, tag: "div" },
  559. InsertAfter { n: 2, root: 4 }
  560. ]
  561. );
  562. }
  563. #[test]
  564. fn keyed_diffing_additions_and_moves_on_ends() {
  565. let dom = TestDom::new();
  566. let left = rsx!({
  567. [/**/ 4, 5, 6, 7 /**/].iter().map(|f| {
  568. rsx! { div { key: "{f}" }}
  569. })
  570. });
  571. let right = rsx!({
  572. [/**/ 7, 4, 5, 6, 11, 12 /**/].iter().map(|f| {
  573. rsx! { div { key: "{f}" }}
  574. })
  575. });
  576. let (_, change) = dom.lazy_diff(left, right);
  577. log::debug!("{:?}", change);
  578. assert_eq!(
  579. change.edits,
  580. [
  581. // create 11, 12
  582. CreateElement { tag: "div", id: 4 },
  583. CreateElement { tag: "div", id: 5 },
  584. InsertAfter { root: 2, n: 2 },
  585. // move 7 to the front
  586. PushRoot { id: 3 },
  587. InsertBefore { root: 0, n: 1 }
  588. ]
  589. );
  590. }
  591. #[test]
  592. fn keyed_diffing_additions_and_moves_in_middle() {
  593. let dom = TestDom::new();
  594. let left = rsx!({
  595. [/**/ 4, 5, 6, 7 /**/].iter().map(|f| {
  596. rsx! { div { key: "{f}" }}
  597. })
  598. });
  599. let right = rsx!({
  600. [/**/ 7, 4, 13, 17, 5, 11, 12, 6 /**/].iter().map(|f| {
  601. rsx! { div { key: "{f}" }}
  602. })
  603. });
  604. // LIS: 4, 5, 6
  605. let (_, change) = dom.lazy_diff(left, right);
  606. log::debug!("{:#?}", change);
  607. assert_eq!(
  608. change.edits,
  609. [
  610. // create 13, 17
  611. CreateElement { tag: "div", id: 4 },
  612. CreateElement { tag: "div", id: 5 },
  613. InsertBefore { root: 1, n: 2 },
  614. // create 11, 12
  615. CreateElement { tag: "div", id: 6 },
  616. CreateElement { tag: "div", id: 7 },
  617. InsertBefore { root: 2, n: 2 },
  618. // move 7
  619. PushRoot { id: 3 },
  620. InsertBefore { root: 0, n: 1 }
  621. ]
  622. );
  623. }
  624. #[test]
  625. fn controlled_keyed_diffing_out_of_order() {
  626. let dom = TestDom::new();
  627. let left = rsx!({
  628. [4, 5, 6, 7].iter().map(|f| {
  629. rsx! { div { key: "{f}" }}
  630. })
  631. });
  632. let right = rsx!({
  633. [0, 5, 9, 6, 4].iter().map(|f| {
  634. rsx! { div { key: "{f}" }}
  635. })
  636. });
  637. // LIS: 5, 6
  638. let (_, changes) = dom.lazy_diff(left, right);
  639. log::debug!("{:#?}", &changes);
  640. assert_eq!(
  641. changes.edits,
  642. [
  643. // move 4 to after 6
  644. PushRoot { id: 0 },
  645. InsertAfter { n: 1, root: 2 },
  646. // remove 7
  647. // create 9 and insert before 6
  648. CreateElement { id: 4, tag: "div" },
  649. InsertBefore { n: 1, root: 2 },
  650. // create 0 and insert before 5
  651. CreateElement { id: 5, tag: "div" },
  652. InsertBefore { n: 1, root: 1 },
  653. ]
  654. );
  655. }
  656. #[test]
  657. fn controlled_keyed_diffing_out_of_order_max_test() {
  658. let dom = TestDom::new();
  659. let left = rsx!({
  660. [0, 1, 2, 3, 4].iter().map(|f| {
  661. rsx! { div { key: "{f}" }}
  662. })
  663. });
  664. let right = rsx!({
  665. [3, 0, 1, 10, 2].iter().map(|f| {
  666. rsx! { div { key: "{f}" }}
  667. })
  668. });
  669. let (_, changes) = dom.lazy_diff(left, right);
  670. log::debug!("{:#?}", &changes);
  671. assert_eq!(
  672. changes.edits,
  673. [
  674. CreateElement { id: 5, tag: "div" },
  675. InsertBefore { n: 1, root: 2 },
  676. PushRoot { id: 3 },
  677. InsertBefore { n: 1, root: 0 },
  678. ]
  679. );
  680. }