use xml_dom::level2::convert::*; use xml_dom::level2::ext::dom_impl as ext_dom_impl; use xml_dom::level2::*; pub mod common; #[test] fn test_is_child_allowed() { // // This logic is shared by append, insert, and replace, so we only test once. // let test_matrix: Vec<(NodeType, Vec)> = vec![ ( NodeType::Element, vec![ NodeType::Element, NodeType::Text, NodeType::Comment, NodeType::ProcessingInstruction, NodeType::CData, NodeType::EntityReference, ], ), ( NodeType::Attribute, vec![NodeType::Text, NodeType::EntityReference], ), (NodeType::Text, vec![]), (NodeType::CData, vec![]), ( NodeType::EntityReference, vec![ NodeType::Element, NodeType::Text, NodeType::Comment, NodeType::ProcessingInstruction, NodeType::CData, NodeType::EntityReference, ], ), ( NodeType::Entity, vec![ NodeType::Element, NodeType::Text, NodeType::Comment, NodeType::ProcessingInstruction, NodeType::CData, NodeType::EntityReference, ], ), (NodeType::ProcessingInstruction, vec![]), (NodeType::Comment, vec![]), (NodeType::DocumentType, vec![]), ( NodeType::DocumentFragment, vec![ NodeType::Element, NodeType::Text, NodeType::Comment, NodeType::ProcessingInstruction, NodeType::CData, NodeType::EntityReference, ], ), (NodeType::Notation, vec![]), ]; let implementation = get_implementation(); let document_node = implementation .create_document(Some("http://www.w3.org/1999/xhtml"), Some("html"), None) .unwrap(); for (parent_type, allowed_child_types) in test_matrix { test_parent(document_node.clone(), parent_type, &allowed_child_types); } } #[test] fn test_insert_child_node() { let document_node = make_sibling_document(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); let mut_root = as_element_mut(&mut root_node).unwrap(); let child_nodes = mut_root.child_nodes(); compare_node_names( &child_nodes, &["child-1", "child-2", "child-3", "child-4", "child-5"], ); { common::sub_test("test_insert_child_node", "insert_before(_, mid_node)"); let mid_node = child_nodes.get(2).unwrap(); let new_child_node = ref_document.create_element("inserted-1").unwrap(); let result = mut_root.insert_before(new_child_node, Some(mid_node.clone())); assert!(result.is_ok()); let new_node = result.unwrap(); assert!(new_node.parent_node().is_some()); assert!(new_node.owner_document().is_some()); compare_node_names( &mut_root.child_nodes(), &[ "child-1", "child-2", "inserted-1", "child-3", "child-4", "child-5", ], ); } { common::sub_test("test_insert_child_node", "insert_before(_, first_node)"); let first_node = child_nodes.first().unwrap(); let new_child_node = ref_document.create_element("inserted-2").unwrap(); let result = mut_root.insert_before(new_child_node, Some(first_node.clone())); assert!(result.is_ok()); let new_node = result.unwrap(); assert!(new_node.parent_node().is_some()); assert!(new_node.owner_document().is_some()); compare_node_names( &mut_root.child_nodes(), &[ "inserted-2", "child-1", "child-2", "inserted-1", "child-3", "child-4", "child-5", ], ); } { common::sub_test("test_insert_child_node", "insert_before(_, last_node)"); let new_child_node = ref_document.create_element("inserted-3").unwrap(); let result = mut_root.insert_before(new_child_node, None); assert!(result.is_ok()); let new_node = result.unwrap(); assert!(new_node.parent_node().is_some()); assert!(new_node.owner_document().is_some()); compare_node_names( &mut_root.child_nodes(), &[ "inserted-2", "child-1", "child-2", "inserted-1", "child-3", "child-4", "child-5", "inserted-3", ], ); } { common::sub_test("test_insert_child_node", "insert_before(_, not_a_child)"); let not_a_child = ref_document.create_element("not-a-child").unwrap(); let new_child_node = ref_document.create_element("not-inserted").unwrap(); let result = mut_root.insert_before(new_child_node, Some(not_a_child)); assert!(result.is_err()); } } #[test] fn test_replace_child_node() { let document_node = make_sibling_document(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); let mut_root = as_element_mut(&mut root_node).unwrap(); let child_nodes = mut_root.child_nodes(); compare_node_names( &child_nodes, &["child-1", "child-2", "child-3", "child-4", "child-5"], ); { common::sub_test("test_replace_child_node", "remove_child(mid_node)"); let mid_node = child_nodes.get(2).unwrap(); let new_child_node = ref_document.create_element("inserted-1").unwrap(); let result = mut_root.replace_child(new_child_node, mid_node.clone()); assert!(result.is_ok()); compare_node_names( &mut_root.child_nodes(), &["child-1", "child-2", "inserted-1", "child-4", "child-5"], ); } { common::sub_test("test_replace_child_node", "remove_child(first_node)"); let first_node = child_nodes.first().unwrap(); let new_child_node = ref_document.create_element("inserted-2").unwrap(); let result = mut_root.replace_child(new_child_node, first_node.clone()); assert!(result.is_ok()); compare_node_names( &mut_root.child_nodes(), &["inserted-2", "child-2", "inserted-1", "child-4", "child-5"], ); } { common::sub_test("test_replace_child_node", "remove_child(last_node)"); let last_node = child_nodes.last().unwrap(); let new_child_node = ref_document.create_element("inserted-3").unwrap(); let result = mut_root.replace_child(new_child_node, last_node.clone()); assert!(result.is_ok()); compare_node_names( &mut_root.child_nodes(), &[ "inserted-2", "child-2", "inserted-1", "child-4", "inserted-3", ], ); } { common::sub_test("test_replace_child_node", "remove_child(not_a_child)"); let not_a_child = ref_document.create_element("not-a-child").unwrap(); let new_child_node = ref_document.create_element("not-inserted").unwrap(); let result = mut_root.replace_child(new_child_node, not_a_child); assert!(result.is_err()); } } #[test] fn test_remove_child_node() { let document_node = make_sibling_document(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); let mut_root = as_element_mut(&mut root_node).unwrap(); let child_nodes = mut_root.child_nodes(); compare_node_names( &child_nodes, &["child-1", "child-2", "child-3", "child-4", "child-5"], ); { common::sub_test("test_remove_child_node", "remove_child(mid_node)"); let mid_node = child_nodes.get(2).unwrap(); let result = mut_root.remove_child(mid_node.clone()); assert!(result.is_ok()); compare_node_names( &mut_root.child_nodes(), &["child-1", "child-2", "child-4", "child-5"], ); } { common::sub_test("test_remove_child_node", "remove_child(first_node)"); let first_node = child_nodes.first().unwrap(); let result = mut_root.remove_child(first_node.clone()); assert!(result.is_ok()); compare_node_names(&mut_root.child_nodes(), &["child-2", "child-4", "child-5"]); } { common::sub_test("test_remove_child_node", "remove_child(last_node)"); let last_node = child_nodes.last().unwrap(); let result = mut_root.remove_child(last_node.clone()); assert!(result.is_ok()); compare_node_names(&mut_root.child_nodes(), &["child-2", "child-4"]); } { common::sub_test("test_remove_child_node", "remove_child(not_a_child)"); let not_a_child = ref_document.create_element("not-a-child").unwrap(); let result = mut_root.remove_child(not_a_child); assert!(result.is_err()); } } #[test] fn test_next_sibling() { let document_node = make_sibling_document(); let ref_document = as_document(&document_node).unwrap(); let root_node = ref_document.document_element().unwrap(); let ref_root = as_element(&root_node).unwrap(); let child_nodes = ref_root.child_nodes(); // // Ask for siblings // let mid_node = child_nodes.get(2).unwrap(); let ref_mid = as_element(mid_node).unwrap(); assert_eq!(ref_mid.node_name().to_string(), "child-3".to_string()); common::sub_test("test_next_sibling", "next_sibling() 1"); let next_node = ref_mid.next_sibling().unwrap(); let ref_next = as_element(&next_node).unwrap(); assert_eq!(ref_next.node_name().to_string(), "child-4".to_string()); common::sub_test("test_next_sibling", "next_sibling() 2"); let last_node = ref_next.next_sibling().unwrap(); let ref_last = as_element(&last_node).unwrap(); assert_eq!(ref_last.node_name().to_string(), "child-5".to_string()); common::sub_test("test_next_sibling", "next_sibling() 3"); let no_node = ref_last.next_sibling(); assert!(no_node.is_none()); } #[test] fn test_previous_sibling() { let document_node = make_sibling_document(); let ref_document = as_document(&document_node).unwrap(); let root_node = ref_document.document_element().unwrap(); let ref_root = as_element(&root_node).unwrap(); let child_nodes = ref_root.child_nodes(); // // Ask for siblings // let mid_node = child_nodes.get(2).unwrap(); let ref_mid = as_element(mid_node).unwrap(); assert_eq!(ref_mid.node_name().to_string(), "child-3".to_string()); common::sub_test("test_previous_sibling", "previous_sibling() 1"); let previous_node = ref_mid.previous_sibling().unwrap(); let ref_previous = as_element(&previous_node).unwrap(); assert_eq!(ref_previous.node_name().to_string(), "child-2".to_string()); common::sub_test("test_previous_sibling", "previous_sibling() 2"); let first_node = ref_previous.previous_sibling().unwrap(); let ref_first = as_element(&first_node).unwrap(); assert_eq!(ref_first.node_name().to_string(), "child-1".to_string()); common::sub_test("test_previous_sibling", "previous_sibling() 3"); let no_node = ref_first.previous_sibling(); assert!(no_node.is_none()); } #[test] #[ignore] fn test_clone_node() { unimplemented!() } #[test] fn test_normalize() { let document_node = get_implementation() .create_document(Some("http://example.org/"), Some("root"), None) .unwrap(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); { let _safe_to_ignore = append_element_node(&mut root_node, "element-1"); let _safe_to_ignore = append_text_node(&mut root_node, "text-1"); let _safe_to_ignore = append_text_node(&mut root_node, "text-2"); let _safe_to_ignore = append_element_node(&mut root_node, "element-2"); let _safe_to_ignore = append_text_node(&mut root_node, "text-3"); let _safe_to_ignore = append_text_node(&mut root_node, ""); let _safe_to_ignore = append_text_node(&mut root_node, "text-4"); let _safe_to_ignore = append_element_node(&mut root_node, "element-3"); } { assert_eq!(root_node.child_nodes().len(), 8); } root_node.normalize(); { assert_eq!(root_node.child_nodes().len(), 5); } } #[test] fn test_normalize_empty() { let document_node = get_implementation() .create_document(Some("http://example.org/"), Some("root"), None) .unwrap(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); { let _safe_to_ignore = append_element_node(&mut root_node, "element-1"); let _safe_to_ignore = append_text_node(&mut root_node, ""); let _safe_to_ignore = append_element_node(&mut root_node, "element-2"); } { assert_eq!(root_node.child_nodes().len(), 3); } root_node.normalize(); { assert_eq!(root_node.child_nodes().len(), 2); } } #[test] fn test_wrong_document() { let document_1_node = get_implementation() .create_document(Some("http://example.org/"), Some("root-1"), None) .unwrap(); let document_1 = as_document(&document_1_node).unwrap(); let root_1_node = document_1.document_element().unwrap(); println!("root_1_node {:#?}", root_1_node); let document_2_node = get_implementation() .create_document(Some("http://example.org/"), Some("root-2"), None) .unwrap(); let document_2 = as_document(&document_2_node).unwrap(); let mut root_2_node = document_2.document_element().unwrap(); println!("root_2_node {:#?}", root_2_node); let root_2 = as_element_mut(&mut root_2_node).unwrap(); let result = root_2.append_child(root_1_node); assert_eq!(result, Err(Error::WrongDocument)) } // ------------------------------------------------------------------------------------------------ // Private Functions // ------------------------------------------------------------------------------------------------ fn make_node(document: RefNode, node_type: NodeType, prefix: &str) -> RefNode { let named = |s| format!("{}-{}", prefix, s); match node_type { NodeType::Element => document.create_element(&named("element")).unwrap(), NodeType::Attribute => document.create_attribute(&named("attribute")).unwrap(), NodeType::Text => document.create_text_node(&named("text")), NodeType::CData => document.create_cdata_section(&named("cdata")).unwrap(), NodeType::EntityReference => document.create_entity_reference(&named("text")).unwrap(), NodeType::ProcessingInstruction => document .create_processing_instruction(&named("pi"), None) .unwrap(), NodeType::Comment => document.create_comment(&named("comment")), NodeType::Document => document, NodeType::DocumentType => { let implementation = get_implementation(); implementation .create_document_type( "html", Some("-//W3C//DTD XHTML 1.0 Transitional//EN"), Some("http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"), ) .unwrap() } NodeType::DocumentFragment => document.create_document_fragment().unwrap(), // Created by dom_impl not Document NodeType::Entity => { ext_dom_impl::create_internal_entity(document, &named("entity"), "some value").unwrap() } NodeType::Notation => { ext_dom_impl::create_notation(document, &named("notation"), Some("file-name.xml"), None) .unwrap() } } } const ALL_CHILDREN: [NodeType; 12] = [ NodeType::Element, NodeType::Attribute, NodeType::Text, NodeType::CData, NodeType::EntityReference, NodeType::Entity, NodeType::ProcessingInstruction, NodeType::Comment, NodeType::Document, NodeType::DocumentType, NodeType::DocumentFragment, NodeType::Notation, ]; fn test_parent(document: RefNode, parent_type: NodeType, allowed: impl AsRef<[NodeType]>) { let mut parent_node = make_node(document.clone(), parent_type.clone(), "parent"); let allowed = allowed.as_ref(); for child_type in ALL_CHILDREN.iter() { common::sub_test( "test_is_child_allowed", &format!( "{:?}.append_child({:?}) -> {}?", parent_type, child_type, allowed.contains(child_type) ), ); let child_node = make_node(document.clone(), child_type.clone(), "child"); assert_eq!( parent_node.append_child(child_node).is_ok(), allowed.contains(child_type) ); } } fn append_element_node(parent_node: &mut RefNode, name: &str) -> RefNode { let mut_parent = as_element_mut(parent_node).unwrap(); let mut document_node = mut_parent.owner_document().unwrap(); let mut_document = as_document_mut(&mut document_node).unwrap(); let new_element_node = mut_document.create_element(name).unwrap(); let result = mut_parent.append_child(new_element_node.clone()); assert!(result.is_ok()); new_element_node } fn append_text_node(parent_node: &mut RefNode, content: &str) -> RefNode { let mut_parent = as_element_mut(parent_node).unwrap(); let mut document_node = mut_parent.owner_document().unwrap(); let mut_document = as_document_mut(&mut document_node).unwrap(); let new_text_node = mut_document.create_text_node(content); let result = mut_parent.append_child(new_text_node.clone()); assert!(result.is_ok()); new_text_node } fn make_sibling_document() -> RefNode { let document_node = get_implementation() .create_document(Some("http://example.org/"), Some("root"), None) .unwrap(); let ref_document = as_document(&document_node).unwrap(); let mut root_node = ref_document.document_element().unwrap(); { for index in 1..6 { let _safe_to_ignore = append_element_node(&mut root_node, &format!("child-{}", index)); } } { assert_eq!(root_node.child_nodes().len(), 5); } document_node } fn compare_node_names(nodes: impl AsRef<[RefNode]>, expected_names: &[&str]) { let names: Vec = nodes .as_ref() .iter() .map(|n| n.node_name().to_string()) .collect(); let expected_names: Vec = expected_names.iter().map(|s| String::from(*s)).collect(); assert_eq!(names, expected_names); }