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 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(())
}