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