#![allow(clippy::approx_constant, clippy::unreadable_literal)]
use tinyxml2::{Attribute, Document, Result, XmlError};
#[test]
fn test_factory_methods() {
let mut doc = Document::new();
let root = doc.root();
assert_eq!(doc.parent(root), None);
let el = doc.new_element("test");
let txt = doc.new_text("hello");
let cdata = doc.new_cdata("world");
let comment = doc.new_comment("this is a comment");
let decl = doc.new_declaration("xml version=\"1.0\"");
let unknown = doc.new_unknown("DOCTYPE html");
assert_eq!(doc.parent(el), None);
assert_eq!(doc.parent(txt), None);
assert_eq!(doc.parent(cdata), None);
assert_eq!(doc.parent(comment), None);
assert_eq!(doc.parent(decl), None);
assert_eq!(doc.parent(unknown), None);
}
#[test]
fn test_tree_mutations_end_child() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, el2)?;
assert_eq!(doc.parent(el1), Some(root));
assert_eq!(doc.parent(el2), Some(root));
assert_eq!(doc.first_child(root), Some(el1));
assert_eq!(doc.last_child(root), Some(el2));
assert_eq!(doc.next_sibling(el1), Some(el2));
assert_eq!(doc.prev_sibling(el2), Some(el1));
assert_eq!(doc.next_sibling(el2), None);
assert_eq!(doc.prev_sibling(el1), None);
Ok(())
}
#[test]
fn test_tree_mutations_first_child() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
doc.insert_first_child(root, el1)?;
doc.insert_first_child(root, el2)?;
assert_eq!(doc.first_child(root), Some(el2));
assert_eq!(doc.last_child(root), Some(el1));
assert_eq!(doc.next_sibling(el2), Some(el1));
assert_eq!(doc.prev_sibling(el1), Some(el2));
Ok(())
}
#[test]
fn test_tree_mutations_after_child() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
let el3 = doc.new_element("el3");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, el3)?;
doc.insert_after_child(el1, el2)?;
assert_eq!(doc.first_child(root), Some(el1));
assert_eq!(doc.next_sibling(el1), Some(el2));
assert_eq!(doc.next_sibling(el2), Some(el3));
assert_eq!(doc.last_child(root), Some(el3));
Ok(())
}
#[test]
fn test_tree_mutations_delete_child() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
let el3 = doc.new_element("el3");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, el2)?;
doc.insert_end_child(root, el3)?;
doc.delete_child(root, el2)?;
assert_eq!(doc.first_child(root), Some(el1));
assert_eq!(doc.next_sibling(el1), Some(el3));
assert_eq!(doc.prev_sibling(el3), Some(el1));
assert_eq!(doc.parent(el2), None);
Ok(())
}
#[test]
fn test_tree_mutations_delete_children() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, el2)?;
doc.delete_children(root)?;
assert_eq!(doc.first_child(root), None);
assert_eq!(doc.last_child(root), None);
Ok(())
}
#[test]
fn test_tree_mutations_delete_node() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, el2)?;
doc.delete_node(el1)?;
assert_eq!(doc.first_child(root), Some(el2));
assert_eq!(doc.prev_sibling(el2), None);
assert!(doc.delete_node(root).is_err());
Ok(())
}
#[test]
fn test_hierarchy_violation_cycles() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("el1");
let el2 = doc.new_element("el2");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(el1, el2)?;
let res = doc.insert_end_child(el2, el1);
assert!(res.is_err());
let res = doc.insert_end_child(el1, root);
assert!(res.is_err());
Ok(())
}
#[test]
fn test_navigation_element_filters() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el1 = doc.new_element("item");
let txt = doc.new_text("some text");
let el2 = doc.new_element("special");
let el3 = doc.new_element("item");
doc.insert_end_child(root, el1)?;
doc.insert_end_child(root, txt)?;
doc.insert_end_child(root, el2)?;
doc.insert_end_child(root, el3)?;
assert_eq!(doc.first_child_element(root, None), Some(el1));
assert_eq!(doc.first_child_element(root, Some("special")), Some(el2));
assert_eq!(doc.first_child_element(root, Some("missing")), None);
assert_eq!(doc.last_child_element(root, None), Some(el3));
assert_eq!(doc.last_child_element(root, Some("special")), Some(el2));
assert_eq!(doc.next_sibling_element(el1, None), Some(el2)); assert_eq!(doc.next_sibling_element(el1, Some("item")), Some(el3));
assert_eq!(doc.prev_sibling_element(el3, None), Some(el2));
assert_eq!(doc.prev_sibling_element(el3, Some("item")), Some(el1));
assert_eq!(doc.root_element(), Some(el1));
Ok(())
}
#[test]
fn test_attributes() -> Result<()> {
let mut doc = Document::new();
let el = doc.new_element("node");
assert_eq!(doc.attribute(el, "a"), None);
assert_eq!(doc.attribute_count(el), 0);
doc.set_attribute(el, "a", "1")?;
doc.set_attribute(el, "b", "2")?;
assert_eq!(doc.attribute(el, "a"), Some("1"));
assert_eq!(doc.attribute(el, "b"), Some("2"));
assert_eq!(doc.attribute_count(el), 2);
doc.set_attribute(el, "a", "10")?;
assert_eq!(doc.attribute(el, "a"), Some("10"));
assert_eq!(doc.attribute_count(el), 2);
let first = doc.first_attribute(el).unwrap();
assert_eq!(first.name, "a");
assert_eq!(first.value, "10");
assert_eq!(doc.find_attribute(el, "b").unwrap().value, "2");
let attrs: Vec<Attribute> = doc.iterate_attributes(el).cloned().collect();
assert_eq!(attrs.len(), 2);
assert_eq!(attrs[0].name, "a");
assert_eq!(attrs[1].name, "b");
doc.delete_attribute(el, "a")?;
assert_eq!(doc.attribute(el, "a"), None);
assert_eq!(doc.attribute_count(el), 1);
Ok(())
}
#[test]
fn test_typed_attribute_access() -> Result<()> {
let mut doc = Document::new();
let el = doc.new_element("node");
doc.set_attribute(el, "int", "42")?;
doc.set_attribute(el, "uint", "100")?;
doc.set_attribute(el, "int64", "-9223372036854775808")?;
doc.set_attribute(el, "bool_t", "true")?;
doc.set_attribute(el, "bool_1", "1")?;
doc.set_attribute(el, "bool_f", "false")?;
doc.set_attribute(el, "double", "3.14159")?;
doc.set_attribute(el, "float", "2.718")?;
doc.set_attribute(el, "bad", "abc")?;
assert_eq!(doc.query_int_attribute(el, "int")?, 42);
assert_eq!(doc.query_unsigned_attribute(el, "uint")?, 100);
assert_eq!(
doc.query_int64_attribute(el, "int64")?,
-9223372036854775808
);
assert!(doc.query_bool_attribute(el, "bool_t")?);
assert!(doc.query_bool_attribute(el, "bool_1")?);
assert!(!doc.query_bool_attribute(el, "bool_f")?);
assert!((doc.query_double_attribute(el, "double")? - 3.14159).abs() < 1e-5);
assert!((doc.query_float_attribute(el, "float")? - 2.718).abs() < 1e-5);
assert!(doc.query_int_attribute(el, "bad").is_err());
assert!(doc.query_bool_attribute(el, "bad").is_err());
assert_eq!(doc.int_attribute(el, "int", 0), 42);
assert_eq!(doc.int_attribute(el, "bad", 99), 99);
assert_eq!(doc.int_attribute(el, "missing", -1), -1);
assert!(doc.bool_attribute(el, "bool_t", false));
assert!(!doc.bool_attribute(el, "bad", false));
assert!(doc.bool_attribute(el, "missing", true));
Ok(())
}
#[test]
fn test_text_helpers() -> Result<()> {
let mut doc = Document::new();
let el = doc.new_element("node");
assert_eq!(doc.get_text(el), None);
doc.set_text(el, "first text")?;
assert_eq!(doc.get_text(el), Some("first text"));
doc.set_text(el, "updated text")?;
assert_eq!(doc.get_text(el), Some("updated text"));
let child1 = doc.first_child(el).unwrap();
assert_eq!(doc.next_sibling(child1), None);
Ok(())
}
#[test]
fn test_typed_text_access() -> Result<()> {
let mut doc = Document::new();
let el = doc.new_element("node");
doc.set_text(el, "123")?;
assert_eq!(doc.query_int_text(el)?, 123);
assert_eq!(doc.int_text(el, 0), 123);
doc.set_text(el, "true")?;
assert!(doc.query_bool_text(el)?);
assert!(doc.bool_text(el, false));
doc.set_text(el, "3.14")?;
assert!((doc.query_double_text(el)? - 3.14).abs() < 1e-5);
doc.set_text(el, "not a number")?;
assert_eq!(doc.query_int_text(el), Err(XmlError::CanNotConvertText));
assert_eq!(doc.int_text(el, 999), 999);
Ok(())
}
#[test]
fn test_cloning() -> Result<()> {
let mut doc = Document::new();
let el1 = doc.new_element("parent");
doc.set_attribute(el1, "attr", "val")?;
let child = doc.new_element("child");
doc.insert_end_child(el1, child)?;
let shallow = doc.shallow_clone(el1)?;
assert_eq!(doc.attribute(shallow, "attr"), Some("val"));
assert_eq!(doc.first_child(shallow), None);
let deep = doc.deep_clone(el1)?;
assert_eq!(doc.attribute(deep, "attr"), Some("val"));
let deep_child = doc.first_child(deep).unwrap();
assert_ne!(deep_child, child); assert_eq!(doc.parent(deep_child), Some(deep));
doc.set_attribute(el1, "attr", "mutated")?;
assert_eq!(doc.attribute(deep, "attr"), Some("val"));
Ok(())
}
#[test]
fn test_stale_node_id_checks() -> Result<()> {
let mut doc = Document::new();
let root = doc.root();
let el = doc.new_element("el");
doc.insert_end_child(root, el)?;
doc.delete_node(el)?;
assert_eq!(doc.parent(el), None);
assert_eq!(doc.first_child(el), None);
assert_eq!(doc.attribute(el, "any"), None);
assert!(doc.set_attribute(el, "any", "val").is_err());
assert!(doc.delete_node(el).is_err());
Ok(())
}