quick_xml/events/
attributes.rs

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