From e62e544ed2f6a659a784fbeee2fd847a70e29a43 Mon Sep 17 00:00:00 2001 From: Bryant Luk Date: Tue, 14 Nov 2023 10:40:55 -0600 Subject: [PATCH] Remove from_str and From impls from types - Due to assumptions made about the contents of a type (for instance a start tag must end in '>'), the ability to construct token and property types directly is removed. This also leaves open the door for further changes in the implementation. - Remove as_str(), as_bytes(), as_str_unchecked(), to_str(), and into_inner() from Attribute and Attributes types. Both are opaque types. --- maybe_xml/src/lib.rs | 35 +++++- maybe_xml/src/read.rs | 66 ++++++++--- maybe_xml/src/token.rs | 18 +-- maybe_xml/src/token/prop.rs | 101 ++++++++++------- maybe_xml/tests/reader.rs | 219 +++++++++++++++++++----------------- 5 files changed, 265 insertions(+), 174 deletions(-) diff --git a/maybe_xml/src/lib.rs b/maybe_xml/src/lib.rs index 0a1e020..958a846 100644 --- a/maybe_xml/src/lib.rs +++ b/maybe_xml/src/lib.rs @@ -15,15 +15,29 @@ //! let mut pos = 0; //! //! let token = reader.tokenize(&mut pos); -//! assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), token.map(|t| t.ty())); +//! if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { +//! assert_eq!("id", tag.name().local().as_str()); +//! assert_eq!(None, tag.name().namespace_prefix()); +//! } else { +//! panic!(); +//! } //! assert_eq!(4, pos); //! //! let token = reader.tokenize(&mut pos); -//! assert_eq!(Some(Ty::Characters(Characters::from_str("123"))), token.map(|t| t.ty())); +//! if let Some(Ty::Characters(chars)) = token.map(|t| t.ty()) { +//! assert_eq!("123", chars.content().as_str()); +//! } else { +//! panic!(); +//! } //! assert_eq!(7, pos); //! //! let token = reader.tokenize(&mut pos); -//! assert_eq!(Some(Ty::EndTag(EndTag::from_str(""))), token.map(|t| t.ty())); +//! if let Some(Ty::EndTag(tag)) = token.map(|t| t.ty()) { +//! assert_eq!("", tag.as_str()); +//! assert_eq!("id", tag.name().local().as_str()); +//! } else { +//! panic!(); +//! } //! assert_eq!(12, pos); //! //! let token = reader.tokenize(&mut pos); @@ -45,15 +59,24 @@ //! let mut iter = reader.into_iter().map(|token| token.ty()); //! //! let token_type = iter.next(); -//! assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), token_type); //! match token_type { //! Some(Ty::StartTag(start_tag)) => { //! assert_eq!(start_tag.name().as_str(), "id"); //! } //! _ => panic!("unexpected token"), //! } -//! assert_eq!(Some(Ty::Characters(Characters::from_str("Example"))), iter.next()); -//! assert_eq!(Some(Ty::EndTag(EndTag::from_str(""))), iter.next()); +//! if let Some(Ty::Characters(chars)) = iter.next() { +//! assert_eq!("Example", chars.content().as_str()); +//! } else { +//! panic!(); +//! } +//! +//! if let Some(Ty::EndTag(tag)) = iter.next() { +//! assert_eq!("", tag.as_str()); +//! assert_eq!("id", tag.name().local().as_str()); +//! } else { +//! panic!(); +//! } //! assert_eq!(None, iter.next()); //! ``` //! diff --git a/maybe_xml/src/read.rs b/maybe_xml/src/read.rs index 36ebc55..8f952c2 100644 --- a/maybe_xml/src/read.rs +++ b/maybe_xml/src/read.rs @@ -23,15 +23,29 @@ use scanner::scan; /// let mut pos = 0; /// /// let token = reader.tokenize(&mut pos); -/// assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), token.map(|t| t.ty())); +/// if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { +/// assert_eq!("id", tag.name().local().as_str()); +/// assert_eq!(None, tag.name().namespace_prefix()); +/// } else { +/// panic!(); +/// } /// assert_eq!(4, pos); /// /// let token = reader.tokenize(&mut pos); -/// assert_eq!(Some(Ty::Characters(Characters::from_str("123"))), token.map(|t| t.ty())); +/// if let Some(Ty::Characters(chars)) = token.map(|t| t.ty()) { +/// assert_eq!("123", chars.content().as_str()); +/// } else { +/// panic!(); +/// } /// assert_eq!(7, pos); /// /// let token = reader.tokenize(&mut pos); -/// assert_eq!(Some(Ty::EndTag(EndTag::from_str(""))), token.map(|t| t.ty())); +/// if let Some(Ty::EndTag(tag)) = token.map(|t| t.ty()) { +/// assert_eq!("", tag.as_str()); +/// assert_eq!("id", tag.name().local().as_str()); +/// } else { +/// panic!(); +/// } /// assert_eq!(12, pos); /// /// let token = reader.tokenize(&mut pos); @@ -94,14 +108,23 @@ impl<'a> Reader<'a> { /// let reader = unsafe { Reader::from_slice_unchecked(&buf) }; /// let mut pos = 0; /// - /// let ty = reader.tokenize(&mut pos).map(|token| token.ty()); - /// assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), ty); + /// let token = reader.tokenize(&mut pos); + /// if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { + /// assert_eq!("id", tag.name().local().as_str()); + /// assert_eq!(None, tag.name().namespace_prefix()); + /// } else { + /// panic!(); + /// } /// /// // Position was assigned to the index after the end of the token /// assert_eq!(4, pos); /// - /// let ty = reader.tokenize(&mut pos).map(|token| token.ty()); - /// assert_eq!(Some(Ty::Characters(Characters::from_str("123"))), ty); + /// let token = reader.tokenize(&mut pos); + /// if let Some(Ty::Characters(chars)) = token.map(|t| t.ty()) { + /// assert_eq!("123", chars.content().as_str()); + /// } else { + /// panic!(); + /// } /// /// // Position was assigned to the index after the end of the token /// assert_eq!(7, pos); @@ -120,8 +143,13 @@ impl<'a> Reader<'a> { /// // Start tokenizing again with the input /// let reader = unsafe { Reader::from_slice_unchecked(&buf) }; /// - /// let ty = reader.tokenize(&mut pos).map(|token| token.ty()); - /// assert_eq!(Some(Ty::EndTag(EndTag::from_str(""))), ty); + /// let token = reader.tokenize(&mut pos); + /// if let Some(Ty::EndTag(tag)) = token.map(|t| t.ty()) { + /// assert_eq!("", tag.as_str()); + /// assert_eq!("id", tag.name().local().as_str()); + /// } else { + /// panic!(); + /// } /// /// // Position was assigned to the index after the end of the token /// assert_eq!(5, pos); @@ -187,7 +215,12 @@ impl<'a> Reader<'a> { /// let mut pos = 0; /// /// let token = reader.tokenize(&mut pos); - /// assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), token.map(|t| t.ty())); + /// if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { + /// assert_eq!("id", tag.name().local().as_str()); + /// assert_eq!(None, tag.name().namespace_prefix()); + /// } else { + /// panic!(); + /// } /// /// // Position was assigned to the index after the end of the token /// assert_eq!(4, pos); @@ -250,7 +283,12 @@ impl<'a> Reader<'a> { /// let mut pos = 0; /// /// let token = reader.parse(pos); - /// assert_eq!(Some(Ty::StartTag(StartTag::from_str(""))), token.map(|t| t.ty())); + /// if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { + /// assert_eq!("id", tag.name().local().as_str()); + /// assert_eq!(None, tag.name().namespace_prefix()); + /// } else { + /// panic!(); + /// } /// /// pos += token.map(|t| t.len()).unwrap_or_default(); /// assert_eq!(4, pos); @@ -518,17 +556,17 @@ mod tests { let mut pos = 0; buf.extend("Hello".as_bytes()); let reader = unsafe { Reader::from_slice_unchecked(&buf) }; - assert_eq!(Some(Token::from_str("Hello")), reader.tokenize(&mut pos)); + assert_eq!(Some("Hello"), reader.tokenize(&mut pos).map(|t| t.as_str())); assert_eq!(buf.len(), pos); buf.extend("wo".as_bytes()); let reader = unsafe { Reader::from_slice_unchecked(&buf) }; - assert_eq!(Some(Token::from_str("wo")), reader.tokenize(&mut pos)); + assert_eq!(Some("wo"), reader.tokenize(&mut pos).map(|t| t.as_str())); assert_eq!(buf.len(), pos); buf.extend("rld!<".as_bytes()); let reader = unsafe { Reader::from_slice_unchecked(&buf) }; - assert_eq!(Some(Token::from_str("rld!")), reader.tokenize(&mut pos)); + assert_eq!(Some("rld!"), reader.tokenize(&mut pos).map(|t| t.as_str())); assert_eq!(buf.len() - 1, pos); } diff --git a/maybe_xml/src/token.rs b/maybe_xml/src/token.rs index cb63d96..1b1fda3 100644 --- a/maybe_xml/src/token.rs +++ b/maybe_xml/src/token.rs @@ -25,7 +25,7 @@ impl<'a> Token<'a> { /// Instantiates a new instance with a string. #[inline] #[must_use] - pub const fn from_str(input: &'a str) -> Self { + pub(crate) const fn from_str(input: &'a str) -> Self { Self(input) } @@ -135,19 +135,13 @@ impl<'a> fmt::Display for Token<'a> { } } -impl<'a> From<&'a str> for Token<'a> { - #[inline] - fn from(value: &'a str) -> Self { - Self(value) - } -} - macro_rules! converters { ($name:ident) => { impl<'a> $name<'a> { /// Instantiates a new view with the given string. #[inline] #[must_use] + #[cfg(test)] pub const fn from_str(value: &'a str) -> Self { Self(value) } @@ -212,15 +206,9 @@ macro_rules! converters { f.write_str(self.0) } } - - impl<'a> From<&'a str> for $name<'a> { - #[inline] - fn from(value: &'a str) -> Self { - Self(value) - } - } }; } + pub(crate) use converters; /// Type of token diff --git a/maybe_xml/src/token/prop.rs b/maybe_xml/src/token/prop.rs index 934a221..23f9313 100644 --- a/maybe_xml/src/token/prop.rs +++ b/maybe_xml/src/token/prop.rs @@ -14,7 +14,7 @@ macro_rules! converters { /// Instantiates a new instance with a string. #[inline] #[must_use] - pub const fn from_str(value: &'a str) -> Self { + pub(crate) const fn from_str(value: &'a str) -> Self { Self(value) } @@ -78,12 +78,6 @@ macro_rules! converters { f.write_str(self.0) } } - - impl<'a> From<&'a str> for $name<'a> { - fn from(value: &'a str) -> Self { - Self(value) - } - } }; } @@ -119,7 +113,7 @@ impl<'a> TagName<'a> { let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - LocalName(value) + LocalName::from_str(value) } /// The namespace prefix if available. @@ -148,7 +142,7 @@ impl<'a> TagName<'a> { let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - Some(NamespacePrefix(value)) + Some(NamespacePrefix::from_str(value)) } } @@ -182,12 +176,20 @@ converters!(NamespacePrefix); pub struct Attributes<'a>(&'a str); impl<'a> Attributes<'a> { + /// Instantiates a new instance with a string. + #[inline] + #[must_use] + pub(crate) const fn from_str(value: &'a str) -> Self { + Self(value) + } + /// Parses the attributes value into an individual attribute. /// /// # Important /// - /// The `pos` is **not** updated and should be updated with the - /// [`Attribute::len()`][Attribute::len()]. + /// The `pos` should be updated with + /// [`Attribute::len()`][Attribute::len()]. Random `pos` values are not + /// supported and is undefined behavior. /// /// # Panics /// @@ -197,18 +199,31 @@ impl<'a> Attributes<'a> { /// # Examples /// /// ``` - /// use maybe_xml::token::prop::{Attribute, Attributes}; + /// use maybe_xml::{Reader, token::{Ty, prop::Attributes}}; + /// + /// let xml = r#""#; + /// # let reader = Reader::from_str(xml); + /// # let token = reader.parse(0); + /// # + /// let attributes: Attributes; // get the attributes via start_tag.attributes() + /// # + /// # if let Some(Ty::StartTag(tag)) = token.map(|t| t.ty()) { + /// # attributes = tag.attributes().unwrap(); + /// # } else { + /// # panic!() + /// # } /// - /// let attributes = Attributes::from_str("attr=\"1\" id=test"); /// let mut pos = 0; /// /// let attr = attributes.parse(pos); - /// assert_eq!(Some(Attribute::from_str("attr=\"1\"")), attr); - /// pos += attr.map(|a| a.as_bytes().len()).unwrap_or_default(); + /// assert_eq!(Some("attr"), attr.map(|a| a.name().as_str())); + /// assert_eq!(Some("1"), attr.and_then(|a| a.value().map(|val| val.as_str()))); + /// pos += attr.map(|a| a.len()).unwrap_or_default(); /// /// let attr = attributes.parse(pos); - /// assert_eq!(Some(Attribute::from_str(" id=test")), attr); - /// pos += attr.map(|a| a.as_bytes().len()).unwrap_or_default(); + /// assert_eq!(Some("id"), attr.map(|a| a.name().as_str())); + /// assert_eq!(Some("test"), attr.and_then(|a| a.value().map(|val| val.as_str()))); + /// pos += attr.map(|a| a.len()).unwrap_or_default(); /// /// assert_eq!(None, attributes.parse(pos)); /// ``` @@ -251,8 +266,6 @@ impl<'a> IntoIterator for Attributes<'a> { } } -converters!(Attributes); - #[rustversion::attr(since(1.71), const)] #[must_use] fn iter_attr(index: usize, bytes: &[u8]) -> Option { @@ -377,6 +390,22 @@ impl<'a> Iterator for AttributeIntoIter<'a> { pub struct Attribute<'a>(&'a str); impl<'a> Attribute<'a> { + /// Instantiates a new instance with a string. + #[inline] + #[must_use] + #[cfg(test)] + pub const fn from_str(value: &'a str) -> Self { + Self(value) + } + + /// Returns the length of the token in bytes. + #[allow(clippy::len_without_is_empty)] + #[inline] + #[must_use] + pub const fn len(&self) -> usize { + self.0.len() + } + /// The attribute's name. #[rustversion::attr(since(1.71), const)] #[must_use] @@ -386,7 +415,7 @@ impl<'a> Attribute<'a> { let mut begin = 0; loop { if bytes.len() <= begin { - return AttributeName(self.0); + return AttributeName::from_str(self.0); } let byte = bytes[begin]; @@ -403,7 +432,7 @@ impl<'a> Attribute<'a> { if index == bytes.len() { let (_, bytes) = bytes.split_at(begin); let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - return AttributeName(value); + return AttributeName::from_str(value); } let byte = bytes[index]; @@ -420,7 +449,7 @@ impl<'a> Attribute<'a> { if end == 0 { let (_, bytes) = bytes.split_at(begin); let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - return AttributeName(value); + return AttributeName::from_str(value); } let byte = bytes[end]; @@ -437,7 +466,7 @@ impl<'a> Attribute<'a> { let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - AttributeName(value) + AttributeName::from_str(value) } /// The optional attribute value with the quotes removed. @@ -483,7 +512,7 @@ impl<'a> Attribute<'a> { let (bytes, _) = bytes.split_at(loop_index); let (_, bytes) = bytes.split_at(begin); let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - return Some(AttributeValue(value)); + return Some(AttributeValue::from_str(value)); } }, b'\'' => match quote_state { @@ -495,7 +524,7 @@ impl<'a> Attribute<'a> { let (bytes, _) = bytes.split_at(loop_index); let (_, bytes) = bytes.split_at(begin); let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - return Some(AttributeValue(value)); + return Some(AttributeValue::from_str(value)); } QuoteState::Double => {} }, @@ -516,15 +545,13 @@ impl<'a> Attribute<'a> { let (bytes, _) = bytes.split_at(last_nonspace); let (_, bytes) = bytes.split_at(begin); let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - return Some(AttributeValue(value)); + return Some(AttributeValue::from_str(value)); } None } } -converters!(Attribute); - /// An attribute's name. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AttributeName<'a>(&'a str); @@ -557,7 +584,7 @@ impl<'a> AttributeName<'a> { let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - LocalName(value) + LocalName::from_str(value) } /// The namespace prefix if available. @@ -586,7 +613,7 @@ impl<'a> AttributeName<'a> { let value = unsafe { core::str::from_utf8_unchecked(bytes) }; - Some(NamespacePrefix(value)) + Some(NamespacePrefix::from_str(value)) } } @@ -759,41 +786,39 @@ mod tests { assert_eq!(Attribute::from_str(" attr=\"1\""), attr); assert_eq!("attr", attr.name().as_str()); assert_eq!("1", attr.value().unwrap().as_str()); - pos += attr.as_bytes().len(); + pos += attr.len(); let attr = attributes.parse(pos).unwrap(); assert_eq!(Attribute::from_str(" id='test'"), attr); assert_eq!("id", attr.name().as_str()); assert_eq!("test", attr.value().unwrap().as_str()); - pos += attr.as_bytes().len(); + pos += attr.len(); let attr = attributes.parse(pos).unwrap(); assert_eq!(Attribute::from_str(" test = new"), attr); assert_eq!("test", attr.name().as_str()); assert_eq!("new", attr.value().unwrap().as_str()); - pos += attr.as_bytes().len(); + pos += attr.len(); let attr = attributes.parse(pos).unwrap(); assert_eq!(Attribute::from_str(" name= invalid"), attr); assert_eq!("name", attr.name().as_str()); assert_eq!("invalid", attr.value().unwrap().as_str()); - pos += attr.as_bytes().len(); + pos += attr.len(); let attr = attributes.parse(pos).unwrap(); assert_eq!(Attribute::from_str(" standalone"), attr); assert_eq!("standalone", attr.name().as_str()); assert_eq!(None, attr.value()); - pos += attr.as_bytes().len(); + pos += attr.len(); let attr = attributes.parse(pos).unwrap(); assert_eq!(Attribute::from_str(" name=\"example\""), attr); assert_eq!("name", attr.name().as_str()); assert_eq!("example", attr.value().unwrap().as_str()); - pos += attr.as_bytes().len(); + pos += attr.len(); assert_eq!(None, attributes.parse(pos)); - - assert_eq!(attributes.as_bytes().len() - 1, pos); } #[test] diff --git a/maybe_xml/tests/reader.rs b/maybe_xml/tests/reader.rs index 3296e09..fe16ee6 100644 --- a/maybe_xml/tests/reader.rs +++ b/maybe_xml/tests/reader.rs @@ -1,137 +1,154 @@ -use maybe_xml::{ - token::{ - Characters, Declaration, EmptyElementTag, EndTag, ProcessingInstruction, StartTag, Ty, - }, - Reader, -}; +use maybe_xml::{token::Ty, Reader}; const SIMPLE_1_XML: &str = include_str!("../tests/resources/simple-1.xml"); const SVG_1_XML: &str = include_str!("../tests/resources/svg-1.xml"); -fn tokenize_via_iterator(input: &str, expected_tokens: &[Ty<'_>]) { - let reader = Reader::from_str(input); +macro_rules! test_iter { + ($iter:expr ;) => {}; + ($iter:expr ; [$expected_txt:literal, $expected_ty:pat] $(,)?) => { + let token = $iter.next(); + assert_eq!(token.map(|t| t.as_str()), Some($expected_txt)); + assert!(matches!(token.map(|t| t.ty()), Some($expected_ty))); + }; + ($iter:expr; [$expected_txt:literal, $expected_ty:pat], $([$exp_txt_y:literal, $exp_ty_y:pat]),+ $(,)?) => { + test_iter!($iter; [$expected_txt, $expected_ty]); + test_iter!($iter; $([$exp_txt_y, $exp_ty_y]),+); + }; + ($xml_str:expr, $([$exp_txt_y:literal, $exp_ty_y:pat]),+ $(,)?) => { + let reader = Reader::from_str($xml_str); + let mut iter = reader.iter(0); - for (expected_token, token) in expected_tokens.iter().zip(reader.iter(0)) { - assert_eq!(*expected_token, token.ty()); - } + test_iter!(iter; $([$exp_txt_y, $exp_ty_y]),+); - assert_eq!(reader.into_iter().count(), expected_tokens.len()); + assert_eq!(None, iter.next()); + } } -fn tokenize(input: &str, expected_tokens: &[Ty<'_>]) { - let reader = Reader::from_str(input); - let mut pos = 0; +macro_rules! test_tokenize { + ($reader:expr, $pos:expr ;) => {}; + ($reader:expr, $pos:expr ; [$expected_txt:literal, $expected_ty:pat] $(,)?) => { + let token = $reader.tokenize(&mut $pos); + assert_eq!(token.map(|t| t.as_str()), Some($expected_txt)); + assert!(matches!(token.map(|t| t.ty()), Some($expected_ty))); + }; + ($reader:expr, $pos:expr ; [$expected_txt:literal, $expected_ty:pat], $([$exp_txt_y:literal, $exp_ty_y:pat]),+ $(,)?) => { + test_tokenize!($reader, $pos; [$expected_txt, $expected_ty]); + test_tokenize!($reader, $pos; $([$exp_txt_y, $exp_ty_y]),+); + }; + ($xml_str:expr, $([$exp_txt_y:literal, $exp_ty_y:pat]),+ $(,)?) => { + let reader = Reader::from_str($xml_str); + let mut pos = 0; - let mut expected_iter = expected_tokens.iter().copied(); + test_tokenize!(reader, pos ; $([$exp_txt_y, $exp_ty_y]),+); - while let Some(token) = reader.tokenize(&mut pos) { - assert_eq!(Some(token.ty()), expected_iter.next()); + assert_eq!(pos, $xml_str.len()); } - - assert_eq!(pos, input.len()); - assert_eq!(None, expected_iter.next()); } #[test] fn tokenize_simple_1_xml() { - tokenize( + #[cfg(not(target_os = "windows"))] + test_tokenize!( + SIMPLE_1_XML, + [r#""#, Ty::ProcessingInstruction(_)], + ["\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["Hello world!", Ty::Characters(_)], + ["", Ty::EndTag(_)], + ); + + #[cfg(target_os = "windows")] + test_tokenize!( SIMPLE_1_XML, - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from_str(r#""#)), - #[cfg(not(target_os = "windows"))] - Ty::Characters(Characters::from_str("\n")), - #[cfg(target_os = "windows")] - Ty::Characters(Characters::from("\r\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("Hello world!")), - Ty::EndTag(EndTag::from_str("")), - ], + [r#""#, Ty::ProcessingInstruction(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["Hello world!", Ty::Characters(_)], + ["", Ty::EndTag(_)], ); } #[test] fn tokenize_iter_simple_1_xml() { - tokenize_via_iterator( + #[cfg(not(target_os = "windows"))] + test_iter!( SIMPLE_1_XML, - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from_str(r#""#)), - #[cfg(not(target_os = "windows"))] - Ty::Characters(Characters::from_str("\n")), - #[cfg(target_os = "windows")] - Ty::Characters(Characters::from("\r\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("Hello world!")), - Ty::EndTag(EndTag::from_str("")), - ], + [r#""#, Ty::ProcessingInstruction(_)], + ["\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["Hello world!", Ty::Characters(_)], + ["", Ty::EndTag(_)], + ); + + #[cfg(target_os = "windows")] + test_iter!( + SIMPLE_1_XML, + [r#""#, Ty::ProcessingInstruction(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["Hello world!", Ty::Characters(_)], + ["", Ty::EndTag(_)], ); } #[test] fn tokenize_svg_1_xml() { - tokenize( + #[cfg(not(target_os = "windows"))] + test_tokenize!( + SVG_1_XML, + [r#""#, Ty::ProcessingInstruction(_)], + ["\n", Ty::Characters(_)], + ["", Ty::Declaration(_)], + ["\n\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["\n ", Ty::Characters(_)], + ["", Ty::EmptyElementTag(_)], + ["\n", Ty::Characters(_)], + ["", Ty::EndTag(_)], + ); + + #[cfg(target_os = "windows")] + test_tokenize!( SVG_1_XML, - #[cfg(not(target_os = "windows"))] - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from_str( - r#""#, - )), - Ty::Characters(Characters::from_str("\n")), - Ty::Declaration(Declaration::from_str("")), - Ty::Characters(Characters::from_str("\n\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("\n ")), - Ty::EmptyElementTag(EmptyElementTag::from_str("")), - Ty::Characters(Characters::from_str("\n")), - Ty::EndTag(EndTag::from_str("")), - ], - #[cfg(target_os = "windows")] - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from( - r#""#, - )), - Ty::Characters(Characters::from_str("\r\n")), - Ty::Declaration(Declaration::from_str("")), - Ty::Characters(Characters::from_str("\r\n\r\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("\r\n ")), - Ty::EmptyElementTag(EmptyElementTag::from_str("")), - Ty::Characters(Characters::from_str("\r\n")), - Ty::EndTag(EndTag::from_str("")), - ], + [r#""#, Ty::ProcessingInstruction(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::Declaration(_)], + ["\r\n\r\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["\r\n ", Ty::Characters(_)], + ["", Ty::EmptyElementTag(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::EndTag(_)], ); } #[test] fn tokenize_iter_svg_1_xml() { - tokenize_via_iterator( + #[cfg(not(target_os = "windows"))] + test_iter!( + SVG_1_XML, + [r#""#, Ty::ProcessingInstruction(_)], + ["\n", Ty::Characters(_)], + ["", Ty::Declaration(_)], + ["\n\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["\n ", Ty::Characters(_)], + ["", Ty::EmptyElementTag(_)], + ["\n", Ty::Characters(_)], + ["", Ty::EndTag(_)], + ); + + #[cfg(target_os = "windows")] + test_iter!( SVG_1_XML, - #[cfg(not(target_os = "windows"))] - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from_str( - r#""#, - )), - Ty::Characters(Characters::from_str("\n")), - Ty::Declaration(Declaration::from_str("")), - Ty::Characters(Characters::from_str("\n\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("\n ")), - Ty::EmptyElementTag(EmptyElementTag::from_str("")), - Ty::Characters(Characters::from_str("\n")), - Ty::EndTag(EndTag::from_str("")), - ], - #[cfg(target_os = "windows")] - &[ - Ty::ProcessingInstruction(ProcessingInstruction::from_str( - r#""#, - )), - Ty::Characters(Characters::from_str("\r\n")), - Ty::Declaration(Declaration::from_str("")), - Ty::Characters(Characters::from_str("\r\n\r\n")), - Ty::StartTag(StartTag::from_str("")), - Ty::Characters(Characters::from_str("\r\n ")), - Ty::EmptyElementTag(EmptyElementTag::from_str("")), - Ty::Characters(Characters::from_str("\r\n")), - Ty::EndTag(EndTag::from_str("")), - ], + [r#""#, Ty::ProcessingInstruction(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::Declaration(_)], + ["\r\n\r\n", Ty::Characters(_)], + ["", Ty::StartTag(_)], + ["\r\n ", Ty::Characters(_)], + ["", Ty::EmptyElementTag(_)], + ["\r\n", Ty::Characters(_)], + ["", Ty::EndTag(_)], ); }