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 `>` 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 `>` 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 & whistles".as_bytes()));
250 /// assert_eq!(features.value, "Bells & 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 & 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>`</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}