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