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