use fastxml::Parser;
use std::io::Cursor;
fn rejected_by_both(xml: &str) -> (bool, bool) {
let dom = Parser::from(xml.as_bytes()).parse().is_err();
let streaming = Parser::from_reader(Cursor::new(xml.as_bytes().to_vec()))
.for_each_event(|_| Ok(()))
.is_err();
(dom, streaming)
}
fn assert_rejected(xml: &str, why: &str) {
let (dom, streaming) = rejected_by_both(xml);
assert!(dom, "DOM should reject {why}: {xml:?}");
assert!(streaming, "streaming should reject {why}: {xml:?}");
}
fn assert_accepted(xml: &str, why: &str) {
let (dom, streaming) = rejected_by_both(xml);
assert!(!dom, "DOM should accept {why}: {xml:?}");
assert!(!streaming, "streaming should accept {why}: {xml:?}");
}
#[test]
fn rejects_no_document_element() {
assert_rejected("", "an empty document");
assert_rejected(" \n ", "a whitespace-only document");
assert_rejected("<!-- just a comment -->", "a comment-only document");
}
#[test]
fn rejects_second_root_element() {
assert_rejected("<a/><b/>", "a second document element");
assert_rejected("<a></a><b></b>", "a second document element");
}
#[test]
fn rejects_content_after_root() {
assert_rejected("<a/>trailing", "text after the root element");
assert_rejected("<a/> ", "a character reference after the root element");
}
#[test]
fn rejects_content_before_root() {
assert_rejected("illegal<a/>", "text before the root element");
assert_rejected("<![CDATA[x]]><a/>", "a CDATA section in the prolog");
}
#[test]
fn rejects_cdata_outside_root() {
assert_rejected("<a/><![CDATA[x]]>", "a CDATA section in the epilog");
}
#[test]
fn rejects_unclosed_root() {
assert_rejected("<a>", "an unclosed root element");
assert_rejected("<a><b></b>", "an unclosed root element");
}
#[test]
fn rejects_cdata_close_in_char_data() {
assert_rejected("<a>]]></a>", "']]>' in character data");
assert_rejected("<a>x]]]>y</a>", "']]>' in character data");
}
#[test]
fn rejects_less_than_in_attribute_value() {
assert_rejected("<a x=\"<\"/>", "'<' in an attribute value");
assert_rejected("<a x=\"a<b\"></a>", "'<' in an attribute value");
}
#[test]
fn rejects_bad_pi_target() {
assert_rejected("<a><? ?></a>", "a processing instruction with no target");
assert_rejected("<a><?XmL foo?></a>", "the reserved target 'xml' (any case)");
}
#[test]
fn rejects_misplaced_or_duplicate_doctype() {
assert_rejected("<a/><!DOCTYPE a>", "a DOCTYPE after the document element");
assert_rejected(
"<!DOCTYPE a><!DOCTYPE a><a/>",
"a duplicate DOCTYPE declaration",
);
}
#[test]
fn accepts_well_formed_prolog_and_epilog() {
assert_accepted(
"<?xml version=\"1.0\"?><!-- c --><?pi data?>\n<root/>\n<!-- after -->\n<?pi x?>",
"comments, PIs and white space around the root",
);
}
#[test]
fn accepts_escaped_gt_after_brackets_in_text() {
assert_accepted("<a>x]]>y</a>", "']]>' in character data");
}
#[test]
fn accepts_gt_inside_internal_subset_literal() {
assert_accepted(
"<!DOCTYPE foo [\n<!ELEMENT foo ANY>\n<!ENTITY gt \">\">\n]>\n<foo>ok</foo>",
"a '>' inside an internal-subset entity value",
);
}
#[test]
fn accepts_non_reserved_xml_prefixed_pi_target() {
assert_accepted(
"<a><?xml-stylesheet href=\"x\"?></a>",
"a PI target that merely starts with 'xml'",
);
}