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