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