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