use serde::serde_if_integer128;
macro_rules! deserialize_type {
($deserialize:ident => $visit:ident, $($mut:tt)?) => {
fn $deserialize<V>($($mut)? self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
let text = self.read_string()?;
visitor.$visit(text.parse()?)
}
};
}
macro_rules! deserialize_primitives {
($($mut:tt)?) => {
deserialize_type!(deserialize_i8 => visit_i8, $($mut)?);
deserialize_type!(deserialize_i16 => visit_i16, $($mut)?);
deserialize_type!(deserialize_i32 => visit_i32, $($mut)?);
deserialize_type!(deserialize_i64 => visit_i64, $($mut)?);
deserialize_type!(deserialize_u8 => visit_u8, $($mut)?);
deserialize_type!(deserialize_u16 => visit_u16, $($mut)?);
deserialize_type!(deserialize_u32 => visit_u32, $($mut)?);
deserialize_type!(deserialize_u64 => visit_u64, $($mut)?);
serde_if_integer128! {
deserialize_type!(deserialize_i128 => visit_i128, $($mut)?);
deserialize_type!(deserialize_u128 => visit_u128, $($mut)?);
}
deserialize_type!(deserialize_f32 => visit_f32, $($mut)?);
deserialize_type!(deserialize_f64 => visit_f64, $($mut)?);
fn deserialize_bool<V>($($mut)? self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
let text = self.read_string()?;
str2bool(&text, visitor)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_str<V>($($mut)? self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
let text = self.read_string()?;
match text {
Cow::Borrowed(string) => visitor.visit_borrowed_str(string),
Cow::Owned(string) => visitor.visit_string(string),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
Err(DeError::Unsupported("binary data content is not supported by XML format".into()))
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
#[inline]
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_struct("", &[], visitor)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
};
}
mod key;
mod map;
mod resolver;
mod simple_type;
mod text;
mod var;
pub use crate::errors::serialize::DeError;
pub use resolver::{EntityResolver, NoEntityResolver};
use crate::{
de::map::ElementMapAccess,
encoding::Decoder,
errors::Error,
events::{BytesCData, BytesEnd, BytesStart, BytesText, Event},
name::QName,
reader::Reader,
};
use serde::de::{self, Deserialize, DeserializeOwned, DeserializeSeed, SeqAccess, Visitor};
use std::borrow::Cow;
#[cfg(feature = "overlapped-lists")]
use std::collections::VecDeque;
use std::io::BufRead;
use std::mem::replace;
#[cfg(feature = "overlapped-lists")]
use std::num::NonZeroUsize;
use std::ops::Deref;
pub(crate) const TEXT_KEY: &str = "$text";
pub(crate) const VALUE_KEY: &str = "$value";
#[derive(Debug, PartialEq, Eq)]
pub struct Text<'a> {
text: Cow<'a, str>,
}
impl<'a> Deref for Text<'a> {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.text.deref()
}
}
impl<'a> From<&'a str> for Text<'a> {
#[inline]
fn from(text: &'a str) -> Self {
Self {
text: Cow::Borrowed(text),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum DeEvent<'a> {
Start(BytesStart<'a>),
End(BytesEnd<'a>),
Text(Text<'a>),
Eof,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PayloadEvent<'a> {
Start(BytesStart<'a>),
End(BytesEnd<'a>),
Text(BytesText<'a>),
CData(BytesCData<'a>),
DocType(BytesText<'a>),
Eof,
}
impl<'a> PayloadEvent<'a> {
#[inline]
fn into_owned(self) -> PayloadEvent<'static> {
match self {
PayloadEvent::Start(e) => PayloadEvent::Start(e.into_owned()),
PayloadEvent::End(e) => PayloadEvent::End(e.into_owned()),
PayloadEvent::Text(e) => PayloadEvent::Text(e.into_owned()),
PayloadEvent::CData(e) => PayloadEvent::CData(e.into_owned()),
PayloadEvent::DocType(e) => PayloadEvent::DocType(e.into_owned()),
PayloadEvent::Eof => PayloadEvent::Eof,
}
}
}
struct XmlReader<'i, R: XmlRead<'i>, E: EntityResolver = NoEntityResolver> {
reader: R,
lookahead: Result<PayloadEvent<'i>, DeError>,
entity_resolver: E,
}
impl<'i, R: XmlRead<'i>, E: EntityResolver> XmlReader<'i, R, E> {
fn new(mut reader: R, entity_resolver: E) -> Self {
let lookahead = reader.next();
Self {
reader,
lookahead,
entity_resolver,
}
}
fn is_empty(&self) -> bool {
matches!(self.lookahead, Ok(PayloadEvent::Eof))
}
#[inline(always)]
fn next_impl(&mut self) -> Result<PayloadEvent<'i>, DeError> {
replace(&mut self.lookahead, self.reader.next())
}
#[inline(always)]
fn need_trim_end(&self) -> bool {
!matches!(
self.lookahead,
Ok(PayloadEvent::Text(_)) | Ok(PayloadEvent::CData(_))
)
}
fn drain_text(&mut self, mut result: Cow<'i, str>) -> Result<DeEvent<'i>, DeError> {
loop {
match self.lookahead {
Ok(PayloadEvent::Text(_) | PayloadEvent::CData(_)) => {
let text = self.next_text()?;
let mut s = result.into_owned();
s += &text;
result = Cow::Owned(s);
}
_ => break,
}
}
Ok(DeEvent::Text(Text { text: result }))
}
#[inline(always)]
fn next_text(&mut self) -> Result<Cow<'i, str>, DeError> {
match self.next_impl()? {
PayloadEvent::Text(mut e) => {
if self.need_trim_end() {
e.inplace_trim_end();
}
Ok(e.unescape_with(|entity| self.entity_resolver.resolve(entity))?)
}
PayloadEvent::CData(e) => Ok(e.decode()?),
_ => unreachable!("Only `Text` and `CData` events can come here"),
}
}
fn next(&mut self) -> Result<DeEvent<'i>, DeError> {
loop {
return match self.next_impl()? {
PayloadEvent::Start(e) => Ok(DeEvent::Start(e)),
PayloadEvent::End(e) => Ok(DeEvent::End(e)),
PayloadEvent::Text(mut e) => {
if self.need_trim_end() && e.inplace_trim_end() {
continue;
}
self.drain_text(e.unescape_with(|entity| self.entity_resolver.resolve(entity))?)
}
PayloadEvent::CData(e) => self.drain_text(e.decode()?),
PayloadEvent::DocType(e) => {
self.entity_resolver
.capture(e)
.map_err(|err| DeError::Custom(format!("cannot parse DTD: {}", err)))?;
continue;
}
PayloadEvent::Eof => Ok(DeEvent::Eof),
};
}
}
#[inline]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.lookahead {
Ok(PayloadEvent::Start(ref e)) if e.name() == name => {
let result1 = self.reader.read_to_end(name);
let result2 = self.reader.read_to_end(name);
let _ = self.next_impl();
result1?;
result2?;
}
Ok(PayloadEvent::End(ref e)) if e.name() == name => {
let _ = self.next_impl();
}
Ok(_) => {
let result = self.reader.read_to_end(name);
let _ = self.next_impl();
result?;
}
Err(_) => {
self.next_impl()?;
}
}
Ok(())
}
#[inline]
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
}
pub fn from_str<'de, T>(s: &'de str) -> Result<T, DeError>
where
T: Deserialize<'de>,
{
let mut de = Deserializer::from_str(s);
T::deserialize(&mut de)
}
pub fn from_reader<R, T>(reader: R) -> Result<T, DeError>
where
R: BufRead,
T: DeserializeOwned,
{
let mut de = Deserializer::from_reader(reader);
T::deserialize(&mut de)
}
fn str2bool<'de, V>(value: &str, visitor: V) -> Result<V::Value, DeError>
where
V: de::Visitor<'de>,
{
match value {
"true" | "1" | "True" | "TRUE" | "t" | "Yes" | "YES" | "yes" | "y" => {
visitor.visit_bool(true)
}
"false" | "0" | "False" | "FALSE" | "f" | "No" | "NO" | "no" | "n" => {
visitor.visit_bool(false)
}
_ => Err(DeError::InvalidBoolean(value.into())),
}
}
fn deserialize_bool<'de, V>(value: &[u8], decoder: Decoder, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
#[cfg(feature = "encoding")]
{
let value = decoder.decode(value)?;
str2bool(value.as_ref(), visitor)
}
#[cfg(not(feature = "encoding"))]
{
match value {
b"true" | b"1" | b"True" | b"TRUE" | b"t" | b"Yes" | b"YES" | b"yes" | b"y" => {
visitor.visit_bool(true)
}
b"false" | b"0" | b"False" | b"FALSE" | b"f" | b"No" | b"NO" | b"no" | b"n" => {
visitor.visit_bool(false)
}
e => Err(DeError::InvalidBoolean(decoder.decode(e)?.into())),
}
}
}
pub struct Deserializer<'de, R, E: EntityResolver = NoEntityResolver>
where
R: XmlRead<'de>,
{
reader: XmlReader<'de, R, E>,
#[cfg(feature = "overlapped-lists")]
read: VecDeque<DeEvent<'de>>,
#[cfg(feature = "overlapped-lists")]
write: VecDeque<DeEvent<'de>>,
#[cfg(feature = "overlapped-lists")]
limit: Option<NonZeroUsize>,
#[cfg(not(feature = "overlapped-lists"))]
peek: Option<DeEvent<'de>>,
}
impl<'de, R, E> Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
fn new(reader: R, entity_resolver: E) -> Self {
Self {
reader: XmlReader::new(reader, entity_resolver),
#[cfg(feature = "overlapped-lists")]
read: VecDeque::new(),
#[cfg(feature = "overlapped-lists")]
write: VecDeque::new(),
#[cfg(feature = "overlapped-lists")]
limit: None,
#[cfg(not(feature = "overlapped-lists"))]
peek: None,
}
}
pub fn is_empty(&self) -> bool {
#[cfg(feature = "overlapped-lists")]
if self.read.is_empty() {
return self.reader.is_empty();
}
#[cfg(not(feature = "overlapped-lists"))]
if self.peek.is_none() {
return self.reader.is_empty();
}
false
}
#[cfg(feature = "overlapped-lists")]
pub fn event_buffer_size(&mut self, limit: Option<NonZeroUsize>) -> &mut Self {
self.limit = limit;
self
}
#[cfg(feature = "overlapped-lists")]
fn peek(&mut self) -> Result<&DeEvent<'de>, DeError> {
if self.read.is_empty() {
self.read.push_front(self.reader.next()?);
}
if let Some(event) = self.read.front() {
return Ok(event);
}
unreachable!()
}
#[cfg(not(feature = "overlapped-lists"))]
fn peek(&mut self) -> Result<&DeEvent<'de>, DeError> {
if self.peek.is_none() {
self.peek = Some(self.reader.next()?);
}
match self.peek.as_ref() {
Some(v) => Ok(v),
None => unreachable!(),
}
}
fn next(&mut self) -> Result<DeEvent<'de>, DeError> {
#[cfg(feature = "overlapped-lists")]
if let Some(event) = self.read.pop_front() {
return Ok(event);
}
#[cfg(not(feature = "overlapped-lists"))]
if let Some(e) = self.peek.take() {
return Ok(e);
}
self.reader.next()
}
#[cfg(feature = "overlapped-lists")]
#[inline]
#[must_use = "returned checkpoint should be used in `start_replay`"]
fn skip_checkpoint(&self) -> usize {
self.write.len()
}
#[cfg(feature = "overlapped-lists")]
fn skip(&mut self) -> Result<(), DeError> {
let event = self.next()?;
self.skip_event(event)?;
match self.write.back() {
Some(DeEvent::Start(e)) => {
let end = e.name().as_ref().to_owned();
let mut depth = 0;
loop {
let event = self.next()?;
match event {
DeEvent::Start(ref e) if e.name().as_ref() == end => {
self.skip_event(event)?;
depth += 1;
}
DeEvent::End(ref e) if e.name().as_ref() == end => {
self.skip_event(event)?;
if depth == 0 {
break;
}
depth -= 1;
}
DeEvent::Eof => {
self.skip_event(event)?;
break;
}
_ => self.skip_event(event)?,
}
}
}
_ => (),
}
Ok(())
}
#[cfg(feature = "overlapped-lists")]
#[inline]
fn skip_event(&mut self, event: DeEvent<'de>) -> Result<(), DeError> {
if let Some(max) = self.limit {
if self.write.len() >= max.get() {
return Err(DeError::TooManyEvents(max));
}
}
self.write.push_back(event);
Ok(())
}
#[cfg(feature = "overlapped-lists")]
fn start_replay(&mut self, checkpoint: usize) {
if checkpoint == 0 {
self.write.append(&mut self.read);
std::mem::swap(&mut self.read, &mut self.write);
} else {
let mut read = self.write.split_off(checkpoint);
read.append(&mut self.read);
self.read = read;
}
}
#[inline]
fn read_string(&mut self) -> Result<Cow<'de, str>, DeError> {
self.read_string_impl(true)
}
fn read_string_impl(&mut self, allow_start: bool) -> Result<Cow<'de, str>, DeError> {
match self.next()? {
DeEvent::Text(e) => Ok(e.text),
DeEvent::Start(_) if allow_start => self.read_text(),
DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn read_text(&mut self) -> Result<Cow<'de, str>, DeError> {
match self.next()? {
DeEvent::Text(e) => match self.next()? {
DeEvent::End(_) => Ok(e.text),
DeEvent::Text(_) => unreachable!(),
DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
DeEvent::Eof => Err(DeError::UnexpectedEof),
},
DeEvent::End(_) => Ok("".into()),
DeEvent::Start(s) => Err(DeError::UnexpectedStart(s.name().as_ref().to_owned())),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
#[cfg(feature = "overlapped-lists")]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
let mut depth = 0;
loop {
match self.read.pop_front() {
Some(DeEvent::Start(e)) if e.name() == name => {
depth += 1;
}
Some(DeEvent::End(e)) if e.name() == name => {
if depth == 0 {
break;
}
depth -= 1;
}
Some(_) => continue,
None => {
loop {
self.reader.read_to_end(name)?;
if depth == 0 {
break;
}
depth -= 1;
}
break;
}
}
}
Ok(())
}
#[cfg(not(feature = "overlapped-lists"))]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.next()? {
DeEvent::Start(e) => self.reader.read_to_end(e.name())?,
DeEvent::End(e) if e.name() == name => return Ok(()),
_ => (),
}
self.reader.read_to_end(name)
}
}
impl<'de> Deserializer<'de, SliceReader<'de>> {
#[allow(clippy::should_implement_trait)]
pub fn from_str(source: &'de str) -> Self {
Self::from_str_with_resolver(source, NoEntityResolver)
}
}
impl<'de, E> Deserializer<'de, SliceReader<'de>, E>
where
E: EntityResolver,
{
pub fn from_str_with_resolver(source: &'de str, entity_resolver: E) -> Self {
let mut reader = Reader::from_str(source);
reader.expand_empty_elements(true);
Self::new(
SliceReader {
reader,
start_trimmer: StartTrimmer::default(),
},
entity_resolver,
)
}
}
impl<'de, R> Deserializer<'de, IoReader<R>>
where
R: BufRead,
{
pub fn from_reader(reader: R) -> Self {
Self::with_resolver(reader, NoEntityResolver)
}
}
impl<'de, R, E> Deserializer<'de, IoReader<R>, E>
where
R: BufRead,
E: EntityResolver,
{
pub fn with_resolver(reader: R, entity_resolver: E) -> Self {
let mut reader = Reader::from_reader(reader);
reader.expand_empty_elements(true);
Self::new(
IoReader {
reader,
start_trimmer: StartTrimmer::default(),
buf: Vec::new(),
},
entity_resolver,
)
}
}
impl<'de, 'a, R, E> de::Deserializer<'de> for &'a mut Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
type Error = DeError;
deserialize_primitives!();
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.next()? {
DeEvent::Start(e) => visitor.visit_map(ElementMapAccess::new(self, e, fields)?),
DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
DeEvent::Text(_) => Err(DeError::ExpectedStart),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.next()? {
DeEvent::Start(s) => {
self.read_to_end(s.name())?;
visitor.visit_unit()
}
DeEvent::Text(_) => visitor.visit_unit(),
DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
visitor.visit_enum(var::EnumAccess::new(self))
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
visitor.visit_seq(self)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.peek()? {
DeEvent::Text(t) if t.is_empty() => visitor.visit_none(),
DeEvent::Eof => visitor.visit_none(),
_ => visitor.visit_some(self),
}
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.peek()? {
DeEvent::Text(_) => self.deserialize_str(visitor),
_ => self.deserialize_map(visitor),
}
}
}
impl<'de, 'a, R, E> SeqAccess<'de> for &'a mut Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
type Error = DeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.peek()? {
DeEvent::Eof => {
self.next()?;
Ok(None)
}
_ => seed.deserialize(&mut **self).map(Some),
}
}
}
struct StartTrimmer {
trim_start: bool,
}
impl StartTrimmer {
#[inline(always)]
fn trim<'a>(&mut self, event: Event<'a>) -> Option<PayloadEvent<'a>> {
let (event, trim_next_event) = match event {
Event::DocType(e) => (PayloadEvent::DocType(e), true),
Event::Start(e) => (PayloadEvent::Start(e), true),
Event::End(e) => (PayloadEvent::End(e), true),
Event::Eof => (PayloadEvent::Eof, true),
Event::CData(e) => (PayloadEvent::CData(e), false),
Event::Text(mut e) => {
if self.trim_start && e.inplace_trim_start() {
return None;
}
(PayloadEvent::Text(e), false)
}
_ => return None,
};
self.trim_start = trim_next_event;
Some(event)
}
}
impl Default for StartTrimmer {
#[inline]
fn default() -> Self {
Self { trim_start: true }
}
}
pub trait XmlRead<'i> {
fn next(&mut self) -> Result<PayloadEvent<'i>, DeError>;
fn read_to_end(&mut self, name: QName) -> Result<(), DeError>;
fn decoder(&self) -> Decoder;
}
pub struct IoReader<R: BufRead> {
reader: Reader<R>,
start_trimmer: StartTrimmer,
buf: Vec<u8>,
}
impl<'i, R: BufRead> XmlRead<'i> for IoReader<R> {
fn next(&mut self) -> Result<PayloadEvent<'static>, DeError> {
loop {
self.buf.clear();
let event = self.reader.read_event_into(&mut self.buf)?;
if let Some(event) = self.start_trimmer.trim(event) {
return Ok(event.into_owned());
}
}
}
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.reader.read_to_end_into(name, &mut self.buf) {
Err(Error::UnexpectedEof(_)) => Err(DeError::UnexpectedEof),
Err(e) => Err(e.into()),
Ok(_) => Ok(()),
}
}
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
}
pub struct SliceReader<'de> {
reader: Reader<&'de [u8]>,
start_trimmer: StartTrimmer,
}
impl<'de> XmlRead<'de> for SliceReader<'de> {
fn next(&mut self) -> Result<PayloadEvent<'de>, DeError> {
loop {
let event = self.reader.read_event()?;
if let Some(event) = self.start_trimmer.trim(event) {
return Ok(event);
}
}
}
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.reader.read_to_end(name) {
Err(Error::UnexpectedEof(_)) => Err(DeError::UnexpectedEof),
Err(e) => Err(e.into()),
Ok(_) => Ok(()),
}
}
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
fn make_de<'de>(source: &'de str) -> Deserializer<'de, SliceReader<'de>> {
dbg!(source);
Deserializer::from_str(source)
}
#[cfg(feature = "overlapped-lists")]
mod skip {
use super::*;
use crate::de::DeEvent::*;
use crate::events::BytesEnd;
use pretty_assertions::assert_eq;
#[test]
fn read_and_peek() {
let mut de = make_de(
r#"
<root>
<inner>
text
<inner/>
</inner>
<next/>
<target/>
</root>
"#,
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("inner")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("inner")),
Text("text".into()),
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("next")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("next")));
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("inner")),
Text("text".into()),
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(
de.read,
vec![
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Text("text".into()),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Text("text".into()),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Text("text".into()));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn read_to_end() {
let mut de = make_de(
r#"
<root>
<skip>
text
<skip/>
</skip>
<target>
<target/>
</target>
</root>
"#,
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
de.read_to_end(QName(b"target")).unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skip")));
de.read_to_end(QName(b"skip")).unwrap();
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn partial_replay() {
let mut de = make_de(
r#"
<root>
<skipped-1/>
<skipped-2/>
<inner>
<skipped-3/>
<skipped-4/>
<target-2/>
</inner>
<target-1/>
</root>
"#,
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
let checkpoint1 = de.skip_checkpoint();
assert_eq!(checkpoint1, 0);
de.skip().unwrap(); de.skip().unwrap(); assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("skipped-3")));
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-3")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
let checkpoint2 = de.skip_checkpoint();
assert_eq!(checkpoint2, 4);
de.skip().unwrap(); de.skip().unwrap(); assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-2")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-2")));
assert_eq!(de.peek().unwrap(), &End(BytesEnd::new("inner")));
assert_eq!(
de.read,
vec![
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
]
);
de.start_replay(checkpoint2);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-3")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-3")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-4")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-4")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-1")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-1")));
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
de.start_replay(checkpoint1);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-1")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-1")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-2")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-2")));
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn limit() {
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[allow(unused)]
struct List {
item: Vec<()>,
}
let mut de = make_de(
r#"
<any-name>
<item/>
<another-item>
<some-element>with text</some-element>
<yet-another-element/>
</another-item>
<item/>
<item/>
</any-name>
"#,
);
de.event_buffer_size(NonZeroUsize::new(3));
match List::deserialize(&mut de) {
Err(DeError::TooManyEvents(count)) => assert_eq!(count.get(), 3),
e => panic!("Expected `Err(TooManyEvents(3))`, but found {:?}", e),
}
}
#[test]
fn invalid_xml() {
use crate::de::DeEvent::*;
let mut de = make_de("<root>");
let checkpoint = de.skip_checkpoint();
de.skip().unwrap();
de.start_replay(checkpoint);
assert_eq!(de.read, vec![Start(BytesStart::new("root")), Eof]);
}
}
mod read_to_end {
use super::*;
use crate::de::DeEvent::*;
use pretty_assertions::assert_eq;
#[test]
fn complex() {
let mut de = make_de(
r#"
<root>
<tag a="1"><tag>text</tag>content</tag>
<tag a="2"><![CDATA[cdata content]]></tag>
<self-closed/>
</root>
"#,
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
assert_eq!(
de.next().unwrap(),
Start(BytesStart::from_content(r#"tag a="1""#, 3))
);
assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ());
assert_eq!(
de.next().unwrap(),
Start(BytesStart::from_content(r#"tag a="2""#, 3))
);
assert_eq!(de.next().unwrap(), Text("cdata content".into()));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed")));
assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ());
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn invalid_xml1() {
let mut de = make_de("<tag><tag></tag>");
assert_eq!(de.next().unwrap(), Start(BytesStart::new("tag")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("tag")));
match de.read_to_end(QName(b"tag")) {
Err(DeError::UnexpectedEof) => (),
x => panic!("Expected `Err(UnexpectedEof)`, but found {:?}", x),
}
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn invalid_xml2() {
let mut de = make_de("<tag><![CDATA[]]><tag></tag>");
assert_eq!(de.next().unwrap(), Start(BytesStart::new("tag")));
assert_eq!(de.peek().unwrap(), &Text("".into()));
match de.read_to_end(QName(b"tag")) {
Err(DeError::UnexpectedEof) => (),
x => panic!("Expected `Err(UnexpectedEof)`, but found {:?}", x),
}
assert_eq!(de.next().unwrap(), Eof);
}
}
#[test]
fn borrowing_reader_parity() {
let s = r#"
<item name="hello" source="world.rs">Some text</item>
<item2/>
<item3 value="world" />
"#;
let mut reader1 = IoReader {
reader: Reader::from_reader(s.as_bytes()),
start_trimmer: StartTrimmer::default(),
buf: Vec::new(),
};
let mut reader2 = SliceReader {
reader: Reader::from_str(s),
start_trimmer: StartTrimmer::default(),
};
loop {
let event1 = reader1.next().unwrap();
let event2 = reader2.next().unwrap();
if let (PayloadEvent::Eof, PayloadEvent::Eof) = (&event1, &event2) {
break;
}
assert_eq!(event1, event2);
}
}
#[test]
fn borrowing_reader_events() {
let s = r#"
<item name="hello" source="world.rs">Some text</item>
<item2></item2>
<item3/>
<item4 value="world" />
"#;
let mut reader = SliceReader {
reader: Reader::from_str(s),
start_trimmer: StartTrimmer::default(),
};
reader.reader.expand_empty_elements(true);
let mut events = Vec::new();
loop {
let event = reader.next().unwrap();
if let PayloadEvent::Eof = event {
break;
}
events.push(event);
}
use crate::de::PayloadEvent::*;
assert_eq!(
events,
vec![
Start(BytesStart::from_content(
r#"item name="hello" source="world.rs""#,
4
)),
Text(BytesText::from_escaped("Some text")),
End(BytesEnd::new("item")),
Start(BytesStart::from_content("item2", 5)),
End(BytesEnd::new("item2")),
Start(BytesStart::from_content("item3", 5)),
End(BytesEnd::new("item3")),
Start(BytesStart::from_content(r#"item4 value="world" "#, 5)),
End(BytesEnd::new("item4")),
]
)
}
#[test]
fn read_string() {
match from_str::<String>(r#"</root>"#) {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "root");
}
x => panic!(
r#"Expected `Err(InvalidXml(EndEventMismatch("", "root")))`, but found {:?}"#,
x
),
}
let s: String = from_str(r#"<root></root>"#).unwrap();
assert_eq!(s, "");
match from_str::<String>(r#"<root></other>"#) {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "root");
assert_eq!(found, "other");
}
x => panic!(
r#"Expected `Err(InvalidXml(EndEventMismatch("root", "other")))`, but found {:?}"#,
x
),
}
}
mod merge_text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de("text");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[cdata]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de("text and <![CDATA[cdata]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text and cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de("text and <![CDATA[]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text and ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de("<![CDATA[cdata]]> and text");
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata and text".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de("<![CDATA[]]> and text");
assert_eq!(de.next().unwrap(), DeEvent::Text(" and text".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
mod comment_between {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2--> \
text\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text text".into()));
}
#[test]
fn cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<!--comment 1--><!--comment 2-->\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2-->\
<![CDATA[ cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2-->\
<![CDATA[]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[cdata ]]>\
<!--comment 1--><!--comment 2--> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata text".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[]]>\
<!--comment 1--><!--comment 2--> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text(" text".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]>\
<!--comment 1--><!--comment 2-->\
<![CDATA[]>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
}
mod pi_between {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?> \
text\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text text".into()));
}
#[test]
fn cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<?pi 1?><?pi 2?>\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?>\
<![CDATA[ cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?>\
<![CDATA[]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[cdata ]]>\
<?pi 1?><?pi 2?> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata text".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[]]>\
<?pi 1?><?pi 2?> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text(" text".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]>\
<?pi 1?><?pi 2?>\
<![CDATA[]>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
}
}
mod triples {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag1><tag2><tag3>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag3")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag1><tag2></tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag1><tag2> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag1><tag2><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod end {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag></tag><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag></tag></tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag2");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag2' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag></tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag></tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag> text <tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag> text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag> text <![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag><![CDATA[ cdata ]]><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag><![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag><![CDATA[ cdata ]]> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag><![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
#[test]
fn end() {
let mut de = make_de("</tag>");
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de(" text <tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de(" text <tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de(" text <tag> text2 ");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text2".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de(" text <tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de(" text <tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
#[test]
fn end() {
let mut de = make_de(" text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de(" text <![CDATA[ cdata ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de(" text <![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de(" text <![CDATA[ cdata ]]> text2 ");
assert_eq!(
de.next().unwrap(),
DeEvent::Text("text cdata text2".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de(" text <![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text("text cdata cdata2 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de(" text <![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]><tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]><tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<![CDATA[ cdata ]]><tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[ cdata ]]><tag><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]> text <tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]> text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text".into()));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[ cdata ]]> text <![CDATA[ cdata2 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata text cdata2 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]> text ");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
assert_eq!(expected, "");
assert_eq!(found, "tag");
}
x => panic!("Expected `InvalidXml(EndEventMismatch {{ expected = '', found = 'tag' }})`, but got {:?}", x),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]> text ");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata cdata2 text".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de =
make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]><![CDATA[ cdata3 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata cdata2 cdata3 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
}
}