quick_xml/se/
simple_type.rs

1//! Contains Serde `Serializer` for XML [simple types] [as defined] in the XML Schema.
2//!
3//! [simple types]: https://www.w3schools.com/xml/el_simpletype.asp
4//! [as defined]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
5
6use crate::escape::escape_char;
7use crate::se::{QuoteLevel, SeError};
8use crate::utils::CDataIterator;
9use serde::ser::{
10    Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
11    SerializeTupleVariant, Serializer,
12};
13use serde::serde_if_integer128;
14use std::fmt::{self, Write};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum QuoteTarget {
18    /// Escape data for a text content. No additional escape symbols
19    Text,
20    /// Escape data for a double-quoted attribute. `"` always escaped
21    DoubleQAttr,
22    /// Escape data for a single-quoted attribute. `'` always escaped
23    SingleQAttr,
24    /// Escape data for a CDATA content. No escaping for `&` and `>`, but split
25    /// content on `]]>` and make several CDATA sections
26    CData,
27}
28
29fn escape_into<W, F>(mut writer: W, value: &str, escape_chars: F) -> fmt::Result
30where
31    W: Write,
32    F: Fn(u8) -> bool,
33{
34    let bytes = value.as_bytes();
35    let mut iter = bytes.iter();
36    let mut pos = 0;
37    while let Some(i) = iter.position(|&b| escape_chars(b)) {
38        let new_pos = pos + i;
39        escape_char(&mut writer, value, pos, new_pos)?;
40        pos = new_pos + 1;
41    }
42
43    if let Some(raw) = value.get(pos..) {
44        writer.write_str(raw)?;
45    }
46    Ok(())
47}
48
49/// Escapes atomic value that could be part of a `xs:list`. All whitespace characters
50/// additionally escaped
51fn escape_item<W>(mut writer: W, value: &str, target: QuoteTarget, level: QuoteLevel) -> fmt::Result
52where
53    W: Write,
54{
55    use QuoteLevel::*;
56    use QuoteTarget::*;
57
58    match (target, level) {
59        (CData, _) => {
60            let mut it = CDataIterator::new(value);
61            if let Some(part) = it.next() {
62                writer.write_str(part)?;
63            }
64            for part in it {
65                writer.write_str("]]><![CDATA[")?;
66                writer.write_str(part)?;
67            }
68            Ok(())
69        }
70        (_, Full) => escape_into(writer, value, |ch| match ch {
71            // Spaces used as delimiters of list items, cannot be used in the item
72            b' ' | b'\r' | b'\n' | b'\t' => true,
73            // Required characters to escape
74            b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
75            _ => false,
76        }),
77        //----------------------------------------------------------------------
78        (Text, Partial) => escape_into(writer, value, |ch| match ch {
79            // Spaces used as delimiters of list items, cannot be used in the item
80            b' ' | b'\r' | b'\n' | b'\t' => true,
81            // Required characters to escape
82            b'&' | b'<' | b'>' => true,
83            _ => false,
84        }),
85        (Text, Minimal) => escape_into(writer, value, |ch| match ch {
86            // Spaces used as delimiters of list items, cannot be used in the item
87            b' ' | b'\r' | b'\n' | b'\t' => true,
88            // Required characters to escape
89            b'&' | b'<' => true,
90            _ => false,
91        }),
92        //----------------------------------------------------------------------
93        (DoubleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
94            // Spaces used as delimiters of list items, cannot be used in the item
95            b' ' | b'\r' | b'\n' | b'\t' => true,
96            // Required characters to escape
97            b'&' | b'<' | b'>' => true,
98            // Double quoted attribute should escape quote
99            b'"' => true,
100            _ => false,
101        }),
102        (DoubleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
103            // Spaces used as delimiters of list items, cannot be used in the item
104            b' ' | b'\r' | b'\n' | b'\t' => true,
105            // Required characters to escape
106            b'&' | b'<' => true,
107            // Double quoted attribute should escape quote
108            b'"' => true,
109            _ => false,
110        }),
111        //----------------------------------------------------------------------
112        (SingleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
113            // Spaces used as delimiters of list items
114            b' ' | b'\r' | b'\n' | b'\t' => true,
115            // Required characters to escape
116            b'&' | b'<' | b'>' => true,
117            // Single quoted attribute should escape quote
118            b'\'' => true,
119            _ => false,
120        }),
121        (SingleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
122            // Spaces used as delimiters of list items
123            b' ' | b'\r' | b'\n' | b'\t' => true,
124            // Required characters to escape
125            b'&' | b'<' => true,
126            // Single quoted attribute should escape quote
127            b'\'' => true,
128            _ => false,
129        }),
130    }
131}
132
133/// Escapes XSD simple type value
134fn escape_list<W>(mut writer: W, value: &str, target: QuoteTarget, level: QuoteLevel) -> fmt::Result
135where
136    W: Write,
137{
138    use QuoteLevel::*;
139    use QuoteTarget::*;
140
141    match (target, level) {
142        (CData, _) => {
143            for part in CDataIterator::new(value) {
144                writer.write_str("<![CDATA[")?;
145                writer.write_str(part)?;
146                writer.write_str("]]>")?;
147            }
148            Ok(())
149        }
150        (_, Full) => escape_into(writer, value, |ch| match ch {
151            // Required characters to escape
152            b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
153            _ => false,
154        }),
155        //----------------------------------------------------------------------
156        (Text, Partial) => escape_into(writer, value, |ch| match ch {
157            // Required characters to escape
158            b'&' | b'<' | b'>' => true,
159            _ => false,
160        }),
161        (Text, Minimal) => escape_into(writer, value, |ch| match ch {
162            // Required characters to escape
163            b'&' | b'<' => true,
164            _ => false,
165        }),
166        //----------------------------------------------------------------------
167        (DoubleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
168            // Required characters to escape
169            b'&' | b'<' | b'>' => true,
170            // Double quoted attribute should escape quote
171            b'"' => true,
172            _ => false,
173        }),
174        (DoubleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
175            // Required characters to escape
176            b'&' | b'<' => true,
177            // Double quoted attribute should escape quote
178            b'"' => true,
179            _ => false,
180        }),
181        //----------------------------------------------------------------------
182        (SingleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
183            // Required characters to escape
184            b'&' | b'<' | b'>' => true,
185            // Single quoted attribute should escape quote
186            b'\'' => true,
187            _ => false,
188        }),
189        (SingleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
190            // Required characters to escape
191            b'&' | b'<' => true,
192            // Single quoted attribute should escape quote
193            b'\'' => true,
194            _ => false,
195        }),
196    }
197}
198
199////////////////////////////////////////////////////////////////////////////////////////////////////
200
201macro_rules! write_atomic {
202    ($method:ident ( $ty:ty )) => {
203        fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
204            self.write_fmt(format_args!("{}", value))?;
205            Ok(true)
206        }
207    };
208}
209
210/// A serializer that handles ordinary [simple type definition][item] with
211/// `{variety} = atomic`, or an ordinary [simple type] definition with
212/// `{variety} = union` whose basic members are all atomic.
213///
214/// This serializer can serialize only primitive types:
215/// - numbers
216/// - booleans
217/// - strings
218/// - units
219/// - options
220/// - unit variants of enums
221///
222/// Identifiers represented as strings and serialized accordingly.
223///
224/// Serialization of all other types returns [`Unsupported`][SeError::Unsupported] error.
225///
226/// This serializer returns `true` if something was written and `false` otherwise.
227///
228/// [item]: https://www.w3.org/TR/xmlschema11-1/#std-item_type_definition
229/// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
230pub struct AtomicSerializer<W: Write> {
231    pub writer: W,
232    pub target: QuoteTarget,
233    /// Defines which XML characters need to be escaped
234    pub level: QuoteLevel,
235    /// When `true` an `xs:list` delimiter (a space) should be written
236    pub(crate) write_delimiter: bool,
237}
238
239impl<W: Write> AtomicSerializer<W> {
240    fn write_delimiter(&mut self) -> fmt::Result {
241        if self.write_delimiter {
242            // TODO: Customization point -- possible non-XML compatible extension to specify delimiter char
243            return self.writer.write_char(' ');
244        }
245        Ok(())
246    }
247    fn write_str(&mut self, value: &str) -> Result<(), SeError> {
248        self.write_delimiter()?;
249        Ok(self.writer.write_str(value)?)
250    }
251    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), SeError> {
252        self.write_delimiter()?;
253        Ok(self.writer.write_fmt(args)?)
254    }
255}
256
257impl<W: Write> Serializer for AtomicSerializer<W> {
258    type Ok = bool;
259    type Error = SeError;
260
261    type SerializeSeq = Impossible<Self::Ok, Self::Error>;
262    type SerializeTuple = Impossible<Self::Ok, Self::Error>;
263    type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
264    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
265    type SerializeMap = Impossible<Self::Ok, Self::Error>;
266    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
267    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
268
269    fn serialize_bool(mut self, value: bool) -> Result<Self::Ok, Self::Error> {
270        self.write_str(if value { "true" } else { "false" })?;
271        Ok(true)
272    }
273
274    write_atomic!(serialize_i8(i8));
275    write_atomic!(serialize_i16(i16));
276    write_atomic!(serialize_i32(i32));
277    write_atomic!(serialize_i64(i64));
278
279    write_atomic!(serialize_u8(u8));
280    write_atomic!(serialize_u16(u16));
281    write_atomic!(serialize_u32(u32));
282    write_atomic!(serialize_u64(u64));
283
284    serde_if_integer128! {
285        write_atomic!(serialize_i128(i128));
286        write_atomic!(serialize_u128(u128));
287    }
288
289    write_atomic!(serialize_f32(f32));
290    write_atomic!(serialize_f64(f64));
291
292    fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
293        self.serialize_str(value.encode_utf8(&mut [0u8; 4]))
294    }
295
296    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
297        if !value.is_empty() {
298            self.write_delimiter()?;
299            escape_item(self.writer, value, self.target, self.level)?;
300        }
301        Ok(!value.is_empty())
302    }
303
304    fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
305        //TODO: Customization point - allow user to decide how to encode bytes
306        Err(SeError::Unsupported(
307            "`serialize_bytes` not supported yet".into(),
308        ))
309    }
310
311    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
312        Ok(false)
313    }
314
315    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
316        value.serialize(self)
317    }
318
319    /// We cannot store anything, so the absence of a unit and presence of it
320    /// does not differ, so serialization of unit returns `Err(Unsupported)`
321    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
322        Err(SeError::Unsupported(
323            "cannot serialize unit type `()` as an `xs:list` item".into(),
324        ))
325    }
326
327    /// We cannot store anything, so the absence of a unit and presence of it
328    /// does not differ, so serialization of unit returns `Err(Unsupported)`
329    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
330        Err(SeError::Unsupported(
331            format!(
332                "cannot serialize unit struct `{}` as an `xs:list` item",
333                name
334            )
335            .into(),
336        ))
337    }
338
339    fn serialize_unit_variant(
340        self,
341        _name: &'static str,
342        _variant_index: u32,
343        variant: &'static str,
344    ) -> Result<Self::Ok, Self::Error> {
345        self.serialize_str(variant)
346    }
347
348    fn serialize_newtype_struct<T: ?Sized + Serialize>(
349        self,
350        _name: &'static str,
351        value: &T,
352    ) -> Result<Self::Ok, Self::Error> {
353        value.serialize(self)
354    }
355
356    /// We cannot store both a variant discriminant and a variant value,
357    /// so serialization of enum newtype variant returns `Err(Unsupported)`
358    fn serialize_newtype_variant<T: ?Sized + Serialize>(
359        self,
360        name: &'static str,
361        _variant_index: u32,
362        variant: &'static str,
363        _value: &T,
364    ) -> Result<Self::Ok, SeError> {
365        Err(SeError::Unsupported(
366            format!(
367                "cannot serialize enum newtype variant `{}::{}` as an `xs:list` item",
368                name, variant
369            )
370            .into(),
371        ))
372    }
373
374    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
375        Err(SeError::Unsupported(
376            "cannot serialize sequence as an `xs:list` item".into(),
377        ))
378    }
379
380    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
381        Err(SeError::Unsupported(
382            "cannot serialize tuple as an `xs:list` item".into(),
383        ))
384    }
385
386    fn serialize_tuple_struct(
387        self,
388        name: &'static str,
389        _len: usize,
390    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
391        Err(SeError::Unsupported(
392            format!(
393                "cannot serialize tuple struct `{}` as an `xs:list` item",
394                name
395            )
396            .into(),
397        ))
398    }
399
400    fn serialize_tuple_variant(
401        self,
402        name: &'static str,
403        _variant_index: u32,
404        variant: &'static str,
405        _len: usize,
406    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
407        Err(SeError::Unsupported(
408            format!(
409                "cannot serialize enum tuple variant `{}::{}` as an `xs:list` item",
410                name, variant
411            )
412            .into(),
413        ))
414    }
415
416    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
417        Err(SeError::Unsupported(
418            "cannot serialize map as an `xs:list` item".into(),
419        ))
420    }
421
422    fn serialize_struct(
423        self,
424        name: &'static str,
425        _len: usize,
426    ) -> Result<Self::SerializeStruct, Self::Error> {
427        Err(SeError::Unsupported(
428            format!("cannot serialize struct `{}` as an `xs:list` item", name).into(),
429        ))
430    }
431
432    fn serialize_struct_variant(
433        self,
434        name: &'static str,
435        _variant_index: u32,
436        variant: &'static str,
437        _len: usize,
438    ) -> Result<Self::SerializeStructVariant, Self::Error> {
439        Err(SeError::Unsupported(
440            format!(
441                "cannot serialize enum struct variant `{}::{}` as an `xs:list` item",
442                name, variant
443            )
444            .into(),
445        ))
446    }
447}
448
449////////////////////////////////////////////////////////////////////////////////////////////////////
450
451/// A serializer for a values representing XSD [simple types], which used in:
452/// - attribute values (`<... ...="value" ...>`)
453/// - text content (`<...>text</...>`)
454/// - CDATA content (`<...><![CDATA[cdata]]></...>`)
455///
456/// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
457pub struct SimpleTypeSerializer<W: Write> {
458    /// Writer to which this serializer writes content
459    pub writer: W,
460    /// Target for which element is serializing. Affects additional characters to escape.
461    pub target: QuoteTarget,
462    /// Defines which XML characters need to be escaped
463    pub level: QuoteLevel,
464}
465
466impl<W: Write> SimpleTypeSerializer<W> {
467    #[inline]
468    fn write_str(&mut self, value: &str) -> Result<(), SeError> {
469        Ok(self.writer.write_str(value)?)
470    }
471    #[inline]
472    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), SeError> {
473        Ok(self.writer.write_fmt(args)?)
474    }
475}
476
477impl<W: Write> Serializer for SimpleTypeSerializer<W> {
478    type Ok = W;
479    type Error = SeError;
480
481    type SerializeSeq = SimpleSeq<W>;
482    type SerializeTuple = SimpleSeq<W>;
483    type SerializeTupleStruct = SimpleSeq<W>;
484    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
485    type SerializeMap = Impossible<Self::Ok, Self::Error>;
486    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
487    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
488
489    write_primitive!();
490
491    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
492        if !value.is_empty() {
493            escape_list(&mut self.writer, value, self.target, self.level)?;
494        }
495        Ok(self.writer)
496    }
497
498    /// Does not write anything
499    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
500        Ok(self.writer)
501    }
502
503    /// Does not write anything
504    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
505        Ok(self.writer)
506    }
507
508    /// We cannot store both a variant discriminant and a variant value,
509    /// so serialization of enum newtype variant returns `Err(Unsupported)`
510    fn serialize_newtype_variant<T: ?Sized + Serialize>(
511        self,
512        name: &'static str,
513        _variant_index: u32,
514        variant: &'static str,
515        _value: &T,
516    ) -> Result<Self::Ok, SeError> {
517        Err(SeError::Unsupported(
518            format!("cannot serialize enum newtype variant `{}::{}` as an attribute or text content value", name, variant).into(),
519        ))
520    }
521
522    #[inline]
523    fn serialize_seq(mut self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
524        if let QuoteTarget::CData = self.target {
525            self.writer.write_str("<![CDATA[")?;
526        }
527        Ok(SimpleSeq {
528            writer: self.writer,
529            target: self.target,
530            level: self.level,
531            is_empty: true,
532        })
533    }
534
535    #[inline]
536    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
537        self.serialize_seq(None)
538    }
539
540    #[inline]
541    fn serialize_tuple_struct(
542        self,
543        _name: &'static str,
544        _len: usize,
545    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
546        self.serialize_seq(None)
547    }
548
549    fn serialize_tuple_variant(
550        self,
551        name: &'static str,
552        _variant_index: u32,
553        variant: &'static str,
554        _len: usize,
555    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
556        Err(SeError::Unsupported(
557            format!("cannot serialize enum tuple variant `{}::{}` as an attribute or text content value", name, variant).into(),
558        ))
559    }
560
561    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
562        Err(SeError::Unsupported(
563            "cannot serialize map as an attribute or text content value".into(),
564        ))
565    }
566
567    fn serialize_struct(
568        self,
569        name: &'static str,
570        _len: usize,
571    ) -> Result<Self::SerializeStruct, Self::Error> {
572        Err(SeError::Unsupported(
573            format!(
574                "cannot serialize struct `{}` as an attribute or text content value",
575                name
576            )
577            .into(),
578        ))
579    }
580
581    fn serialize_struct_variant(
582        self,
583        name: &'static str,
584        _variant_index: u32,
585        variant: &'static str,
586        _len: usize,
587    ) -> Result<Self::SerializeStructVariant, Self::Error> {
588        Err(SeError::Unsupported(
589            format!("cannot serialize enum struct variant `{}::{}` as an attribute or text content value", name, variant).into(),
590        ))
591    }
592}
593
594/// Serializer for a sequence of atomic values delimited by space
595pub struct SimpleSeq<W: Write> {
596    writer: W,
597    target: QuoteTarget,
598    level: QuoteLevel,
599    /// If `true`, nothing was written yet to the `writer`
600    is_empty: bool,
601}
602
603impl<W: Write> SerializeSeq for SimpleSeq<W> {
604    type Ok = W;
605    type Error = SeError;
606
607    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
608    where
609        T: ?Sized + Serialize,
610    {
611        if value.serialize(AtomicSerializer {
612            writer: &mut self.writer,
613            target: self.target,
614            level: self.level,
615            write_delimiter: !self.is_empty,
616        })? {
617            self.is_empty = false;
618        }
619        Ok(())
620    }
621
622    #[inline]
623    fn end(mut self) -> Result<Self::Ok, Self::Error> {
624        if let QuoteTarget::CData = self.target {
625            self.writer.write_str("]]>")?;
626        }
627        Ok(self.writer)
628    }
629}
630
631impl<W: Write> SerializeTuple for SimpleSeq<W> {
632    type Ok = W;
633    type Error = SeError;
634
635    #[inline]
636    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
637    where
638        T: ?Sized + Serialize,
639    {
640        SerializeSeq::serialize_element(self, value)
641    }
642
643    #[inline]
644    fn end(self) -> Result<Self::Ok, Self::Error> {
645        SerializeSeq::end(self)
646    }
647}
648
649impl<W: Write> SerializeTupleStruct for SimpleSeq<W> {
650    type Ok = W;
651    type Error = SeError;
652
653    #[inline]
654    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
655    where
656        T: ?Sized + Serialize,
657    {
658        SerializeSeq::serialize_element(self, value)
659    }
660
661    #[inline]
662    fn end(self) -> Result<Self::Ok, Self::Error> {
663        SerializeSeq::end(self)
664    }
665}
666
667impl<W: Write> SerializeTupleVariant for SimpleSeq<W> {
668    type Ok = W;
669    type Error = SeError;
670
671    #[inline]
672    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
673    where
674        T: ?Sized + Serialize,
675    {
676        SerializeSeq::serialize_element(self, value)
677    }
678
679    #[inline]
680    fn end(self) -> Result<Self::Ok, Self::Error> {
681        SerializeSeq::end(self)
682    }
683}
684
685////////////////////////////////////////////////////////////////////////////////////////////////////
686
687#[cfg(test)]
688mod tests {
689    use super::*;
690    use crate::utils::Bytes;
691    use serde::Serialize;
692    use std::collections::BTreeMap;
693
694    #[derive(Debug, Serialize, PartialEq)]
695    struct Unit;
696
697    #[derive(Debug, Serialize, PartialEq)]
698    struct Newtype(usize);
699
700    #[derive(Debug, Serialize, PartialEq)]
701    struct Tuple(&'static str, usize);
702
703    #[derive(Debug, Serialize, PartialEq)]
704    struct Struct {
705        key: &'static str,
706        val: usize,
707    }
708
709    #[derive(Debug, Serialize, PartialEq)]
710    enum Enum {
711        Unit,
712        #[serde(rename = "<\"&'>")]
713        UnitEscaped,
714        Newtype(usize),
715        Tuple(&'static str, usize),
716        Struct {
717            key: &'static str,
718            val: usize,
719        },
720    }
721
722    mod escape_item {
723        use super::*;
724        use pretty_assertions::assert_eq;
725
726        fn escape_item(value: &str, target: QuoteTarget, level: QuoteLevel) -> String {
727            let mut result = String::new();
728            super::escape_item(&mut result, value, target, level).unwrap();
729            result
730        }
731
732        mod full {
733            use super::*;
734            use pretty_assertions::assert_eq;
735
736            #[test]
737            fn text() {
738                assert_eq!(
739                    escape_item("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
740                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
741                );
742            }
743
744            #[test]
745            fn double_quote_attr() {
746                assert_eq!(
747                    escape_item(
748                        "text<\"'&> \t\n\rtext",
749                        QuoteTarget::DoubleQAttr,
750                        QuoteLevel::Full
751                    ),
752                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
753                );
754            }
755
756            #[test]
757            fn single_quote_attr() {
758                assert_eq!(
759                    escape_item(
760                        "text<\"'&> \t\n\rtext",
761                        QuoteTarget::SingleQAttr,
762                        QuoteLevel::Full
763                    ),
764                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
765                );
766            }
767        }
768
769        mod partial {
770            use super::*;
771            use pretty_assertions::assert_eq;
772
773            #[test]
774            fn text() {
775                assert_eq!(
776                    escape_item(
777                        "text<\"'&> \t\n\rtext",
778                        QuoteTarget::Text,
779                        QuoteLevel::Partial
780                    ),
781                    "text&lt;\"'&amp;&gt;&#32;&#9;&#10;&#13;text"
782                );
783            }
784
785            #[test]
786            fn double_quote_attr() {
787                assert_eq!(
788                    escape_item(
789                        "text<\"'&> \t\n\rtext",
790                        QuoteTarget::DoubleQAttr,
791                        QuoteLevel::Partial
792                    ),
793                    "text&lt;&quot;'&amp;&gt;&#32;&#9;&#10;&#13;text"
794                );
795            }
796
797            #[test]
798            fn single_quote_attr() {
799                assert_eq!(
800                    escape_item(
801                        "text<\"'&> \t\n\rtext",
802                        QuoteTarget::SingleQAttr,
803                        QuoteLevel::Partial
804                    ),
805                    "text&lt;\"&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
806                );
807            }
808        }
809
810        mod minimal {
811            use super::*;
812            use pretty_assertions::assert_eq;
813
814            #[test]
815            fn text() {
816                assert_eq!(
817                    escape_item(
818                        "text<\"'&> \t\n\rtext",
819                        QuoteTarget::Text,
820                        QuoteLevel::Minimal
821                    ),
822                    "text&lt;\"'&amp;>&#32;&#9;&#10;&#13;text"
823                );
824            }
825
826            #[test]
827            fn double_quote_attr() {
828                assert_eq!(
829                    escape_item(
830                        "text<\"'&> \t\n\rtext",
831                        QuoteTarget::DoubleQAttr,
832                        QuoteLevel::Minimal
833                    ),
834                    "text&lt;&quot;'&amp;>&#32;&#9;&#10;&#13;text"
835                );
836            }
837
838            #[test]
839            fn single_quote_attr() {
840                assert_eq!(
841                    escape_item(
842                        "text<\"'&> \t\n\rtext",
843                        QuoteTarget::SingleQAttr,
844                        QuoteLevel::Minimal
845                    ),
846                    "text&lt;\"&apos;&amp;>&#32;&#9;&#10;&#13;text"
847                );
848            }
849        }
850
851        /// Escape function does not surround text with `<![CDATA[` and `]]>`, that should be done outside
852        #[test]
853        fn cdata() {
854            assert_eq!(
855                escape_item(
856                    "text<\"'&>]]> \t\n\rtext",
857                    QuoteTarget::CData,
858                    QuoteLevel::Full
859                ),
860                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
861            );
862            assert_eq!(
863                escape_item(
864                    "text<\"'&>]]> \t\n\rtext",
865                    QuoteTarget::CData,
866                    QuoteLevel::Partial
867                ),
868                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
869            );
870            assert_eq!(
871                escape_item(
872                    "text<\"'&>]]> \t\n\rtext",
873                    QuoteTarget::CData,
874                    QuoteLevel::Minimal
875                ),
876                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
877            );
878        }
879    }
880
881    mod escape_list {
882        use super::*;
883        use pretty_assertions::assert_eq;
884
885        fn escape_list(value: &str, target: QuoteTarget, level: QuoteLevel) -> String {
886            let mut result = String::new();
887            super::escape_list(&mut result, value, target, level).unwrap();
888            result
889        }
890
891        mod full {
892            use super::*;
893            use pretty_assertions::assert_eq;
894
895            #[test]
896            fn text() {
897                assert_eq!(
898                    escape_list("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
899                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
900                );
901            }
902
903            #[test]
904            fn double_quote_attr() {
905                assert_eq!(
906                    escape_list(
907                        "text<\"'&> \t\n\rtext",
908                        QuoteTarget::DoubleQAttr,
909                        QuoteLevel::Full
910                    ),
911                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
912                );
913            }
914
915            #[test]
916            fn single_quote_attr() {
917                assert_eq!(
918                    escape_list(
919                        "text<\"'&> \t\n\rtext",
920                        QuoteTarget::SingleQAttr,
921                        QuoteLevel::Full
922                    ),
923                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
924                );
925            }
926        }
927
928        mod partial {
929            use super::*;
930            use pretty_assertions::assert_eq;
931
932            #[test]
933            fn text() {
934                assert_eq!(
935                    escape_list(
936                        "text<\"'&> \t\n\rtext",
937                        QuoteTarget::Text,
938                        QuoteLevel::Partial
939                    ),
940                    "text&lt;\"'&amp;&gt; \t\n\rtext"
941                );
942            }
943
944            #[test]
945            fn double_quote_attr() {
946                assert_eq!(
947                    escape_list(
948                        "text<\"'&> \t\n\rtext",
949                        QuoteTarget::DoubleQAttr,
950                        QuoteLevel::Partial
951                    ),
952                    "text&lt;&quot;'&amp;&gt; \t\n\rtext"
953                );
954            }
955
956            #[test]
957            fn single_quote_attr() {
958                assert_eq!(
959                    escape_list(
960                        "text<\"'&> \t\n\rtext",
961                        QuoteTarget::SingleQAttr,
962                        QuoteLevel::Partial
963                    ),
964                    "text&lt;\"&apos;&amp;&gt; \t\n\rtext"
965                );
966            }
967        }
968
969        mod minimal {
970            use super::*;
971            use pretty_assertions::assert_eq;
972
973            #[test]
974            fn text() {
975                assert_eq!(
976                    escape_list(
977                        "text<\"'&> \t\n\rtext",
978                        QuoteTarget::Text,
979                        QuoteLevel::Minimal
980                    ),
981                    "text&lt;\"'&amp;> \t\n\rtext"
982                );
983            }
984
985            #[test]
986            fn double_quote_attr() {
987                assert_eq!(
988                    escape_list(
989                        "text<\"'&> \t\n\rtext",
990                        QuoteTarget::DoubleQAttr,
991                        QuoteLevel::Minimal
992                    ),
993                    "text&lt;&quot;'&amp;> \t\n\rtext"
994                );
995            }
996
997            #[test]
998            fn single_quote_attr() {
999                assert_eq!(
1000                    escape_list(
1001                        "text<\"'&> \t\n\rtext",
1002                        QuoteTarget::SingleQAttr,
1003                        QuoteLevel::Minimal
1004                    ),
1005                    "text&lt;\"&apos;&amp;> \t\n\rtext"
1006                );
1007            }
1008        }
1009
1010        #[test]
1011        fn cdata() {
1012            assert_eq!(
1013                escape_list(
1014                    "text<\"'&>]]> \t\n\rtext",
1015                    QuoteTarget::CData,
1016                    QuoteLevel::Full
1017                ),
1018                "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1019            );
1020            assert_eq!(
1021                escape_list(
1022                    "text<\"'&>]]> \t\n\rtext",
1023                    QuoteTarget::CData,
1024                    QuoteLevel::Partial
1025                ),
1026                "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1027            );
1028            assert_eq!(
1029                escape_list(
1030                    "text<\"'&>]]> \t\n\rtext",
1031                    QuoteTarget::CData,
1032                    QuoteLevel::Minimal
1033                ),
1034                "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1035            );
1036        }
1037    }
1038
1039    /// Tests for serialize atomic and union values, as defined in XSD specification
1040    mod atomic {
1041        use super::*;
1042        use pretty_assertions::assert_eq;
1043
1044        /// Checks that given `$data` successfully serialized as `$expected`
1045        macro_rules! serialize_as {
1046            ($name:ident: $data:expr => $expected:literal) => {
1047                #[test]
1048                fn $name() {
1049                    let mut buffer = String::new();
1050                    let ser = AtomicSerializer {
1051                        writer: &mut buffer,
1052                        target: QuoteTarget::Text,
1053                        level: QuoteLevel::Full,
1054                        write_delimiter: false,
1055                    };
1056
1057                    let has_written = $data.serialize(ser).unwrap();
1058                    assert_eq!(buffer, $expected);
1059                    assert_eq!(has_written, !buffer.is_empty());
1060                }
1061            };
1062        }
1063
1064        /// Checks that attempt to serialize given `$data` results to a
1065        /// serialization error `$kind` with `$reason`
1066        macro_rules! err {
1067            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1068                #[test]
1069                fn $name() {
1070                    let mut buffer = String::new();
1071                    let ser = AtomicSerializer {
1072                        writer: &mut buffer,
1073                        target: QuoteTarget::Text,
1074                        level: QuoteLevel::Full,
1075                        write_delimiter: false,
1076                    };
1077
1078                    match $data.serialize(ser).unwrap_err() {
1079                        SeError::$kind(e) => assert_eq!(e, $reason),
1080                        e => panic!(
1081                            "Expected `Err({}({}))`, but got `{:?}`",
1082                            stringify!($kind),
1083                            $reason,
1084                            e
1085                        ),
1086                    }
1087                    assert_eq!(buffer, "");
1088                }
1089            };
1090        }
1091
1092        serialize_as!(false_: false => "false");
1093        serialize_as!(true_:  true  => "true");
1094
1095        serialize_as!(i8_:    -42i8                => "-42");
1096        serialize_as!(i16_:   -4200i16             => "-4200");
1097        serialize_as!(i32_:   -42000000i32         => "-42000000");
1098        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
1099        serialize_as!(isize_: -42000000isize       => "-42000000");
1100
1101        serialize_as!(u8_:    42u8                => "42");
1102        serialize_as!(u16_:   4200u16             => "4200");
1103        serialize_as!(u32_:   42000000u32         => "42000000");
1104        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
1105        serialize_as!(usize_: 42000000usize       => "42000000");
1106
1107        serde_if_integer128! {
1108            serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1109            serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1110        }
1111
1112        serialize_as!(f32_: 4.2f32 => "4.2");
1113        serialize_as!(f64_: 4.2f64 => "4.2");
1114
1115        serialize_as!(char_non_escaped: 'h' => "h");
1116        serialize_as!(char_lt:   '<' => "&lt;");
1117        serialize_as!(char_gt:   '>' => "&gt;");
1118        serialize_as!(char_amp:  '&' => "&amp;");
1119        serialize_as!(char_apos: '\'' => "&apos;");
1120        serialize_as!(char_quot: '"' => "&quot;");
1121
1122        serialize_as!(str_non_escaped: "non-escaped-string" => "non-escaped-string");
1123        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped&#32;&amp;&#32;string&apos;&gt;");
1124
1125        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1126            => Unsupported("`serialize_bytes` not supported yet"));
1127
1128        serialize_as!(option_none: Option::<&str>::None => "");
1129        serialize_as!(option_some: Some("non-escaped-string") => "non-escaped-string");
1130
1131        err!(unit: ()
1132            => Unsupported("cannot serialize unit type `()` as an `xs:list` item"));
1133        err!(unit_struct: Unit
1134            => Unsupported("cannot serialize unit struct `Unit` as an `xs:list` item"));
1135
1136        serialize_as!(enum_unit: Enum::Unit => "Unit");
1137        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1138
1139        serialize_as!(newtype: Newtype(42) => "42");
1140        err!(enum_newtype: Enum::Newtype(42)
1141            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an `xs:list` item"));
1142
1143        err!(seq: vec![1, 2, 3]
1144            => Unsupported("cannot serialize sequence as an `xs:list` item"));
1145        err!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1146            => Unsupported("cannot serialize tuple as an `xs:list` item"));
1147        err!(tuple_struct: Tuple("first", 42)
1148            => Unsupported("cannot serialize tuple struct `Tuple` as an `xs:list` item"));
1149        err!(enum_tuple: Enum::Tuple("first", 42)
1150            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an `xs:list` item"));
1151
1152        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1153            => Unsupported("cannot serialize map as an `xs:list` item"));
1154        err!(struct_: Struct { key: "answer", val: 42 }
1155            => Unsupported("cannot serialize struct `Struct` as an `xs:list` item"));
1156        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1157            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an `xs:list` item"));
1158    }
1159
1160    mod simple_type {
1161        use super::*;
1162        use pretty_assertions::assert_eq;
1163
1164        /// Checks that given `$data` successfully serialized as `$expected`
1165        macro_rules! serialize_as {
1166            ($name:ident: $data:expr => $expected:literal) => {
1167                #[test]
1168                fn $name() {
1169                    let ser = SimpleTypeSerializer {
1170                        writer: String::new(),
1171                        target: QuoteTarget::Text,
1172                        level: QuoteLevel::Full,
1173                    };
1174
1175                    let buffer = $data.serialize(ser).unwrap();
1176                    assert_eq!(buffer, $expected);
1177                }
1178            };
1179        }
1180
1181        /// Checks that attempt to serialize given `$data` results to a
1182        /// serialization error `$kind` with `$reason`
1183        macro_rules! err {
1184            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1185                #[test]
1186                fn $name() {
1187                    let mut buffer = String::new();
1188                    let ser = SimpleTypeSerializer {
1189                        writer: &mut buffer,
1190                        target: QuoteTarget::Text,
1191                        level: QuoteLevel::Full,
1192                    };
1193
1194                    match $data.serialize(ser).unwrap_err() {
1195                        SeError::$kind(e) => assert_eq!(e, $reason),
1196                        e => panic!(
1197                            "Expected `Err({}({}))`, but got `{:?}`",
1198                            stringify!($kind),
1199                            $reason,
1200                            e
1201                        ),
1202                    }
1203                    assert_eq!(buffer, "");
1204                }
1205            };
1206        }
1207
1208        serialize_as!(false_: false => "false");
1209        serialize_as!(true_:  true  => "true");
1210
1211        serialize_as!(i8_:    -42i8                => "-42");
1212        serialize_as!(i16_:   -4200i16             => "-4200");
1213        serialize_as!(i32_:   -42000000i32         => "-42000000");
1214        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
1215        serialize_as!(isize_: -42000000isize       => "-42000000");
1216
1217        serialize_as!(u8_:    42u8                => "42");
1218        serialize_as!(u16_:   4200u16             => "4200");
1219        serialize_as!(u32_:   42000000u32         => "42000000");
1220        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
1221        serialize_as!(usize_: 42000000usize       => "42000000");
1222
1223        serde_if_integer128! {
1224            serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1225            serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1226        }
1227
1228        serialize_as!(f32_: 4.2f32 => "4.2");
1229        serialize_as!(f64_: 4.2f64 => "4.2");
1230
1231        serialize_as!(char_non_escaped: 'h' => "h");
1232        serialize_as!(char_lt:   '<' => "&lt;");
1233        serialize_as!(char_gt:   '>' => "&gt;");
1234        serialize_as!(char_amp:  '&' => "&amp;");
1235        serialize_as!(char_apos: '\'' => "&apos;");
1236        serialize_as!(char_quot: '"' => "&quot;");
1237
1238        serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
1239        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1240
1241        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1242            => Unsupported("`serialize_bytes` not supported yet"));
1243
1244        serialize_as!(option_none: Option::<&str>::None => "");
1245        serialize_as!(option_some: Some("non-escaped string") => "non-escaped string");
1246
1247        serialize_as!(unit: () => "");
1248        serialize_as!(unit_struct: Unit => "");
1249
1250        serialize_as!(enum_unit: Enum::Unit => "Unit");
1251        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1252
1253        serialize_as!(newtype: Newtype(42) => "42");
1254        err!(enum_newtype: Enum::Newtype(42)
1255            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an attribute or text content value"));
1256
1257        serialize_as!(seq: vec![1, 2, 3] => "1 2 3");
1258        serialize_as!(seq_empty: Vec::<usize>::new() => "");
1259        serialize_as!(seq_with_1_empty_str: vec![""] => "");
1260        serialize_as!(seq_with_2_empty_strs: vec!["", ""] => "");
1261        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1262            => "&lt;&quot;&amp;&apos;&gt; with&#9;&#10;&#13;&#32;spaces 3");
1263        serialize_as!(tuple_struct: Tuple("first", 42) => "first 42");
1264        err!(enum_tuple: Enum::Tuple("first", 42)
1265            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an attribute or text content value"));
1266
1267        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1268            => Unsupported("cannot serialize map as an attribute or text content value"));
1269        err!(struct_: Struct { key: "answer", val: 42 }
1270            => Unsupported("cannot serialize struct `Struct` as an attribute or text content value"));
1271        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1272            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an attribute or text content value"));
1273    }
1274
1275    mod simple_seq {
1276        use super::*;
1277        use pretty_assertions::assert_eq;
1278
1279        #[test]
1280        fn empty_seq() {
1281            let mut buffer = String::new();
1282            let ser = SimpleSeq {
1283                writer: &mut buffer,
1284                target: QuoteTarget::Text,
1285                level: QuoteLevel::Full,
1286                is_empty: true,
1287            };
1288
1289            SerializeSeq::end(ser).unwrap();
1290            assert_eq!(buffer, "");
1291        }
1292
1293        #[test]
1294        fn all_items_empty() {
1295            let mut buffer = String::new();
1296            let mut ser = SimpleSeq {
1297                writer: &mut buffer,
1298                target: QuoteTarget::Text,
1299                level: QuoteLevel::Full,
1300                is_empty: true,
1301            };
1302
1303            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1304            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1305            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1306            SerializeSeq::end(ser).unwrap();
1307            assert_eq!(buffer, "");
1308        }
1309
1310        #[test]
1311        fn some_items_empty1() {
1312            let mut buffer = String::new();
1313            let mut ser = SimpleSeq {
1314                writer: &mut buffer,
1315                target: QuoteTarget::Text,
1316                level: QuoteLevel::Full,
1317                is_empty: true,
1318            };
1319
1320            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1321            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1322            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1323            SerializeSeq::end(ser).unwrap();
1324            assert_eq!(buffer, "1");
1325        }
1326
1327        #[test]
1328        fn some_items_empty2() {
1329            let mut buffer = String::new();
1330            let mut ser = SimpleSeq {
1331                writer: &mut buffer,
1332                target: QuoteTarget::Text,
1333                level: QuoteLevel::Full,
1334                is_empty: true,
1335            };
1336
1337            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1338            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1339            SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1340            SerializeSeq::end(ser).unwrap();
1341            assert_eq!(buffer, "1 2");
1342        }
1343
1344        #[test]
1345        fn items() {
1346            let mut buffer = String::new();
1347            let mut ser = SimpleSeq {
1348                writer: &mut buffer,
1349                target: QuoteTarget::Text,
1350                level: QuoteLevel::Full,
1351                is_empty: true,
1352            };
1353
1354            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1355            SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1356            SerializeSeq::serialize_element(&mut ser, &3).unwrap();
1357            SerializeSeq::end(ser).unwrap();
1358            assert_eq!(buffer, "1 2 3");
1359        }
1360    }
1361
1362    mod cdata {
1363        use super::*;
1364        use pretty_assertions::assert_eq;
1365
1366        macro_rules! serialize_as_cdata {
1367            ($name:ident: $data:expr => $expected:literal) => {
1368                #[test]
1369                fn $name() {
1370                    let ser = SimpleTypeSerializer {
1371                        writer: String::new(),
1372                        target: QuoteTarget::CData,
1373                        level: QuoteLevel::Full,
1374                    };
1375
1376                    let buffer = $data.serialize(ser).unwrap();
1377                    assert_eq!(buffer, $expected);
1378                }
1379            };
1380        }
1381
1382        serialize_as_cdata!(empty_string: "" => "");
1383        serialize_as_cdata!(simple_text: "Hello World" => "<![CDATA[Hello World]]>");
1384        serialize_as_cdata!(with_markup: "<tag>content</tag>" => "<![CDATA[<tag>content</tag>]]>");
1385        serialize_as_cdata!(with_ampersand: "Tom & Jerry" => "<![CDATA[Tom & Jerry]]>");
1386        serialize_as_cdata!(with_quotes: r#"He said "Hello""# => r#"<![CDATA[He said "Hello"]]>"#);
1387        serialize_as_cdata!(all_xml_chars: "<>&\"'" => "<![CDATA[<>&\"']]>");
1388
1389        serialize_as_cdata!(with_cdata_end: "foo]]>bar" => "<![CDATA[foo]]]]><![CDATA[>bar]]>");
1390        serialize_as_cdata!(multiple_cdata_ends: "a]]>b]]>c" => "<![CDATA[a]]]]><![CDATA[>b]]]]><![CDATA[>c]]>");
1391        serialize_as_cdata!(starts_with_cdata_end: "]]>hello" => "<![CDATA[]]]]><![CDATA[>hello]]>");
1392        serialize_as_cdata!(ends_with_cdata_end: "hello]]>" => "<![CDATA[hello]]]]><![CDATA[>]]>");
1393        serialize_as_cdata!(only_cdata_end: "]]>" => "<![CDATA[]]]]><![CDATA[>]]>");
1394
1395        serialize_as_cdata!(seq_basic: vec!["foo", "bar", "baz"] => "<![CDATA[foo bar baz]]>");
1396        serialize_as_cdata!(seq_with_space: vec!["hello world", "hello\tworld", "world"] => "<![CDATA[hello world hello\tworld world]]>");
1397        serialize_as_cdata!(seq_with_markup_chars: vec!["<tag>", "&entity", "\"quoted\""] => "<![CDATA[<tag> &entity \"quoted\"]]>");
1398        serialize_as_cdata!(seq_with_cdata_end_split: vec!["foo]]>bar", "test"] => "<![CDATA[foo]]]]><![CDATA[>bar test]]>");
1399        serialize_as_cdata!(tuple_cdata: ("first", 42, "third") => "<![CDATA[first 42 third]]>");
1400    }
1401}