use crate::XmlVersion;
use crate::errors::Error;
use crate::events::Event;
use crate::name::{Namespace, NamespaceError, PrefixDeclaration, QName, ResolveResult};
use crate::reader::{DEFAULT_MAX_ELEMENT_DEPTH, NsReader};
type TestResult = Result<(), Error>;
fn expect_start<'i>(reader: &mut NsReader<&'i [u8]>) -> Event<'i> {
match reader.read_event().expect("event") {
e @ (Event::Start(_) | Event::Empty(_)) => e,
other => panic!("expected start/empty, got {:?}", other),
}
}
#[test]
fn default_namespace_binds_unprefixed_element() -> TestResult {
let mut reader = NsReader::from_str(r#"<tag xmlns="urn:d">x</tag>"#);
match reader.read_resolved_event()? {
(ns, Event::Start(e)) => {
assert_eq!(ns, ResolveResult::Bound(Namespace(b"urn:d")));
assert_eq!(e.local_name().as_ref(), b"tag");
}
other => panic!("unexpected {:?}", other),
}
Ok(())
}
#[test]
fn unprefixed_attribute_is_unbound_even_with_default_ns() -> TestResult {
let mut reader = NsReader::from_str(r#"<tag xmlns="urn:d" a="1"/>"#);
let event = expect_start(&mut reader);
if let Event::Empty(e) = event {
assert_eq!(
reader.resolve_element(e.name()).0,
ResolveResult::Bound(Namespace(b"urn:d")),
);
let attr = e
.attributes()
.with_checks(false)
.find_map(|a| {
let a = a.expect("attr");
(a.key.as_ref() == b"a").then_some(a)
})
.expect("attr a");
assert_eq!(reader.resolve_attribute(attr.key).0, ResolveResult::Unbound,);
} else {
panic!("expected empty");
}
Ok(())
}
#[test]
fn resolve_flag_distinguishes_element_and_attribute() -> TestResult {
let mut reader = NsReader::from_str(r#"<tag xmlns="urn:d"/>"#);
let _ = reader.read_event()?;
assert_eq!(
reader.resolve(QName(b"x"), false).0,
ResolveResult::Bound(Namespace(b"urn:d")),
);
assert_eq!(reader.resolve(QName(b"x"), true).0, ResolveResult::Unbound);
Ok(())
}
#[test]
fn unknown_prefix_reports_unknown() -> TestResult {
let mut reader = NsReader::from_str(r#"<p:tag>x</p:tag>"#);
match reader.read_resolved_event()? {
(ns, Event::Start(_)) => {
assert_eq!(ns, ResolveResult::Unknown(b"p".to_vec()));
}
other => panic!("unexpected {:?}", other),
}
Ok(())
}
#[test]
fn nested_prefixes_resolve_to_nearest_binding() -> TestResult {
let xml = r#"<x:a xmlns:x="ns1"><x:b xmlns:x="ns2"><x:c/></x:b><x:d/></x:a>"#;
let mut reader = NsReader::from_str(xml);
match reader.read_resolved_event()? {
(ns, Event::Start(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns1"))),
other => panic!("a: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::Start(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns2"))),
other => panic!("b: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::Empty(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns2"))),
other => panic!("c: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::End(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns2"))),
other => panic!("/b: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::Empty(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns1"))),
other => panic!("d: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::End(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns1"))),
other => panic!("/a: {:?}", other),
}
assert_eq!(reader.read_resolved_event()?.1, Event::Eof);
Ok(())
}
#[test]
fn empty_element_scope_is_popped_after_next_read() -> TestResult {
let xml = r#"<x:a xmlns:x="ns1"><b xmlns:x="ns2"/><x:c/></x:a>"#;
let mut reader = NsReader::from_str(xml);
let _ = reader.read_resolved_event()?; let _ = reader.read_resolved_event()?; match reader.read_resolved_event()? {
(ns, Event::Empty(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns1"))),
other => panic!("c: {:?}", other),
}
Ok(())
}
#[test]
fn default_namespace_reset_to_empty() -> TestResult {
let xml = r#"<a xmlns="ns1"><b xmlns=""><c/></b></a>"#;
let mut reader = NsReader::from_str(xml);
match reader.read_resolved_event()? {
(ns, Event::Start(_)) => assert_eq!(ns, ResolveResult::Bound(Namespace(b"ns1"))),
other => panic!("a: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::Start(_)) => assert_eq!(ns, ResolveResult::Unbound),
other => panic!("b: {:?}", other),
}
match reader.read_resolved_event()? {
(ns, Event::Empty(_)) => assert_eq!(ns, ResolveResult::Unbound),
other => panic!("c: {:?}", other),
}
Ok(())
}
#[test]
fn prefixes_iterator_lists_in_scope_bindings() -> TestResult {
let mut reader = NsReader::from_str(r#"<tag xmlns="d" xmlns:a="a1" xmlns:b="b1"/>"#);
let _ = reader.read_event()?;
let mut prefixes = reader.prefixes().collect::<Vec<_>>();
prefixes.sort_by(|l, r| l.1.as_ref().cmp(r.1.as_ref()));
assert_eq!(
prefixes,
vec![
(PrefixDeclaration::Named(b"a"), Namespace(b"a1")),
(PrefixDeclaration::Named(b"b"), Namespace(b"b1")),
(PrefixDeclaration::Default, Namespace(b"d")),
],
);
Ok(())
}
#[test]
fn read_to_end_pops_scope() -> TestResult {
let xml = r#"<a xmlns:x="ns1"><x:inner/></a><x:after/>"#;
let mut reader = NsReader::from_str(xml);
reader.config_mut().allow_unmatched_ends = true;
reader.config_mut().check_end_names = false;
let start = match reader.read_event()? {
Event::Start(e) => e.into_owned(),
other => panic!("a: {:?}", other),
};
reader.read_to_end(start.name())?;
match reader.read_resolved_event()? {
(ns, Event::Empty(_)) => assert_eq!(ns, ResolveResult::Unknown(b"x".to_vec())),
other => panic!("after: {:?}", other),
}
Ok(())
}
#[test]
fn resolver_and_resolver_mut_are_exposed() -> TestResult {
let mut reader = NsReader::from_str(r#"<tag xmlns:a="a1"/>"#);
reader.resolver_mut().set_max_declarations_per_element(4);
assert_eq!(reader.resolver().max_declarations_per_element(), 4);
let _ = reader.read_event()?;
assert_eq!(reader.resolver().level(), 1);
Ok(())
}
#[test]
fn buffered_reader_resolves_like_slice_reader() -> TestResult {
let xml = r#"<x:tag xmlns:x="urn:x">t</x:tag>"#;
let mut reader = NsReader::from_reader(xml.as_bytes());
let mut buf = Vec::new();
match reader.read_resolved_event_into(&mut buf)? {
(ns, Event::Start(e)) => {
assert_eq!(ns, ResolveResult::Bound(Namespace(b"urn:x")));
assert_eq!(e.local_name().as_ref(), b"tag");
}
other => panic!("unexpected {:?}", other),
}
Ok(())
}
#[test]
fn too_many_declarations_is_an_error() {
let mut reader = NsReader::from_str(r#"<tag xmlns:a="1" xmlns:b="2" xmlns:c="3"/>"#);
reader.resolver_mut().set_max_declarations_per_element(2);
match reader.read_event() {
Err(Error::Namespace(_)) => {}
other => panic!("expected namespace error, got {:?}", other),
}
}
#[test]
fn deref_exposes_reader_inspection_methods() -> TestResult {
let mut reader = NsReader::from_str("<tag/>");
let _ = reader.read_event()?;
assert_eq!(reader.buffer_position(), 6);
Ok(())
}
fn nested_document(depth: usize) -> String {
let mut xml = String::new();
for i in 0..depth {
xml.push_str(&format!("<e{i} xmlns=\"urn:ns{i}\">"));
}
xml.push_str("text");
for i in (0..depth).rev() {
xml.push_str(&format!("</e{i}>"));
}
xml
}
#[test]
fn document_deeper_than_default_limit_errors_cleanly() {
let depth = DEFAULT_MAX_ELEMENT_DEPTH + 1;
let xml = nested_document(depth);
let mut reader = NsReader::from_str(&xml);
loop {
match reader.read_event() {
Ok(Event::Eof) => panic!("expected a TooDeeplyNested error before EOF"),
Ok(_) => {}
Err(Error::Namespace(inner)) => {
assert_eq!(
inner,
NamespaceError::TooDeeplyNested(DEFAULT_MAX_ELEMENT_DEPTH)
);
break;
}
Err(other) => panic!("expected a namespace error, got {other:?}"),
}
}
}
#[test]
fn a_binding_uses_the_normalized_attribute_value() -> TestResult {
for (document, expected) in [
(r#"<r xmlns:p="urn:a
b"><p:e/></r>"#, "urn:a\nb"),
(r#"<r xmlns:p="urn:a	b"><p:e/></r>"#, "urn:a\tb"),
("<r xmlns:p=\"urn:a\r\nb\"><p:e/></r>", "urn:a b"),
("<r xmlns:p=\"urn:a\tb\"><p:e/></r>", "urn:a b"),
(r#"<r xmlns:p="urn:a&b"><p:e/></r>"#, "urn:a&b"),
(r#"<r xmlns:p="urn:plain"><p:e/></r>"#, "urn:plain"),
] {
let mut reader = NsReader::from_str(document);
let root = match expect_start(&mut reader) {
Event::Start(e) => e,
other => panic!("unexpected {:?}", other),
};
let declared = root
.attributes()
.next()
.expect("the declaration")
.expect("a well-formed attribute")
.normalized_value(XmlVersion::Implicit1_0)
.expect("a normalizable value")
.into_owned();
assert_eq!(declared, expected, "in `{document}`");
match reader.read_resolved_event()? {
(ResolveResult::Bound(namespace), Event::Empty(_)) => {
assert_eq!(
std::str::from_utf8(namespace.into_inner()).expect("utf-8"),
declared,
"in `{document}`",
);
}
other => panic!("unexpected {:?}", other),
}
}
Ok(())
}
#[test]
fn a_declaration_using_a_document_entity_is_left_to_the_reader() -> TestResult {
let mut reader = NsReader::from_str(
r#"<!DOCTYPE r [<!ENTITY tilde "~">]><r xmlns:p="urn:a˜b"><p:e/></r>"#,
);
loop {
match reader.read_resolved_event()? {
(ResolveResult::Bound(namespace), Event::Empty(_)) => {
assert_eq!(namespace, Namespace(b"urn:a˜b"));
break;
}
(_, Event::Eof) => panic!("the prefixed element was never reached"),
_ => {}
}
}
let mut checking = NsReader::from_str(
r#"<!DOCTYPE foo [<!ENTITY tilde "~">]><foo xmlns:a="urn:~w" xmlns:b="urn:˜w"><bar a:attr="1" b:attr="2"/></foo>"#,
);
checking.config_mut().check_well_formedness = true;
let failure = loop {
match checking.read_resolved_event() {
Ok((_, Event::Eof)) => panic!("the duplicate expanded name went undetected"),
Ok(_) => {}
Err(error) => break error,
}
};
assert!(
failure.to_string().contains("more than once"),
"unexpected error: {failure}"
);
Ok(())
}
#[test]
fn raising_the_limit_allows_deep_nesting_without_corruption() -> TestResult {
let depth: usize = 70_000;
let xml = nested_document(depth);
let mut reader = NsReader::from_str(&xml);
reader.config_mut().max_element_depth = depth + 1;
let mut opens = 0usize;
let mut deepest_namespace: Option<Vec<u8>> = None;
loop {
match reader.read_resolved_event()? {
(ResolveResult::Bound(ns), Event::Start(_)) => {
opens += 1;
if opens == depth {
deepest_namespace = Some(ns.into_inner().to_vec());
}
}
(_, Event::Start(_)) => opens += 1,
(_, Event::Eof) => break,
_ => {}
}
}
assert_eq!(opens, depth);
assert_eq!(
deepest_namespace.as_deref(),
Some(format!("urn:ns{}", depth - 1).as_bytes()),
);
assert_eq!(reader.resolver().level(), 0);
Ok(())
}