Skip to main content

eure_document/
document.rs

1pub mod constructor;
2pub mod interpreter_sink;
3pub mod node;
4pub mod source_constructor;
5
6use crate::document::node::{NodeArray, NodeTuple};
7use crate::map::PartialNodeMap;
8use crate::prelude_internal::*;
9use crate::value::PartialObjectKey;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct NodeId(pub usize);
13
14#[derive(Debug, Clone)]
15pub struct EureDocument {
16    pub(crate) root: NodeId,
17    nodes: Vec<Node>,
18}
19
20#[derive(Debug, PartialEq, thiserror::Error, Clone)]
21#[error("Insert error: {kind} at {path}")]
22pub struct InsertError {
23    pub kind: InsertErrorKind,
24    pub path: EurePath,
25}
26
27#[derive(Debug, PartialEq, thiserror::Error, Clone)]
28pub enum InsertErrorKind {
29    #[error("Already assigned")]
30    AlreadyAssigned { key: ObjectKey },
31    #[error("Extension already assigned: {identifier}")]
32    AlreadyAssignedExtension { identifier: Identifier },
33    #[error("Expected array")]
34    ExpectedArray,
35    #[error("Array index invalid: expected {expected_index} but got {index}")]
36    ArrayIndexInvalid { index: usize, expected_index: usize },
37    #[error("Expected map")]
38    ExpectedMap,
39    #[error("Expected tuple")]
40    ExpectedTuple,
41    #[error("Tuple index invalid: expected {expected_index} but got {index}")]
42    TupleIndexInvalid { index: u8, expected_index: usize },
43    #[error("Binding target already has a value")]
44    BindingTargetHasValue,
45    #[error("Scope error: {0}")]
46    ScopeError(#[from] constructor::ScopeError),
47    #[error("Constructor error: {0}")]
48    ConstructorError(#[from] ConstructorError),
49}
50
51/// Protocol errors for SourceConstructor operations.
52#[derive(Debug, PartialEq, thiserror::Error, Clone)]
53pub enum ConstructorError {
54    #[error("set_block_value called without a preceding bind operation")]
55    MissingBindBeforeSetBlockValue,
56    #[error("end_binding_value called without a preceding bind operation")]
57    MissingBindBeforeEndBindingValue,
58    #[error("end_binding_block called without a preceding end_eure_block")]
59    MissingEndEureBlockBeforeEndBindingBlock,
60    #[error("end_section_block called without a preceding end_eure_block")]
61    MissingEndEureBlockBeforeEndSectionBlock,
62    #[error("end_eure_block called but builder stack is not in EureBlock state")]
63    InvalidBuilderStackForEndEureBlock,
64    #[error("end_section_items called but builder stack is not in SectionItems state")]
65    InvalidBuilderStackForEndSectionItems,
66    #[error("ArrayIndex must follow a key segment; standalone [] is not valid")]
67    StandaloneArrayIndex,
68}
69
70impl Default for EureDocument {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76impl PartialEq for EureDocument {
77    fn eq(&self, other: &Self) -> bool {
78        self.nodes_equal(self.root, other, other.root)
79    }
80}
81
82impl EureDocument {
83    /// Returns the total number of nodes in this document.
84    pub fn node_count(&self) -> usize {
85        self.nodes.len()
86    }
87
88    /// Compare two nodes structurally, ignoring NodeId values
89    fn nodes_equal(&self, id1: NodeId, other: &EureDocument, id2: NodeId) -> bool {
90        let node1 = &self.nodes[id1.0];
91        let node2 = &other.nodes[id2.0];
92
93        // Compare extensions
94        if node1.extensions.len() != node2.extensions.len() {
95            return false;
96        }
97
98        for (key1, &child_id1) in &node1.extensions {
99            match node2.extensions.get(key1) {
100                Some(&child_id2) => {
101                    if !self.nodes_equal(child_id1, other, child_id2) {
102                        return false;
103                    }
104                }
105                None => return false,
106            }
107        }
108
109        // Compare content
110        self.node_values_equal(&node1.content, other, &node2.content)
111    }
112
113    /// Compare two NodeValues structurally
114    fn node_values_equal(
115        &self,
116        value1: &NodeValue,
117        other: &EureDocument,
118        value2: &NodeValue,
119    ) -> bool {
120        match (value1, value2) {
121            (NodeValue::Hole(l1), NodeValue::Hole(l2)) => l1 == l2,
122            (NodeValue::Primitive(p1), NodeValue::Primitive(p2)) => p1 == p2,
123            (NodeValue::Array(arr1), NodeValue::Array(arr2)) => {
124                self.node_arrays_equal(arr1, other, arr2)
125            }
126            (NodeValue::Tuple(tup1), NodeValue::Tuple(tup2)) => {
127                self.node_tuples_equal(tup1, other, tup2)
128            }
129            (NodeValue::Map(map1), NodeValue::Map(map2)) => self.node_maps_equal(map1, other, map2),
130            (NodeValue::PartialMap(pm1), NodeValue::PartialMap(pm2)) => {
131                self.node_partial_maps_equal(pm1, other, pm2)
132            }
133            _ => false,
134        }
135    }
136
137    fn node_arrays_equal(&self, arr1: &NodeArray, other: &EureDocument, arr2: &NodeArray) -> bool {
138        if arr1.len() != arr2.len() {
139            return false;
140        }
141
142        for (child_id1, child_id2) in arr1.iter().zip(arr2.iter()) {
143            if !self.nodes_equal(*child_id1, other, *child_id2) {
144                return false;
145            }
146        }
147
148        true
149    }
150
151    fn node_tuples_equal(&self, tup1: &NodeTuple, other: &EureDocument, tup2: &NodeTuple) -> bool {
152        if tup1.len() != tup2.len() {
153            return false;
154        }
155
156        for (child_id1, child_id2) in tup1.iter().zip(tup2.iter()) {
157            if !self.nodes_equal(*child_id1, other, *child_id2) {
158                return false;
159            }
160        }
161
162        true
163    }
164
165    fn node_partial_maps_equal(
166        &self,
167        pm1: &PartialNodeMap,
168        other: &EureDocument,
169        pm2: &PartialNodeMap,
170    ) -> bool {
171        if pm1.len() != pm2.len() {
172            return false;
173        }
174        for ((key1, &child_id1), (key2, &child_id2)) in pm1.iter().zip(pm2.iter()) {
175            if key1 != key2 {
176                return false;
177            }
178            if !self.nodes_equal(child_id1, other, child_id2) {
179                return false;
180            }
181        }
182        true
183    }
184
185    fn node_maps_equal(&self, map1: &NodeMap, other: &EureDocument, map2: &NodeMap) -> bool {
186        if map1.len() != map2.len() {
187            return false;
188        }
189
190        for (key1, &child_id1) in map1.iter() {
191            match map2.get(key1) {
192                Some(&child_id2) => {
193                    if !self.nodes_equal(child_id1, other, child_id2) {
194                        return false;
195                    }
196                }
197                None => return false,
198            }
199        }
200
201        true
202    }
203
204    pub fn new() -> Self {
205        Self {
206            root: NodeId(0),
207            nodes: vec![Node {
208                content: NodeValue::hole(),
209                extensions: Map::new(),
210            }],
211        }
212    }
213
214    pub fn new_empty() -> Self {
215        Self {
216            root: NodeId(0),
217            nodes: vec![Node {
218                content: NodeValue::Map(Default::default()),
219                extensions: Map::new(),
220            }],
221        }
222    }
223
224    pub fn new_primitive(value: PrimitiveValue) -> Self {
225        Self {
226            root: NodeId(0),
227            nodes: vec![Node {
228                content: NodeValue::Primitive(value),
229                extensions: Map::new(),
230            }],
231        }
232    }
233
234    pub fn root(&self) -> &Node {
235        &self.nodes[self.root.0]
236    }
237
238    pub fn get_root_id(&self) -> NodeId {
239        self.root
240    }
241
242    pub fn node(&self, id: NodeId) -> &Node {
243        &self.nodes[id.0]
244    }
245
246    pub fn get_node(&self, id: NodeId) -> Option<&Node> {
247        self.nodes.get(id.0)
248    }
249
250    pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
251        &mut self.nodes[id.0]
252    }
253
254    pub fn get_node_mut(&mut self, id: NodeId) -> Option<&mut Node> {
255        self.nodes.get_mut(id.0)
256    }
257
258    pub fn create_node(&mut self, new: NodeValue) -> NodeId {
259        self.nodes.push(Node {
260            content: new,
261            extensions: Map::new(),
262        });
263        NodeId(self.nodes.len() - 1)
264    }
265
266    pub fn create_node_uninitialized(&mut self) -> NodeId {
267        self.create_node(NodeValue::hole())
268    }
269
270    /// Set the content of a node directly
271    pub fn set_content(&mut self, node_id: NodeId, content: NodeValue) {
272        self.nodes[node_id.0].content = content;
273    }
274
275    pub fn add_child_by_segment(
276        &mut self,
277        segment: PathSegment,
278        parent_node_id: NodeId,
279    ) -> Result<NodeMut<'_>, InsertErrorKind> {
280        match segment {
281            PathSegment::Ident(identifier) => {
282                let key = ObjectKey::String(identifier.into_string());
283                // If parent is already a PartialMap, add as resolved key there
284                if matches!(self.node(parent_node_id).content, NodeValue::PartialMap(_)) {
285                    self.add_partial_map_child(PartialObjectKey::from(key), parent_node_id)
286                } else {
287                    self.add_map_child(key, parent_node_id)
288                }
289            }
290            PathSegment::Value(object_key) => {
291                if matches!(self.node(parent_node_id).content, NodeValue::PartialMap(_)) {
292                    self.add_partial_map_child(PartialObjectKey::from(object_key), parent_node_id)
293                } else {
294                    self.add_map_child(object_key, parent_node_id)
295                }
296            }
297            PathSegment::PartialValue(key) => self.add_partial_map_child(key, parent_node_id),
298            PathSegment::Extension(identifier) => self.add_extension(identifier, parent_node_id),
299            PathSegment::TupleIndex(index) => self.add_tuple_element(index, parent_node_id),
300            PathSegment::ArrayIndex(index) => self.add_array_element(index, parent_node_id),
301            PathSegment::HoleKey(label) => {
302                self.add_partial_map_child(PartialObjectKey::Hole(label), parent_node_id)
303            }
304        }
305    }
306
307    /// Add a child node to a PartialMap, upgrading from Hole or Map if necessary.
308    pub fn add_partial_map_child(
309        &mut self,
310        key: PartialObjectKey,
311        parent_node_id: NodeId,
312    ) -> Result<NodeMut<'_>, InsertErrorKind> {
313        let node_id = self.create_node_uninitialized();
314        let node = self.node_mut(parent_node_id);
315        let pm = node.require_partial_map()?;
316        pm.push(key, node_id);
317        Ok(NodeMut::new(self, node_id))
318    }
319
320    pub fn add_map_child(
321        &mut self,
322        object_key: ObjectKey,
323        parent_node_id: NodeId,
324    ) -> Result<NodeMut<'_>, InsertErrorKind> {
325        let node_id = self.create_node_uninitialized();
326        let node = self.node_mut(parent_node_id);
327        let map = node.require_map()?;
328        map.add(object_key, node_id)?;
329        Ok(NodeMut::new(self, node_id))
330    }
331
332    pub fn add_extension(
333        &mut self,
334        identifier: Identifier,
335        parent_node_id: NodeId,
336    ) -> Result<NodeMut<'_>, InsertErrorKind> {
337        let node_id = self.create_node_uninitialized();
338        let node = self.node_mut(parent_node_id);
339        if node.extensions.contains_key(&identifier) {
340            return Err(InsertErrorKind::AlreadyAssignedExtension { identifier });
341        }
342        node.extensions.insert(identifier, node_id);
343        Ok(NodeMut::new(self, node_id))
344    }
345
346    pub fn add_tuple_element(
347        &mut self,
348        index: u8,
349        parent_node_id: NodeId,
350    ) -> Result<NodeMut<'_>, InsertErrorKind> {
351        let node_id = self.create_node_uninitialized();
352        let node = self.node_mut(parent_node_id);
353        let tuple = node.require_tuple()?;
354        tuple.add_at(index, node_id)?;
355        Ok(NodeMut::new(self, node_id))
356    }
357
358    pub fn add_array_element(
359        &mut self,
360        index: Option<usize>,
361        parent_node_id: NodeId,
362    ) -> Result<NodeMut<'_>, InsertErrorKind> {
363        let node_id = self.create_node_uninitialized();
364        let node = self.node_mut(parent_node_id);
365        let array = node.require_array()?;
366        if let Some(index) = index {
367            array.add_at(index, node_id)?;
368        } else {
369            array.push(node_id)?;
370        }
371        Ok(NodeMut::new(self, node_id))
372    }
373
374    /// Resolves a path segment to a node ID, creating if necessary.
375    ///
376    /// This operation is idempotent for most segments, reusing existing nodes.
377    /// Exception: `ArrayIndex(None)` always creates a new array element (push operation).
378    pub fn resolve_child_by_segment(
379        &mut self,
380        segment: PathSegment,
381        parent_node_id: NodeId,
382    ) -> Result<NodeMut<'_>, InsertErrorKind> {
383        // 既存のノードを探す
384        let node = self.node(parent_node_id);
385
386        let existing = match &segment {
387            PathSegment::Ident(identifier) => {
388                let obj_key = ObjectKey::String(identifier.clone().into_string());
389                // Check both Map and PartialMap
390                node.as_map()
391                    .and_then(|m| m.get(&obj_key))
392                    .copied()
393                    .or_else(|| {
394                        node.as_partial_map()
395                            .and_then(|pm| {
396                                pm.find(&PartialObjectKey::String(identifier.clone().into_string()))
397                            })
398                            .copied()
399                    })
400            }
401            PathSegment::Value(object_key) => {
402                let partial_key = PartialObjectKey::from(object_key.clone());
403                node.as_map()
404                    .and_then(|m| m.get(object_key))
405                    .copied()
406                    .or_else(|| {
407                        node.as_partial_map()
408                            .and_then(|pm| pm.find(&partial_key))
409                            .copied()
410                    })
411            }
412            PathSegment::PartialValue(key) => node
413                .as_partial_map()
414                .and_then(|pm| pm.find(key))
415                .copied()
416                .or_else(|| {
417                    ObjectKey::try_from(key.clone())
418                        .ok()
419                        .and_then(|object_key| node.as_map().and_then(|m| m.get(&object_key)))
420                        .copied()
421                }),
422            PathSegment::Extension(identifier) => node.get_extension(identifier),
423            PathSegment::TupleIndex(index) => node.as_tuple().and_then(|t| t.get(*index as usize)),
424            PathSegment::ArrayIndex(Some(index)) => node.as_array().and_then(|a| a.get(*index)),
425            PathSegment::ArrayIndex(None) => None, // push always creates new
426            PathSegment::HoleKey(label) => node
427                .as_partial_map()
428                .and_then(|pm| pm.find(&PartialObjectKey::Hole(label.clone())))
429                .copied(),
430        };
431
432        // 既存ノードがあればそれを返す
433        if let Some(node_id) = existing {
434            return Ok(NodeMut::new(self, node_id));
435        }
436
437        // なければ作成
438        self.add_child_by_segment(segment, parent_node_id)
439    }
440
441    /// Convert a subtree of a document to a standalone document.
442    pub fn node_subtree_to_document(&self, node_id: NodeId) -> EureDocument {
443        let mut result = EureDocument::new();
444        let root_id = result.get_root_id();
445        self.copy_subtree(node_id, &mut result, root_id);
446        result
447    }
448
449    pub fn copy_subtree(&self, src_id: NodeId, dst: &mut EureDocument, dst_id: NodeId) {
450        let src_node = self.node(src_id);
451
452        // Copy content based on type. For containers, we must NOT clone the content
453        // directly because it contains NodeIds from the source document. Instead,
454        // create empty containers and populate with recursively copied children.
455        match &src_node.content {
456            NodeValue::Hole(label) => {
457                dst.node_mut(dst_id).content = NodeValue::Hole(label.clone());
458            }
459            NodeValue::Primitive(p) => {
460                dst.node_mut(dst_id).content = NodeValue::Primitive(p.clone());
461            }
462            NodeValue::Array(arr) => {
463                dst.node_mut(dst_id).content = NodeValue::empty_array();
464                for &child_src_id in arr.iter() {
465                    if let Ok(result) = dst.add_array_element(None, dst_id) {
466                        let child_dst_id = result.node_id;
467                        self.copy_subtree(child_src_id, dst, child_dst_id);
468                    }
469                }
470            }
471            NodeValue::Tuple(tuple) => {
472                dst.node_mut(dst_id).content = NodeValue::empty_tuple();
473                for (idx, &child_src_id) in tuple.iter().enumerate() {
474                    if let Ok(result) = dst.add_tuple_element(idx as u8, dst_id) {
475                        let child_dst_id = result.node_id;
476                        self.copy_subtree(child_src_id, dst, child_dst_id);
477                    }
478                }
479            }
480            NodeValue::Map(map) => {
481                dst.node_mut(dst_id).content = NodeValue::empty_map();
482                for (key, &child_src_id) in map.iter() {
483                    if let Ok(result) = dst.add_map_child(key.clone(), dst_id) {
484                        let child_dst_id = result.node_id;
485                        self.copy_subtree(child_src_id, dst, child_dst_id);
486                    }
487                }
488            }
489            NodeValue::PartialMap(pm) => {
490                dst.node_mut(dst_id).content = NodeValue::empty_partial_map();
491                let entries: Vec<(PartialObjectKey, NodeId)> =
492                    pm.iter().map(|(k, &v)| (k.clone(), v)).collect();
493                for (key, child_src_id) in entries {
494                    let child_dst_id = dst.create_node_uninitialized();
495                    if let NodeValue::PartialMap(dst_pm) = &mut dst.node_mut(dst_id).content {
496                        dst_pm.push(key, child_dst_id);
497                    }
498                    self.copy_subtree(child_src_id, dst, child_dst_id);
499                }
500            }
501        }
502
503        // Copy extensions recursively
504        let extensions: Vec<_> = self
505            .node(src_id)
506            .extensions
507            .iter()
508            .map(|(k, v)| (k.clone(), *v))
509            .collect();
510        for (ext_name, ext_src_id) in extensions {
511            if let Ok(result) = dst.add_extension(ext_name, dst_id) {
512                let ext_dst_id = result.node_id;
513                self.copy_subtree(ext_src_id, dst, ext_dst_id);
514            }
515        }
516    }
517}
518
519/// Commands
520impl EureDocument {
521    pub fn replace_with_primitive(&mut self, value: PrimitiveValue) -> Result<(), InsertErrorKind> {
522        self.nodes.clear();
523        self.nodes[self.root.0].content = NodeValue::Primitive(value);
524        Ok(())
525    }
526
527    pub fn reset_as_map(&mut self) -> Result<(), InsertErrorKind> {
528        self.nodes.clear();
529        self.nodes[self.root.0].content = NodeValue::Map(Default::default());
530        Ok(())
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537
538    fn identifier(s: &str) -> Identifier {
539        s.parse().unwrap()
540    }
541
542    #[test]
543    fn test_add_map_child_success() {
544        let mut doc = EureDocument::new();
545        let map_id = {
546            let doc: &mut EureDocument = &mut doc;
547            doc.create_node(NodeValue::empty_map())
548        };
549        let key = ObjectKey::String("test_key".to_string());
550
551        let child_id = doc
552            .add_map_child(key.clone(), map_id)
553            .expect("Failed to add map child")
554            .node_id;
555
556        let map = doc.node(map_id).as_map().expect("Expected map");
557        assert_eq!(map.get(&key), Some(&child_id));
558    }
559
560    #[test]
561    fn test_add_map_child_error_expected_map() {
562        let mut doc = EureDocument::new();
563        let primitive_id = {
564            let doc: &mut EureDocument = &mut doc;
565            doc.create_node(NodeValue::Primitive(PrimitiveValue::Null))
566        };
567        let key = ObjectKey::String("test".to_string());
568
569        let result = doc.add_map_child(key, primitive_id);
570        assert_eq!(result.err(), Some(InsertErrorKind::ExpectedMap));
571    }
572
573    #[test]
574    fn test_add_map_child_error_already_assigned() {
575        let mut doc = EureDocument::new();
576        let root_id = doc.get_root_id();
577        let key = ObjectKey::String("test".to_string());
578
579        let _result1 = doc
580            .add_map_child(key.clone(), root_id)
581            .expect("First add should succeed");
582
583        let result2 = doc.add_map_child(key.clone(), root_id);
584        assert_eq!(
585            result2.err(),
586            Some(InsertErrorKind::AlreadyAssigned { key })
587        );
588    }
589
590    #[test]
591    fn test_add_extension_success_multiple() {
592        let mut doc = EureDocument::new();
593        let root_id = doc.get_root_id();
594        let id1 = identifier("ext1");
595        let id2 = identifier("ext2");
596
597        let node_id1 = doc
598            .add_extension(id1.clone(), root_id)
599            .expect("Failed to add extension")
600            .node_id;
601
602        let node_id2 = doc
603            .add_extension(id2.clone(), root_id)
604            .expect("Failed to add extension")
605            .node_id;
606
607        let node = doc.node(root_id);
608        assert_eq!(node.extensions.get(&id1), Some(&node_id1));
609        assert_eq!(node.extensions.get(&id2), Some(&node_id2));
610    }
611
612    #[test]
613    fn test_add_extension_success() {
614        let mut doc = EureDocument::new();
615        let primitive_id = {
616            let doc: &mut EureDocument = &mut doc;
617            doc.create_node(NodeValue::Primitive(PrimitiveValue::Null))
618        };
619        let identifier = identifier("ext");
620
621        let node_id = doc
622            .add_extension(identifier.clone(), primitive_id)
623            .expect("Failed to add extension")
624            .node_id;
625
626        let node = doc.node(primitive_id);
627        assert_eq!(node.extensions.get(&identifier), Some(&node_id));
628    }
629
630    #[test]
631    fn test_add_extension_error_already_assigned() {
632        let mut doc = EureDocument::new();
633        let map_id = {
634            let doc: &mut EureDocument = &mut doc;
635            doc.create_node(NodeValue::empty_map())
636        };
637        let identifier = identifier("ext");
638
639        let _result1 = doc
640            .add_extension(identifier.clone(), map_id)
641            .expect("First add should succeed");
642
643        let result2 = doc.add_extension(identifier.clone(), map_id);
644        assert_eq!(
645            result2.err(),
646            Some(InsertErrorKind::AlreadyAssignedExtension { identifier })
647        );
648    }
649
650    #[test]
651    fn test_add_tuple_element_success_index_0() {
652        let mut doc = EureDocument::new();
653        let tuple_id = {
654            let doc: &mut EureDocument = &mut doc;
655            doc.create_node(NodeValue::empty_tuple())
656        };
657
658        let node_id = doc
659            .add_tuple_element(0, tuple_id)
660            .expect("Failed to add tuple element")
661            .node_id;
662
663        let tuple = doc.node(tuple_id).as_tuple().expect("Expected tuple");
664        assert_eq!(tuple.to_vec(), vec![node_id]);
665    }
666
667    #[test]
668    fn test_add_tuple_element_success_sequential() {
669        let mut doc = EureDocument::new();
670        let tuple_id = {
671            let doc: &mut EureDocument = &mut doc;
672            doc.create_node(NodeValue::empty_tuple())
673        };
674
675        let node_id1 = doc
676            .add_tuple_element(0, tuple_id)
677            .expect("Failed to add tuple element")
678            .node_id;
679
680        let node_id2 = doc
681            .add_tuple_element(1, tuple_id)
682            .expect("Failed to add tuple element")
683            .node_id;
684
685        let tuple = doc.node(tuple_id).as_tuple().expect("Expected tuple");
686        assert_eq!(tuple.to_vec(), vec![node_id1, node_id2]);
687    }
688
689    #[test]
690    fn test_add_tuple_element_error_expected_tuple() {
691        let mut doc = EureDocument::new();
692        let map_id = {
693            let doc: &mut EureDocument = &mut doc;
694            doc.create_node(NodeValue::empty_map())
695        };
696
697        let result = doc.add_tuple_element(0, map_id);
698        assert_eq!(result.err(), Some(InsertErrorKind::ExpectedTuple));
699    }
700
701    #[test]
702    fn test_add_tuple_element_error_invalid_index() {
703        let mut doc = EureDocument::new();
704        let tuple_id = {
705            let doc: &mut EureDocument = &mut doc;
706            doc.create_node(NodeValue::empty_tuple())
707        };
708
709        let result = doc.add_tuple_element(1, tuple_id);
710        assert_eq!(
711            result.err(),
712            Some(InsertErrorKind::TupleIndexInvalid {
713                index: 1,
714                expected_index: 0
715            })
716        );
717    }
718
719    #[test]
720    fn test_add_array_element_success_push() {
721        let mut doc = EureDocument::new();
722        let array_id = {
723            let doc: &mut EureDocument = &mut doc;
724            doc.create_node(NodeValue::empty_array())
725        };
726
727        let node_id = doc
728            .add_array_element(None, array_id)
729            .expect("Failed to add array element")
730            .node_id;
731
732        let array = doc.node(array_id).as_array().expect("Expected array");
733        assert_eq!(array.to_vec(), vec![node_id]);
734    }
735
736    #[test]
737    fn test_add_array_element_success_at_index() {
738        let mut doc = EureDocument::new();
739        let array_id = {
740            let doc: &mut EureDocument = &mut doc;
741            doc.create_node(NodeValue::empty_array())
742        };
743
744        let node_id1 = doc
745            .add_array_element(Some(0), array_id)
746            .expect("Failed to add array element")
747            .node_id;
748
749        let node_id2 = doc
750            .add_array_element(Some(1), array_id)
751            .expect("Failed to add array element")
752            .node_id;
753
754        let array = doc.node(array_id).as_array().expect("Expected array");
755        assert_eq!(array.to_vec(), vec![node_id1, node_id2]);
756    }
757
758    #[test]
759    fn test_add_array_element_error_expected_array() {
760        let mut doc = EureDocument::new();
761        let map_id = {
762            let doc: &mut EureDocument = &mut doc;
763            doc.create_node(NodeValue::empty_map())
764        };
765
766        let result = doc.add_array_element(None, map_id);
767        assert_eq!(result.err(), Some(InsertErrorKind::ExpectedArray));
768    }
769
770    #[test]
771    fn test_add_array_element_error_invalid_index() {
772        let mut doc = EureDocument::new();
773        let array_id = {
774            let doc: &mut EureDocument = &mut doc;
775            doc.create_node(NodeValue::empty_array())
776        };
777
778        let result = doc.add_array_element(Some(1), array_id);
779        assert_eq!(
780            result.err(),
781            Some(InsertErrorKind::ArrayIndexInvalid {
782                index: 1,
783                expected_index: 0
784            })
785        );
786    }
787
788    #[test]
789    fn test_add_child_by_segment_ident() {
790        let mut doc = EureDocument::new();
791        let root_id = doc.get_root_id();
792        let identifier = identifier("test");
793        let segment = PathSegment::Ident(identifier.clone());
794
795        let result = doc.add_child_by_segment(segment, root_id);
796        assert!(result.is_ok());
797
798        let map = doc.node(root_id).as_map().expect("Expected map");
799        let key = ObjectKey::String(identifier.into_string());
800        assert!(map.get(&key).is_some());
801    }
802
803    #[test]
804    fn test_add_child_by_segment_value() {
805        let mut doc = EureDocument::new();
806        let root_id = doc.get_root_id();
807        let key = ObjectKey::String("test".to_string());
808        let segment = PathSegment::Value(key.clone());
809
810        let result = doc.add_child_by_segment(segment, root_id);
811        assert!(result.is_ok());
812
813        let map = doc.node(root_id).as_map().expect("Expected map");
814        assert!(map.get(&key).is_some());
815    }
816
817    #[test]
818    fn test_add_child_by_segment_extension() {
819        let mut doc = EureDocument::new();
820        let root_id = doc.get_root_id();
821        let identifier = identifier("ext");
822        let segment = PathSegment::Extension(identifier.clone());
823
824        let result = doc.add_child_by_segment(segment, root_id);
825        assert!(result.is_ok());
826
827        let node = doc.node(root_id);
828        assert!(node.extensions.contains_key(&identifier));
829    }
830
831    #[test]
832    fn test_add_child_by_segment_tuple_index() {
833        let mut doc = EureDocument::new();
834        let tuple_id = {
835            let doc: &mut EureDocument = &mut doc;
836            doc.create_node(NodeValue::empty_tuple())
837        };
838        let segment = PathSegment::TupleIndex(0);
839
840        let result = doc.add_child_by_segment(segment, tuple_id);
841        assert!(result.is_ok());
842
843        let tuple = doc.node(tuple_id).as_tuple().expect("Expected tuple");
844        assert_eq!(tuple.len(), 1);
845    }
846
847    #[test]
848    fn test_add_child_by_segment_array_index_none() {
849        let mut doc = EureDocument::new();
850        let array_id = {
851            let doc: &mut EureDocument = &mut doc;
852            doc.create_node(NodeValue::empty_array())
853        };
854        let segment = PathSegment::ArrayIndex(None);
855
856        let result = doc.add_child_by_segment(segment, array_id);
857        assert!(result.is_ok());
858
859        let array = doc.node(array_id).as_array().expect("Expected array");
860        assert_eq!(array.len(), 1);
861    }
862
863    #[test]
864    fn test_add_child_by_segment_array_index_some() {
865        let mut doc = EureDocument::new();
866        let array_id = {
867            let doc: &mut EureDocument = &mut doc;
868            doc.create_node(NodeValue::empty_array())
869        };
870        let segment = PathSegment::ArrayIndex(Some(0));
871
872        let result = doc.add_child_by_segment(segment, array_id);
873        assert!(result.is_ok());
874
875        let array = doc.node(array_id).as_array().expect("Expected array");
876        assert_eq!(array.len(), 1);
877    }
878
879    #[test]
880    fn test_resolve_ident_idempotent() {
881        let mut doc = EureDocument::new();
882        let root_id = doc.get_root_id();
883        let identifier = identifier("field");
884
885        // First call - creates new node
886        let node_id1 = doc
887            .resolve_child_by_segment(PathSegment::Ident(identifier.clone()), root_id)
888            .expect("First call failed")
889            .node_id;
890
891        // Second call - returns existing node
892        let node_id2 = doc
893            .resolve_child_by_segment(PathSegment::Ident(identifier), root_id)
894            .expect("Second call failed")
895            .node_id;
896
897        assert_eq!(node_id1, node_id2);
898    }
899
900    #[test]
901    fn test_resolve_value_idempotent() {
902        let mut doc = EureDocument::new();
903        let root_id = doc.get_root_id();
904        let object_key = ObjectKey::String("key".to_string());
905
906        // First call - creates new node
907        let node_id1 = doc
908            .resolve_child_by_segment(PathSegment::Value(object_key.clone()), root_id)
909            .expect("First call failed")
910            .node_id;
911
912        // Second call - returns existing node
913        let node_id2 = doc
914            .resolve_child_by_segment(PathSegment::Value(object_key), root_id)
915            .expect("Second call failed")
916            .node_id;
917
918        assert_eq!(node_id1, node_id2);
919    }
920
921    #[test]
922    fn test_resolve_extension_idempotent() {
923        let mut doc = EureDocument::new();
924        let root_id = doc.get_root_id();
925        let identifier = identifier("ext");
926
927        // First call - creates new node
928        let node_id1 = doc
929            .resolve_child_by_segment(PathSegment::Extension(identifier.clone()), root_id)
930            .expect("First call failed")
931            .node_id;
932
933        // Second call - returns existing node
934        let node_id2 = doc
935            .resolve_child_by_segment(PathSegment::Extension(identifier), root_id)
936            .expect("Second call failed")
937            .node_id;
938
939        assert_eq!(node_id1, node_id2);
940    }
941
942    #[test]
943    fn test_resolve_tuple_index_idempotent() {
944        let mut doc = EureDocument::new();
945        let parent_id = doc.create_node_uninitialized();
946
947        // First call - creates new node
948        let node_id1 = doc
949            .resolve_child_by_segment(PathSegment::TupleIndex(0), parent_id)
950            .expect("First call failed")
951            .node_id;
952
953        // Second call - returns existing node
954        let node_id2 = doc
955            .resolve_child_by_segment(PathSegment::TupleIndex(0), parent_id)
956            .expect("Second call failed")
957            .node_id;
958
959        assert_eq!(node_id1, node_id2);
960    }
961
962    #[test]
963    fn test_resolve_array_index_some_idempotent() {
964        let mut doc = EureDocument::new();
965        let parent_id = doc.create_node_uninitialized();
966
967        // First call - creates new node
968        let node_id1 = doc
969            .resolve_child_by_segment(PathSegment::ArrayIndex(Some(0)), parent_id)
970            .expect("First call failed")
971            .node_id;
972
973        // Second call - returns existing node
974        let node_id2 = doc
975            .resolve_child_by_segment(PathSegment::ArrayIndex(Some(0)), parent_id)
976            .expect("Second call failed")
977            .node_id;
978
979        assert_eq!(node_id1, node_id2);
980    }
981
982    #[test]
983    fn test_resolve_array_index_none_always_creates_new() {
984        let mut doc = EureDocument::new();
985        let parent_id = doc.create_node_uninitialized();
986
987        // First call - creates new node
988        let node_id1 = doc
989            .resolve_child_by_segment(PathSegment::ArrayIndex(None), parent_id)
990            .expect("First call failed")
991            .node_id;
992
993        // Second call - creates another new node (NOT idempotent)
994        let node_id2 = doc
995            .resolve_child_by_segment(PathSegment::ArrayIndex(None), parent_id)
996            .expect("Second call failed")
997            .node_id;
998
999        // ArrayIndex(None) always creates new nodes (push operation)
1000        assert_ne!(node_id1, node_id2);
1001
1002        // Verify both nodes exist in array
1003        let array = doc.node(parent_id).as_array().expect("Expected array");
1004        assert_eq!(array.len(), 2);
1005        assert_eq!(array.get(0).unwrap(), node_id1);
1006        assert_eq!(array.get(1).unwrap(), node_id2);
1007    }
1008
1009    #[test]
1010    fn test_get_node_with_valid_id() {
1011        let mut doc = EureDocument::new();
1012        let node_id = doc.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1013
1014        let result = doc.get_node(node_id);
1015        assert!(result.is_some());
1016
1017        let node = result.unwrap();
1018        assert_eq!(node.content, NodeValue::Primitive(PrimitiveValue::Null));
1019    }
1020
1021    #[test]
1022    fn test_get_node_with_invalid_id() {
1023        let doc = EureDocument::new();
1024        // Create an invalid NodeId that's out of bounds
1025        let invalid_id = NodeId(9999);
1026
1027        let result = doc.get_node(invalid_id);
1028        assert!(result.is_none());
1029    }
1030
1031    #[test]
1032    fn test_get_node_mut_with_valid_id() {
1033        let mut doc = EureDocument::new();
1034        let node_id = doc.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1035
1036        let result = doc.get_node_mut(node_id);
1037        assert!(result.is_some());
1038
1039        // Verify we can mutate through the returned reference
1040        let node = result.unwrap();
1041        node.content = NodeValue::Primitive(PrimitiveValue::Bool(true));
1042
1043        // Verify the mutation persisted
1044        assert_eq!(
1045            doc.node(node_id).content,
1046            NodeValue::Primitive(PrimitiveValue::Bool(true))
1047        );
1048    }
1049
1050    #[test]
1051    fn test_get_node_mut_with_invalid_id() {
1052        let mut doc = EureDocument::new();
1053        // Create an invalid NodeId that's out of bounds
1054        let invalid_id = NodeId(9999);
1055
1056        let result = doc.get_node_mut(invalid_id);
1057        assert!(result.is_none());
1058    }
1059
1060    #[test]
1061    fn test_partialeq_empty_documents() {
1062        let doc1 = EureDocument::new();
1063        let doc2 = EureDocument::new();
1064        assert_eq!(doc1, doc2);
1065    }
1066
1067    #[test]
1068    fn test_partialeq_primitive_documents() {
1069        let doc1 = EureDocument::new_primitive(PrimitiveValue::Bool(true));
1070        let doc2 = EureDocument::new_primitive(PrimitiveValue::Bool(true));
1071        let doc3 = EureDocument::new_primitive(PrimitiveValue::Bool(false));
1072
1073        assert_eq!(doc1, doc2);
1074        assert_ne!(doc1, doc3);
1075    }
1076
1077    #[test]
1078    fn test_partialeq_with_map_children() {
1079        let mut doc1 = EureDocument::new();
1080        let mut doc2 = EureDocument::new();
1081
1082        let root1 = doc1.get_root_id();
1083        let root2 = doc2.get_root_id();
1084
1085        let key = ObjectKey::String("test".to_string());
1086
1087        doc1.add_map_child(key.clone(), root1)
1088            .expect("Failed to add child");
1089        doc2.add_map_child(key.clone(), root2)
1090            .expect("Failed to add child");
1091
1092        assert_eq!(doc1, doc2);
1093    }
1094
1095    #[test]
1096    fn test_partialeq_with_different_map_children() {
1097        let mut doc1 = EureDocument::new();
1098        let mut doc2 = EureDocument::new();
1099
1100        let root1 = doc1.get_root_id();
1101        let root2 = doc2.get_root_id();
1102
1103        doc1.add_map_child(ObjectKey::String("key1".to_string()), root1)
1104            .expect("Failed to add child");
1105        doc2.add_map_child(ObjectKey::String("key2".to_string()), root2)
1106            .expect("Failed to add child");
1107
1108        assert_ne!(doc1, doc2);
1109    }
1110
1111    #[test]
1112    fn test_partialeq_with_extensions() {
1113        let mut doc1 = EureDocument::new();
1114        let mut doc2 = EureDocument::new();
1115
1116        let root1 = doc1.get_root_id();
1117        let root2 = doc2.get_root_id();
1118
1119        let ext_id = identifier("ext");
1120
1121        doc1.add_extension(ext_id.clone(), root1)
1122            .expect("Failed to add extension");
1123        doc2.add_extension(ext_id.clone(), root2)
1124            .expect("Failed to add extension");
1125
1126        assert_eq!(doc1, doc2);
1127    }
1128
1129    #[test]
1130    fn test_partialeq_with_different_extensions() {
1131        let mut doc1 = EureDocument::new();
1132        let mut doc2 = EureDocument::new();
1133
1134        let root1 = doc1.get_root_id();
1135        let root2 = doc2.get_root_id();
1136
1137        doc1.add_extension(identifier("ext1"), root1)
1138            .expect("Failed to add extension");
1139        doc2.add_extension(identifier("ext2"), root2)
1140            .expect("Failed to add extension");
1141
1142        assert_ne!(doc1, doc2);
1143    }
1144
1145    #[test]
1146    fn test_partialeq_with_arrays() {
1147        let mut doc1 = EureDocument::new();
1148        let mut doc2 = EureDocument::new();
1149
1150        // Create array in doc1
1151        let array_id1 = doc1.create_node(NodeValue::empty_array());
1152        doc1.add_array_element(None, array_id1)
1153            .expect("Failed to add array element");
1154        doc1.root = array_id1;
1155
1156        // Create array in doc2
1157        let array_id2 = doc2.create_node(NodeValue::empty_array());
1158        doc2.add_array_element(None, array_id2)
1159            .expect("Failed to add array element");
1160        doc2.root = array_id2;
1161
1162        assert_eq!(doc1, doc2);
1163    }
1164
1165    #[test]
1166    fn test_partialeq_with_tuples() {
1167        let mut doc1 = EureDocument::new();
1168        let mut doc2 = EureDocument::new();
1169
1170        // Create tuple in doc1
1171        let tuple_id1 = doc1.create_node(NodeValue::empty_tuple());
1172        doc1.add_tuple_element(0, tuple_id1)
1173            .expect("Failed to add tuple element");
1174        doc1.root = tuple_id1;
1175
1176        // Create tuple in doc2
1177        let tuple_id2 = doc2.create_node(NodeValue::empty_tuple());
1178        doc2.add_tuple_element(0, tuple_id2)
1179            .expect("Failed to add tuple element");
1180        doc2.root = tuple_id2;
1181
1182        assert_eq!(doc1, doc2);
1183    }
1184
1185    #[test]
1186    fn test_partialeq_nested_structure() {
1187        let mut doc1 = EureDocument::new();
1188        let mut doc2 = EureDocument::new();
1189
1190        // Create nested structure in doc1
1191        let root1 = doc1.get_root_id();
1192        let child1 = doc1
1193            .add_map_child(ObjectKey::String("child".to_string()), root1)
1194            .expect("Failed to add child")
1195            .node_id;
1196        doc1.node_mut(child1).content = NodeValue::Primitive(PrimitiveValue::Bool(true));
1197
1198        // Create nested structure in doc2
1199        let root2 = doc2.get_root_id();
1200        let child2 = doc2
1201            .add_map_child(ObjectKey::String("child".to_string()), root2)
1202            .expect("Failed to add child")
1203            .node_id;
1204        doc2.node_mut(child2).content = NodeValue::Primitive(PrimitiveValue::Bool(true));
1205
1206        assert_eq!(doc1, doc2);
1207    }
1208
1209    #[test]
1210    fn test_partialeq_ignores_node_id_values() {
1211        let mut doc1 = EureDocument::new();
1212        let mut doc2 = EureDocument::new();
1213
1214        // Create a more complex structure in doc1
1215        let root1 = doc1.get_root_id();
1216        let _intermediate = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1217        let child1 = doc1
1218            .add_map_child(ObjectKey::String("key".to_string()), root1)
1219            .expect("Failed")
1220            .node_id;
1221
1222        // Create the same structure in doc2 (without intermediate node)
1223        let root2 = doc2.get_root_id();
1224        let child2 = doc2
1225            .add_map_child(ObjectKey::String("key".to_string()), root2)
1226            .expect("Failed")
1227            .node_id;
1228
1229        // Even though child1 and child2 have different NodeId values,
1230        // the structures should be equal
1231        assert_eq!(doc1, doc2);
1232
1233        // Verify that NodeIds are actually different
1234        assert_ne!(child1.0, child2.0);
1235    }
1236
1237    #[test]
1238    fn test_require_map_converts_hole() {
1239        let mut doc = EureDocument::new();
1240        let node_id = doc.create_node(NodeValue::hole());
1241
1242        assert!(doc.node(node_id).content.is_hole());
1243
1244        {
1245            let node = doc.node_mut(node_id);
1246            let _map = node.require_map().expect("Should convert to map");
1247        }
1248
1249        assert!(doc.node(node_id).as_map().is_some());
1250    }
1251
1252    #[test]
1253    fn test_require_array_converts_hole() {
1254        let mut doc = EureDocument::new();
1255        let node_id = doc.create_node(NodeValue::hole());
1256
1257        assert!(doc.node(node_id).content.is_hole());
1258
1259        {
1260            let node = doc.node_mut(node_id);
1261            let _array = node.require_array().expect("Should convert to array");
1262        }
1263
1264        assert!(doc.node(node_id).as_array().is_some());
1265    }
1266
1267    #[test]
1268    fn test_require_tuple_converts_hole() {
1269        let mut doc = EureDocument::new();
1270        let node_id = doc.create_node(NodeValue::hole());
1271
1272        assert!(doc.node(node_id).content.is_hole());
1273
1274        {
1275            let node = doc.node_mut(node_id);
1276            let _tuple = node.require_tuple().expect("Should convert to tuple");
1277        }
1278
1279        assert!(doc.node(node_id).as_tuple().is_some());
1280    }
1281
1282    #[test]
1283    fn test_require_methods_fail_on_wrong_type() {
1284        let mut doc = EureDocument::new();
1285        let primitive_id = doc.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1286
1287        let node = doc.node_mut(primitive_id);
1288        assert_eq!(node.require_map().err(), Some(InsertErrorKind::ExpectedMap));
1289
1290        let node = doc.node_mut(primitive_id);
1291        assert_eq!(
1292            node.require_array().err(),
1293            Some(InsertErrorKind::ExpectedArray)
1294        );
1295
1296        let node = doc.node_mut(primitive_id);
1297        assert_eq!(
1298            node.require_tuple().err(),
1299            Some(InsertErrorKind::ExpectedTuple)
1300        );
1301    }
1302}
1303
1304#[cfg(test)]
1305mod proptests {
1306    extern crate std;
1307
1308    use super::*;
1309    use proptest::prelude::*;
1310    use std::vec::Vec;
1311
1312    // =========================================================================
1313    // Strategy generators
1314    // =========================================================================
1315
1316    /// Characters valid as the first character of an identifier (XID_Start or underscore).
1317    fn xid_start_char() -> impl Strategy<Value = char> {
1318        prop_oneof![
1319            prop::char::range('a', 'z'),
1320            prop::char::range('A', 'Z'),
1321            Just('_'),
1322            Just('α'),
1323            Just('日'),
1324        ]
1325    }
1326
1327    /// Characters valid in the continuation of an identifier (XID_Continue or hyphen).
1328    fn xid_continue_char() -> impl Strategy<Value = char> {
1329        prop_oneof![
1330            prop::char::range('a', 'z'),
1331            prop::char::range('A', 'Z'),
1332            prop::char::range('0', '9'),
1333            Just('_'),
1334            Just('-'),
1335            Just('α'),
1336            Just('日'),
1337        ]
1338    }
1339
1340    /// Strategy for generating valid identifiers with broader character coverage.
1341    fn arb_identifier() -> impl Strategy<Value = Identifier> {
1342        (
1343            xid_start_char(),
1344            proptest::collection::vec(xid_continue_char(), 0..15),
1345        )
1346            .prop_map(|(first, rest)| {
1347                let mut s = alloc::string::String::with_capacity(1 + rest.len());
1348                s.push(first);
1349                s.extend(rest);
1350                s
1351            })
1352            .prop_filter_map("valid identifier", |s| s.parse::<Identifier>().ok())
1353    }
1354
1355    /// Strategy for generating object keys with broader coverage.
1356    fn arb_object_key() -> impl Strategy<Value = ObjectKey> {
1357        prop_oneof![
1358            // Identifier-style string keys (broader range)
1359            arb_identifier().prop_map(|id| ObjectKey::String(id.to_string())),
1360            // Numeric keys (including negative)
1361            (-1000i64..1000).prop_map(|n| ObjectKey::Number(n.into())),
1362        ]
1363    }
1364
1365    /// Strategy for generating primitive values.
1366    fn arb_primitive_value() -> impl Strategy<Value = PrimitiveValue> {
1367        prop_oneof![
1368            Just(PrimitiveValue::Null),
1369            proptest::bool::ANY.prop_map(PrimitiveValue::Bool),
1370            (-1000i64..1000).prop_map(|n| PrimitiveValue::Integer(n.into())),
1371            proptest::num::f64::NORMAL.prop_map(PrimitiveValue::F64),
1372            "[a-zA-Z0-9 ]{0,50}".prop_map(|s| PrimitiveValue::Text(Text::plaintext(s))),
1373        ]
1374    }
1375
1376    // =========================================================================
1377    // resolve_child_by_segment idempotency tests
1378    // =========================================================================
1379
1380    proptest! {
1381        /// Invariant: resolve_child_by_segment is idempotent for Ident segments.
1382        /// Calling twice with the same identifier returns the same NodeId.
1383        #[test]
1384        fn resolve_ident_is_idempotent(ident in arb_identifier()) {
1385            let mut doc = EureDocument::new();
1386            let root_id = doc.get_root_id();
1387
1388            let node_id1 = doc
1389                .resolve_child_by_segment(PathSegment::Ident(ident.clone()), root_id)
1390                .expect("First resolve failed")
1391                .node_id;
1392
1393            let node_id2 = doc
1394                .resolve_child_by_segment(PathSegment::Ident(ident), root_id)
1395                .expect("Second resolve failed")
1396                .node_id;
1397
1398            prop_assert_eq!(node_id1, node_id2, "Ident resolution should be idempotent");
1399        }
1400
1401        /// Invariant: resolve_child_by_segment is idempotent for Value segments.
1402        #[test]
1403        fn resolve_value_is_idempotent(key in arb_object_key()) {
1404            let mut doc = EureDocument::new();
1405            let root_id = doc.get_root_id();
1406
1407            let node_id1 = doc
1408                .resolve_child_by_segment(PathSegment::Value(key.clone()), root_id)
1409                .expect("First resolve failed")
1410                .node_id;
1411
1412            let node_id2 = doc
1413                .resolve_child_by_segment(PathSegment::Value(key), root_id)
1414                .expect("Second resolve failed")
1415                .node_id;
1416
1417            prop_assert_eq!(node_id1, node_id2, "Value resolution should be idempotent");
1418        }
1419
1420        /// Invariant: resolve_child_by_segment is idempotent for Extension segments.
1421        #[test]
1422        fn resolve_extension_is_idempotent(ident in arb_identifier()) {
1423            let mut doc = EureDocument::new();
1424            let root_id = doc.get_root_id();
1425
1426            let node_id1 = doc
1427                .resolve_child_by_segment(PathSegment::Extension(ident.clone()), root_id)
1428                .expect("First resolve failed")
1429                .node_id;
1430
1431            let node_id2 = doc
1432                .resolve_child_by_segment(PathSegment::Extension(ident), root_id)
1433                .expect("Second resolve failed")
1434                .node_id;
1435
1436            prop_assert_eq!(node_id1, node_id2, "Extension resolution should be idempotent");
1437        }
1438
1439        /// Invariant: resolve_child_by_segment is idempotent for TupleIndex segments.
1440        #[test]
1441        fn resolve_tuple_index_is_idempotent(index in 0u8..10) {
1442            let mut doc = EureDocument::new();
1443            let parent_id = doc.create_node_uninitialized();
1444
1445            // First add indices sequentially up to `index`
1446            for i in 0..index {
1447                doc.add_tuple_element(i, parent_id).expect("Sequential add failed");
1448            }
1449
1450            // Now resolve the next index
1451            let node_id1 = doc
1452                .resolve_child_by_segment(PathSegment::TupleIndex(index), parent_id)
1453                .expect("First resolve failed")
1454                .node_id;
1455
1456            let node_id2 = doc
1457                .resolve_child_by_segment(PathSegment::TupleIndex(index), parent_id)
1458                .expect("Second resolve failed")
1459                .node_id;
1460
1461            prop_assert_eq!(node_id1, node_id2, "TupleIndex resolution should be idempotent");
1462        }
1463
1464        /// Invariant: resolve_child_by_segment is idempotent for ArrayIndex(Some(n)) segments.
1465        #[test]
1466        fn resolve_array_index_some_is_idempotent(index in 0usize..10) {
1467            let mut doc = EureDocument::new();
1468            let parent_id = doc.create_node_uninitialized();
1469
1470            // First add indices sequentially up to `index`
1471            for i in 0..index {
1472                doc.add_array_element(Some(i), parent_id).expect("Sequential add failed");
1473            }
1474
1475            // Now resolve the next index
1476            let node_id1 = doc
1477                .resolve_child_by_segment(PathSegment::ArrayIndex(Some(index)), parent_id)
1478                .expect("First resolve failed")
1479                .node_id;
1480
1481            let node_id2 = doc
1482                .resolve_child_by_segment(PathSegment::ArrayIndex(Some(index)), parent_id)
1483                .expect("Second resolve failed")
1484                .node_id;
1485
1486            prop_assert_eq!(node_id1, node_id2, "ArrayIndex(Some) resolution should be idempotent");
1487        }
1488
1489        /// Invariant: ArrayIndex(None) always creates new elements (NOT idempotent - push behavior).
1490        #[test]
1491        fn resolve_array_index_none_always_creates_new(count in 1usize..10) {
1492            let mut doc = EureDocument::new();
1493            let parent_id = doc.create_node_uninitialized();
1494
1495            let mut node_ids = Vec::new();
1496            for _ in 0..count {
1497                let node_id = doc
1498                    .resolve_child_by_segment(PathSegment::ArrayIndex(None), parent_id)
1499                    .expect("Resolve failed")
1500                    .node_id;
1501                node_ids.push(node_id);
1502            }
1503
1504            // All node IDs should be unique
1505            for i in 0..node_ids.len() {
1506                for j in (i+1)..node_ids.len() {
1507                    prop_assert_ne!(node_ids[i], node_ids[j],
1508                        "ArrayIndex(None) should create unique nodes");
1509                }
1510            }
1511
1512            // Array length should match push count
1513            let array = doc.node(parent_id).as_array().expect("Expected array");
1514            prop_assert_eq!(array.len(), count, "Array length should match push count");
1515        }
1516
1517        /// Error: ArrayIndex segment on non-array parent fails.
1518        #[test]
1519        fn resolve_array_index_on_map_fails(index in 0usize..10) {
1520            let mut doc = EureDocument::new();
1521            let root_id = doc.get_root_id(); // Root starts as a hole/map
1522
1523            // Make root explicitly a map
1524            doc.node_mut(root_id).content = NodeValue::empty_map();
1525
1526            let result = doc.resolve_child_by_segment(PathSegment::ArrayIndex(Some(index)), root_id);
1527            prop_assert!(result.is_err(), "ArrayIndex on map should fail");
1528            prop_assert_eq!(result.err(), Some(InsertErrorKind::ExpectedArray));
1529        }
1530
1531        /// Error: TupleIndex segment on non-tuple parent fails.
1532        #[test]
1533        fn resolve_tuple_index_on_array_fails(index in 0u8..10) {
1534            let mut doc = EureDocument::new();
1535            let parent_id = doc.create_node(NodeValue::empty_array());
1536
1537            let result = doc.resolve_child_by_segment(PathSegment::TupleIndex(index), parent_id);
1538            prop_assert!(result.is_err(), "TupleIndex on array should fail");
1539            prop_assert_eq!(result.err(), Some(InsertErrorKind::ExpectedTuple));
1540        }
1541
1542        /// Error: ArrayIndex segment on primitive fails.
1543        #[test]
1544        fn resolve_array_index_on_primitive_fails(value in arb_primitive_value()) {
1545            let mut doc = EureDocument::new();
1546            let node_id = doc.create_node(NodeValue::Primitive(value));
1547
1548            let result = doc.resolve_child_by_segment(PathSegment::ArrayIndex(Some(0)), node_id);
1549            prop_assert!(result.is_err(), "ArrayIndex on primitive should fail");
1550            prop_assert_eq!(result.err(), Some(InsertErrorKind::ExpectedArray));
1551        }
1552
1553        /// Error: Non-sequential ArrayIndex fails.
1554        #[test]
1555        fn resolve_array_index_non_sequential_fails(skip in 1usize..10) {
1556            let mut doc = EureDocument::new();
1557            let parent_id = doc.create_node(NodeValue::empty_array());
1558
1559            // Try to add at index `skip` without filling 0..skip first
1560            let result = doc.resolve_child_by_segment(PathSegment::ArrayIndex(Some(skip)), parent_id);
1561            prop_assert!(result.is_err(), "Non-sequential ArrayIndex should fail");
1562
1563            match result.err() {
1564                Some(InsertErrorKind::ArrayIndexInvalid { index, expected_index }) => {
1565                    prop_assert_eq!(index, skip);
1566                    prop_assert_eq!(expected_index, 0);
1567                }
1568                other => prop_assert!(false, "Expected ArrayIndexInvalid, got {:?}", other),
1569            }
1570        }
1571
1572        /// Error: Non-sequential TupleIndex fails.
1573        #[test]
1574        fn resolve_tuple_index_non_sequential_fails(skip in 1u8..10) {
1575            let mut doc = EureDocument::new();
1576            let parent_id = doc.create_node(NodeValue::empty_tuple());
1577
1578            let result = doc.resolve_child_by_segment(PathSegment::TupleIndex(skip), parent_id);
1579            prop_assert!(result.is_err(), "Non-sequential TupleIndex should fail");
1580
1581            match result.err() {
1582                Some(InsertErrorKind::TupleIndexInvalid { index, expected_index }) => {
1583                    prop_assert_eq!(index, skip);
1584                    prop_assert_eq!(expected_index, 0);
1585                }
1586                other => prop_assert!(false, "Expected TupleIndexInvalid, got {:?}", other),
1587            }
1588        }
1589    }
1590
1591    // =========================================================================
1592    // Extension uniqueness tests
1593    // =========================================================================
1594
1595    proptest! {
1596        /// Invariant: Multiple different extensions can be added to a single node.
1597        #[test]
1598        fn multiple_different_extensions_allowed(
1599            ext1 in arb_identifier(),
1600            ext2 in arb_identifier(),
1601        ) {
1602            prop_assume!(ext1 != ext2);
1603
1604            let mut doc = EureDocument::new();
1605            let root_id = doc.get_root_id();
1606
1607            let node_id1 = doc.add_extension(ext1.clone(), root_id)
1608                .expect("First extension failed")
1609                .node_id;
1610            let node_id2 = doc.add_extension(ext2.clone(), root_id)
1611                .expect("Second extension failed")
1612                .node_id;
1613
1614            let node = doc.node(root_id);
1615            prop_assert_eq!(node.extensions.get(&ext1), Some(&node_id1));
1616            prop_assert_eq!(node.extensions.get(&ext2), Some(&node_id2));
1617        }
1618
1619        /// Invariant: Duplicate extension identifier fails with AlreadyAssignedExtension.
1620        #[test]
1621        fn duplicate_extension_fails(ext in arb_identifier()) {
1622            let mut doc = EureDocument::new();
1623            let root_id = doc.get_root_id();
1624
1625            let _first = doc.add_extension(ext.clone(), root_id)
1626                .expect("First extension should succeed");
1627
1628            let result = doc.add_extension(ext.clone(), root_id);
1629            prop_assert_eq!(
1630                result.err(),
1631                Some(InsertErrorKind::AlreadyAssignedExtension { identifier: ext }),
1632                "Duplicate extension should fail"
1633            );
1634        }
1635    }
1636
1637    // =========================================================================
1638    // Document equality tests
1639    // =========================================================================
1640
1641    proptest! {
1642        /// Invariant: Two documents with same structure are equal even with different NodeIds.
1643        #[test]
1644        fn document_equality_ignores_node_ids(
1645            keys in proptest::collection::vec(arb_object_key(), 1..5)
1646                .prop_filter("unique keys", |keys| {
1647                    let unique: std::collections::HashSet<_> = keys.iter().collect();
1648                    unique.len() == keys.len()
1649                }),
1650        ) {
1651            let mut doc1 = EureDocument::new();
1652            let mut doc2 = EureDocument::new();
1653
1654            // Add an unrelated node to doc1 to offset NodeIds
1655            let _ = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1656
1657            let root1 = doc1.get_root_id();
1658            let root2 = doc2.get_root_id();
1659
1660            // Add same children to both documents
1661            for key in &keys {
1662                doc1.add_map_child(key.clone(), root1).expect("Add failed");
1663                doc2.add_map_child(key.clone(), root2).expect("Add failed");
1664            }
1665
1666            prop_assert_eq!(doc1, doc2, "Documents with same structure should be equal");
1667        }
1668
1669        /// Invariant: Reflexive equality - a document equals itself.
1670        #[test]
1671        fn document_equality_reflexive(
1672            keys in proptest::collection::vec(arb_object_key(), 0..5)
1673                .prop_filter("unique keys", |keys| {
1674                    let unique: std::collections::HashSet<_> = keys.iter().collect();
1675                    unique.len() == keys.len()
1676                }),
1677        ) {
1678            let mut doc = EureDocument::new();
1679            let root_id = doc.get_root_id();
1680
1681            for key in &keys {
1682                doc.add_map_child(key.clone(), root_id).expect("Add failed");
1683            }
1684
1685            prop_assert_eq!(&doc, &doc, "Document should equal itself");
1686        }
1687
1688        /// Invariant: Documents with different content are not equal.
1689        #[test]
1690        fn document_equality_different_content(
1691            key1 in arb_object_key(),
1692            key2 in arb_object_key(),
1693        ) {
1694            prop_assume!(key1 != key2);
1695
1696            let mut doc1 = EureDocument::new();
1697            let mut doc2 = EureDocument::new();
1698
1699            let root1 = doc1.get_root_id();
1700            let root2 = doc2.get_root_id();
1701
1702            doc1.add_map_child(key1, root1).expect("Add failed");
1703            doc2.add_map_child(key2, root2).expect("Add failed");
1704
1705            prop_assert_ne!(doc1, doc2, "Documents with different keys should not be equal");
1706        }
1707
1708        /// Invariant: Document equality works for arrays.
1709        #[test]
1710        fn document_equality_for_arrays(count in 1usize..10) {
1711            let mut doc1 = EureDocument::new();
1712            let mut doc2 = EureDocument::new();
1713
1714            // Offset NodeIds in doc1
1715            let _ = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1716
1717            let root1 = doc1.get_root_id();
1718            let root2 = doc2.get_root_id();
1719
1720            // Convert roots to arrays
1721            doc1.node_mut(root1).content = NodeValue::empty_array();
1722            doc2.node_mut(root2).content = NodeValue::empty_array();
1723
1724            for _ in 0..count {
1725                doc1.add_array_element(None, root1).expect("Add failed");
1726                doc2.add_array_element(None, root2).expect("Add failed");
1727            }
1728
1729            prop_assert_eq!(doc1, doc2, "Documents with same array structure should be equal");
1730        }
1731
1732        /// Invariant: Document equality works for tuples.
1733        #[test]
1734        fn document_equality_for_tuples(count in 1u8..10) {
1735            let mut doc1 = EureDocument::new();
1736            let mut doc2 = EureDocument::new();
1737
1738            let _ = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1739
1740            let root1 = doc1.get_root_id();
1741            let root2 = doc2.get_root_id();
1742
1743            doc1.node_mut(root1).content = NodeValue::empty_tuple();
1744            doc2.node_mut(root2).content = NodeValue::empty_tuple();
1745
1746            for i in 0..count {
1747                doc1.add_tuple_element(i, root1).expect("Add failed");
1748                doc2.add_tuple_element(i, root2).expect("Add failed");
1749            }
1750
1751            prop_assert_eq!(doc1, doc2, "Documents with same tuple structure should be equal");
1752        }
1753
1754        /// Invariant: Document equality works for primitive values.
1755        #[test]
1756        fn document_equality_for_primitives(value in arb_primitive_value()) {
1757            let mut doc1 = EureDocument::new();
1758            let mut doc2 = EureDocument::new();
1759
1760            let _ = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1761
1762            let root1 = doc1.get_root_id();
1763            let root2 = doc2.get_root_id();
1764
1765            doc1.node_mut(root1).content = NodeValue::Primitive(value.clone());
1766            doc2.node_mut(root2).content = NodeValue::Primitive(value);
1767
1768            prop_assert_eq!(doc1, doc2, "Documents with same primitive value should be equal");
1769        }
1770
1771        /// Invariant: Document equality considers extensions.
1772        #[test]
1773        fn document_equality_considers_extensions(
1774            ext_name in arb_identifier(),
1775            value in arb_primitive_value(),
1776        ) {
1777            let mut doc1 = EureDocument::new();
1778            let mut doc2 = EureDocument::new();
1779
1780            let _ = doc1.create_node(NodeValue::Primitive(PrimitiveValue::Null));
1781
1782            let root1 = doc1.get_root_id();
1783            let root2 = doc2.get_root_id();
1784
1785            // Add same extension to both
1786            let ext1_id = doc1.add_extension(ext_name.clone(), root1).expect("Add ext failed").node_id;
1787            let ext2_id = doc2.add_extension(ext_name.clone(), root2).expect("Add ext failed").node_id;
1788
1789            // Set same value in extensions
1790            doc1.node_mut(ext1_id).content = NodeValue::Primitive(value.clone());
1791            doc2.node_mut(ext2_id).content = NodeValue::Primitive(value);
1792
1793            prop_assert_eq!(doc1, doc2, "Documents with same extensions should be equal");
1794        }
1795
1796        /// Invariant: Documents with different extensions are not equal.
1797        #[test]
1798        fn document_equality_different_extensions(
1799            ext1 in arb_identifier(),
1800            ext2 in arb_identifier(),
1801        ) {
1802            prop_assume!(ext1 != ext2);
1803
1804            let mut doc1 = EureDocument::new();
1805            let mut doc2 = EureDocument::new();
1806
1807            let root1 = doc1.get_root_id();
1808            let root2 = doc2.get_root_id();
1809
1810            doc1.add_extension(ext1, root1).expect("Add ext failed");
1811            doc2.add_extension(ext2, root2).expect("Add ext failed");
1812
1813            prop_assert_ne!(doc1, doc2, "Documents with different extensions should not be equal");
1814        }
1815    }
1816
1817    // =========================================================================
1818    // Copy subtree tests
1819    // =========================================================================
1820
1821    proptest! {
1822        /// Invariant: copy_subtree preserves primitive values.
1823        #[test]
1824        fn copy_subtree_preserves_primitive(value in arb_primitive_value()) {
1825            let mut src = EureDocument::new();
1826            let src_id = src.create_node(NodeValue::Primitive(value.clone()));
1827
1828            let dst = src.node_subtree_to_document(src_id);
1829
1830            let dst_node = dst.root();
1831            match &dst_node.content {
1832                NodeValue::Primitive(copied_value) => {
1833                    prop_assert_eq!(copied_value, &value, "Primitive value should be preserved");
1834                }
1835                other => {
1836                    prop_assert!(false, "Expected Primitive, got {:?}", other);
1837                }
1838            }
1839        }
1840
1841        /// Invariant: copy_subtree for arrays must create valid NodeIds in destination.
1842        /// All NodeIds stored in the copied array must exist in the destination document.
1843        #[test]
1844        fn copy_subtree_array_has_valid_node_ids(count in 1usize..10) {
1845            let mut src = EureDocument::new();
1846            let array_id = src.create_node(NodeValue::empty_array());
1847
1848            for _ in 0..count {
1849                src.add_array_element(None, array_id).expect("Add failed");
1850            }
1851
1852            let dst = src.node_subtree_to_document(array_id);
1853
1854            // The destination array should have exactly `count` elements
1855            let dst_array = dst.root().as_array().expect("Expected array");
1856            prop_assert_eq!(dst_array.len(), count, "Copied array should have correct length");
1857
1858            // All NodeIds in the destination array must be valid
1859            for i in 0..dst_array.len() {
1860                let child_id = dst_array.get(i).expect("Should have element");
1861                prop_assert!(
1862                    dst.get_node(child_id).is_some(),
1863                    "NodeId {:?} at index {} must exist in destination", child_id, i
1864                );
1865            }
1866        }
1867
1868        /// Invariant: copy_subtree for maps must create valid NodeIds in destination.
1869        #[test]
1870        fn copy_subtree_map_has_valid_node_ids(
1871            keys in proptest::collection::vec(arb_object_key(), 1..5)
1872                .prop_filter("unique keys", |keys| {
1873                    let unique: std::collections::HashSet<_> = keys.iter().collect();
1874                    unique.len() == keys.len()
1875                }),
1876        ) {
1877            let mut src = EureDocument::new();
1878            let map_id = src.create_node(NodeValue::empty_map());
1879
1880            for key in &keys {
1881                src.add_map_child(key.clone(), map_id).expect("Add failed");
1882            }
1883
1884            let dst = src.node_subtree_to_document(map_id);
1885
1886            let dst_map = dst.root().as_map().expect("Expected map");
1887            prop_assert_eq!(dst_map.len(), keys.len(), "Copied map should have correct size");
1888
1889            // All NodeIds in the destination map must be valid
1890            for (key, &child_id) in dst_map.iter() {
1891                prop_assert!(
1892                    dst.get_node(child_id).is_some(),
1893                    "NodeId {:?} for key {:?} must exist in destination", child_id, key
1894                );
1895            }
1896        }
1897
1898        /// Invariant: copy_subtree for tuples must create valid NodeIds in destination.
1899        #[test]
1900        fn copy_subtree_tuple_has_valid_node_ids(count in 1u8..10) {
1901            let mut src = EureDocument::new();
1902            let tuple_id = src.create_node(NodeValue::empty_tuple());
1903
1904            for i in 0..count {
1905                src.add_tuple_element(i, tuple_id).expect("Add failed");
1906            }
1907
1908            let dst = src.node_subtree_to_document(tuple_id);
1909
1910            let dst_tuple = dst.root().as_tuple().expect("Expected tuple");
1911            prop_assert_eq!(dst_tuple.len(), count as usize, "Copied tuple should have correct length");
1912
1913            // All NodeIds in the destination tuple must be valid
1914            for i in 0..dst_tuple.len() {
1915                let child_id = dst_tuple.get(i).expect("Should have element");
1916                prop_assert!(
1917                    dst.get_node(child_id).is_some(),
1918                    "NodeId {:?} at index {} must exist in destination", child_id, i
1919                );
1920            }
1921        }
1922
1923        /// Invariant: copy_subtree preserves nested mixed content (map → array → primitive).
1924        #[test]
1925        fn copy_subtree_preserves_nested_mixed_content(
1926            key in arb_object_key(),
1927            value in arb_primitive_value(),
1928        ) {
1929            let mut src = EureDocument::new();
1930            let map_id = src.create_node(NodeValue::empty_map());
1931
1932            // Create map → array → primitive structure
1933            let child_id = src.add_map_child(key.clone(), map_id).expect("Add failed").node_id;
1934            src.node_mut(child_id).content = NodeValue::empty_array();
1935            let elem_id = src.add_array_element(None, child_id).expect("Add failed").node_id;
1936            src.node_mut(elem_id).content = NodeValue::Primitive(value.clone());
1937
1938            let dst = src.node_subtree_to_document(map_id);
1939
1940            // Verify structure
1941            let dst_map = dst.root().as_map().expect("Expected map");
1942            let dst_child_id = dst_map.get(&key).expect("Should have key");
1943            let dst_child = dst.get_node(*dst_child_id).expect("Child should exist");
1944            let dst_array = dst_child.as_array().expect("Expected array");
1945            prop_assert_eq!(dst_array.len(), 1);
1946
1947            let dst_elem_id = dst_array.get(0).expect("Should have element");
1948            let dst_elem = dst.get_node(dst_elem_id).expect("Element should exist");
1949            prop_assert_eq!(
1950                &dst_elem.content,
1951                &NodeValue::Primitive(value),
1952                "Primitive value should be preserved in nested structure"
1953            );
1954        }
1955
1956        /// Invariant: copy_subtree preserves extensions on nodes.
1957        #[test]
1958        fn copy_subtree_preserves_extensions(
1959            ext_name in arb_identifier(),
1960            ext_value in arb_primitive_value(),
1961        ) {
1962            let mut src = EureDocument::new();
1963            let node_id = src.create_node(NodeValue::empty_map());
1964
1965            // Add extension to the node
1966            let ext_id = src.add_extension(ext_name.clone(), node_id).expect("Add ext failed").node_id;
1967            src.node_mut(ext_id).content = NodeValue::Primitive(ext_value.clone());
1968
1969            let dst = src.node_subtree_to_document(node_id);
1970
1971            // Verify extension exists in destination
1972            let dst_ext = dst.root().extensions.get(&ext_name);
1973            prop_assert!(dst_ext.is_some(), "Extension should be copied");
1974
1975            let dst_ext_id = *dst_ext.unwrap();
1976            let dst_ext_node = dst.get_node(dst_ext_id).expect("Extension node should exist");
1977            prop_assert_eq!(
1978                &dst_ext_node.content,
1979                &NodeValue::Primitive(ext_value),
1980                "Extension value should be preserved"
1981            );
1982        }
1983
1984        /// Invariant: copy_subtree preserves extensions on nested nodes.
1985        #[test]
1986        fn copy_subtree_preserves_nested_extensions(
1987            key in arb_object_key(),
1988            ext_name in arb_identifier(),
1989        ) {
1990            let mut src = EureDocument::new();
1991            let map_id = src.create_node(NodeValue::empty_map());
1992
1993            // Add child to map
1994            let child_id = src.add_map_child(key.clone(), map_id).expect("Add failed").node_id;
1995            // Add extension to child
1996            src.add_extension(ext_name.clone(), child_id).expect("Add ext failed");
1997
1998            let dst = src.node_subtree_to_document(map_id);
1999
2000            // Verify nested extension exists
2001            let dst_map = dst.root().as_map().expect("Expected map");
2002            let dst_child_id = dst_map.get(&key).expect("Should have key");
2003            let dst_child = dst.get_node(*dst_child_id).expect("Child should exist");
2004
2005            prop_assert!(
2006                dst_child.extensions.contains_key(&ext_name),
2007                "Extension on nested node should be preserved"
2008            );
2009        }
2010    }
2011
2012    // =========================================================================
2013    // Map key uniqueness tests
2014    // =========================================================================
2015
2016    proptest! {
2017        /// Invariant: Map keys must be unique; duplicate key fails with AlreadyAssigned.
2018        #[test]
2019        fn map_key_uniqueness(key in arb_object_key()) {
2020            let mut doc = EureDocument::new();
2021            let root_id = doc.get_root_id();
2022
2023            let _first = doc.add_map_child(key.clone(), root_id)
2024                .expect("First add should succeed");
2025
2026            let result = doc.add_map_child(key.clone(), root_id);
2027            prop_assert_eq!(
2028                result.err(),
2029                Some(InsertErrorKind::AlreadyAssigned { key }),
2030                "Duplicate map key should fail"
2031            );
2032        }
2033
2034        /// Invariant: Multiple different map keys can coexist.
2035        #[test]
2036        fn multiple_map_keys_allowed(
2037            keys in proptest::collection::vec(arb_object_key(), 2..10)
2038                .prop_filter("unique keys", |keys| {
2039                    let unique: std::collections::HashSet<_> = keys.iter().collect();
2040                    unique.len() == keys.len()
2041                })
2042        ) {
2043            let mut doc = EureDocument::new();
2044            let root_id = doc.get_root_id();
2045
2046            for key in &keys {
2047                doc.add_map_child(key.clone(), root_id).expect("Add should succeed");
2048            }
2049
2050            let map = doc.node(root_id).as_map().expect("Expected map");
2051            prop_assert_eq!(map.len(), keys.len(), "All unique keys should be present");
2052        }
2053    }
2054
2055    // =========================================================================
2056    // Node validity tests
2057    // =========================================================================
2058
2059    proptest! {
2060        /// Invariant: All created nodes can be accessed via get_node.
2061        #[test]
2062        fn created_nodes_are_accessible(count in 1usize..20) {
2063            let mut doc = EureDocument::new();
2064            let mut node_ids = Vec::new();
2065
2066            for _ in 0..count {
2067                let id = doc.create_node_uninitialized();
2068                node_ids.push(id);
2069            }
2070
2071            for id in node_ids {
2072                prop_assert!(doc.get_node(id).is_some(),
2073                    "Created node {:?} should be accessible", id);
2074            }
2075        }
2076
2077        /// Invariant: Invalid NodeIds return None from get_node.
2078        #[test]
2079        fn invalid_node_ids_return_none(count in 1usize..10) {
2080            let mut doc = EureDocument::new();
2081
2082            for _ in 0..count {
2083                doc.create_node_uninitialized();
2084            }
2085
2086            // Access an invalid NodeId (beyond the nodes vector)
2087            let invalid_id = NodeId(count + 100);
2088            prop_assert!(doc.get_node(invalid_id).is_none(),
2089                "Invalid NodeId should return None");
2090        }
2091
2092        /// Invariant: Root node is always accessible.
2093        #[test]
2094        fn root_is_always_accessible(count in 0usize..10) {
2095            let mut doc = EureDocument::new();
2096
2097            // Create some additional nodes
2098            for _ in 0..count {
2099                doc.create_node_uninitialized();
2100            }
2101
2102            let root_id = doc.get_root_id();
2103            prop_assert!(doc.get_node(root_id).is_some(), "Root should always be accessible");
2104            prop_assert_eq!(root_id, NodeId(0), "Root should be NodeId(0)");
2105        }
2106    }
2107
2108    // =========================================================================
2109    // Nested structure tests
2110    // =========================================================================
2111
2112    proptest! {
2113        /// Invariant: Nested structures can be built and are equal across documents.
2114        #[test]
2115        fn nested_structures_are_equal(
2116            keys in proptest::collection::vec(arb_object_key(), 1..3),
2117            depth in 1usize..4,
2118        ) {
2119            let mut doc1 = EureDocument::new();
2120            let mut doc2 = EureDocument::new();
2121
2122            fn build_nested(
2123                doc: &mut EureDocument,
2124                parent_id: NodeId,
2125                keys: &[ObjectKey],
2126                depth: usize,
2127            ) {
2128                if depth == 0 {
2129                    return;
2130                }
2131                // First collect child node IDs to avoid borrow conflict
2132                let child_ids: Vec<NodeId> = keys
2133                    .iter()
2134                    .filter_map(|key| {
2135                        doc.add_map_child(key.clone(), parent_id).ok().map(|c| c.node_id)
2136                    })
2137                    .collect();
2138
2139                // Then recursively build nested structures
2140                for child_id in child_ids {
2141                    build_nested(doc, child_id, keys, depth - 1);
2142                }
2143            }
2144
2145            let root1 = doc1.get_root_id();
2146            let root2 = doc2.get_root_id();
2147
2148            build_nested(&mut doc1, root1, &keys, depth);
2149            build_nested(&mut doc2, root2, &keys, depth);
2150
2151            prop_assert_eq!(doc1, doc2, "Nested structures should be equal");
2152        }
2153    }
2154}