web engine - experimental web browser
at x25519 823 lines 26 kB view raw
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}