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