fast_xml/events/
attributes.rs

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