Coverage Report

Created: 2025-06-16 06:50

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