quick_xml/events/
attributes.rs

1//! Xml Attributes module
2//!
3//! Provides an iterator over attributes key/value pairs
4
5use crate::encoding::Decoder;
6use crate::errors::Result as XmlResult;
7use crate::escape::{escape, resolve_predefined_entity, unescape_with};
8use crate::name::{LocalName, Namespace, QName};
9use crate::reader::NsReader;
10use crate::utils::{is_whitespace, Bytes};
11
12use std::fmt::{self, Debug, Display, Formatter};
13use std::iter::FusedIterator;
14use std::{borrow::Cow, ops::Range};
15
16/// A struct representing a key/value XML attribute.
17///
18/// Field `value` stores raw bytes, possibly containing escape-sequences. Most users will likely
19/// want to access the value using one of the [`unescape_value`] and [`decode_and_unescape_value`]
20/// functions.
21///
22/// [`unescape_value`]: Self::unescape_value
23/// [`decode_and_unescape_value`]: Self::decode_and_unescape_value
24#[derive(Clone, Eq, PartialEq)]
25pub struct Attribute<'a> {
26    /// The key to uniquely define the attribute.
27    ///
28    /// If [`Attributes::with_checks`] is turned off, the key might not be unique.
29    pub key: QName<'a>,
30    /// The raw value of the attribute.
31    pub value: Cow<'a, [u8]>,
32}
33
34impl<'a> Attribute<'a> {
35    /// Decodes using UTF-8 then unescapes the value.
36    ///
37    /// This is normally the value you are interested in. Escape sequences such as `&gt;` are
38    /// replaced with their unescaped equivalents such as `>`.
39    ///
40    /// This will allocate if the value contains any escape sequences.
41    ///
42    /// See also [`unescape_value_with()`](Self::unescape_value_with)
43    ///
44    /// This method is available only if [`encoding`] feature is **not** enabled.
45    ///
46    /// [`encoding`]: ../../index.html#encoding
47    #[cfg(any(doc, not(feature = "encoding")))]
48    pub fn unescape_value(&self) -> XmlResult<Cow<'a, str>> {
49        self.unescape_value_with(resolve_predefined_entity)
50    }
51
52    /// Decodes using UTF-8 then unescapes the value, using custom entities.
53    ///
54    /// This is normally the value you are interested in. Escape sequences such as `&gt;` are
55    /// replaced with their unescaped equivalents such as `>`.
56    /// A fallback resolver for additional custom entities can be provided via
57    /// `resolve_entity`.
58    ///
59    /// This will allocate if the value contains any escape sequences.
60    ///
61    /// See also [`unescape_value()`](Self::unescape_value)
62    ///
63    /// This method is available only if [`encoding`] feature is **not** enabled.
64    ///
65    /// [`encoding`]: ../../index.html#encoding
66    #[cfg(any(doc, not(feature = "encoding")))]
67    #[inline]
68    pub fn unescape_value_with<'entity>(
69        &self,
70        resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
71    ) -> XmlResult<Cow<'a, str>> {
72        self.decode_and_unescape_value_with(Decoder::utf8(), resolve_entity)
73    }
74
75    /// Decodes then unescapes the value.
76    ///
77    /// This will allocate if the value contains any escape sequences or in
78    /// non-UTF-8 encoding.
79    pub fn decode_and_unescape_value(&self, decoder: Decoder) -> XmlResult<Cow<'a, str>> {
80        self.decode_and_unescape_value_with(decoder, resolve_predefined_entity)
81    }
82
83    /// Decodes then unescapes the value with custom entities.
84    ///
85    /// This will allocate if the value contains any escape sequences or in
86    /// non-UTF-8 encoding.
87    pub fn decode_and_unescape_value_with<'entity>(
88        &self,
89        decoder: Decoder,
90        resolve_entity: impl FnMut(&str) -> Option<&'entity str>,
91    ) -> XmlResult<Cow<'a, str>> {
92        let decoded = decoder.decode_cow(&self.value)?;
93
94        match unescape_with(&decoded, resolve_entity)? {
95            // Because result is borrowed, no replacements was done and we can use original string
96            Cow::Borrowed(_) => Ok(decoded),
97            Cow::Owned(s) => Ok(s.into()),
98        }
99    }
100
101    /// If attribute value [represents] valid boolean values, returns `Some`, otherwise returns `None`.
102    ///
103    /// The valid boolean representations are only `"true"`, `"false"`, `"1"`, and `"0"`.
104    ///
105    /// # Examples
106    ///
107    /// ```
108    /// # use pretty_assertions::assert_eq;
109    /// use quick_xml::events::attributes::Attribute;
110    ///
111    /// let attr = Attribute::from(("attr", "false"));
112    /// assert_eq!(attr.as_bool(), Some(false));
113    ///
114    /// let attr = Attribute::from(("attr", "0"));
115    /// assert_eq!(attr.as_bool(), Some(false));
116    ///
117    /// let attr = Attribute::from(("attr", "true"));
118    /// assert_eq!(attr.as_bool(), Some(true));
119    ///
120    /// let attr = Attribute::from(("attr", "1"));
121    /// assert_eq!(attr.as_bool(), Some(true));
122    ///
123    /// let attr = Attribute::from(("attr", "bot bool"));
124    /// assert_eq!(attr.as_bool(), None);
125    /// ```
126    ///
127    /// [represents]: https://www.w3.org/TR/xmlschema11-2/#boolean
128    #[inline]
129    pub fn as_bool(&self) -> Option<bool> {
130        match self.value.as_ref() {
131            b"1" | b"true" => Some(true),
132            b"0" | b"false" => Some(false),
133            _ => None,
134        }
135    }
136}
137
138impl<'a> Debug for Attribute<'a> {
139    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
140        f.debug_struct("Attribute")
141            .field("key", &Bytes(self.key.as_ref()))
142            .field("value", &Bytes(&self.value))
143            .finish()
144    }
145}
146
147impl<'a> From<(&'a [u8], &'a [u8])> for Attribute<'a> {
148    /// Creates new attribute from raw bytes.
149    /// Does not apply any transformation to both key and value.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// # use pretty_assertions::assert_eq;
155    /// use quick_xml::events::attributes::Attribute;
156    ///
157    /// let features = Attribute::from(("features".as_bytes(), "Bells &amp; whistles".as_bytes()));
158    /// assert_eq!(features.value, "Bells &amp; whistles".as_bytes());
159    /// ```
160    fn from(val: (&'a [u8], &'a [u8])) -> Attribute<'a> {
161        Attribute {
162            key: QName(val.0),
163            value: Cow::from(val.1),
164        }
165    }
166}
167
168impl<'a> From<(&'a str, &'a str)> for Attribute<'a> {
169    /// Creates new attribute from text representation.
170    /// Key is stored as-is, but the value will be escaped.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// # use pretty_assertions::assert_eq;
176    /// use quick_xml::events::attributes::Attribute;
177    ///
178    /// let features = Attribute::from(("features", "Bells & whistles"));
179    /// assert_eq!(features.value, "Bells &amp; whistles".as_bytes());
180    /// ```
181    fn from(val: (&'a str, &'a str)) -> Attribute<'a> {
182        Attribute {
183            key: QName(val.0.as_bytes()),
184            value: match escape(val.1) {
185                Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
186                Cow::Owned(s) => Cow::Owned(s.into_bytes()),
187            },
188        }
189    }
190}
191
192impl<'a> From<(&'a str, Cow<'a, str>)> for Attribute<'a> {
193    /// Creates new attribute from text representation.
194    /// Key is stored as-is, but the value will be escaped.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// # use std::borrow::Cow;
200    /// use pretty_assertions::assert_eq;
201    /// use quick_xml::events::attributes::Attribute;
202    ///
203    /// let features = Attribute::from(("features", Cow::Borrowed("Bells & whistles")));
204    /// assert_eq!(features.value, "Bells &amp; whistles".as_bytes());
205    /// ```
206    fn from(val: (&'a str, Cow<'a, str>)) -> Attribute<'a> {
207        Attribute {
208            key: QName(val.0.as_bytes()),
209            value: match escape(val.1) {
210                Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
211                Cow::Owned(s) => Cow::Owned(s.into_bytes()),
212            },
213        }
214    }
215}
216
217impl<'a> From<Attr<&'a [u8]>> for Attribute<'a> {
218    #[inline]
219    fn from(attr: Attr<&'a [u8]>) -> Self {
220        Self {
221            key: attr.key(),
222            value: Cow::Borrowed(attr.value()),
223        }
224    }
225}
226
227////////////////////////////////////////////////////////////////////////////////////////////////////
228
229/// Iterator over XML attributes.
230///
231/// Yields `Result<Attribute>`. An `Err` will be yielded if an attribute is malformed or duplicated.
232/// The duplicate check can be turned off by calling [`with_checks(false)`].
233///
234/// [`with_checks(false)`]: Self::with_checks
235#[derive(Clone)]
236pub struct Attributes<'a> {
237    /// Slice of `BytesStart` corresponding to attributes
238    bytes: &'a [u8],
239    /// Iterator state, independent from the actual source of bytes
240    state: IterState,
241}
242
243impl<'a> Attributes<'a> {
244    /// Internal constructor, used by `BytesStart`. Supplies data in reader's encoding
245    #[inline]
246    pub(crate) const fn wrap(buf: &'a [u8], pos: usize, html: bool) -> Self {
247        Self {
248            bytes: buf,
249            state: IterState::new(pos, html),
250        }
251    }
252
253    /// Creates a new attribute iterator from a buffer.
254    pub const fn new(buf: &'a str, pos: usize) -> Self {
255        Self::wrap(buf.as_bytes(), pos, false)
256    }
257
258    /// Creates a new attribute iterator from a buffer, allowing HTML attribute syntax.
259    pub const fn html(buf: &'a str, pos: usize) -> Self {
260        Self::wrap(buf.as_bytes(), pos, true)
261    }
262
263    /// Changes whether attributes should be checked for uniqueness.
264    ///
265    /// The XML specification requires attribute keys in the same element to be unique. This check
266    /// can be disabled to improve performance slightly.
267    ///
268    /// (`true` by default)
269    pub fn with_checks(&mut self, val: bool) -> &mut Attributes<'a> {
270        self.state.check_duplicates = val;
271        self
272    }
273
274    /// Checks if the current tag has a [`xsi:nil`] attribute. This method ignores any errors in
275    /// attributes.
276    ///
277    /// # Examples
278    ///
279    /// ```
280    /// # use pretty_assertions::assert_eq;
281    /// use quick_xml::events::Event;
282    /// use quick_xml::name::QName;
283    /// use quick_xml::reader::NsReader;
284    ///
285    /// let mut reader = NsReader::from_str("
286    ///     <root xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
287    ///         <true xsi:nil='true'/>
288    ///         <false xsi:nil='false'/>
289    ///         <none/>
290    ///         <non-xsi xsi:nil='true' xmlns:xsi='namespace'/>
291    ///         <unbound-nil nil='true' xmlns='http://www.w3.org/2001/XMLSchema-instance'/>
292    ///         <another-xmlns f:nil='true' xmlns:f='http://www.w3.org/2001/XMLSchema-instance'/>
293    ///     </root>
294    /// ");
295    /// reader.config_mut().trim_text(true);
296    ///
297    /// macro_rules! check {
298    ///     ($reader:expr, $name:literal, $value:literal) => {
299    ///         let event = match $reader.read_event().unwrap() {
300    ///             Event::Empty(e) => e,
301    ///             e => panic!("Unexpected event {:?}", e),
302    ///         };
303    ///         assert_eq!(
304    ///             (event.name(), event.attributes().has_nil(&$reader)),
305    ///             (QName($name.as_bytes()), $value),
306    ///         );
307    ///     };
308    /// }
309    ///
310    /// let root = match reader.read_event().unwrap() {
311    ///     Event::Start(e) => e,
312    ///     e => panic!("Unexpected event {:?}", e),
313    /// };
314    /// assert_eq!(root.attributes().has_nil(&reader), false);
315    ///
316    /// // definitely true
317    /// check!(reader, "true",          true);
318    /// // definitely false
319    /// check!(reader, "false",         false);
320    /// // absence of the attribute means that attribute is not set
321    /// check!(reader, "none",          false);
322    /// // attribute not bound to the correct namespace
323    /// check!(reader, "non-xsi",       false);
324    /// // attributes without prefix not bound to any namespace
325    /// check!(reader, "unbound-nil",   false);
326    /// // prefix can be any while it is bound to the correct namespace
327    /// check!(reader, "another-xmlns", true);
328    /// ```
329    ///
330    /// [`xsi:nil`]: https://www.w3.org/TR/xmlschema-1/#xsi_nil
331    pub fn has_nil<R>(&mut self, reader: &NsReader<R>) -> bool {
332        use crate::name::ResolveResult::*;
333
334        self.any(|attr| {
335            if let Ok(attr) = attr {
336                match reader.resolve_attribute(attr.key) {
337                    (
338                        Bound(Namespace(b"http://www.w3.org/2001/XMLSchema-instance")),
339                        LocalName(b"nil"),
340                    ) => attr.as_bool().unwrap_or_default(),
341                    _ => false,
342                }
343            } else {
344                false
345            }
346        })
347    }
348}
349
350impl<'a> Debug for Attributes<'a> {
351    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
352        f.debug_struct("Attributes")
353            .field("bytes", &Bytes(&self.bytes))
354            .field("state", &self.state)
355            .finish()
356    }
357}
358
359impl<'a> Iterator for Attributes<'a> {
360    type Item = Result<Attribute<'a>, AttrError>;
361
362    #[inline]
363    fn next(&mut self) -> Option<Self::Item> {
364        match self.state.next(self.bytes) {
365            None => None,
366            Some(Ok(a)) => Some(Ok(a.map(|range| &self.bytes[range]).into())),
367            Some(Err(e)) => Some(Err(e)),
368        }
369    }
370}
371
372impl<'a> FusedIterator for Attributes<'a> {}
373
374////////////////////////////////////////////////////////////////////////////////////////////////////
375
376/// Errors that can be raised during parsing attributes.
377///
378/// Recovery position in examples shows the position from which parsing of the
379/// next attribute will be attempted.
380#[derive(Clone, Debug, PartialEq, Eq)]
381pub enum AttrError {
382    /// Attribute key was not followed by `=`, position relative to the start of
383    /// the owning tag is provided.
384    ///
385    /// Example of input that raises this error:
386    ///
387    /// ```xml
388    /// <tag key another="attribute"/>
389    /// <!--     ^~~ error position, recovery position (8) -->
390    /// ```
391    ///
392    /// This error can be raised only when the iterator is in XML mode.
393    ExpectedEq(usize),
394    /// Attribute value was not found after `=`, position relative to the start
395    /// of the owning tag is provided.
396    ///
397    /// Example of input that raises this error:
398    ///
399    /// ```xml
400    /// <tag key = />
401    /// <!--       ^~~ error position, recovery position (10) -->
402    /// ```
403    ///
404    /// This error can be returned only for the last attribute in the list,
405    /// because otherwise any content after `=` will be threated as a value.
406    /// The XML
407    ///
408    /// ```xml
409    /// <tag key = another-key = "value"/>
410    /// <!--                   ^ ^- recovery position (24) -->
411    /// <!--                   '~~ error position (22) -->
412    /// ```
413    ///
414    /// will be treated as `Attribute { key = b"key", value = b"another-key" }`
415    /// and or [`Attribute`] is returned, or [`AttrError::UnquotedValue`] is raised,
416    /// depending on the parsing mode.
417    ExpectedValue(usize),
418    /// Attribute value is not quoted, position relative to the start of the
419    /// owning tag is provided.
420    ///
421    /// Example of input that raises this error:
422    ///
423    /// ```xml
424    /// <tag key = value />
425    /// <!--       ^    ^~~ recovery position (15) -->
426    /// <!--       '~~ error position (10) -->
427    /// ```
428    ///
429    /// This error can be raised only when the iterator is in XML mode.
430    UnquotedValue(usize),
431    /// Attribute value was not finished with a matching quote, position relative
432    /// to the start of owning tag and a quote is provided. That position is always
433    /// a last character in the tag content.
434    ///
435    /// Example of input that raises this error:
436    ///
437    /// ```xml
438    /// <tag key = "value  />
439    /// <tag key = 'value  />
440    /// <!--               ^~~ error position, recovery position (18) -->
441    /// ```
442    ///
443    /// This error can be returned only for the last attribute in the list,
444    /// because all input was consumed during scanning for a quote.
445    ExpectedQuote(usize, u8),
446    /// An attribute with the same name was already encountered. Two parameters
447    /// define (1) the error position relative to the start of the owning tag
448    /// for a new attribute and (2) the start position of a previously encountered
449    /// attribute with the same name.
450    ///
451    /// Example of input that raises this error:
452    ///
453    /// ```xml
454    /// <tag key = 'value'  key="value2" attr3='value3' />
455    /// <!-- ^              ^            ^~~ recovery position (32) -->
456    /// <!-- |              '~~ error position (19) -->
457    /// <!-- '~~ previous position (4) -->
458    /// ```
459    ///
460    /// This error is returned only when [`Attributes::with_checks()`] is set
461    /// to `true` (that is default behavior).
462    Duplicated(usize, usize),
463}
464
465impl Display for AttrError {
466    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
467        match self {
468            Self::ExpectedEq(pos) => write!(
469                f,
470                r#"position {}: attribute key must be directly followed by `=` or space"#,
471                pos
472            ),
473            Self::ExpectedValue(pos) => write!(
474                f,
475                r#"position {}: `=` must be followed by an attribute value"#,
476                pos
477            ),
478            Self::UnquotedValue(pos) => write!(
479                f,
480                r#"position {}: attribute value must be enclosed in `"` or `'`"#,
481                pos
482            ),
483            Self::ExpectedQuote(pos, quote) => write!(
484                f,
485                r#"position {}: missing closing quote `{}` in attribute value"#,
486                pos, *quote as char
487            ),
488            Self::Duplicated(pos1, pos2) => write!(
489                f,
490                r#"position {}: duplicated attribute, previous declaration at position {}"#,
491                pos1, pos2
492            ),
493        }
494    }
495}
496
497impl std::error::Error for AttrError {}
498
499////////////////////////////////////////////////////////////////////////////////////////////////////
500
501/// A struct representing a key/value XML or HTML [attribute].
502///
503/// [attribute]: https://www.w3.org/TR/xml11/#NT-Attribute
504#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
505pub enum Attr<T> {
506    /// Attribute with value enclosed in double quotes (`"`). Attribute key and
507    /// value provided. This is a canonical XML-style attribute.
508    DoubleQ(T, T),
509    /// Attribute with value enclosed in single quotes (`'`). Attribute key and
510    /// value provided. This is an XML-style attribute.
511    SingleQ(T, T),
512    /// Attribute with value not enclosed in quotes. Attribute key and value
513    /// provided. This is HTML-style attribute, it can be returned in HTML-mode
514    /// parsing only. In an XML mode [`AttrError::UnquotedValue`] will be raised
515    /// instead.
516    ///
517    /// Attribute value can be invalid according to the [HTML specification],
518    /// in particular, it can contain `"`, `'`, `=`, `<`, and <code>&#96;</code>
519    /// characters. The absence of the `>` character is nevertheless guaranteed,
520    /// since the parser extracts [events] based on them even before the start
521    /// of parsing attributes.
522    ///
523    /// [HTML specification]: https://html.spec.whatwg.org/#unquoted
524    /// [events]: crate::events::Event::Start
525    Unquoted(T, T),
526    /// Attribute without value. Attribute key provided. This is HTML-style attribute,
527    /// it can be returned in HTML-mode parsing only. In XML mode
528    /// [`AttrError::ExpectedEq`] will be raised instead.
529    Empty(T),
530}
531
532impl<T> Attr<T> {
533    /// Maps an `Attr<T>` to `Attr<U>` by applying a function to a contained key and value.
534    #[inline]
535    pub fn map<U, F>(self, mut f: F) -> Attr<U>
536    where
537        F: FnMut(T) -> U,
538    {
539        match self {
540            Attr::DoubleQ(key, value) => Attr::DoubleQ(f(key), f(value)),
541            Attr::SingleQ(key, value) => Attr::SingleQ(f(key), f(value)),
542            Attr::Empty(key) => Attr::Empty(f(key)),
543            Attr::Unquoted(key, value) => Attr::Unquoted(f(key), f(value)),
544        }
545    }
546}
547
548impl<'a> Attr<&'a [u8]> {
549    /// Returns the key value
550    #[inline]
551    pub const fn key(&self) -> QName<'a> {
552        QName(match self {
553            Attr::DoubleQ(key, _) => key,
554            Attr::SingleQ(key, _) => key,
555            Attr::Empty(key) => key,
556            Attr::Unquoted(key, _) => key,
557        })
558    }
559    /// Returns the attribute value. For [`Self::Empty`] variant an empty slice
560    /// is returned according to the [HTML specification].
561    ///
562    /// [HTML specification]: https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#syntax-attr-empty
563    #[inline]
564    pub const fn value(&self) -> &'a [u8] {
565        match self {
566            Attr::DoubleQ(_, value) => value,
567            Attr::SingleQ(_, value) => value,
568            Attr::Empty(_) => &[],
569            Attr::Unquoted(_, value) => value,
570        }
571    }
572}
573
574impl<T: AsRef<[u8]>> Debug for Attr<T> {
575    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
576        match self {
577            Attr::DoubleQ(key, value) => f
578                .debug_tuple("Attr::DoubleQ")
579                .field(&Bytes(key.as_ref()))
580                .field(&Bytes(value.as_ref()))
581                .finish(),
582            Attr::SingleQ(key, value) => f
583                .debug_tuple("Attr::SingleQ")
584                .field(&Bytes(key.as_ref()))
585                .field(&Bytes(value.as_ref()))
586                .finish(),
587            Attr::Empty(key) => f
588                .debug_tuple("Attr::Empty")
589                // Comment to prevent formatting and keep style consistent
590                .field(&Bytes(key.as_ref()))
591                .finish(),
592            Attr::Unquoted(key, value) => f
593                .debug_tuple("Attr::Unquoted")
594                .field(&Bytes(key.as_ref()))
595                .field(&Bytes(value.as_ref()))
596                .finish(),
597        }
598    }
599}
600
601/// Unpacks attribute key and value into tuple of this two elements.
602/// `None` value element is returned only for [`Attr::Empty`] variant.
603impl<T> From<Attr<T>> for (T, Option<T>) {
604    #[inline]
605    fn from(attr: Attr<T>) -> Self {
606        match attr {
607            Attr::DoubleQ(key, value) => (key, Some(value)),
608            Attr::SingleQ(key, value) => (key, Some(value)),
609            Attr::Empty(key) => (key, None),
610            Attr::Unquoted(key, value) => (key, Some(value)),
611        }
612    }
613}
614
615////////////////////////////////////////////////////////////////////////////////////////////////////
616
617type AttrResult = Result<Attr<Range<usize>>, AttrError>;
618
619#[derive(Clone, Copy, Debug)]
620enum State {
621    /// Iteration finished, iterator will return `None` to all [`IterState::next`]
622    /// requests.
623    Done,
624    /// The last attribute returned was deserialized successfully. Contains an
625    /// offset from which next attribute should be searched.
626    Next(usize),
627    /// The last attribute returns [`AttrError::UnquotedValue`], offset pointed
628    /// to the beginning of the value. Recover should skip a value
629    SkipValue(usize),
630    /// The last attribute returns [`AttrError::Duplicated`], offset pointed to
631    /// the equal (`=`) sign. Recover should skip it and a value
632    SkipEqValue(usize),
633}
634
635/// External iterator over spans of attribute key and value
636#[derive(Clone, Debug)]
637pub(crate) struct IterState {
638    /// Iteration state that determines what actions should be done before the
639    /// actual parsing of the next attribute
640    state: State,
641    /// If `true`, enables ability to parse unquoted values and key-only (empty)
642    /// attributes
643    html: bool,
644    /// If `true`, checks for duplicate names
645    check_duplicates: bool,
646    /// If `check_duplicates` is set, contains the ranges of already parsed attribute
647    /// names. We store a ranges instead of slices to able to report a previous
648    /// attribute position
649    keys: Vec<Range<usize>>,
650}
651
652impl IterState {
653    pub const fn new(offset: usize, html: bool) -> Self {
654        Self {
655            state: State::Next(offset),
656            html,
657            check_duplicates: true,
658            keys: Vec::new(),
659        }
660    }
661
662    /// Recover from an error that could have been made on a previous step.
663    /// Returns an offset from which parsing should continue.
664    /// If there no input left, returns `None`.
665    fn recover(&self, slice: &[u8]) -> Option<usize> {
666        match self.state {
667            State::Done => None,
668            State::Next(offset) => Some(offset),
669            State::SkipValue(offset) => self.skip_value(slice, offset),
670            State::SkipEqValue(offset) => self.skip_eq_value(slice, offset),
671        }
672    }
673
674    /// Skip all characters up to first space symbol or end-of-input
675    #[inline]
676    #[allow(clippy::manual_map)]
677    fn skip_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
678        let mut iter = (offset..).zip(slice[offset..].iter());
679
680        match iter.find(|(_, &b)| is_whitespace(b)) {
681            // Input: `    key  =  value `
682            //                     |    ^
683            //                offset    e
684            Some((e, _)) => Some(e),
685            // Input: `    key  =  value`
686            //                     |    ^
687            //                offset    e = len()
688            None => None,
689        }
690    }
691
692    /// Skip all characters up to first space symbol or end-of-input
693    #[inline]
694    fn skip_eq_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
695        let mut iter = (offset..).zip(slice[offset..].iter());
696
697        // Skip all up to the quote and get the quote type
698        let quote = match iter.find(|(_, &b)| !is_whitespace(b)) {
699            // Input: `    key  =  "`
700            //                  |  ^
701            //             offset
702            Some((_, b'"')) => b'"',
703            // Input: `    key  =  '`
704            //                  |  ^
705            //             offset
706            Some((_, b'\'')) => b'\'',
707
708            // Input: `    key  =  x`
709            //                  |  ^
710            //             offset
711            Some((offset, _)) => return self.skip_value(slice, offset),
712            // Input: `    key  =  `
713            //                  |  ^
714            //             offset
715            None => return None,
716        };
717
718        match iter.find(|(_, &b)| b == quote) {
719            // Input: `    key  =  "   "`
720            //                         ^
721            Some((e, b'"')) => Some(e),
722            // Input: `    key  =  '   '`
723            //                         ^
724            Some((e, _)) => Some(e),
725
726            // Input: `    key  =  "   `
727            // Input: `    key  =  '   `
728            //                         ^
729            // Closing quote not found
730            None => None,
731        }
732    }
733
734    #[inline]
735    fn check_for_duplicates(
736        &mut self,
737        slice: &[u8],
738        key: Range<usize>,
739    ) -> Result<Range<usize>, AttrError> {
740        if self.check_duplicates {
741            if let Some(prev) = self
742                .keys
743                .iter()
744                .find(|r| slice[(*r).clone()] == slice[key.clone()])
745            {
746                return Err(AttrError::Duplicated(key.start, prev.start));
747            }
748            self.keys.push(key.clone());
749        }
750        Ok(key)
751    }
752
753    /// # Parameters
754    ///
755    /// - `slice`: content of the tag, used for checking for duplicates
756    /// - `key`: Range of key in slice, if iterator in HTML mode
757    /// - `offset`: Position of error if iterator in XML mode
758    #[inline]
759    fn key_only(&mut self, slice: &[u8], key: Range<usize>, offset: usize) -> Option<AttrResult> {
760        Some(if self.html {
761            self.check_for_duplicates(slice, key).map(Attr::Empty)
762        } else {
763            Err(AttrError::ExpectedEq(offset))
764        })
765    }
766
767    #[inline]
768    fn double_q(&mut self, key: Range<usize>, value: Range<usize>) -> Option<AttrResult> {
769        self.state = State::Next(value.end + 1); // +1 for `"`
770
771        Some(Ok(Attr::DoubleQ(key, value)))
772    }
773
774    #[inline]
775    fn single_q(&mut self, key: Range<usize>, value: Range<usize>) -> Option<AttrResult> {
776        self.state = State::Next(value.end + 1); // +1 for `'`
777
778        Some(Ok(Attr::SingleQ(key, value)))
779    }
780
781    pub fn next(&mut self, slice: &[u8]) -> Option<AttrResult> {
782        let mut iter = match self.recover(slice) {
783            Some(offset) => (offset..).zip(slice[offset..].iter()),
784            None => return None,
785        };
786
787        // Index where next key started
788        let start_key = match iter.find(|(_, &b)| !is_whitespace(b)) {
789            // Input: `    key`
790            //             ^
791            Some((s, _)) => s,
792            // Input: `    `
793            //             ^
794            None => {
795                // Because we reach end-of-input, stop iteration on next call
796                self.state = State::Done;
797                return None;
798            }
799        };
800        // Span of a key
801        let (key, offset) = match iter.find(|(_, &b)| b == b'=' || is_whitespace(b)) {
802            // Input: `    key=`
803            //             |  ^
804            //             s  e
805            Some((e, b'=')) => (start_key..e, e),
806
807            // Input: `    key `
808            //                ^
809            Some((e, _)) => match iter.find(|(_, &b)| !is_whitespace(b)) {
810                // Input: `    key  =`
811                //             |  | ^
812                //     start_key  e
813                Some((offset, b'=')) => (start_key..e, offset),
814                // Input: `    key  x`
815                //             |  | ^
816                //     start_key  e
817                // If HTML-like attributes is allowed, this is the result, otherwise error
818                Some((offset, _)) => {
819                    // In any case, recovering is not required
820                    self.state = State::Next(offset);
821                    return self.key_only(slice, start_key..e, offset);
822                }
823                // Input: `    key  `
824                //             |  | ^
825                //     start_key  e
826                // If HTML-like attributes is allowed, this is the result, otherwise error
827                None => {
828                    // Because we reach end-of-input, stop iteration on next call
829                    self.state = State::Done;
830                    return self.key_only(slice, start_key..e, slice.len());
831                }
832            },
833
834            // Input: `    key`
835            //             |  ^
836            //             s  e = len()
837            // If HTML-like attributes is allowed, this is the result, otherwise error
838            None => {
839                // Because we reach end-of-input, stop iteration on next call
840                self.state = State::Done;
841                let e = slice.len();
842                return self.key_only(slice, start_key..e, e);
843            }
844        };
845
846        let key = match self.check_for_duplicates(slice, key) {
847            Err(e) => {
848                self.state = State::SkipEqValue(offset);
849                return Some(Err(e));
850            }
851            Ok(key) => key,
852        };
853
854        ////////////////////////////////////////////////////////////////////////
855
856        // Gets the position of quote and quote type
857        let (start_value, quote) = match iter.find(|(_, &b)| !is_whitespace(b)) {
858            // Input: `    key  =  "`
859            //                     ^
860            Some((s, b'"')) => (s + 1, b'"'),
861            // Input: `    key  =  '`
862            //                     ^
863            Some((s, b'\'')) => (s + 1, b'\''),
864
865            // Input: `    key  =  x`
866            //                     ^
867            // If HTML-like attributes is allowed, this is the start of the value
868            Some((s, _)) if self.html => {
869                // We do not check validity of attribute value characters as required
870                // according to https://html.spec.whatwg.org/#unquoted. It can be done
871                // during validation phase
872                let end = match iter.find(|(_, &b)| is_whitespace(b)) {
873                    // Input: `    key  =  value `
874                    //                     |    ^
875                    //                     s    e
876                    Some((e, _)) => e,
877                    // Input: `    key  =  value`
878                    //                     |    ^
879                    //                     s    e = len()
880                    None => slice.len(),
881                };
882                self.state = State::Next(end);
883                return Some(Ok(Attr::Unquoted(key, s..end)));
884            }
885            // Input: `    key  =  x`
886            //                     ^
887            Some((s, _)) => {
888                self.state = State::SkipValue(s);
889                return Some(Err(AttrError::UnquotedValue(s)));
890            }
891
892            // Input: `    key  =  `
893            //                     ^
894            None => {
895                // Because we reach end-of-input, stop iteration on next call
896                self.state = State::Done;
897                return Some(Err(AttrError::ExpectedValue(slice.len())));
898            }
899        };
900
901        match iter.find(|(_, &b)| b == quote) {
902            // Input: `    key  =  "   "`
903            //                         ^
904            Some((e, b'"')) => self.double_q(key, start_value..e),
905            // Input: `    key  =  '   '`
906            //                         ^
907            Some((e, _)) => self.single_q(key, start_value..e),
908
909            // Input: `    key  =  "   `
910            // Input: `    key  =  '   `
911            //                         ^
912            // Closing quote not found
913            None => {
914                // Because we reach end-of-input, stop iteration on next call
915                self.state = State::Done;
916                Some(Err(AttrError::ExpectedQuote(slice.len(), quote)))
917            }
918        }
919    }
920}
921
922////////////////////////////////////////////////////////////////////////////////////////////////////
923
924/// Checks, how parsing of XML-style attributes works. Each attribute should
925/// have a value, enclosed in single or double quotes.
926#[cfg(test)]
927mod xml {
928    use super::*;
929    use pretty_assertions::assert_eq;
930
931    /// Checked attribute is the single attribute
932    mod single {
933        use super::*;
934        use pretty_assertions::assert_eq;
935
936        /// Attribute have a value enclosed in single quotes
937        #[test]
938        fn single_quoted() {
939            let mut iter = Attributes::new(r#"tag key='value'"#, 3);
940
941            assert_eq!(
942                iter.next(),
943                Some(Ok(Attribute {
944                    key: QName(b"key"),
945                    value: Cow::Borrowed(b"value"),
946                }))
947            );
948            assert_eq!(iter.next(), None);
949            assert_eq!(iter.next(), None);
950        }
951
952        /// Attribute have a value enclosed in double quotes
953        #[test]
954        fn double_quoted() {
955            let mut iter = Attributes::new(r#"tag key="value""#, 3);
956
957            assert_eq!(
958                iter.next(),
959                Some(Ok(Attribute {
960                    key: QName(b"key"),
961                    value: Cow::Borrowed(b"value"),
962                }))
963            );
964            assert_eq!(iter.next(), None);
965            assert_eq!(iter.next(), None);
966        }
967
968        /// Attribute have a value, not enclosed in quotes
969        #[test]
970        fn unquoted() {
971            let mut iter = Attributes::new(r#"tag key=value"#, 3);
972            //                                0       ^ = 8
973
974            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(8))));
975            assert_eq!(iter.next(), None);
976            assert_eq!(iter.next(), None);
977        }
978
979        /// Only attribute key is present
980        #[test]
981        fn key_only() {
982            let mut iter = Attributes::new(r#"tag key"#, 3);
983            //                                0      ^ = 7
984
985            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(7))));
986            assert_eq!(iter.next(), None);
987            assert_eq!(iter.next(), None);
988        }
989
990        /// Key is started with an invalid symbol (a single quote in this test).
991        /// Because we do not check validity of keys and values during parsing,
992        /// that invalid attribute will be returned
993        #[test]
994        fn key_start_invalid() {
995            let mut iter = Attributes::new(r#"tag 'key'='value'"#, 3);
996
997            assert_eq!(
998                iter.next(),
999                Some(Ok(Attribute {
1000                    key: QName(b"'key'"),
1001                    value: Cow::Borrowed(b"value"),
1002                }))
1003            );
1004            assert_eq!(iter.next(), None);
1005            assert_eq!(iter.next(), None);
1006        }
1007
1008        /// Key contains an invalid symbol (an ampersand in this test).
1009        /// Because we do not check validity of keys and values during parsing,
1010        /// that invalid attribute will be returned
1011        #[test]
1012        fn key_contains_invalid() {
1013            let mut iter = Attributes::new(r#"tag key&jey='value'"#, 3);
1014
1015            assert_eq!(
1016                iter.next(),
1017                Some(Ok(Attribute {
1018                    key: QName(b"key&jey"),
1019                    value: Cow::Borrowed(b"value"),
1020                }))
1021            );
1022            assert_eq!(iter.next(), None);
1023            assert_eq!(iter.next(), None);
1024        }
1025
1026        /// Attribute value is missing after `=`
1027        #[test]
1028        fn missed_value() {
1029            let mut iter = Attributes::new(r#"tag key="#, 3);
1030            //                                0       ^ = 8
1031
1032            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedValue(8))));
1033            assert_eq!(iter.next(), None);
1034            assert_eq!(iter.next(), None);
1035        }
1036    }
1037
1038    /// Checked attribute is the first attribute in the list of many attributes
1039    mod first {
1040        use super::*;
1041        use pretty_assertions::assert_eq;
1042
1043        /// Attribute have a value enclosed in single quotes
1044        #[test]
1045        fn single_quoted() {
1046            let mut iter = Attributes::new(r#"tag key='value' regular='attribute'"#, 3);
1047
1048            assert_eq!(
1049                iter.next(),
1050                Some(Ok(Attribute {
1051                    key: QName(b"key"),
1052                    value: Cow::Borrowed(b"value"),
1053                }))
1054            );
1055            assert_eq!(
1056                iter.next(),
1057                Some(Ok(Attribute {
1058                    key: QName(b"regular"),
1059                    value: Cow::Borrowed(b"attribute"),
1060                }))
1061            );
1062            assert_eq!(iter.next(), None);
1063            assert_eq!(iter.next(), None);
1064        }
1065
1066        /// Attribute have a value enclosed in double quotes
1067        #[test]
1068        fn double_quoted() {
1069            let mut iter = Attributes::new(r#"tag key="value" regular='attribute'"#, 3);
1070
1071            assert_eq!(
1072                iter.next(),
1073                Some(Ok(Attribute {
1074                    key: QName(b"key"),
1075                    value: Cow::Borrowed(b"value"),
1076                }))
1077            );
1078            assert_eq!(
1079                iter.next(),
1080                Some(Ok(Attribute {
1081                    key: QName(b"regular"),
1082                    value: Cow::Borrowed(b"attribute"),
1083                }))
1084            );
1085            assert_eq!(iter.next(), None);
1086            assert_eq!(iter.next(), None);
1087        }
1088
1089        /// Attribute have a value, not enclosed in quotes
1090        #[test]
1091        fn unquoted() {
1092            let mut iter = Attributes::new(r#"tag key=value regular='attribute'"#, 3);
1093            //                                0       ^ = 8
1094
1095            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(8))));
1096            // check error recovery
1097            assert_eq!(
1098                iter.next(),
1099                Some(Ok(Attribute {
1100                    key: QName(b"regular"),
1101                    value: Cow::Borrowed(b"attribute"),
1102                }))
1103            );
1104            assert_eq!(iter.next(), None);
1105            assert_eq!(iter.next(), None);
1106        }
1107
1108        /// Only attribute key is present
1109        #[test]
1110        fn key_only() {
1111            let mut iter = Attributes::new(r#"tag key regular='attribute'"#, 3);
1112            //                                0       ^ = 8
1113
1114            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(8))));
1115            // check error recovery
1116            assert_eq!(
1117                iter.next(),
1118                Some(Ok(Attribute {
1119                    key: QName(b"regular"),
1120                    value: Cow::Borrowed(b"attribute"),
1121                }))
1122            );
1123            assert_eq!(iter.next(), None);
1124            assert_eq!(iter.next(), None);
1125        }
1126
1127        /// Key is started with an invalid symbol (a single quote in this test).
1128        /// Because we do not check validity of keys and values during parsing,
1129        /// that invalid attribute will be returned
1130        #[test]
1131        fn key_start_invalid() {
1132            let mut iter = Attributes::new(r#"tag 'key'='value' regular='attribute'"#, 3);
1133
1134            assert_eq!(
1135                iter.next(),
1136                Some(Ok(Attribute {
1137                    key: QName(b"'key'"),
1138                    value: Cow::Borrowed(b"value"),
1139                }))
1140            );
1141            assert_eq!(
1142                iter.next(),
1143                Some(Ok(Attribute {
1144                    key: QName(b"regular"),
1145                    value: Cow::Borrowed(b"attribute"),
1146                }))
1147            );
1148            assert_eq!(iter.next(), None);
1149            assert_eq!(iter.next(), None);
1150        }
1151
1152        /// Key contains an invalid symbol (an ampersand in this test).
1153        /// Because we do not check validity of keys and values during parsing,
1154        /// that invalid attribute will be returned
1155        #[test]
1156        fn key_contains_invalid() {
1157            let mut iter = Attributes::new(r#"tag key&jey='value' regular='attribute'"#, 3);
1158
1159            assert_eq!(
1160                iter.next(),
1161                Some(Ok(Attribute {
1162                    key: QName(b"key&jey"),
1163                    value: Cow::Borrowed(b"value"),
1164                }))
1165            );
1166            assert_eq!(
1167                iter.next(),
1168                Some(Ok(Attribute {
1169                    key: QName(b"regular"),
1170                    value: Cow::Borrowed(b"attribute"),
1171                }))
1172            );
1173            assert_eq!(iter.next(), None);
1174            assert_eq!(iter.next(), None);
1175        }
1176
1177        /// Attribute value is missing after `=`.
1178        #[test]
1179        fn missed_value() {
1180            let mut iter = Attributes::new(r#"tag key= regular='attribute'"#, 3);
1181            //                                0        ^ = 9
1182
1183            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(9))));
1184            // Because we do not check validity of keys and values during parsing,
1185            // "error='recovery'" is considered, as unquoted attribute value and
1186            // skipped during recovery and iteration finished
1187            assert_eq!(iter.next(), None);
1188            assert_eq!(iter.next(), None);
1189
1190            ////////////////////////////////////////////////////////////////////
1191
1192            let mut iter = Attributes::new(r#"tag key= regular= 'attribute'"#, 3);
1193            //                                0        ^ = 9               ^ = 29
1194
1195            // In that case "regular=" considered as unquoted value
1196            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(9))));
1197            // In that case "'attribute'" considered as a key, because we do not check
1198            // validity of key names
1199            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(29))));
1200            assert_eq!(iter.next(), None);
1201            assert_eq!(iter.next(), None);
1202
1203            ////////////////////////////////////////////////////////////////////
1204
1205            let mut iter = Attributes::new(r#"tag key= regular ='attribute'"#, 3);
1206            //                                0        ^ = 9               ^ = 29
1207
1208            // In that case "regular" considered as unquoted value
1209            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(9))));
1210            // In that case "='attribute'" considered as a key, because we do not check
1211            // validity of key names
1212            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(29))));
1213            assert_eq!(iter.next(), None);
1214            assert_eq!(iter.next(), None);
1215
1216            ////////////////////////////////////////////////////////////////////
1217
1218            let mut iter = Attributes::new(r#"tag key= regular = 'attribute'"#, 3);
1219            //                                0        ^ = 9     ^ = 19     ^ = 30
1220
1221            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(9))));
1222            // In that case second "=" considered as a key, because we do not check
1223            // validity of key names
1224            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(19))));
1225            // In that case "'attribute'" considered as a key, because we do not check
1226            // validity of key names
1227            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(30))));
1228            assert_eq!(iter.next(), None);
1229            assert_eq!(iter.next(), None);
1230        }
1231    }
1232
1233    /// Copy of single, but with additional spaces in markup
1234    mod sparsed {
1235        use super::*;
1236        use pretty_assertions::assert_eq;
1237
1238        /// Attribute have a value enclosed in single quotes
1239        #[test]
1240        fn single_quoted() {
1241            let mut iter = Attributes::new(r#"tag key = 'value' "#, 3);
1242
1243            assert_eq!(
1244                iter.next(),
1245                Some(Ok(Attribute {
1246                    key: QName(b"key"),
1247                    value: Cow::Borrowed(b"value"),
1248                }))
1249            );
1250            assert_eq!(iter.next(), None);
1251            assert_eq!(iter.next(), None);
1252        }
1253
1254        /// Attribute have a value enclosed in double quotes
1255        #[test]
1256        fn double_quoted() {
1257            let mut iter = Attributes::new(r#"tag key = "value" "#, 3);
1258
1259            assert_eq!(
1260                iter.next(),
1261                Some(Ok(Attribute {
1262                    key: QName(b"key"),
1263                    value: Cow::Borrowed(b"value"),
1264                }))
1265            );
1266            assert_eq!(iter.next(), None);
1267            assert_eq!(iter.next(), None);
1268        }
1269
1270        /// Attribute have a value, not enclosed in quotes
1271        #[test]
1272        fn unquoted() {
1273            let mut iter = Attributes::new(r#"tag key = value "#, 3);
1274            //                                0         ^ = 10
1275
1276            assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(10))));
1277            assert_eq!(iter.next(), None);
1278            assert_eq!(iter.next(), None);
1279        }
1280
1281        /// Only attribute key is present
1282        #[test]
1283        fn key_only() {
1284            let mut iter = Attributes::new(r#"tag key "#, 3);
1285            //                                0       ^ = 8
1286
1287            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(8))));
1288            assert_eq!(iter.next(), None);
1289            assert_eq!(iter.next(), None);
1290        }
1291
1292        /// Key is started with an invalid symbol (a single quote in this test).
1293        /// Because we do not check validity of keys and values during parsing,
1294        /// that invalid attribute will be returned
1295        #[test]
1296        fn key_start_invalid() {
1297            let mut iter = Attributes::new(r#"tag 'key' = 'value' "#, 3);
1298
1299            assert_eq!(
1300                iter.next(),
1301                Some(Ok(Attribute {
1302                    key: QName(b"'key'"),
1303                    value: Cow::Borrowed(b"value"),
1304                }))
1305            );
1306            assert_eq!(iter.next(), None);
1307            assert_eq!(iter.next(), None);
1308        }
1309
1310        /// Key contains an invalid symbol (an ampersand in this test).
1311        /// Because we do not check validity of keys and values during parsing,
1312        /// that invalid attribute will be returned
1313        #[test]
1314        fn key_contains_invalid() {
1315            let mut iter = Attributes::new(r#"tag key&jey = 'value' "#, 3);
1316
1317            assert_eq!(
1318                iter.next(),
1319                Some(Ok(Attribute {
1320                    key: QName(b"key&jey"),
1321                    value: Cow::Borrowed(b"value"),
1322                }))
1323            );
1324            assert_eq!(iter.next(), None);
1325            assert_eq!(iter.next(), None);
1326        }
1327
1328        /// Attribute value is missing after `=`
1329        #[test]
1330        fn missed_value() {
1331            let mut iter = Attributes::new(r#"tag key = "#, 3);
1332            //                                0         ^ = 10
1333
1334            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedValue(10))));
1335            assert_eq!(iter.next(), None);
1336            assert_eq!(iter.next(), None);
1337        }
1338    }
1339
1340    /// Checks that duplicated attributes correctly reported and recovering is
1341    /// possible after that
1342    mod duplicated {
1343        use super::*;
1344
1345        mod with_check {
1346            use super::*;
1347            use pretty_assertions::assert_eq;
1348
1349            /// Attribute have a value enclosed in single quotes
1350            #[test]
1351            fn single_quoted() {
1352                let mut iter = Attributes::new(r#"tag key='value' key='dup' another=''"#, 3);
1353                //                                0   ^ = 4       ^ = 16
1354
1355                assert_eq!(
1356                    iter.next(),
1357                    Some(Ok(Attribute {
1358                        key: QName(b"key"),
1359                        value: Cow::Borrowed(b"value"),
1360                    }))
1361                );
1362                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
1363                assert_eq!(
1364                    iter.next(),
1365                    Some(Ok(Attribute {
1366                        key: QName(b"another"),
1367                        value: Cow::Borrowed(b""),
1368                    }))
1369                );
1370                assert_eq!(iter.next(), None);
1371                assert_eq!(iter.next(), None);
1372            }
1373
1374            /// Attribute have a value enclosed in double quotes
1375            #[test]
1376            fn double_quoted() {
1377                let mut iter = Attributes::new(r#"tag key='value' key="dup" another=''"#, 3);
1378                //                                0   ^ = 4       ^ = 16
1379
1380                assert_eq!(
1381                    iter.next(),
1382                    Some(Ok(Attribute {
1383                        key: QName(b"key"),
1384                        value: Cow::Borrowed(b"value"),
1385                    }))
1386                );
1387                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
1388                assert_eq!(
1389                    iter.next(),
1390                    Some(Ok(Attribute {
1391                        key: QName(b"another"),
1392                        value: Cow::Borrowed(b""),
1393                    }))
1394                );
1395                assert_eq!(iter.next(), None);
1396                assert_eq!(iter.next(), None);
1397            }
1398
1399            /// Attribute have a value, not enclosed in quotes
1400            #[test]
1401            fn unquoted() {
1402                let mut iter = Attributes::new(r#"tag key='value' key=dup another=''"#, 3);
1403                //                                0   ^ = 4       ^ = 16
1404
1405                assert_eq!(
1406                    iter.next(),
1407                    Some(Ok(Attribute {
1408                        key: QName(b"key"),
1409                        value: Cow::Borrowed(b"value"),
1410                    }))
1411                );
1412                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
1413                assert_eq!(
1414                    iter.next(),
1415                    Some(Ok(Attribute {
1416                        key: QName(b"another"),
1417                        value: Cow::Borrowed(b""),
1418                    }))
1419                );
1420                assert_eq!(iter.next(), None);
1421                assert_eq!(iter.next(), None);
1422            }
1423
1424            /// Only attribute key is present
1425            #[test]
1426            fn key_only() {
1427                let mut iter = Attributes::new(r#"tag key='value' key another=''"#, 3);
1428                //                                0                   ^ = 20
1429
1430                assert_eq!(
1431                    iter.next(),
1432                    Some(Ok(Attribute {
1433                        key: QName(b"key"),
1434                        value: Cow::Borrowed(b"value"),
1435                    }))
1436                );
1437                assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(20))));
1438                assert_eq!(
1439                    iter.next(),
1440                    Some(Ok(Attribute {
1441                        key: QName(b"another"),
1442                        value: Cow::Borrowed(b""),
1443                    }))
1444                );
1445                assert_eq!(iter.next(), None);
1446                assert_eq!(iter.next(), None);
1447            }
1448        }
1449
1450        /// Check for duplicated names is disabled
1451        mod without_check {
1452            use super::*;
1453            use pretty_assertions::assert_eq;
1454
1455            /// Attribute have a value enclosed in single quotes
1456            #[test]
1457            fn single_quoted() {
1458                let mut iter = Attributes::new(r#"tag key='value' key='dup' another=''"#, 3);
1459                iter.with_checks(false);
1460
1461                assert_eq!(
1462                    iter.next(),
1463                    Some(Ok(Attribute {
1464                        key: QName(b"key"),
1465                        value: Cow::Borrowed(b"value"),
1466                    }))
1467                );
1468                assert_eq!(
1469                    iter.next(),
1470                    Some(Ok(Attribute {
1471                        key: QName(b"key"),
1472                        value: Cow::Borrowed(b"dup"),
1473                    }))
1474                );
1475                assert_eq!(
1476                    iter.next(),
1477                    Some(Ok(Attribute {
1478                        key: QName(b"another"),
1479                        value: Cow::Borrowed(b""),
1480                    }))
1481                );
1482                assert_eq!(iter.next(), None);
1483                assert_eq!(iter.next(), None);
1484            }
1485
1486            /// Attribute have a value enclosed in double quotes
1487            #[test]
1488            fn double_quoted() {
1489                let mut iter = Attributes::new(r#"tag key='value' key="dup" another=''"#, 3);
1490                iter.with_checks(false);
1491
1492                assert_eq!(
1493                    iter.next(),
1494                    Some(Ok(Attribute {
1495                        key: QName(b"key"),
1496                        value: Cow::Borrowed(b"value"),
1497                    }))
1498                );
1499                assert_eq!(
1500                    iter.next(),
1501                    Some(Ok(Attribute {
1502                        key: QName(b"key"),
1503                        value: Cow::Borrowed(b"dup"),
1504                    }))
1505                );
1506                assert_eq!(
1507                    iter.next(),
1508                    Some(Ok(Attribute {
1509                        key: QName(b"another"),
1510                        value: Cow::Borrowed(b""),
1511                    }))
1512                );
1513                assert_eq!(iter.next(), None);
1514                assert_eq!(iter.next(), None);
1515            }
1516
1517            /// Attribute have a value, not enclosed in quotes
1518            #[test]
1519            fn unquoted() {
1520                let mut iter = Attributes::new(r#"tag key='value' key=dup another=''"#, 3);
1521                //                                0                   ^ = 20
1522                iter.with_checks(false);
1523
1524                assert_eq!(
1525                    iter.next(),
1526                    Some(Ok(Attribute {
1527                        key: QName(b"key"),
1528                        value: Cow::Borrowed(b"value"),
1529                    }))
1530                );
1531                assert_eq!(iter.next(), Some(Err(AttrError::UnquotedValue(20))));
1532                assert_eq!(
1533                    iter.next(),
1534                    Some(Ok(Attribute {
1535                        key: QName(b"another"),
1536                        value: Cow::Borrowed(b""),
1537                    }))
1538                );
1539                assert_eq!(iter.next(), None);
1540                assert_eq!(iter.next(), None);
1541            }
1542
1543            /// Only attribute key is present
1544            #[test]
1545            fn key_only() {
1546                let mut iter = Attributes::new(r#"tag key='value' key another=''"#, 3);
1547                //                                0                   ^ = 20
1548                iter.with_checks(false);
1549
1550                assert_eq!(
1551                    iter.next(),
1552                    Some(Ok(Attribute {
1553                        key: QName(b"key"),
1554                        value: Cow::Borrowed(b"value"),
1555                    }))
1556                );
1557                assert_eq!(iter.next(), Some(Err(AttrError::ExpectedEq(20))));
1558                assert_eq!(
1559                    iter.next(),
1560                    Some(Ok(Attribute {
1561                        key: QName(b"another"),
1562                        value: Cow::Borrowed(b""),
1563                    }))
1564                );
1565                assert_eq!(iter.next(), None);
1566                assert_eq!(iter.next(), None);
1567            }
1568        }
1569    }
1570
1571    #[test]
1572    fn mixed_quote() {
1573        let mut iter = Attributes::new(r#"tag a='a' b = "b" c='cc"cc' d="dd'dd""#, 3);
1574
1575        assert_eq!(
1576            iter.next(),
1577            Some(Ok(Attribute {
1578                key: QName(b"a"),
1579                value: Cow::Borrowed(b"a"),
1580            }))
1581        );
1582        assert_eq!(
1583            iter.next(),
1584            Some(Ok(Attribute {
1585                key: QName(b"b"),
1586                value: Cow::Borrowed(b"b"),
1587            }))
1588        );
1589        assert_eq!(
1590            iter.next(),
1591            Some(Ok(Attribute {
1592                key: QName(b"c"),
1593                value: Cow::Borrowed(br#"cc"cc"#),
1594            }))
1595        );
1596        assert_eq!(
1597            iter.next(),
1598            Some(Ok(Attribute {
1599                key: QName(b"d"),
1600                value: Cow::Borrowed(b"dd'dd"),
1601            }))
1602        );
1603        assert_eq!(iter.next(), None);
1604        assert_eq!(iter.next(), None);
1605    }
1606}
1607
1608/// Checks, how parsing of HTML-style attributes works. Each attribute can be
1609/// in three forms:
1610/// - XML-like: have a value, enclosed in single or double quotes
1611/// - have a value, do not enclosed in quotes
1612/// - without value, key only
1613#[cfg(test)]
1614mod html {
1615    use super::*;
1616    use pretty_assertions::assert_eq;
1617
1618    /// Checked attribute is the single attribute
1619    mod single {
1620        use super::*;
1621        use pretty_assertions::assert_eq;
1622
1623        /// Attribute have a value enclosed in single quotes
1624        #[test]
1625        fn single_quoted() {
1626            let mut iter = Attributes::html(r#"tag key='value'"#, 3);
1627
1628            assert_eq!(
1629                iter.next(),
1630                Some(Ok(Attribute {
1631                    key: QName(b"key"),
1632                    value: Cow::Borrowed(b"value"),
1633                }))
1634            );
1635            assert_eq!(iter.next(), None);
1636            assert_eq!(iter.next(), None);
1637        }
1638
1639        /// Attribute have a value enclosed in double quotes
1640        #[test]
1641        fn double_quoted() {
1642            let mut iter = Attributes::html(r#"tag key="value""#, 3);
1643
1644            assert_eq!(
1645                iter.next(),
1646                Some(Ok(Attribute {
1647                    key: QName(b"key"),
1648                    value: Cow::Borrowed(b"value"),
1649                }))
1650            );
1651            assert_eq!(iter.next(), None);
1652            assert_eq!(iter.next(), None);
1653        }
1654
1655        /// Attribute have a value, not enclosed in quotes
1656        #[test]
1657        fn unquoted() {
1658            let mut iter = Attributes::html(r#"tag key=value"#, 3);
1659
1660            assert_eq!(
1661                iter.next(),
1662                Some(Ok(Attribute {
1663                    key: QName(b"key"),
1664                    value: Cow::Borrowed(b"value"),
1665                }))
1666            );
1667            assert_eq!(iter.next(), None);
1668            assert_eq!(iter.next(), None);
1669        }
1670
1671        /// Only attribute key is present
1672        #[test]
1673        fn key_only() {
1674            let mut iter = Attributes::html(r#"tag key"#, 3);
1675
1676            assert_eq!(
1677                iter.next(),
1678                Some(Ok(Attribute {
1679                    key: QName(b"key"),
1680                    value: Cow::Borrowed(&[]),
1681                }))
1682            );
1683            assert_eq!(iter.next(), None);
1684            assert_eq!(iter.next(), None);
1685        }
1686
1687        /// Key is started with an invalid symbol (a single quote in this test).
1688        /// Because we do not check validity of keys and values during parsing,
1689        /// that invalid attribute will be returned
1690        #[test]
1691        fn key_start_invalid() {
1692            let mut iter = Attributes::html(r#"tag 'key'='value'"#, 3);
1693
1694            assert_eq!(
1695                iter.next(),
1696                Some(Ok(Attribute {
1697                    key: QName(b"'key'"),
1698                    value: Cow::Borrowed(b"value"),
1699                }))
1700            );
1701            assert_eq!(iter.next(), None);
1702            assert_eq!(iter.next(), None);
1703        }
1704
1705        /// Key contains an invalid symbol (an ampersand in this test).
1706        /// Because we do not check validity of keys and values during parsing,
1707        /// that invalid attribute will be returned
1708        #[test]
1709        fn key_contains_invalid() {
1710            let mut iter = Attributes::html(r#"tag key&jey='value'"#, 3);
1711
1712            assert_eq!(
1713                iter.next(),
1714                Some(Ok(Attribute {
1715                    key: QName(b"key&jey"),
1716                    value: Cow::Borrowed(b"value"),
1717                }))
1718            );
1719            assert_eq!(iter.next(), None);
1720            assert_eq!(iter.next(), None);
1721        }
1722
1723        /// Attribute value is missing after `=`
1724        #[test]
1725        fn missed_value() {
1726            let mut iter = Attributes::html(r#"tag key="#, 3);
1727            //                                0       ^ = 8
1728
1729            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedValue(8))));
1730            assert_eq!(iter.next(), None);
1731            assert_eq!(iter.next(), None);
1732        }
1733    }
1734
1735    /// Checked attribute is the first attribute in the list of many attributes
1736    mod first {
1737        use super::*;
1738        use pretty_assertions::assert_eq;
1739
1740        /// Attribute have a value enclosed in single quotes
1741        #[test]
1742        fn single_quoted() {
1743            let mut iter = Attributes::html(r#"tag key='value' regular='attribute'"#, 3);
1744
1745            assert_eq!(
1746                iter.next(),
1747                Some(Ok(Attribute {
1748                    key: QName(b"key"),
1749                    value: Cow::Borrowed(b"value"),
1750                }))
1751            );
1752            assert_eq!(
1753                iter.next(),
1754                Some(Ok(Attribute {
1755                    key: QName(b"regular"),
1756                    value: Cow::Borrowed(b"attribute"),
1757                }))
1758            );
1759            assert_eq!(iter.next(), None);
1760            assert_eq!(iter.next(), None);
1761        }
1762
1763        /// Attribute have a value enclosed in double quotes
1764        #[test]
1765        fn double_quoted() {
1766            let mut iter = Attributes::html(r#"tag key="value" regular='attribute'"#, 3);
1767
1768            assert_eq!(
1769                iter.next(),
1770                Some(Ok(Attribute {
1771                    key: QName(b"key"),
1772                    value: Cow::Borrowed(b"value"),
1773                }))
1774            );
1775            assert_eq!(
1776                iter.next(),
1777                Some(Ok(Attribute {
1778                    key: QName(b"regular"),
1779                    value: Cow::Borrowed(b"attribute"),
1780                }))
1781            );
1782            assert_eq!(iter.next(), None);
1783            assert_eq!(iter.next(), None);
1784        }
1785
1786        /// Attribute have a value, not enclosed in quotes
1787        #[test]
1788        fn unquoted() {
1789            let mut iter = Attributes::html(r#"tag key=value regular='attribute'"#, 3);
1790
1791            assert_eq!(
1792                iter.next(),
1793                Some(Ok(Attribute {
1794                    key: QName(b"key"),
1795                    value: Cow::Borrowed(b"value"),
1796                }))
1797            );
1798            assert_eq!(
1799                iter.next(),
1800                Some(Ok(Attribute {
1801                    key: QName(b"regular"),
1802                    value: Cow::Borrowed(b"attribute"),
1803                }))
1804            );
1805            assert_eq!(iter.next(), None);
1806            assert_eq!(iter.next(), None);
1807        }
1808
1809        /// Only attribute key is present
1810        #[test]
1811        fn key_only() {
1812            let mut iter = Attributes::html(r#"tag key regular='attribute'"#, 3);
1813
1814            assert_eq!(
1815                iter.next(),
1816                Some(Ok(Attribute {
1817                    key: QName(b"key"),
1818                    value: Cow::Borrowed(&[]),
1819                }))
1820            );
1821            assert_eq!(
1822                iter.next(),
1823                Some(Ok(Attribute {
1824                    key: QName(b"regular"),
1825                    value: Cow::Borrowed(b"attribute"),
1826                }))
1827            );
1828            assert_eq!(iter.next(), None);
1829            assert_eq!(iter.next(), None);
1830        }
1831
1832        /// Key is started with an invalid symbol (a single quote in this test).
1833        /// Because we do not check validity of keys and values during parsing,
1834        /// that invalid attribute will be returned
1835        #[test]
1836        fn key_start_invalid() {
1837            let mut iter = Attributes::html(r#"tag 'key'='value' regular='attribute'"#, 3);
1838
1839            assert_eq!(
1840                iter.next(),
1841                Some(Ok(Attribute {
1842                    key: QName(b"'key'"),
1843                    value: Cow::Borrowed(b"value"),
1844                }))
1845            );
1846            assert_eq!(
1847                iter.next(),
1848                Some(Ok(Attribute {
1849                    key: QName(b"regular"),
1850                    value: Cow::Borrowed(b"attribute"),
1851                }))
1852            );
1853            assert_eq!(iter.next(), None);
1854            assert_eq!(iter.next(), None);
1855        }
1856
1857        /// Key contains an invalid symbol (an ampersand in this test).
1858        /// Because we do not check validity of keys and values during parsing,
1859        /// that invalid attribute will be returned
1860        #[test]
1861        fn key_contains_invalid() {
1862            let mut iter = Attributes::html(r#"tag key&jey='value' regular='attribute'"#, 3);
1863
1864            assert_eq!(
1865                iter.next(),
1866                Some(Ok(Attribute {
1867                    key: QName(b"key&jey"),
1868                    value: Cow::Borrowed(b"value"),
1869                }))
1870            );
1871            assert_eq!(
1872                iter.next(),
1873                Some(Ok(Attribute {
1874                    key: QName(b"regular"),
1875                    value: Cow::Borrowed(b"attribute"),
1876                }))
1877            );
1878            assert_eq!(iter.next(), None);
1879            assert_eq!(iter.next(), None);
1880        }
1881
1882        /// Attribute value is missing after `=`
1883        #[test]
1884        fn missed_value() {
1885            let mut iter = Attributes::html(r#"tag key= regular='attribute'"#, 3);
1886
1887            // Because we do not check validity of keys and values during parsing,
1888            // "regular='attribute'" is considered as unquoted attribute value
1889            assert_eq!(
1890                iter.next(),
1891                Some(Ok(Attribute {
1892                    key: QName(b"key"),
1893                    value: Cow::Borrowed(b"regular='attribute'"),
1894                }))
1895            );
1896            assert_eq!(iter.next(), None);
1897            assert_eq!(iter.next(), None);
1898
1899            ////////////////////////////////////////////////////////////////////
1900
1901            let mut iter = Attributes::html(r#"tag key= regular= 'attribute'"#, 3);
1902
1903            // Because we do not check validity of keys and values during parsing,
1904            // "regular=" is considered as unquoted attribute value
1905            assert_eq!(
1906                iter.next(),
1907                Some(Ok(Attribute {
1908                    key: QName(b"key"),
1909                    value: Cow::Borrowed(b"regular="),
1910                }))
1911            );
1912            // Because we do not check validity of keys and values during parsing,
1913            // "'attribute'" is considered as key-only attribute
1914            assert_eq!(
1915                iter.next(),
1916                Some(Ok(Attribute {
1917                    key: QName(b"'attribute'"),
1918                    value: Cow::Borrowed(&[]),
1919                }))
1920            );
1921            assert_eq!(iter.next(), None);
1922            assert_eq!(iter.next(), None);
1923
1924            ////////////////////////////////////////////////////////////////////
1925
1926            let mut iter = Attributes::html(r#"tag key= regular ='attribute'"#, 3);
1927
1928            // Because we do not check validity of keys and values during parsing,
1929            // "regular" is considered as unquoted attribute value
1930            assert_eq!(
1931                iter.next(),
1932                Some(Ok(Attribute {
1933                    key: QName(b"key"),
1934                    value: Cow::Borrowed(b"regular"),
1935                }))
1936            );
1937            // Because we do not check validity of keys and values during parsing,
1938            // "='attribute'" is considered as key-only attribute
1939            assert_eq!(
1940                iter.next(),
1941                Some(Ok(Attribute {
1942                    key: QName(b"='attribute'"),
1943                    value: Cow::Borrowed(&[]),
1944                }))
1945            );
1946            assert_eq!(iter.next(), None);
1947            assert_eq!(iter.next(), None);
1948
1949            ////////////////////////////////////////////////////////////////////
1950
1951            let mut iter = Attributes::html(r#"tag key= regular = 'attribute'"#, 3);
1952            //                                 0        ^ = 9     ^ = 19     ^ = 30
1953
1954            // Because we do not check validity of keys and values during parsing,
1955            // "regular" is considered as unquoted attribute value
1956            assert_eq!(
1957                iter.next(),
1958                Some(Ok(Attribute {
1959                    key: QName(b"key"),
1960                    value: Cow::Borrowed(b"regular"),
1961                }))
1962            );
1963            // Because we do not check validity of keys and values during parsing,
1964            // "=" is considered as key-only attribute
1965            assert_eq!(
1966                iter.next(),
1967                Some(Ok(Attribute {
1968                    key: QName(b"="),
1969                    value: Cow::Borrowed(&[]),
1970                }))
1971            );
1972            // Because we do not check validity of keys and values during parsing,
1973            // "'attribute'" is considered as key-only attribute
1974            assert_eq!(
1975                iter.next(),
1976                Some(Ok(Attribute {
1977                    key: QName(b"'attribute'"),
1978                    value: Cow::Borrowed(&[]),
1979                }))
1980            );
1981            assert_eq!(iter.next(), None);
1982            assert_eq!(iter.next(), None);
1983        }
1984    }
1985
1986    /// Copy of single, but with additional spaces in markup
1987    mod sparsed {
1988        use super::*;
1989        use pretty_assertions::assert_eq;
1990
1991        /// Attribute have a value enclosed in single quotes
1992        #[test]
1993        fn single_quoted() {
1994            let mut iter = Attributes::html(r#"tag key = 'value' "#, 3);
1995
1996            assert_eq!(
1997                iter.next(),
1998                Some(Ok(Attribute {
1999                    key: QName(b"key"),
2000                    value: Cow::Borrowed(b"value"),
2001                }))
2002            );
2003            assert_eq!(iter.next(), None);
2004            assert_eq!(iter.next(), None);
2005        }
2006
2007        /// Attribute have a value enclosed in double quotes
2008        #[test]
2009        fn double_quoted() {
2010            let mut iter = Attributes::html(r#"tag key = "value" "#, 3);
2011
2012            assert_eq!(
2013                iter.next(),
2014                Some(Ok(Attribute {
2015                    key: QName(b"key"),
2016                    value: Cow::Borrowed(b"value"),
2017                }))
2018            );
2019            assert_eq!(iter.next(), None);
2020            assert_eq!(iter.next(), None);
2021        }
2022
2023        /// Attribute have a value, not enclosed in quotes
2024        #[test]
2025        fn unquoted() {
2026            let mut iter = Attributes::html(r#"tag key = value "#, 3);
2027
2028            assert_eq!(
2029                iter.next(),
2030                Some(Ok(Attribute {
2031                    key: QName(b"key"),
2032                    value: Cow::Borrowed(b"value"),
2033                }))
2034            );
2035            assert_eq!(iter.next(), None);
2036            assert_eq!(iter.next(), None);
2037        }
2038
2039        /// Only attribute key is present
2040        #[test]
2041        fn key_only() {
2042            let mut iter = Attributes::html(r#"tag key "#, 3);
2043
2044            assert_eq!(
2045                iter.next(),
2046                Some(Ok(Attribute {
2047                    key: QName(b"key"),
2048                    value: Cow::Borrowed(&[]),
2049                }))
2050            );
2051            assert_eq!(iter.next(), None);
2052            assert_eq!(iter.next(), None);
2053        }
2054
2055        /// Key is started with an invalid symbol (a single quote in this test).
2056        /// Because we do not check validity of keys and values during parsing,
2057        /// that invalid attribute will be returned
2058        #[test]
2059        fn key_start_invalid() {
2060            let mut iter = Attributes::html(r#"tag 'key' = 'value' "#, 3);
2061
2062            assert_eq!(
2063                iter.next(),
2064                Some(Ok(Attribute {
2065                    key: QName(b"'key'"),
2066                    value: Cow::Borrowed(b"value"),
2067                }))
2068            );
2069            assert_eq!(iter.next(), None);
2070            assert_eq!(iter.next(), None);
2071        }
2072
2073        /// Key contains an invalid symbol (an ampersand in this test).
2074        /// Because we do not check validity of keys and values during parsing,
2075        /// that invalid attribute will be returned
2076        #[test]
2077        fn key_contains_invalid() {
2078            let mut iter = Attributes::html(r#"tag key&jey = 'value' "#, 3);
2079
2080            assert_eq!(
2081                iter.next(),
2082                Some(Ok(Attribute {
2083                    key: QName(b"key&jey"),
2084                    value: Cow::Borrowed(b"value"),
2085                }))
2086            );
2087            assert_eq!(iter.next(), None);
2088            assert_eq!(iter.next(), None);
2089        }
2090
2091        /// Attribute value is missing after `=`
2092        #[test]
2093        fn missed_value() {
2094            let mut iter = Attributes::html(r#"tag key = "#, 3);
2095            //                                 0         ^ = 10
2096
2097            assert_eq!(iter.next(), Some(Err(AttrError::ExpectedValue(10))));
2098            assert_eq!(iter.next(), None);
2099            assert_eq!(iter.next(), None);
2100        }
2101    }
2102
2103    /// Checks that duplicated attributes correctly reported and recovering is
2104    /// possible after that
2105    mod duplicated {
2106        use super::*;
2107
2108        mod with_check {
2109            use super::*;
2110            use pretty_assertions::assert_eq;
2111
2112            /// Attribute have a value enclosed in single quotes
2113            #[test]
2114            fn single_quoted() {
2115                let mut iter = Attributes::html(r#"tag key='value' key='dup' another=''"#, 3);
2116                //                                 0   ^ = 4       ^ = 16
2117
2118                assert_eq!(
2119                    iter.next(),
2120                    Some(Ok(Attribute {
2121                        key: QName(b"key"),
2122                        value: Cow::Borrowed(b"value"),
2123                    }))
2124                );
2125                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
2126                assert_eq!(
2127                    iter.next(),
2128                    Some(Ok(Attribute {
2129                        key: QName(b"another"),
2130                        value: Cow::Borrowed(b""),
2131                    }))
2132                );
2133                assert_eq!(iter.next(), None);
2134                assert_eq!(iter.next(), None);
2135            }
2136
2137            /// Attribute have a value enclosed in double quotes
2138            #[test]
2139            fn double_quoted() {
2140                let mut iter = Attributes::html(r#"tag key='value' key="dup" another=''"#, 3);
2141                //                                 0   ^ = 4       ^ = 16
2142
2143                assert_eq!(
2144                    iter.next(),
2145                    Some(Ok(Attribute {
2146                        key: QName(b"key"),
2147                        value: Cow::Borrowed(b"value"),
2148                    }))
2149                );
2150                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
2151                assert_eq!(
2152                    iter.next(),
2153                    Some(Ok(Attribute {
2154                        key: QName(b"another"),
2155                        value: Cow::Borrowed(b""),
2156                    }))
2157                );
2158                assert_eq!(iter.next(), None);
2159                assert_eq!(iter.next(), None);
2160            }
2161
2162            /// Attribute have a value, not enclosed in quotes
2163            #[test]
2164            fn unquoted() {
2165                let mut iter = Attributes::html(r#"tag key='value' key=dup another=''"#, 3);
2166                //                                 0   ^ = 4       ^ = 16
2167
2168                assert_eq!(
2169                    iter.next(),
2170                    Some(Ok(Attribute {
2171                        key: QName(b"key"),
2172                        value: Cow::Borrowed(b"value"),
2173                    }))
2174                );
2175                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
2176                assert_eq!(
2177                    iter.next(),
2178                    Some(Ok(Attribute {
2179                        key: QName(b"another"),
2180                        value: Cow::Borrowed(b""),
2181                    }))
2182                );
2183                assert_eq!(iter.next(), None);
2184                assert_eq!(iter.next(), None);
2185            }
2186
2187            /// Only attribute key is present
2188            #[test]
2189            fn key_only() {
2190                let mut iter = Attributes::html(r#"tag key='value' key another=''"#, 3);
2191                //                                 0   ^ = 4       ^ = 16
2192
2193                assert_eq!(
2194                    iter.next(),
2195                    Some(Ok(Attribute {
2196                        key: QName(b"key"),
2197                        value: Cow::Borrowed(b"value"),
2198                    }))
2199                );
2200                assert_eq!(iter.next(), Some(Err(AttrError::Duplicated(16, 4))));
2201                assert_eq!(
2202                    iter.next(),
2203                    Some(Ok(Attribute {
2204                        key: QName(b"another"),
2205                        value: Cow::Borrowed(b""),
2206                    }))
2207                );
2208                assert_eq!(iter.next(), None);
2209                assert_eq!(iter.next(), None);
2210            }
2211        }
2212
2213        /// Check for duplicated names is disabled
2214        mod without_check {
2215            use super::*;
2216            use pretty_assertions::assert_eq;
2217
2218            /// Attribute have a value enclosed in single quotes
2219            #[test]
2220            fn single_quoted() {
2221                let mut iter = Attributes::html(r#"tag key='value' key='dup' another=''"#, 3);
2222                iter.with_checks(false);
2223
2224                assert_eq!(
2225                    iter.next(),
2226                    Some(Ok(Attribute {
2227                        key: QName(b"key"),
2228                        value: Cow::Borrowed(b"value"),
2229                    }))
2230                );
2231                assert_eq!(
2232                    iter.next(),
2233                    Some(Ok(Attribute {
2234                        key: QName(b"key"),
2235                        value: Cow::Borrowed(b"dup"),
2236                    }))
2237                );
2238                assert_eq!(
2239                    iter.next(),
2240                    Some(Ok(Attribute {
2241                        key: QName(b"another"),
2242                        value: Cow::Borrowed(b""),
2243                    }))
2244                );
2245                assert_eq!(iter.next(), None);
2246                assert_eq!(iter.next(), None);
2247            }
2248
2249            /// Attribute have a value enclosed in double quotes
2250            #[test]
2251            fn double_quoted() {
2252                let mut iter = Attributes::html(r#"tag key='value' key="dup" another=''"#, 3);
2253                iter.with_checks(false);
2254
2255                assert_eq!(
2256                    iter.next(),
2257                    Some(Ok(Attribute {
2258                        key: QName(b"key"),
2259                        value: Cow::Borrowed(b"value"),
2260                    }))
2261                );
2262                assert_eq!(
2263                    iter.next(),
2264                    Some(Ok(Attribute {
2265                        key: QName(b"key"),
2266                        value: Cow::Borrowed(b"dup"),
2267                    }))
2268                );
2269                assert_eq!(
2270                    iter.next(),
2271                    Some(Ok(Attribute {
2272                        key: QName(b"another"),
2273                        value: Cow::Borrowed(b""),
2274                    }))
2275                );
2276                assert_eq!(iter.next(), None);
2277                assert_eq!(iter.next(), None);
2278            }
2279
2280            /// Attribute have a value, not enclosed in quotes
2281            #[test]
2282            fn unquoted() {
2283                let mut iter = Attributes::html(r#"tag key='value' key=dup another=''"#, 3);
2284                iter.with_checks(false);
2285
2286                assert_eq!(
2287                    iter.next(),
2288                    Some(Ok(Attribute {
2289                        key: QName(b"key"),
2290                        value: Cow::Borrowed(b"value"),
2291                    }))
2292                );
2293                assert_eq!(
2294                    iter.next(),
2295                    Some(Ok(Attribute {
2296                        key: QName(b"key"),
2297                        value: Cow::Borrowed(b"dup"),
2298                    }))
2299                );
2300                assert_eq!(
2301                    iter.next(),
2302                    Some(Ok(Attribute {
2303                        key: QName(b"another"),
2304                        value: Cow::Borrowed(b""),
2305                    }))
2306                );
2307                assert_eq!(iter.next(), None);
2308                assert_eq!(iter.next(), None);
2309            }
2310
2311            /// Only attribute key is present
2312            #[test]
2313            fn key_only() {
2314                let mut iter = Attributes::html(r#"tag key='value' key another=''"#, 3);
2315                iter.with_checks(false);
2316
2317                assert_eq!(
2318                    iter.next(),
2319                    Some(Ok(Attribute {
2320                        key: QName(b"key"),
2321                        value: Cow::Borrowed(b"value"),
2322                    }))
2323                );
2324                assert_eq!(
2325                    iter.next(),
2326                    Some(Ok(Attribute {
2327                        key: QName(b"key"),
2328                        value: Cow::Borrowed(&[]),
2329                    }))
2330                );
2331                assert_eq!(
2332                    iter.next(),
2333                    Some(Ok(Attribute {
2334                        key: QName(b"another"),
2335                        value: Cow::Borrowed(b""),
2336                    }))
2337                );
2338                assert_eq!(iter.next(), None);
2339                assert_eq!(iter.next(), None);
2340            }
2341        }
2342    }
2343
2344    #[test]
2345    fn mixed_quote() {
2346        let mut iter = Attributes::html(r#"tag a='a' b = "b" c='cc"cc' d="dd'dd""#, 3);
2347
2348        assert_eq!(
2349            iter.next(),
2350            Some(Ok(Attribute {
2351                key: QName(b"a"),
2352                value: Cow::Borrowed(b"a"),
2353            }))
2354        );
2355        assert_eq!(
2356            iter.next(),
2357            Some(Ok(Attribute {
2358                key: QName(b"b"),
2359                value: Cow::Borrowed(b"b"),
2360            }))
2361        );
2362        assert_eq!(
2363            iter.next(),
2364            Some(Ok(Attribute {
2365                key: QName(b"c"),
2366                value: Cow::Borrowed(br#"cc"cc"#),
2367            }))
2368        );
2369        assert_eq!(
2370            iter.next(),
2371            Some(Ok(Attribute {
2372                key: QName(b"d"),
2373                value: Cow::Borrowed(b"dd'dd"),
2374            }))
2375        );
2376        assert_eq!(iter.next(), None);
2377        assert_eq!(iter.next(), None);
2378    }
2379}