web engine - experimental web browser
1//! DOM tree, nodes, and events.
2//!
3//! Arena-based DOM tree with Document, Element, Text, and Comment node types.
4//! Each node is stored in a flat `Vec` and referenced by `NodeId`.
5
6use std::fmt;
7
8/// A handle to a node in the DOM tree.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct NodeId(usize);
11
12impl NodeId {
13 /// Returns the underlying index.
14 pub fn index(self) -> usize {
15 self.0
16 }
17}
18
19/// An HTML/XML attribute (name-value pair).
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Attribute {
22 pub name: String,
23 pub value: String,
24}
25
26/// The data specific to each node type.
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum NodeData {
29 /// The root document node.
30 Document,
31 /// An element node with tag name, attributes, and optional namespace.
32 Element {
33 tag_name: String,
34 attributes: Vec<Attribute>,
35 namespace: Option<String>,
36 },
37 /// A text node containing character data.
38 Text { data: String },
39 /// A comment node.
40 Comment { data: String },
41}
42
43/// A node in the DOM tree, with links to parent, children, and siblings.
44#[derive(Debug)]
45struct Node {
46 data: NodeData,
47 parent: Option<NodeId>,
48 first_child: Option<NodeId>,
49 last_child: Option<NodeId>,
50 next_sibling: Option<NodeId>,
51 prev_sibling: Option<NodeId>,
52}
53
54/// The DOM document: an arena of nodes with a root document node.
55pub struct Document {
56 nodes: Vec<Node>,
57 root: NodeId,
58}
59
60impl fmt::Debug for Document {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.debug_struct("Document")
63 .field("node_count", &self.nodes.len())
64 .field("root", &self.root)
65 .finish()
66 }
67}
68
69impl Document {
70 /// Create a new document with a root Document node.
71 pub fn new() -> Self {
72 let root_node = Node {
73 data: NodeData::Document,
74 parent: None,
75 first_child: None,
76 last_child: None,
77 next_sibling: None,
78 prev_sibling: None,
79 };
80 Document {
81 nodes: vec![root_node],
82 root: NodeId(0),
83 }
84 }
85
86 /// Returns the root document node ID.
87 pub fn root(&self) -> NodeId {
88 self.root
89 }
90
91 /// Create an element node. Returns its `NodeId` (not yet attached to the tree).
92 pub fn create_element(&mut self, tag_name: &str) -> NodeId {
93 self.create_element_ns(tag_name, None)
94 }
95
96 /// Create an element node with an optional namespace.
97 pub fn create_element_ns(&mut self, tag_name: &str, namespace: Option<&str>) -> NodeId {
98 self.push_node(NodeData::Element {
99 tag_name: tag_name.to_string(),
100 attributes: Vec::new(),
101 namespace: namespace.map(|s| s.to_string()),
102 })
103 }
104
105 /// Create a text node. Returns its `NodeId` (not yet attached to the tree).
106 pub fn create_text(&mut self, data: &str) -> NodeId {
107 self.push_node(NodeData::Text {
108 data: data.to_string(),
109 })
110 }
111
112 /// Create a comment node. Returns its `NodeId` (not yet attached to the tree).
113 pub fn create_comment(&mut self, data: &str) -> NodeId {
114 self.push_node(NodeData::Comment {
115 data: data.to_string(),
116 })
117 }
118
119 /// Append `child` as the last child of `parent`.
120 ///
121 /// If `child` is already attached elsewhere, it is first removed from its
122 /// current position.
123 pub fn append_child(&mut self, parent: NodeId, child: NodeId) {
124 self.detach(child);
125
126 let old_last = self.nodes[parent.0].last_child;
127
128 self.nodes[child.0].parent = Some(parent);
129 self.nodes[child.0].prev_sibling = old_last;
130 self.nodes[child.0].next_sibling = None;
131
132 if let Some(old_last_id) = old_last {
133 self.nodes[old_last_id.0].next_sibling = Some(child);
134 } else {
135 self.nodes[parent.0].first_child = Some(child);
136 }
137
138 self.nodes[parent.0].last_child = Some(child);
139 }
140
141 /// Insert `new_child` before `reference` under `parent`.
142 ///
143 /// If `new_child` is already attached elsewhere, it is first removed.
144 /// Panics if `reference` is not a child of `parent`.
145 pub fn insert_before(&mut self, parent: NodeId, new_child: NodeId, reference: NodeId) {
146 assert_eq!(
147 self.nodes[reference.0].parent,
148 Some(parent),
149 "reference node is not a child of parent"
150 );
151
152 self.detach(new_child);
153
154 let prev = self.nodes[reference.0].prev_sibling;
155
156 self.nodes[new_child.0].parent = Some(parent);
157 self.nodes[new_child.0].next_sibling = Some(reference);
158 self.nodes[new_child.0].prev_sibling = prev;
159
160 self.nodes[reference.0].prev_sibling = Some(new_child);
161
162 if let Some(prev_id) = prev {
163 self.nodes[prev_id.0].next_sibling = Some(new_child);
164 } else {
165 self.nodes[parent.0].first_child = Some(new_child);
166 }
167 }
168
169 /// Remove `child` from `parent`.
170 ///
171 /// Panics if `child` is not a child of `parent`.
172 pub fn remove_child(&mut self, parent: NodeId, child: NodeId) {
173 assert_eq!(
174 self.nodes[child.0].parent,
175 Some(parent),
176 "node is not a child of parent"
177 );
178 self.detach(child);
179 }
180
181 /// Returns the parent of `node`, or `None` for the root.
182 pub fn parent(&self, node: NodeId) -> Option<NodeId> {
183 self.nodes[node.0].parent
184 }
185
186 /// Returns an iterator over the direct children of `node`.
187 pub fn children(&self, node: NodeId) -> Children<'_> {
188 Children {
189 doc: self,
190 next: self.nodes[node.0].first_child,
191 }
192 }
193
194 /// Returns the first child of `node`, if any.
195 pub fn first_child(&self, node: NodeId) -> Option<NodeId> {
196 self.nodes[node.0].first_child
197 }
198
199 /// Returns the last child of `node`, if any.
200 pub fn last_child(&self, node: NodeId) -> Option<NodeId> {
201 self.nodes[node.0].last_child
202 }
203
204 /// Returns the next sibling of `node`, if any.
205 pub fn next_sibling(&self, node: NodeId) -> Option<NodeId> {
206 self.nodes[node.0].next_sibling
207 }
208
209 /// Returns the previous sibling of `node`, if any.
210 pub fn prev_sibling(&self, node: NodeId) -> Option<NodeId> {
211 self.nodes[node.0].prev_sibling
212 }
213
214 /// Returns a reference to the node's data.
215 pub fn node_data(&self, node: NodeId) -> &NodeData {
216 &self.nodes[node.0].data
217 }
218
219 /// Returns the tag name if `node` is an Element, or `None`.
220 pub fn tag_name(&self, node: NodeId) -> Option<&str> {
221 match &self.nodes[node.0].data {
222 NodeData::Element { tag_name, .. } => Some(tag_name),
223 _ => None,
224 }
225 }
226
227 /// Get an attribute value by name. Returns `None` if the node is not
228 /// an element or the attribute is not present.
229 pub fn get_attribute(&self, node: NodeId, name: &str) -> Option<&str> {
230 match &self.nodes[node.0].data {
231 NodeData::Element { attributes, .. } => attributes
232 .iter()
233 .find(|a| a.name == name)
234 .map(|a| a.value.as_str()),
235 _ => None,
236 }
237 }
238
239 /// Set an attribute on an element node. If the attribute already exists,
240 /// its value is replaced. Does nothing if `node` is not an element.
241 pub fn set_attribute(&mut self, node: NodeId, name: &str, value: &str) {
242 if let NodeData::Element { attributes, .. } = &mut self.nodes[node.0].data {
243 if let Some(attr) = attributes.iter_mut().find(|a| a.name == name) {
244 attr.value = value.to_string();
245 } else {
246 attributes.push(Attribute {
247 name: name.to_string(),
248 value: value.to_string(),
249 });
250 }
251 }
252 }
253
254 /// Remove an attribute from an element node. Returns `true` if the
255 /// attribute was present.
256 pub fn remove_attribute(&mut self, node: NodeId, name: &str) -> bool {
257 if let NodeData::Element { attributes, .. } = &mut self.nodes[node.0].data {
258 let len_before = attributes.len();
259 attributes.retain(|a| a.name != name);
260 attributes.len() < len_before
261 } else {
262 false
263 }
264 }
265
266 /// Returns the text content of a Text or Comment node, or `None` for
267 /// other node types.
268 pub fn text_content(&self, node: NodeId) -> Option<&str> {
269 match &self.nodes[node.0].data {
270 NodeData::Text { data } | NodeData::Comment { data } => Some(data),
271 _ => None,
272 }
273 }
274
275 /// Set the text content of a Text or Comment node.
276 /// Does nothing for other node types.
277 pub fn set_text_content(&mut self, node: NodeId, new_data: &str) {
278 match &mut self.nodes[node.0].data {
279 NodeData::Text { data } | NodeData::Comment { data } => {
280 *data = new_data.to_string();
281 }
282 _ => {}
283 }
284 }
285
286 /// Returns the total number of nodes in the arena (including detached nodes).
287 pub fn len(&self) -> usize {
288 self.nodes.len()
289 }
290
291 /// Returns true if the document has no nodes besides the root.
292 pub fn is_empty(&self) -> bool {
293 self.nodes.len() == 1
294 }
295
296 // --- private helpers ---
297
298 fn push_node(&mut self, data: NodeData) -> NodeId {
299 let id = NodeId(self.nodes.len());
300 self.nodes.push(Node {
301 data,
302 parent: None,
303 first_child: None,
304 last_child: None,
305 next_sibling: None,
306 prev_sibling: None,
307 });
308 id
309 }
310
311 /// Detach a node from its current parent (if any), updating sibling links.
312 fn detach(&mut self, node: NodeId) {
313 let parent = match self.nodes[node.0].parent {
314 Some(p) => p,
315 None => return,
316 };
317
318 let prev = self.nodes[node.0].prev_sibling;
319 let next = self.nodes[node.0].next_sibling;
320
321 if let Some(prev_id) = prev {
322 self.nodes[prev_id.0].next_sibling = next;
323 } else {
324 self.nodes[parent.0].first_child = next;
325 }
326
327 if let Some(next_id) = next {
328 self.nodes[next_id.0].prev_sibling = prev;
329 } else {
330 self.nodes[parent.0].last_child = prev;
331 }
332
333 self.nodes[node.0].parent = None;
334 self.nodes[node.0].prev_sibling = None;
335 self.nodes[node.0].next_sibling = None;
336 }
337}
338
339impl Default for Document {
340 fn default() -> Self {
341 Self::new()
342 }
343}
344
345/// Iterator over the direct children of a node.
346pub struct Children<'a> {
347 doc: &'a Document,
348 next: Option<NodeId>,
349}
350
351impl<'a> Iterator for Children<'a> {
352 type Item = NodeId;
353
354 fn next(&mut self) -> Option<NodeId> {
355 let current = self.next?;
356 self.next = self.doc.nodes[current.0].next_sibling;
357 Some(current)
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn new_document_has_root() {
367 let doc = Document::new();
368 assert_eq!(doc.root(), NodeId(0));
369 assert_eq!(*doc.node_data(doc.root()), NodeData::Document);
370 assert!(doc.children(doc.root()).next().is_none());
371 }
372
373 #[test]
374 fn create_element() {
375 let mut doc = Document::new();
376 let div = doc.create_element("div");
377 assert_eq!(doc.tag_name(div), Some("div"));
378 assert!(doc.parent(div).is_none());
379 }
380
381 #[test]
382 fn create_element_with_namespace() {
383 let mut doc = Document::new();
384 let svg = doc.create_element_ns("svg", Some("http://www.w3.org/2000/svg"));
385 match doc.node_data(svg) {
386 NodeData::Element { namespace, .. } => {
387 assert_eq!(namespace.as_deref(), Some("http://www.w3.org/2000/svg"));
388 }
389 _ => panic!("expected element"),
390 }
391 }
392
393 #[test]
394 fn create_text() {
395 let mut doc = Document::new();
396 let t = doc.create_text("hello");
397 assert_eq!(doc.text_content(t), Some("hello"));
398 assert_eq!(doc.tag_name(t), None);
399 }
400
401 #[test]
402 fn create_comment() {
403 let mut doc = Document::new();
404 let c = doc.create_comment("a comment");
405 assert_eq!(doc.text_content(c), Some("a comment"));
406 match doc.node_data(c) {
407 NodeData::Comment { data } => assert_eq!(data, "a comment"),
408 _ => panic!("expected comment"),
409 }
410 }
411
412 #[test]
413 fn append_child_single() {
414 let mut doc = Document::new();
415 let root = doc.root();
416 let child = doc.create_element("div");
417 doc.append_child(root, child);
418
419 assert_eq!(doc.parent(child), Some(root));
420 assert_eq!(doc.first_child(root), Some(child));
421 assert_eq!(doc.last_child(root), Some(child));
422 assert!(doc.next_sibling(child).is_none());
423 assert!(doc.prev_sibling(child).is_none());
424 }
425
426 #[test]
427 fn append_child_multiple() {
428 let mut doc = Document::new();
429 let root = doc.root();
430 let a = doc.create_element("a");
431 let b = doc.create_element("b");
432 let c = doc.create_element("c");
433 doc.append_child(root, a);
434 doc.append_child(root, b);
435 doc.append_child(root, c);
436
437 assert_eq!(doc.first_child(root), Some(a));
438 assert_eq!(doc.last_child(root), Some(c));
439
440 assert_eq!(doc.next_sibling(a), Some(b));
441 assert_eq!(doc.next_sibling(b), Some(c));
442 assert!(doc.next_sibling(c).is_none());
443
444 assert!(doc.prev_sibling(a).is_none());
445 assert_eq!(doc.prev_sibling(b), Some(a));
446 assert_eq!(doc.prev_sibling(c), Some(b));
447 }
448
449 #[test]
450 fn children_iterator() {
451 let mut doc = Document::new();
452 let root = doc.root();
453 let a = doc.create_element("a");
454 let b = doc.create_element("b");
455 let c = doc.create_element("c");
456 doc.append_child(root, a);
457 doc.append_child(root, b);
458 doc.append_child(root, c);
459
460 let children: Vec<NodeId> = doc.children(root).collect();
461 assert_eq!(children, vec![a, b, c]);
462 }
463
464 #[test]
465 fn children_iterator_empty() {
466 let doc = Document::new();
467 let children: Vec<NodeId> = doc.children(doc.root()).collect();
468 assert!(children.is_empty());
469 }
470
471 #[test]
472 fn insert_before_first() {
473 let mut doc = Document::new();
474 let root = doc.root();
475 let a = doc.create_element("a");
476 let b = doc.create_element("b");
477 doc.append_child(root, b);
478 doc.insert_before(root, a, b);
479
480 let children: Vec<NodeId> = doc.children(root).collect();
481 assert_eq!(children, vec![a, b]);
482 assert_eq!(doc.first_child(root), Some(a));
483 assert_eq!(doc.prev_sibling(b), Some(a));
484 assert_eq!(doc.next_sibling(a), Some(b));
485 }
486
487 #[test]
488 fn insert_before_middle() {
489 let mut doc = Document::new();
490 let root = doc.root();
491 let a = doc.create_element("a");
492 let b = doc.create_element("b");
493 let c = doc.create_element("c");
494 doc.append_child(root, a);
495 doc.append_child(root, c);
496 doc.insert_before(root, b, c);
497
498 let children: Vec<NodeId> = doc.children(root).collect();
499 assert_eq!(children, vec![a, b, c]);
500 }
501
502 #[test]
503 fn remove_child_only() {
504 let mut doc = Document::new();
505 let root = doc.root();
506 let child = doc.create_element("div");
507 doc.append_child(root, child);
508 doc.remove_child(root, child);
509
510 assert!(doc.parent(child).is_none());
511 assert!(doc.first_child(root).is_none());
512 assert!(doc.last_child(root).is_none());
513 }
514
515 #[test]
516 fn remove_child_first() {
517 let mut doc = Document::new();
518 let root = doc.root();
519 let a = doc.create_element("a");
520 let b = doc.create_element("b");
521 doc.append_child(root, a);
522 doc.append_child(root, b);
523 doc.remove_child(root, a);
524
525 assert_eq!(doc.first_child(root), Some(b));
526 assert_eq!(doc.last_child(root), Some(b));
527 assert!(doc.prev_sibling(b).is_none());
528 }
529
530 #[test]
531 fn remove_child_last() {
532 let mut doc = Document::new();
533 let root = doc.root();
534 let a = doc.create_element("a");
535 let b = doc.create_element("b");
536 doc.append_child(root, a);
537 doc.append_child(root, b);
538 doc.remove_child(root, b);
539
540 assert_eq!(doc.first_child(root), Some(a));
541 assert_eq!(doc.last_child(root), Some(a));
542 assert!(doc.next_sibling(a).is_none());
543 }
544
545 #[test]
546 fn remove_child_middle() {
547 let mut doc = Document::new();
548 let root = doc.root();
549 let a = doc.create_element("a");
550 let b = doc.create_element("b");
551 let c = doc.create_element("c");
552 doc.append_child(root, a);
553 doc.append_child(root, b);
554 doc.append_child(root, c);
555 doc.remove_child(root, b);
556
557 let children: Vec<NodeId> = doc.children(root).collect();
558 assert_eq!(children, vec![a, c]);
559 assert_eq!(doc.next_sibling(a), Some(c));
560 assert_eq!(doc.prev_sibling(c), Some(a));
561 }
562
563 #[test]
564 fn append_child_moves_from_old_parent() {
565 let mut doc = Document::new();
566 let root = doc.root();
567 let parent1 = doc.create_element("div");
568 let parent2 = doc.create_element("span");
569 let child = doc.create_element("p");
570 doc.append_child(root, parent1);
571 doc.append_child(root, parent2);
572 doc.append_child(parent1, child);
573
574 assert_eq!(doc.parent(child), Some(parent1));
575
576 // Move child from parent1 to parent2.
577 doc.append_child(parent2, child);
578
579 assert_eq!(doc.parent(child), Some(parent2));
580 assert!(doc.first_child(parent1).is_none());
581 assert_eq!(doc.first_child(parent2), Some(child));
582 }
583
584 #[test]
585 fn set_and_get_attribute() {
586 let mut doc = Document::new();
587 let div = doc.create_element("div");
588
589 assert!(doc.get_attribute(div, "class").is_none());
590
591 doc.set_attribute(div, "class", "container");
592 assert_eq!(doc.get_attribute(div, "class"), Some("container"));
593
594 doc.set_attribute(div, "id", "main");
595 assert_eq!(doc.get_attribute(div, "id"), Some("main"));
596 assert_eq!(doc.get_attribute(div, "class"), Some("container"));
597 }
598
599 #[test]
600 fn set_attribute_replaces() {
601 let mut doc = Document::new();
602 let div = doc.create_element("div");
603 doc.set_attribute(div, "class", "old");
604 doc.set_attribute(div, "class", "new");
605 assert_eq!(doc.get_attribute(div, "class"), Some("new"));
606 }
607
608 #[test]
609 fn remove_attribute() {
610 let mut doc = Document::new();
611 let div = doc.create_element("div");
612 doc.set_attribute(div, "class", "x");
613 assert!(doc.remove_attribute(div, "class"));
614 assert!(doc.get_attribute(div, "class").is_none());
615 assert!(!doc.remove_attribute(div, "class"));
616 }
617
618 #[test]
619 fn attribute_on_non_element_is_noop() {
620 let mut doc = Document::new();
621 let text = doc.create_text("hello");
622 doc.set_attribute(text, "class", "x");
623 assert!(doc.get_attribute(text, "class").is_none());
624 assert!(!doc.remove_attribute(text, "class"));
625 }
626
627 #[test]
628 fn text_content_set() {
629 let mut doc = Document::new();
630 let t = doc.create_text("hello");
631 doc.set_text_content(t, "world");
632 assert_eq!(doc.text_content(t), Some("world"));
633 }
634
635 #[test]
636 fn text_content_on_element_is_none() {
637 let mut doc = Document::new();
638 let div = doc.create_element("div");
639 assert!(doc.text_content(div).is_none());
640 }
641
642 #[test]
643 fn build_simple_html_tree() {
644 // Build: <html><head><title>Test</title></head><body><p>Hello</p></body></html>
645 let mut doc = Document::new();
646 let root = doc.root();
647
648 let html = doc.create_element("html");
649 let head = doc.create_element("head");
650 let title = doc.create_element("title");
651 let title_text = doc.create_text("Test");
652 let body = doc.create_element("body");
653 let p = doc.create_element("p");
654 let p_text = doc.create_text("Hello");
655
656 doc.append_child(root, html);
657 doc.append_child(html, head);
658 doc.append_child(head, title);
659 doc.append_child(title, title_text);
660 doc.append_child(html, body);
661 doc.append_child(body, p);
662 doc.append_child(p, p_text);
663
664 // Verify structure.
665 assert_eq!(doc.tag_name(html), Some("html"));
666 assert_eq!(doc.parent(html), Some(root));
667
668 let html_children: Vec<NodeId> = doc.children(html).collect();
669 assert_eq!(html_children, vec![head, body]);
670
671 let head_children: Vec<NodeId> = doc.children(head).collect();
672 assert_eq!(head_children, vec![title]);
673
674 let title_children: Vec<NodeId> = doc.children(title).collect();
675 assert_eq!(title_children, vec![title_text]);
676 assert_eq!(doc.text_content(title_text), Some("Test"));
677
678 let body_children: Vec<NodeId> = doc.children(body).collect();
679 assert_eq!(body_children, vec![p]);
680
681 let p_children: Vec<NodeId> = doc.children(p).collect();
682 assert_eq!(p_children, vec![p_text]);
683 assert_eq!(doc.text_content(p_text), Some("Hello"));
684 }
685
686 #[test]
687 fn build_tree_with_attributes() {
688 let mut doc = Document::new();
689 let root = doc.root();
690
691 let a = doc.create_element("a");
692 doc.set_attribute(a, "href", "https://example.com");
693 doc.set_attribute(a, "class", "link");
694 doc.append_child(root, a);
695
696 let text = doc.create_text("Click here");
697 doc.append_child(a, text);
698
699 assert_eq!(doc.get_attribute(a, "href"), Some("https://example.com"));
700 assert_eq!(doc.get_attribute(a, "class"), Some("link"));
701 assert_eq!(doc.text_content(text), Some("Click here"));
702 }
703
704 #[test]
705 fn nested_children_traversal() {
706 // <div><span><em>deep</em></span></div>
707 let mut doc = Document::new();
708 let root = doc.root();
709
710 let div = doc.create_element("div");
711 let span = doc.create_element("span");
712 let em = doc.create_element("em");
713 let text = doc.create_text("deep");
714
715 doc.append_child(root, div);
716 doc.append_child(div, span);
717 doc.append_child(span, em);
718 doc.append_child(em, text);
719
720 // Walk down.
721 let mut current = doc.first_child(root).unwrap();
722 assert_eq!(doc.tag_name(current), Some("div"));
723
724 current = doc.first_child(current).unwrap();
725 assert_eq!(doc.tag_name(current), Some("span"));
726
727 current = doc.first_child(current).unwrap();
728 assert_eq!(doc.tag_name(current), Some("em"));
729
730 let leaf = doc.first_child(current).unwrap();
731 assert_eq!(doc.text_content(leaf), Some("deep"));
732
733 // Walk back up.
734 assert_eq!(doc.parent(leaf).map(|n| doc.tag_name(n)), Some(Some("em")));
735 }
736
737 #[test]
738 fn document_len_and_is_empty() {
739 let doc = Document::new();
740 assert_eq!(doc.len(), 1); // root only
741 assert!(doc.is_empty()); // no children besides root
742
743 let mut doc2 = Document::new();
744 let _ = doc2.create_element("div");
745 assert_eq!(doc2.len(), 2);
746 assert!(!doc2.is_empty());
747 }
748
749 #[test]
750 fn default_document() {
751 let doc = Document::default();
752 assert_eq!(doc.root(), NodeId(0));
753 }
754
755 #[test]
756 fn node_id_equality() {
757 let id1 = NodeId(5);
758 let id2 = NodeId(5);
759 let id3 = NodeId(6);
760 assert_eq!(id1, id2);
761 assert_ne!(id1, id3);
762 }
763
764 #[test]
765 #[should_panic(expected = "reference node is not a child of parent")]
766 fn insert_before_wrong_parent_panics() {
767 let mut doc = Document::new();
768 let root = doc.root();
769 let a = doc.create_element("a");
770 let b = doc.create_element("b");
771 let c = doc.create_element("c");
772 doc.append_child(root, a);
773 // b is not a child of root, so this should panic.
774 doc.insert_before(root, c, b);
775 }
776
777 #[test]
778 #[should_panic(expected = "node is not a child of parent")]
779 fn remove_child_wrong_parent_panics() {
780 let mut doc = Document::new();
781 let root = doc.root();
782 let a = doc.create_element("a");
783 // a is not attached to root.
784 doc.remove_child(root, a);
785 }
786
787 #[test]
788 fn insert_before_moves_from_old_parent() {
789 let mut doc = Document::new();
790 let root = doc.root();
791 let parent1 = doc.create_element("div");
792 let parent2 = doc.create_element("span");
793 let child = doc.create_element("p");
794 let reference = doc.create_element("em");
795
796 doc.append_child(root, parent1);
797 doc.append_child(root, parent2);
798 doc.append_child(parent1, child);
799 doc.append_child(parent2, reference);
800
801 // Move child from parent1 to parent2 before reference.
802 doc.insert_before(parent2, child, reference);
803
804 assert_eq!(doc.parent(child), Some(parent2));
805 assert!(doc.first_child(parent1).is_none());
806 let children: Vec<NodeId> = doc.children(parent2).collect();
807 assert_eq!(children, vec![child, reference]);
808 }
809
810 #[test]
811 fn comment_in_tree() {
812 let mut doc = Document::new();
813 let root = doc.root();
814 let comment = doc.create_comment("TODO: add content");
815 let div = doc.create_element("div");
816 doc.append_child(root, comment);
817 doc.append_child(root, div);
818
819 let children: Vec<NodeId> = doc.children(root).collect();
820 assert_eq!(children, vec![comment, div]);
821 assert_eq!(doc.text_content(comment), Some("TODO: add content"));
822 }
823}