From b612d19871abe74a0e7b79851468fb3bd08531cd Mon Sep 17 00:00:00 2001 From: Mingun Date: Tue, 2 May 2023 22:06:49 +0500 Subject: [PATCH 1/2] Add regression tests for #597 failures (25): ns_reader.rs (24): reader::ns_reader::read_text::cdata reader::ns_reader::read_text::comment reader::ns_reader::read_text::decl reader::ns_reader::read_text::doctype reader::ns_reader::read_text::empty reader::ns_reader::read_text::pi reader::ns_reader::read_text::start reader::ns_reader::read_text::text reader::ns_reader::read_to_end::cdata reader::ns_reader::read_to_end::comment reader::ns_reader::read_to_end::decl reader::ns_reader::read_to_end::doctype reader::ns_reader::read_to_end::empty reader::ns_reader::read_to_end::pi reader::ns_reader::read_to_end::start reader::ns_reader::read_to_end::text reader::ns_reader::read_to_end_into::cdata reader::ns_reader::read_to_end_into::comment reader::ns_reader::read_to_end_into::decl reader::ns_reader::read_to_end_into::doctype reader::ns_reader::read_to_end_into::empty reader::ns_reader::read_to_end_into::pi reader::ns_reader::read_to_end_into::start reader::ns_reader::read_to_end_into::text issues.rs (1) issue597 --- src/reader/ns_reader.rs | 915 ++++++++++++++++++++++++++++++++++++++++ tests/issues.rs | 37 +- 2 files changed, 950 insertions(+), 2 deletions(-) diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs index a3b33746..e30b286f 100644 --- a/src/reader/ns_reader.rs +++ b/src/reader/ns_reader.rs @@ -922,3 +922,918 @@ impl Deref for NsReader { &self.reader } } + +#[cfg(test)] +mod read_to_end { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 45..52 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!(reader.read_event().unwrap(), Event::PI(BytesPI::new("pi"))); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.config_mut().check_end_names = false; + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 29..36 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.config_mut().check_end_names = false; + reader.config_mut().allow_unmatched_ends = true; + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 28..35 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!( + reader.read_to_end(QName(b"root")).unwrap(), + 41..48 // + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } +} + +#[cfg(test)] +mod read_to_end_into { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 45..52 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::PI(BytesPI::new("pi")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 38..45 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + reader.config_mut().check_end_names = false; + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 29..36 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + reader.config_mut().check_end_names = false; + reader.config_mut().allow_unmatched_ends = true; + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 30..37 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 28..35 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + let buf = &mut Vec::new(); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event_into(buf).unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!( + reader.read_to_end_into(QName(b"root"), buf).unwrap(), + 41..48 // + ); + assert_eq!( + reader.read_resolved_event_into(buf).unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event_into(buf).unwrap(), Event::Eof); + } +} + +#[cfg(test)] +mod read_text { + use super::*; + use crate::events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText}; + use crate::name::Namespace; + use pretty_assertions::assert_eq; + use ResolveResult::*; + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn decl() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Decl(BytesDecl::new("1.0", None, None)) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + /// Yes, this test contains invalid XML but since we can parse it, we check + /// that it does not break our parser + #[test] + fn doctype() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::DocType(BytesText::new("dtd")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn pi() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!(reader.read_event().unwrap(), Event::PI(BytesPI::new("pi"))); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn comment() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Comment(BytesText::new("comment")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn start() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.config_mut().check_end_names = false; + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn end() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + reader.config_mut().check_end_names = false; + reader.config_mut().allow_unmatched_ends = true; + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::End(BytesEnd::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn empty() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Empty(BytesStart::new("tag")), + ) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn text() { + let mut reader = NsReader::from_str( + "\ + \ + text\ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::Text(BytesText::new("text")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } + + #[test] + fn cdata() { + let mut reader = NsReader::from_str( + "\ + \ + \ + \ + \ + ", + ); + assert_eq!( + reader.read_resolved_event().unwrap(), + ( + Bound(Namespace(b"namespace")), + Event::Start(BytesStart::from_content("root xmlns='namespace'", 4)), + ) + ); + assert_eq!( + reader.read_event().unwrap(), + Event::CData(BytesCData::new("cdata")) + ); + assert_eq!(reader.read_text(QName(b"root")).unwrap(), ""); + assert_eq!( + reader.read_resolved_event().unwrap(), + (Unbound, Event::Empty(BytesStart::new("element"))) + ); + assert_eq!(reader.read_event().unwrap(), Event::Eof); + } +} diff --git a/tests/issues.rs b/tests/issues.rs index 966aa9ad..799f7f17 100644 --- a/tests/issues.rs +++ b/tests/issues.rs @@ -8,8 +8,8 @@ use std::sync::mpsc; use quick_xml::errors::{Error, IllFormedError, SyntaxError}; use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event}; -use quick_xml::name::QName; -use quick_xml::reader::Reader; +use quick_xml::name::{Namespace, QName, ResolveResult}; +use quick_xml::reader::{NsReader, Reader}; use quick_xml::utils::Bytes; use pretty_assertions::assert_eq; @@ -190,6 +190,39 @@ fn issue590() { } } +#[test] +fn issue597() { + const S: &'static str = r#" + + + + + + + + + + "#; + + let mut reader = NsReader::from_str(S); + let objects_ns = loop { + let (ns, ev) = reader.read_resolved_event().unwrap(); + match ev { + Event::Start(v) if v.local_name().as_ref() == b"xmlfilecontent_test" => { + reader.read_to_end(v.name()).unwrap(); + } + Event::Empty(v) if v.local_name().as_ref() == b"objects" => break ns, + _ => (), + } + }; + assert_eq!( + objects_ns, + ResolveResult::Bound(Namespace( + b"http://oval.mitre.org/XMLSchema/oval-definitions-5" + )) + ); +} + /// Regression test for https://github.com/tafia/quick-xml/issues/604 mod issue604 { use super::*; From f585f99cb4d62a0486a2467e7e1cee67b3c4a3b4 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 10 Jun 2023 21:21:56 +0500 Subject: [PATCH 2/2] Fix #597: Pop namespace scope after NsReader::read_to_end[_into] and read_text failures (4): reader::ns_reader::read_text::start reader::ns_reader::read_text::text reader::ns_reader::read_to_end::start reader::ns_reader::read_to_end_into::start --- Changelog.md | 5 +++++ src/reader/async_tokio.rs | 6 +++++- src/reader/ns_reader.rs | 22 ++++++++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Changelog.md b/Changelog.md index 3f4ae2ec..cbdbf8c5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,8 +18,13 @@ ### Bug Fixes +- [#597]: Fixed incorrect processing of namespace scopes in `NsReader::read_to_end`. + The scope started by a start element was not ended after that call. + ### Misc Changes +[#597]: https://github.com/tafia/quick-xml/issues/597 + ## 0.39.0 -- 2026-01-11 diff --git a/src/reader/async_tokio.rs b/src/reader/async_tokio.rs index 84a5681b..76e6138c 100644 --- a/src/reader/async_tokio.rs +++ b/src/reader/async_tokio.rs @@ -337,7 +337,11 @@ impl NsReader { ) -> Result { // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should // match literally the start name. See `Config::check_end_names` documentation - self.reader.read_to_end_into_async(end, buf).await + let result = self.reader.read_to_end_into_async(end, buf).await?; + // read_to_end_into_async will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(); + Ok(result) } /// An asynchronous version of [`read_resolved_event_into()`]. Reads the next diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs index e30b286f..d8dd4d80 100644 --- a/src/reader/ns_reader.rs +++ b/src/reader/ns_reader.rs @@ -23,7 +23,7 @@ pub struct NsReader { /// An XML reader pub(super) reader: Reader, /// A buffer to manage namespaces - ns_resolver: NamespaceResolver, + pub(super) ns_resolver: NamespaceResolver, /// We cannot pop data from the namespace stack until returned `Empty` or `End` /// event will be processed by the user, so we only mark that we should that /// in the next [`Self::read_event_impl()`] call. @@ -604,7 +604,11 @@ impl NsReader { pub fn read_to_end_into(&mut self, end: QName, buf: &mut Vec) -> Result { // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should // match literally the start name. See `Config::check_end_names` documentation - self.reader.read_to_end_into(end, buf) + let result = self.reader.read_to_end_into(end, buf)?; + // read_to_end_into will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(); + Ok(result) } } @@ -840,7 +844,11 @@ impl<'i> NsReader<&'i [u8]> { pub fn read_to_end(&mut self, end: QName) -> Result { // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should // match literally the start name. See `Config::check_end_names` documentation - self.reader.read_to_end(end) + let result = self.reader.read_to_end(end)?; + // read_to_end will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(); + Ok(result) } /// Reads content between start and end tags, including any markup. This @@ -910,7 +918,13 @@ impl<'i> NsReader<&'i [u8]> { /// [`decoder()`]: Reader::decoder() #[inline] pub fn read_text(&mut self, end: QName) -> Result> { - self.reader.read_text(end) + // According to the https://www.w3.org/TR/xml11/#dt-etag, end name should + // match literally the start name. See `Self::check_end_names` documentation + let result = self.reader.read_text(end)?; + // read_text will consume closing tag. Because nobody can access to its + // content anymore, we directly pop namespace of the opening tag + self.ns_resolver.pop(); + Ok(result) } }