leptos_sync_core/crdt/tree/
mod.rs

1//! Tree CRDT implementations
2//!
3//! This module provides tree-based Conflict-free Replicated Data Types (CRDTs)
4//! with different conflict resolution strategies.
5
6pub mod add_wins;
7pub mod config;
8pub mod error;
9pub mod remove_wins;
10pub mod types;
11
12// Re-export public types
13pub use add_wins::AddWinsTree;
14pub use config::{TreeConfig, TreeStrategy};
15pub use error::TreeError;
16pub use remove_wins::RemoveWinsTree;
17pub use types::{NodeId, NodeMetadata, TreeNode};
18
19#[cfg(test)]
20mod tests {
21    use super::super::{Mergeable, ReplicaId};
22    use super::*;
23    use uuid::Uuid;
24
25    fn create_replica(id: u64) -> ReplicaId {
26        ReplicaId::from(Uuid::from_u64_pair(0, id))
27    }
28
29    #[test]
30    fn test_node_id_creation() {
31        let replica = create_replica(1);
32        let node_id = NodeId::new(replica);
33
34        assert_eq!(node_id.replica, replica);
35        assert_ne!(node_id.id, Uuid::nil());
36    }
37
38    #[test]
39    fn test_tree_node_creation() {
40        let replica = create_replica(1);
41        let timestamp = 1234567890;
42        let node = TreeNode::new("test_value", replica, timestamp);
43
44        assert_eq!(node.value, "test_value");
45        assert_eq!(node.metadata.created_at, timestamp);
46        assert_eq!(node.metadata.modified_at, timestamp);
47        assert_eq!(node.metadata.deleted, false);
48        assert_eq!(node.metadata.last_modified_by, replica);
49        assert!(node.parent.is_none());
50        assert!(node.children.is_empty());
51    }
52
53    #[test]
54    fn test_add_wins_tree_basic_operations() {
55        let replica = create_replica(1);
56        let mut tree = AddWinsTree::new(replica);
57
58        // Add root
59        let root_id = tree.add_root("root", 1000);
60        assert_eq!(tree.len(), 1);
61        assert!(tree.contains(&root_id));
62
63        // Add child
64        let child_id = tree.add_child(&root_id, "child", 2000).unwrap();
65        assert_eq!(tree.len(), 2);
66        assert!(tree.contains(&child_id));
67
68        // Check hierarchy
69        let root = tree.get(&root_id).unwrap();
70        assert!(root.children.contains(&child_id));
71
72        let child = tree.get(&child_id).unwrap();
73        assert_eq!(child.parent, Some(root_id));
74    }
75
76    #[test]
77    fn test_remove_wins_tree_basic_operations() {
78        let replica = create_replica(1);
79        let mut tree = RemoveWinsTree::new(replica);
80
81        // Add root and child
82        let root_id = tree.add_root("root", 1000);
83        let child_id = tree.add_child(&root_id, "child", 2000).unwrap();
84
85        assert_eq!(tree.len(), 2);
86
87        // Remove child completely
88        tree.remove(&child_id).unwrap();
89        assert_eq!(tree.len(), 1);
90        assert!(!tree.contains(&child_id));
91
92        // Root should have no children
93        let root = tree.get(&root_id).unwrap();
94        assert!(root.children.is_empty());
95    }
96
97    #[test]
98    fn test_tree_move_operation() {
99        let replica = create_replica(1);
100        let mut tree = AddWinsTree::new(replica);
101
102        // Create tree: root -> child1 -> child2
103        let root_id = tree.add_root("root", 1000);
104        let child1_id = tree.add_child(&root_id, "child1", 2000).unwrap();
105        let child2_id = tree.add_child(&child1_id, "child2", 3000).unwrap();
106
107        // Move child2 to root
108        tree.move_node(&child2_id, &root_id).unwrap();
109
110        let child2 = tree.get(&child2_id).unwrap();
111        assert_eq!(child2.parent, Some(root_id.clone()));
112
113        let root = tree.get(&root_id).unwrap();
114        assert!(root.children.contains(&child2_id));
115
116        let child1 = tree.get(&child1_id).unwrap();
117        assert!(!child1.children.contains(&child2_id));
118    }
119
120    #[test]
121    fn test_tree_traversal() {
122        let replica = create_replica(1);
123        let mut tree = AddWinsTree::new(replica);
124
125        // Create tree: root -> child1 -> child2
126        let root_id = tree.add_root("root", 1000);
127        let child1_id = tree.add_child(&root_id, "child1", 2000).unwrap();
128        let _child2_id = tree.add_child(&child1_id, "child2", 3000).unwrap();
129
130        // Test descendants
131        let descendants = tree.descendants(&root_id);
132        assert_eq!(descendants.len(), 2);
133
134        // Test children
135        let root_children = tree.children(&root_id);
136        assert_eq!(root_children.len(), 1);
137        assert_eq!(root_children[0].id, child1_id);
138    }
139
140    #[test]
141    fn test_tree_merge() {
142        let replica1 = create_replica(1);
143        let replica2 = create_replica(2);
144
145        let mut tree1 = AddWinsTree::new(replica1);
146        let mut tree2 = AddWinsTree::new(replica2);
147
148        // Add nodes to both trees
149        let root1_id = tree1.add_root("root1", 1000);
150        let root2_id = tree2.add_root("root2", 2000);
151
152        // Merge tree2 into tree1
153        tree1.merge(&tree2).unwrap();
154
155        // Both roots should be present
156        assert_eq!(tree1.len(), 2);
157        assert!(tree1.contains(&root1_id));
158        assert!(tree1.contains(&root2_id));
159    }
160
161    #[test]
162    fn test_tree_configuration() {
163        let replica = create_replica(1);
164        let config = TreeConfig {
165            strategy: TreeStrategy::RemoveWins,
166            preserve_deleted: false,
167            max_depth: Some(5),
168            max_children: Some(10),
169        };
170
171        let tree: AddWinsTree<String> = AddWinsTree::with_config(replica, config);
172        assert_eq!(tree.config().strategy, TreeStrategy::RemoveWins);
173        assert_eq!(tree.config().max_depth, Some(5));
174        assert_eq!(tree.config().max_children, Some(10));
175    }
176}