diff.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. use super::HashNibbles;
  2. use crate::{Hasher, Node, Pair, Pointer, HAMT_BITMASK_BIT_SIZE};
  3. use anyhow::{Ok, Result};
  4. use async_recursion::async_recursion;
  5. use serde::{de::DeserializeOwned, Serialize};
  6. use std::{collections::HashMap, hash::Hash, mem};
  7. use wnfs_common::{
  8. utils::{Arc, CondSync},
  9. BlockStore, Link, Storable,
  10. };
  11. //--------------------------------------------------------------------------------------------------
  12. // Type Definitions
  13. //--------------------------------------------------------------------------------------------------
  14. /// This type represents the different kinds of changes to a node.
  15. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
  16. pub enum ChangeType {
  17. Add,
  18. Remove,
  19. Modify,
  20. }
  21. /// Represents a change to some key-value pair of a HAMT node.
  22. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
  23. pub struct KeyValueChange<K, V> {
  24. pub r#type: ChangeType,
  25. pub key: K,
  26. pub value1: Option<V>,
  27. pub value2: Option<V>,
  28. }
  29. //--------------------------------------------------------------------------------------------------
  30. // Implementations
  31. //--------------------------------------------------------------------------------------------------
  32. impl<K, V> KeyValueChange<K, V> {
  33. pub fn map<W>(self, f: &impl Fn(V) -> W) -> KeyValueChange<K, W> {
  34. let Self {
  35. r#type,
  36. key,
  37. value1,
  38. value2,
  39. } = self;
  40. KeyValueChange {
  41. r#type,
  42. key,
  43. value1: value1.map(f),
  44. value2: value2.map(f),
  45. }
  46. }
  47. }
  48. //--------------------------------------------------------------------------------------------------
  49. // Functions
  50. //--------------------------------------------------------------------------------------------------
  51. /// Compare two nodes and get the key-value changes made to the main node.
  52. ///
  53. /// This implementation gets all the changes to main node at the leaf node level.
  54. ///
  55. /// This is a more expensive operation because it gathers the key value pairs under a node has
  56. /// been added or removed even though we can simply return a reference to the node itself.
  57. ///
  58. /// # Examples
  59. ///
  60. /// ```
  61. /// use std::sync::Arc;
  62. /// use wnfs_hamt::{Node, Pair, diff};
  63. /// use wnfs_common::{Link, MemoryBlockStore};
  64. ///
  65. /// #[async_std::main]
  66. /// async fn main() {
  67. /// let store = &MemoryBlockStore::new();
  68. /// let main_node = &mut Arc::new(Node::<[u8; 4], String>::default());
  69. /// for i in 0u32..3 {
  70. /// main_node
  71. /// .set(i.to_le_bytes(), i.to_string(), store)
  72. /// .await
  73. /// .unwrap();
  74. /// }
  75. ///
  76. /// let other_node = &mut Arc::new(Node::<[u8; 4], String>::default());
  77. /// other_node
  78. /// .set(0_u32.to_le_bytes(), 0_u32.to_string(), store)
  79. /// .await
  80. /// .unwrap();
  81. ///
  82. /// let changes = diff(
  83. /// Link::from(Arc::clone(main_node)),
  84. /// Link::from(Arc::clone(other_node)),
  85. /// store,
  86. /// )
  87. /// .await
  88. /// .unwrap();
  89. ///
  90. ///
  91. /// println!("Changes {:#?}", changes);
  92. /// }
  93. /// ```
  94. pub async fn diff<K, V, H>(
  95. main_link: Link<Arc<Node<K, V, H>>>,
  96. other_link: Link<Arc<Node<K, V, H>>>,
  97. store: &impl BlockStore,
  98. ) -> Result<Vec<KeyValueChange<K, V>>>
  99. where
  100. K: Storable + Clone + Eq + Hash + AsRef<[u8]> + CondSync,
  101. V: Storable + Clone + Eq + CondSync,
  102. K::Serializable: Serialize + DeserializeOwned,
  103. V::Serializable: Serialize + DeserializeOwned,
  104. H: Hasher + CondSync,
  105. {
  106. diff_helper(main_link, other_link, 1, store).await
  107. }
  108. #[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
  109. #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
  110. pub async fn diff_helper<K, V, H>(
  111. main_link: Link<Arc<Node<K, V, H>>>,
  112. other_link: Link<Arc<Node<K, V, H>>>,
  113. depth: usize,
  114. store: &impl BlockStore,
  115. ) -> Result<Vec<KeyValueChange<K, V>>>
  116. where
  117. K: Storable + Clone + Eq + Hash + AsRef<[u8]> + CondSync,
  118. V: Storable + Clone + Eq + CondSync,
  119. K::Serializable: Serialize + DeserializeOwned,
  120. V::Serializable: Serialize + DeserializeOwned,
  121. H: Hasher + CondSync,
  122. {
  123. // If Cids are available, check to see if they are equal so we can skip further comparisons.
  124. if let (Some(cid), Some(cid2)) = (main_link.get_cid(), other_link.get_cid()) {
  125. if cid == cid2 {
  126. return Ok(vec![]);
  127. }
  128. }
  129. // Otherwise, get nodes from store.
  130. let mut main_node = main_link.resolve_owned_value(store).await?;
  131. let mut other_node = other_link.resolve_owned_value(store).await?;
  132. let mut changes = vec![];
  133. for index in 0..HAMT_BITMASK_BIT_SIZE {
  134. match (main_node.bitmask[index], other_node.bitmask[index]) {
  135. (true, false) => {
  136. // Main has a value, other doesn't.
  137. changes.extend(
  138. generate_add_or_remove_changes(
  139. &main_node.pointers[main_node.get_value_index(index)],
  140. ChangeType::Add,
  141. store,
  142. )
  143. .await?,
  144. );
  145. }
  146. (false, true) => {
  147. // Main doesn't have a value, other does.
  148. changes.extend(
  149. generate_add_or_remove_changes(
  150. &other_node.pointers[other_node.get_value_index(index)],
  151. ChangeType::Remove,
  152. store,
  153. )
  154. .await?,
  155. );
  156. }
  157. (true, true) => {
  158. // Main and other have a value. They may be the same or different so we check.
  159. let main_index = main_node.get_value_index(index);
  160. let main_pointer = mem::take(
  161. Arc::make_mut(&mut main_node)
  162. .pointers
  163. .get_mut(main_index)
  164. .unwrap(),
  165. );
  166. let other_index = other_node.get_value_index(index);
  167. let other_pointer = mem::take(
  168. Arc::make_mut(&mut other_node)
  169. .pointers
  170. .get_mut(other_index)
  171. .unwrap(),
  172. );
  173. changes.extend(pointers_diff(main_pointer, other_pointer, depth, store).await?);
  174. }
  175. (false, false) => { /* No change */ }
  176. }
  177. }
  178. Ok(changes)
  179. }
  180. async fn generate_add_or_remove_changes<K, V, H>(
  181. node_pointer: &Pointer<K, V, H>,
  182. r#type: ChangeType,
  183. store: &impl BlockStore,
  184. ) -> Result<Vec<KeyValueChange<K, V>>>
  185. where
  186. K: Storable + Clone + Eq + Hash + AsRef<[u8]> + CondSync,
  187. V: Storable + Clone + Eq + CondSync,
  188. K::Serializable: Serialize + DeserializeOwned,
  189. V::Serializable: Serialize + DeserializeOwned,
  190. H: Hasher + CondSync,
  191. {
  192. match node_pointer {
  193. Pointer::Values(values) => Ok(values
  194. .iter()
  195. .map(|Pair { key, value }| KeyValueChange {
  196. r#type,
  197. key: key.clone(),
  198. value1: Some(value.clone()),
  199. value2: None,
  200. })
  201. .collect()),
  202. Pointer::Link(link) => {
  203. let node = link.resolve_value(store).await?;
  204. node.as_ref()
  205. .flat_map(
  206. &|Pair { key, value }| {
  207. Ok(KeyValueChange {
  208. r#type,
  209. key: key.clone(),
  210. value1: Some(value.clone()),
  211. value2: None,
  212. })
  213. },
  214. store,
  215. )
  216. .await
  217. }
  218. }
  219. }
  220. async fn pointers_diff<K, V, H>(
  221. main_pointer: Pointer<K, V, H>,
  222. other_pointer: Pointer<K, V, H>,
  223. depth: usize,
  224. store: &impl BlockStore,
  225. ) -> Result<Vec<KeyValueChange<K, V>>>
  226. where
  227. K: Storable + Clone + Eq + Hash + AsRef<[u8]> + CondSync,
  228. V: Storable + Clone + Eq + CondSync,
  229. K::Serializable: Serialize + DeserializeOwned,
  230. V::Serializable: Serialize + DeserializeOwned,
  231. H: Hasher + CondSync,
  232. {
  233. match (main_pointer, other_pointer) {
  234. (Pointer::Link(main_link), Pointer::Link(other_link)) => {
  235. diff_helper(main_link, other_link, depth + 1, store).await
  236. }
  237. (Pointer::Values(main_values), Pointer::Values(other_values)) => {
  238. let mut changes = vec![];
  239. let mut main_map = HashMap::<&K, &V>::default();
  240. let other_map = HashMap::<&K, &V>::from_iter(
  241. other_values.iter().map(|Pair { key, value }| (key, value)),
  242. );
  243. for Pair { key, value } in &main_values {
  244. match other_map.get(&key) {
  245. Some(v) => {
  246. if *v != value {
  247. changes.push(KeyValueChange {
  248. r#type: ChangeType::Modify,
  249. key: key.clone(),
  250. value1: Some(value.clone()),
  251. value2: Some((*v).clone()),
  252. });
  253. }
  254. }
  255. None => {
  256. changes.push(KeyValueChange {
  257. r#type: ChangeType::Add,
  258. key: key.clone(),
  259. value1: Some(value.clone()),
  260. value2: None,
  261. });
  262. }
  263. }
  264. main_map.insert(key, value);
  265. }
  266. for Pair { key, value } in &other_values {
  267. if !main_map.contains_key(key) {
  268. changes.push(KeyValueChange {
  269. r#type: ChangeType::Remove,
  270. key: key.clone(),
  271. value1: Some(value.clone()),
  272. value2: None,
  273. });
  274. }
  275. }
  276. Ok(changes)
  277. }
  278. (Pointer::Values(main_values), Pointer::Link(other_link)) => {
  279. let main_link = Link::from(create_node_from_pairs(main_values, depth, store).await?);
  280. diff_helper(main_link, other_link, depth + 1, store).await
  281. }
  282. (Pointer::Link(main_link), Pointer::Values(other_values)) => {
  283. let other_link = Link::from(create_node_from_pairs(other_values, depth, store).await?);
  284. diff_helper(main_link, other_link, depth + 1, store).await
  285. }
  286. }
  287. }
  288. async fn create_node_from_pairs<K, V, H>(
  289. values: Vec<Pair<K, V>>,
  290. depth: usize,
  291. store: &impl BlockStore,
  292. ) -> Result<Arc<Node<K, V, H>>>
  293. where
  294. K: Storable + Clone + Eq + Hash + AsRef<[u8]> + CondSync,
  295. V: Storable + Clone + Eq + CondSync,
  296. K::Serializable: Serialize + DeserializeOwned,
  297. V::Serializable: Serialize + DeserializeOwned,
  298. H: Hasher + CondSync,
  299. {
  300. let mut node = Arc::new(Node::<_, _, H>::default());
  301. for Pair { key, value } in values {
  302. let digest = &H::hash(&key);
  303. let hashnibbles = &mut HashNibbles::with_cursor(digest, depth);
  304. node.set_value(hashnibbles, key, value, store).await?;
  305. }
  306. Ok(node)
  307. }
  308. //--------------------------------------------------------------------------------------------------
  309. // Tests
  310. //--------------------------------------------------------------------------------------------------
  311. #[cfg(test)]
  312. mod tests {
  313. use super::{ChangeType::*, *};
  314. use helper::*;
  315. use std::collections::BTreeSet;
  316. use wnfs_common::MemoryBlockStore;
  317. mod helper {
  318. use crate::Hasher;
  319. use once_cell::sync::Lazy;
  320. use wnfs_common::{utils, HashOutput};
  321. pub(super) static HASH_KV_PAIRS: Lazy<Vec<(HashOutput, &'static str)>> = Lazy::new(|| {
  322. vec![
  323. (utils::to_hash_output(&[0xA0]), "first"),
  324. (utils::to_hash_output(&[0xA3]), "second"),
  325. (utils::to_hash_output(&[0xA7]), "third"),
  326. (utils::to_hash_output(&[0xAC]), "fourth"),
  327. (utils::to_hash_output(&[0xAE]), "fifth"),
  328. ]
  329. });
  330. #[derive(Debug, Clone)]
  331. pub(crate) struct MockHasher;
  332. impl Hasher for MockHasher {
  333. fn hash<K: AsRef<[u8]>>(key: &K) -> HashOutput {
  334. HASH_KV_PAIRS
  335. .iter()
  336. .find(|(_, v)| key.as_ref() == <dyn AsRef<[u8]>>::as_ref(v))
  337. .unwrap()
  338. .0
  339. }
  340. }
  341. }
  342. #[async_std::test]
  343. async fn can_diff_main_node_with_added_removed_pairs() {
  344. let store = &MemoryBlockStore::default();
  345. let main_node = &mut Arc::new(Node::<[u8; 4], String>::default());
  346. for i in 0u32..3 {
  347. main_node
  348. .set(i.to_le_bytes(), i.to_string(), store)
  349. .await
  350. .unwrap();
  351. }
  352. let other_node = &mut Arc::new(Node::<[u8; 4], String>::default());
  353. other_node
  354. .set(0_u32.to_le_bytes(), 0_u32.to_string(), store)
  355. .await
  356. .unwrap();
  357. let changes = diff(
  358. Link::from(Arc::clone(main_node)),
  359. Link::from(Arc::clone(other_node)),
  360. store,
  361. )
  362. .await
  363. .unwrap();
  364. assert_eq!(
  365. changes.into_iter().collect::<BTreeSet<_>>(),
  366. BTreeSet::from([
  367. KeyValueChange {
  368. r#type: Add,
  369. key: [2, 0, 0, 0,],
  370. value1: Some(String::from("2")),
  371. value2: None,
  372. },
  373. KeyValueChange {
  374. r#type: Add,
  375. key: [1, 0, 0, 0,],
  376. value1: Some(String::from("1")),
  377. value2: None,
  378. },
  379. ])
  380. );
  381. let changes = diff(
  382. Link::from(Arc::clone(other_node)),
  383. Link::from(Arc::clone(main_node)),
  384. store,
  385. )
  386. .await
  387. .unwrap();
  388. assert_eq!(
  389. changes.into_iter().collect::<BTreeSet<_>>(),
  390. BTreeSet::from([
  391. KeyValueChange {
  392. r#type: Remove,
  393. key: [2, 0, 0, 0,],
  394. value1: Some(String::from("2")),
  395. value2: None,
  396. },
  397. KeyValueChange {
  398. r#type: Remove,
  399. key: [1, 0, 0, 0,],
  400. value1: Some(String::from("1")),
  401. value2: None,
  402. },
  403. ])
  404. );
  405. }
  406. #[async_std::test]
  407. async fn can_diff_main_node_with_no_changes() {
  408. let store = &MemoryBlockStore::default();
  409. let main_node = &mut Arc::new(Node::<_, _>::default());
  410. for i in 0_u32..3 {
  411. main_node
  412. .set(i.to_le_bytes(), i.to_string(), store)
  413. .await
  414. .unwrap();
  415. }
  416. let other_node = &mut Arc::new(Node::<_, _>::default());
  417. for i in 0_u32..3 {
  418. other_node
  419. .set(i.to_le_bytes(), i.to_string(), store)
  420. .await
  421. .unwrap();
  422. }
  423. let changes = diff(
  424. Link::from(Arc::clone(main_node)),
  425. Link::from(Arc::clone(other_node)),
  426. store,
  427. )
  428. .await
  429. .unwrap();
  430. assert!(changes.is_empty());
  431. }
  432. #[async_std::test]
  433. async fn can_diff_nodes_with_different_structure_and_modified_changes() {
  434. let store = &MemoryBlockStore::default();
  435. // A node that adds the first 3 pairs of HASH_KV_PAIRS.
  436. let other_node = &mut Arc::new(Node::<_, _, MockHasher>::default());
  437. for (digest, kv) in HASH_KV_PAIRS.iter().take(3) {
  438. other_node
  439. .set_value(
  440. &mut HashNibbles::new(digest),
  441. kv.to_string(),
  442. kv.to_string(),
  443. store,
  444. )
  445. .await
  446. .unwrap();
  447. }
  448. // Another node that keeps the first pair, modify the second pair, removes the third pair, and adds the fourth and fifth pair.
  449. let main_node = &mut Arc::new(Node::<_, _, MockHasher>::default());
  450. main_node
  451. .set_value(
  452. &mut HashNibbles::new(&HASH_KV_PAIRS[0].0),
  453. HASH_KV_PAIRS[0].1.to_string(),
  454. HASH_KV_PAIRS[0].1.to_string(),
  455. store,
  456. )
  457. .await
  458. .unwrap();
  459. main_node
  460. .set_value(
  461. &mut HashNibbles::new(&HASH_KV_PAIRS[1].0),
  462. HASH_KV_PAIRS[1].1.to_string(),
  463. String::from("second_modified"),
  464. store,
  465. )
  466. .await
  467. .unwrap();
  468. for (digest, kv) in HASH_KV_PAIRS.iter().skip(3).take(2) {
  469. main_node
  470. .set_value(
  471. &mut HashNibbles::new(digest),
  472. kv.to_string(),
  473. kv.to_string(),
  474. store,
  475. )
  476. .await
  477. .unwrap();
  478. }
  479. let changes = diff(
  480. Link::from(Arc::clone(main_node)),
  481. Link::from(Arc::clone(other_node)),
  482. store,
  483. )
  484. .await
  485. .unwrap();
  486. assert_eq!(
  487. changes,
  488. vec![
  489. KeyValueChange {
  490. r#type: Modify,
  491. key: "second".to_string(),
  492. value1: Some("second_modified".to_string()),
  493. value2: Some("second".to_string()),
  494. },
  495. KeyValueChange {
  496. r#type: Remove,
  497. key: "third".to_string(),
  498. value1: Some("third".to_string()),
  499. value2: None,
  500. },
  501. KeyValueChange {
  502. r#type: Add,
  503. key: "fourth".to_string(),
  504. value1: Some("fourth".to_string()),
  505. value2: None,
  506. },
  507. KeyValueChange {
  508. r#type: Add,
  509. key: "fifth".to_string(),
  510. value1: Some("fifth".to_string()),
  511. value2: None,
  512. },
  513. ]
  514. );
  515. let changes = diff(
  516. Link::from(Arc::clone(other_node)),
  517. Link::from(Arc::clone(main_node)),
  518. store,
  519. )
  520. .await
  521. .unwrap();
  522. assert_eq!(
  523. changes,
  524. vec![
  525. KeyValueChange {
  526. r#type: Modify,
  527. key: "second".to_string(),
  528. value1: Some("second".to_string()),
  529. value2: Some("second_modified".to_string()),
  530. },
  531. KeyValueChange {
  532. r#type: Add,
  533. key: "third".to_string(),
  534. value1: Some("third".to_string()),
  535. value2: None,
  536. },
  537. KeyValueChange {
  538. r#type: Remove,
  539. key: "fourth".to_string(),
  540. value1: Some("fourth".to_string()),
  541. value2: None,
  542. },
  543. KeyValueChange {
  544. r#type: Remove,
  545. key: "fifth".to_string(),
  546. value1: Some("fifth".to_string()),
  547. value2: None,
  548. },
  549. ]
  550. );
  551. }
  552. }
  553. #[cfg(test)]
  554. mod proptests {
  555. use crate::{
  556. strategies::{self, generate_kvs, generate_ops_and_changes, Change, Operations},
  557. ChangeType,
  558. };
  559. use async_std::task;
  560. use proptest::{prop_assert, prop_assert_eq};
  561. use std::collections::HashSet;
  562. use test_strategy::proptest;
  563. use wnfs_common::{utils::Arc, Link, MemoryBlockStore};
  564. #[proptest(cases = 100, max_shrink_iters = 4000)]
  565. fn diff_correspondence(
  566. #[strategy(generate_ops_and_changes())] ops_changes: (
  567. Operations<String, u64>,
  568. Vec<Change<String, u64>>,
  569. ),
  570. ) {
  571. task::block_on(async {
  572. let store = &MemoryBlockStore::default();
  573. let (ops, strategy_changes) = ops_changes;
  574. let other_node = &mut strategies::node_from_operations(&ops, store).await.unwrap();
  575. strategies::prepare_node(other_node, &strategy_changes, store)
  576. .await
  577. .unwrap();
  578. let main_node = &mut Arc::clone(other_node);
  579. strategies::apply_changes(main_node, &strategy_changes, store)
  580. .await
  581. .unwrap();
  582. let changes = super::diff(
  583. Link::from(Arc::clone(main_node)),
  584. Link::from(Arc::clone(other_node)),
  585. store,
  586. )
  587. .await
  588. .unwrap();
  589. prop_assert_eq!(strategy_changes.len(), changes.len());
  590. for strategy_change in strategy_changes {
  591. let found_matching_change = changes.iter().any(|c| match &strategy_change {
  592. Change::Add(k, _) => c.r#type == ChangeType::Add && &c.key == k,
  593. Change::Modify(k, _) => c.r#type == ChangeType::Modify && &c.key == k,
  594. Change::Remove(k) => c.r#type == ChangeType::Remove && &c.key == k,
  595. });
  596. prop_assert!(found_matching_change);
  597. }
  598. Ok(())
  599. })?;
  600. }
  601. #[proptest(cases = 1000, max_shrink_iters = 40000)]
  602. fn diff_unique_keys(
  603. #[strategy(generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100))] kvs1: Vec<(String, u64)>,
  604. #[strategy(generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100))] kvs2: Vec<(String, u64)>,
  605. ) {
  606. task::block_on(async {
  607. let store = &MemoryBlockStore::default();
  608. let node1 = strategies::node_from_kvs(kvs1, store).await.unwrap();
  609. let node2 = strategies::node_from_kvs(kvs2, store).await.unwrap();
  610. let changes = super::diff(Link::from(node1), Link::from(node2), store)
  611. .await
  612. .unwrap();
  613. let change_set = changes
  614. .iter()
  615. .map(|c| c.key.clone())
  616. .collect::<HashSet<_>>();
  617. prop_assert_eq!(change_set.len(), changes.len());
  618. Ok(())
  619. })?;
  620. }
  621. #[proptest(cases = 100)]
  622. fn add_remove_flip(
  623. #[strategy(generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100))] kvs1: Vec<(String, u64)>,
  624. #[strategy(generate_kvs("[a-z0-9]{1,3}", 0u64..1000, 0..100))] kvs2: Vec<(String, u64)>,
  625. ) {
  626. task::block_on(async {
  627. let store = &MemoryBlockStore::default();
  628. let node1 = strategies::node_from_kvs(kvs1, store).await.unwrap();
  629. let node2 = strategies::node_from_kvs(kvs2, store).await.unwrap();
  630. let changes = super::diff(
  631. Link::from(Arc::clone(&node1)),
  632. Link::from(Arc::clone(&node2)),
  633. store,
  634. )
  635. .await
  636. .unwrap();
  637. let flipped_changes = super::diff(Link::from(node2), Link::from(node1), store)
  638. .await
  639. .unwrap();
  640. prop_assert_eq!(changes.len(), flipped_changes.len());
  641. for change in changes {
  642. let found_matching_change = flipped_changes.iter().any(|c| match change.r#type {
  643. ChangeType::Add => c.r#type == ChangeType::Remove && c.key == change.key,
  644. ChangeType::Remove => c.r#type == ChangeType::Add && c.key == change.key,
  645. ChangeType::Modify => c.r#type == ChangeType::Modify && c.key == change.key,
  646. });
  647. prop_assert!(found_matching_change);
  648. }
  649. Ok(())
  650. })?;
  651. }
  652. }