Skip to main content

oxixml_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            // `xs:list` items are always delimited by a single space.
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        // There is no canonical XML representation of a byte string, so callers
303        // must pick one explicitly (e.g. base64) and serialize a string.
304        Err(SeError::Unsupported(
305            "`serialize_bytes` not supported yet".into(),
306        ))
307    }
308
309    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
310        Ok(false)
311    }
312
313    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
314        value.serialize(self)
315    }
316
317    /// We cannot store anything, so the absence of a unit and presence of it
318    /// does not differ, so serialization of unit returns `Err(Unsupported)`
319    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
320        Err(SeError::Unsupported(
321            "cannot serialize unit type `()` as an `xs:list` item".into(),
322        ))
323    }
324
325    /// We cannot store anything, so the absence of a unit and presence of it
326    /// does not differ, so serialization of unit returns `Err(Unsupported)`
327    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
328        Err(SeError::Unsupported(
329            format!(
330                "cannot serialize unit struct `{}` as an `xs:list` item",
331                name
332            )
333            .into(),
334        ))
335    }
336
337    fn serialize_unit_variant(
338        self,
339        _name: &'static str,
340        _variant_index: u32,
341        variant: &'static str,
342    ) -> Result<Self::Ok, Self::Error> {
343        self.serialize_str(variant)
344    }
345
346    fn serialize_newtype_struct<T: ?Sized + Serialize>(
347        self,
348        _name: &'static str,
349        value: &T,
350    ) -> Result<Self::Ok, Self::Error> {
351        value.serialize(self)
352    }
353
354    /// We cannot store both a variant discriminant and a variant value,
355    /// so serialization of enum newtype variant returns `Err(Unsupported)`
356    fn serialize_newtype_variant<T: ?Sized + Serialize>(
357        self,
358        name: &'static str,
359        _variant_index: u32,
360        variant: &'static str,
361        _value: &T,
362    ) -> Result<Self::Ok, SeError> {
363        Err(SeError::Unsupported(
364            format!(
365                "cannot serialize enum newtype variant `{}::{}` as an `xs:list` item",
366                name, variant
367            )
368            .into(),
369        ))
370    }
371
372    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
373        Err(SeError::Unsupported(
374            "cannot serialize sequence as an `xs:list` item".into(),
375        ))
376    }
377
378    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
379        Err(SeError::Unsupported(
380            "cannot serialize tuple as an `xs:list` item".into(),
381        ))
382    }
383
384    fn serialize_tuple_struct(
385        self,
386        name: &'static str,
387        _len: usize,
388    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
389        Err(SeError::Unsupported(
390            format!(
391                "cannot serialize tuple struct `{}` as an `xs:list` item",
392                name
393            )
394            .into(),
395        ))
396    }
397
398    fn serialize_tuple_variant(
399        self,
400        name: &'static str,
401        _variant_index: u32,
402        variant: &'static str,
403        _len: usize,
404    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
405        Err(SeError::Unsupported(
406            format!(
407                "cannot serialize enum tuple variant `{}::{}` as an `xs:list` item",
408                name, variant
409            )
410            .into(),
411        ))
412    }
413
414    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
415        Err(SeError::Unsupported(
416            "cannot serialize map as an `xs:list` item".into(),
417        ))
418    }
419
420    fn serialize_struct(
421        self,
422        name: &'static str,
423        _len: usize,
424    ) -> Result<Self::SerializeStruct, Self::Error> {
425        Err(SeError::Unsupported(
426            format!("cannot serialize struct `{}` as an `xs:list` item", name).into(),
427        ))
428    }
429
430    fn serialize_struct_variant(
431        self,
432        name: &'static str,
433        _variant_index: u32,
434        variant: &'static str,
435        _len: usize,
436    ) -> Result<Self::SerializeStructVariant, Self::Error> {
437        Err(SeError::Unsupported(
438            format!(
439                "cannot serialize enum struct variant `{}::{}` as an `xs:list` item",
440                name, variant
441            )
442            .into(),
443        ))
444    }
445}
446
447////////////////////////////////////////////////////////////////////////////////////////////////////
448
449/// A serializer for a values representing XSD [simple types], which used in:
450/// - attribute values (`<... ...="value" ...>`)
451/// - text content (`<...>text</...>`)
452/// - CDATA content (`<...><![CDATA[cdata]]></...>`)
453///
454/// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
455pub struct SimpleTypeSerializer<W: Write> {
456    /// Writer to which this serializer writes content
457    pub writer: W,
458    /// Target for which element is serializing. Affects additional characters to escape.
459    pub target: QuoteTarget,
460    /// Defines which XML characters need to be escaped
461    pub level: QuoteLevel,
462}
463
464impl<W: Write> SimpleTypeSerializer<W> {
465    #[inline]
466    fn write_str(&mut self, value: &str) -> Result<(), SeError> {
467        Ok(self.writer.write_str(value)?)
468    }
469    #[inline]
470    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), SeError> {
471        Ok(self.writer.write_fmt(args)?)
472    }
473}
474
475impl<W: Write> Serializer for SimpleTypeSerializer<W> {
476    type Ok = W;
477    type Error = SeError;
478
479    type SerializeSeq = SimpleSeq<W>;
480    type SerializeTuple = SimpleSeq<W>;
481    type SerializeTupleStruct = SimpleSeq<W>;
482    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
483    type SerializeMap = Impossible<Self::Ok, Self::Error>;
484    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
485    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
486
487    write_primitive!();
488
489    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
490        if !value.is_empty() {
491            escape_list(&mut self.writer, value, self.target, self.level)?;
492        }
493        Ok(self.writer)
494    }
495
496    /// Does not write anything
497    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
498        Ok(self.writer)
499    }
500
501    /// Does not write anything
502    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
503        Ok(self.writer)
504    }
505
506    /// We cannot store both a variant discriminant and a variant value,
507    /// so serialization of enum newtype variant returns `Err(Unsupported)`
508    fn serialize_newtype_variant<T: ?Sized + Serialize>(
509        self,
510        name: &'static str,
511        _variant_index: u32,
512        variant: &'static str,
513        _value: &T,
514    ) -> Result<Self::Ok, SeError> {
515        Err(SeError::Unsupported(
516            format!("cannot serialize enum newtype variant `{}::{}` as an attribute or text content value", name, variant).into(),
517        ))
518    }
519
520    #[inline]
521    fn serialize_seq(mut self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
522        if let QuoteTarget::CData = self.target {
523            self.writer.write_str("<![CDATA[")?;
524        }
525        Ok(SimpleSeq {
526            writer: self.writer,
527            target: self.target,
528            level: self.level,
529            is_empty: true,
530        })
531    }
532
533    #[inline]
534    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
535        self.serialize_seq(None)
536    }
537
538    #[inline]
539    fn serialize_tuple_struct(
540        self,
541        _name: &'static str,
542        _len: usize,
543    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
544        self.serialize_seq(None)
545    }
546
547    fn serialize_tuple_variant(
548        self,
549        name: &'static str,
550        _variant_index: u32,
551        variant: &'static str,
552        _len: usize,
553    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
554        Err(SeError::Unsupported(
555            format!("cannot serialize enum tuple variant `{}::{}` as an attribute or text content value", name, variant).into(),
556        ))
557    }
558
559    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
560        Err(SeError::Unsupported(
561            "cannot serialize map as an attribute or text content value".into(),
562        ))
563    }
564
565    fn serialize_struct(
566        self,
567        name: &'static str,
568        _len: usize,
569    ) -> Result<Self::SerializeStruct, Self::Error> {
570        Err(SeError::Unsupported(
571            format!(
572                "cannot serialize struct `{}` as an attribute or text content value",
573                name
574            )
575            .into(),
576        ))
577    }
578
579    fn serialize_struct_variant(
580        self,
581        name: &'static str,
582        _variant_index: u32,
583        variant: &'static str,
584        _len: usize,
585    ) -> Result<Self::SerializeStructVariant, Self::Error> {
586        Err(SeError::Unsupported(
587            format!("cannot serialize enum struct variant `{}::{}` as an attribute or text content value", name, variant).into(),
588        ))
589    }
590}
591
592/// Serializer for a sequence of atomic values delimited by space
593pub struct SimpleSeq<W: Write> {
594    writer: W,
595    target: QuoteTarget,
596    level: QuoteLevel,
597    /// If `true`, nothing was written yet to the `writer`
598    is_empty: bool,
599}
600
601impl<W: Write> SerializeSeq for SimpleSeq<W> {
602    type Ok = W;
603    type Error = SeError;
604
605    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
606    where
607        T: ?Sized + Serialize,
608    {
609        if value.serialize(AtomicSerializer {
610            writer: &mut self.writer,
611            target: self.target,
612            level: self.level,
613            write_delimiter: !self.is_empty,
614        })? {
615            self.is_empty = false;
616        }
617        Ok(())
618    }
619
620    #[inline]
621    fn end(mut self) -> Result<Self::Ok, Self::Error> {
622        if let QuoteTarget::CData = self.target {
623            self.writer.write_str("]]>")?;
624        }
625        Ok(self.writer)
626    }
627}
628
629impl<W: Write> SerializeTuple for SimpleSeq<W> {
630    type Ok = W;
631    type Error = SeError;
632
633    #[inline]
634    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
635    where
636        T: ?Sized + Serialize,
637    {
638        SerializeSeq::serialize_element(self, value)
639    }
640
641    #[inline]
642    fn end(self) -> Result<Self::Ok, Self::Error> {
643        SerializeSeq::end(self)
644    }
645}
646
647impl<W: Write> SerializeTupleStruct for SimpleSeq<W> {
648    type Ok = W;
649    type Error = SeError;
650
651    #[inline]
652    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
653    where
654        T: ?Sized + Serialize,
655    {
656        SerializeSeq::serialize_element(self, value)
657    }
658
659    #[inline]
660    fn end(self) -> Result<Self::Ok, Self::Error> {
661        SerializeSeq::end(self)
662    }
663}
664
665impl<W: Write> SerializeTupleVariant for SimpleSeq<W> {
666    type Ok = W;
667    type Error = SeError;
668
669    #[inline]
670    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
671    where
672        T: ?Sized + Serialize,
673    {
674        SerializeSeq::serialize_element(self, value)
675    }
676
677    #[inline]
678    fn end(self) -> Result<Self::Ok, Self::Error> {
679        SerializeSeq::end(self)
680    }
681}
682
683////////////////////////////////////////////////////////////////////////////////////////////////////
684
685#[cfg(test)]
686mod tests {
687    use super::*;
688    use crate::utils::Bytes;
689    use serde::Serialize;
690    use std::collections::BTreeMap;
691
692    #[derive(Debug, Serialize, PartialEq)]
693    struct Unit;
694
695    #[derive(Debug, Serialize, PartialEq)]
696    struct Newtype(usize);
697
698    #[derive(Debug, Serialize, PartialEq)]
699    struct Tuple(&'static str, usize);
700
701    #[derive(Debug, Serialize, PartialEq)]
702    struct Struct {
703        key: &'static str,
704        val: usize,
705    }
706
707    #[derive(Debug, Serialize, PartialEq)]
708    enum Enum {
709        Unit,
710        #[serde(rename = "<\"&'>")]
711        UnitEscaped,
712        Newtype(usize),
713        Tuple(&'static str, usize),
714        Struct {
715            key: &'static str,
716            val: usize,
717        },
718    }
719
720    mod escape_item {
721        use super::*;
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)
726                .expect("serialization should succeed");
727            result
728        }
729
730        mod full {
731            use super::*;
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
769            #[test]
770            fn text() {
771                assert_eq!(
772                    escape_item(
773                        "text<\"'&> \t\n\rtext",
774                        QuoteTarget::Text,
775                        QuoteLevel::Partial
776                    ),
777                    "text&lt;\"'&amp;&gt;&#32;&#9;&#10;&#13;text"
778                );
779            }
780
781            #[test]
782            fn double_quote_attr() {
783                assert_eq!(
784                    escape_item(
785                        "text<\"'&> \t\n\rtext",
786                        QuoteTarget::DoubleQAttr,
787                        QuoteLevel::Partial
788                    ),
789                    "text&lt;&quot;'&amp;&gt;&#32;&#9;&#10;&#13;text"
790                );
791            }
792
793            #[test]
794            fn single_quote_attr() {
795                assert_eq!(
796                    escape_item(
797                        "text<\"'&> \t\n\rtext",
798                        QuoteTarget::SingleQAttr,
799                        QuoteLevel::Partial
800                    ),
801                    "text&lt;\"&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
802                );
803            }
804        }
805
806        mod minimal {
807            use super::*;
808
809            #[test]
810            fn text() {
811                assert_eq!(
812                    escape_item(
813                        "text<\"'&> \t\n\rtext",
814                        QuoteTarget::Text,
815                        QuoteLevel::Minimal
816                    ),
817                    "text&lt;\"'&amp;>&#32;&#9;&#10;&#13;text"
818                );
819            }
820
821            #[test]
822            fn double_quote_attr() {
823                assert_eq!(
824                    escape_item(
825                        "text<\"'&> \t\n\rtext",
826                        QuoteTarget::DoubleQAttr,
827                        QuoteLevel::Minimal
828                    ),
829                    "text&lt;&quot;'&amp;>&#32;&#9;&#10;&#13;text"
830                );
831            }
832
833            #[test]
834            fn single_quote_attr() {
835                assert_eq!(
836                    escape_item(
837                        "text<\"'&> \t\n\rtext",
838                        QuoteTarget::SingleQAttr,
839                        QuoteLevel::Minimal
840                    ),
841                    "text&lt;\"&apos;&amp;>&#32;&#9;&#10;&#13;text"
842                );
843            }
844        }
845
846        /// Escape function does not surround text with `<![CDATA[` and `]]>`, that should be done outside
847        #[test]
848        fn cdata() {
849            assert_eq!(
850                escape_item(
851                    "text<\"'&>]]> \t\n\rtext",
852                    QuoteTarget::CData,
853                    QuoteLevel::Full
854                ),
855                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
856            );
857            assert_eq!(
858                escape_item(
859                    "text<\"'&>]]> \t\n\rtext",
860                    QuoteTarget::CData,
861                    QuoteLevel::Partial
862                ),
863                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
864            );
865            assert_eq!(
866                escape_item(
867                    "text<\"'&>]]> \t\n\rtext",
868                    QuoteTarget::CData,
869                    QuoteLevel::Minimal
870                ),
871                "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
872            );
873        }
874    }
875
876    mod escape_list {
877        use super::*;
878
879        fn escape_list(value: &str, target: QuoteTarget, level: QuoteLevel) -> String {
880            let mut result = String::new();
881            super::escape_list(&mut result, value, target, level)
882                .expect("serialization should succeed");
883            result
884        }
885
886        mod full {
887            use super::*;
888
889            #[test]
890            fn text() {
891                assert_eq!(
892                    escape_list("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
893                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
894                );
895            }
896
897            #[test]
898            fn double_quote_attr() {
899                assert_eq!(
900                    escape_list(
901                        "text<\"'&> \t\n\rtext",
902                        QuoteTarget::DoubleQAttr,
903                        QuoteLevel::Full
904                    ),
905                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
906                );
907            }
908
909            #[test]
910            fn single_quote_attr() {
911                assert_eq!(
912                    escape_list(
913                        "text<\"'&> \t\n\rtext",
914                        QuoteTarget::SingleQAttr,
915                        QuoteLevel::Full
916                    ),
917                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
918                );
919            }
920        }
921
922        mod partial {
923            use super::*;
924
925            #[test]
926            fn text() {
927                assert_eq!(
928                    escape_list(
929                        "text<\"'&> \t\n\rtext",
930                        QuoteTarget::Text,
931                        QuoteLevel::Partial
932                    ),
933                    "text&lt;\"'&amp;&gt; \t\n\rtext"
934                );
935            }
936
937            #[test]
938            fn double_quote_attr() {
939                assert_eq!(
940                    escape_list(
941                        "text<\"'&> \t\n\rtext",
942                        QuoteTarget::DoubleQAttr,
943                        QuoteLevel::Partial
944                    ),
945                    "text&lt;&quot;'&amp;&gt; \t\n\rtext"
946                );
947            }
948
949            #[test]
950            fn single_quote_attr() {
951                assert_eq!(
952                    escape_list(
953                        "text<\"'&> \t\n\rtext",
954                        QuoteTarget::SingleQAttr,
955                        QuoteLevel::Partial
956                    ),
957                    "text&lt;\"&apos;&amp;&gt; \t\n\rtext"
958                );
959            }
960        }
961
962        mod minimal {
963            use super::*;
964
965            #[test]
966            fn text() {
967                assert_eq!(
968                    escape_list(
969                        "text<\"'&> \t\n\rtext",
970                        QuoteTarget::Text,
971                        QuoteLevel::Minimal
972                    ),
973                    "text&lt;\"'&amp;> \t\n\rtext"
974                );
975            }
976
977            #[test]
978            fn double_quote_attr() {
979                assert_eq!(
980                    escape_list(
981                        "text<\"'&> \t\n\rtext",
982                        QuoteTarget::DoubleQAttr,
983                        QuoteLevel::Minimal
984                    ),
985                    "text&lt;&quot;'&amp;> \t\n\rtext"
986                );
987            }
988
989            #[test]
990            fn single_quote_attr() {
991                assert_eq!(
992                    escape_list(
993                        "text<\"'&> \t\n\rtext",
994                        QuoteTarget::SingleQAttr,
995                        QuoteLevel::Minimal
996                    ),
997                    "text&lt;\"&apos;&amp;> \t\n\rtext"
998                );
999            }
1000        }
1001
1002        #[test]
1003        fn cdata() {
1004            assert_eq!(
1005                escape_list(
1006                    "text<\"'&>]]> \t\n\rtext",
1007                    QuoteTarget::CData,
1008                    QuoteLevel::Full
1009                ),
1010                "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1011            );
1012            assert_eq!(
1013                escape_list(
1014                    "text<\"'&>]]> \t\n\rtext",
1015                    QuoteTarget::CData,
1016                    QuoteLevel::Partial
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::Minimal
1025                ),
1026                "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1027            );
1028        }
1029    }
1030
1031    /// Tests for serialize atomic and union values, as defined in XSD specification
1032    mod atomic {
1033        use super::*;
1034
1035        /// Checks that given `$data` successfully serialized as `$expected`
1036        macro_rules! serialize_as {
1037            ($name:ident: $data:expr => $expected:literal) => {
1038                #[test]
1039                fn $name() {
1040                    let mut buffer = String::new();
1041                    let ser = AtomicSerializer {
1042                        writer: &mut buffer,
1043                        target: QuoteTarget::Text,
1044                        level: QuoteLevel::Full,
1045                        write_delimiter: false,
1046                    };
1047
1048                    let has_written = $data.serialize(ser).expect("serialization should succeed");
1049                    assert_eq!(buffer, $expected);
1050                    assert_eq!(has_written, !buffer.is_empty());
1051                }
1052            };
1053        }
1054
1055        /// Checks that attempt to serialize given `$data` results to a
1056        /// serialization error `$kind` with `$reason`
1057        macro_rules! err {
1058            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1059                #[test]
1060                fn $name() {
1061                    let mut buffer = String::new();
1062                    let ser = AtomicSerializer {
1063                        writer: &mut buffer,
1064                        target: QuoteTarget::Text,
1065                        level: QuoteLevel::Full,
1066                        write_delimiter: false,
1067                    };
1068
1069                    match $data.serialize(ser).expect_err("serialization should fail") {
1070                        SeError::$kind(e) => assert_eq!(e, $reason),
1071                        e => panic!(
1072                            "Expected `Err({}({}))`, but got `{:?}`",
1073                            stringify!($kind),
1074                            $reason,
1075                            e
1076                        ),
1077                    }
1078                    assert_eq!(buffer, "");
1079                }
1080            };
1081        }
1082
1083        serialize_as!(false_: false => "false");
1084        serialize_as!(true_:  true  => "true");
1085
1086        serialize_as!(i8_:    -42i8                => "-42");
1087        serialize_as!(i16_:   -4200i16             => "-4200");
1088        serialize_as!(i32_:   -42000000i32         => "-42000000");
1089        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
1090        serialize_as!(isize_: -42000000isize       => "-42000000");
1091
1092        serialize_as!(u8_:    42u8                => "42");
1093        serialize_as!(u16_:   4200u16             => "4200");
1094        serialize_as!(u32_:   42000000u32         => "42000000");
1095        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
1096        serialize_as!(usize_: 42000000usize       => "42000000");
1097
1098        serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1099        serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1100
1101        serialize_as!(f32_: 4.2f32 => "4.2");
1102        serialize_as!(f64_: 4.2f64 => "4.2");
1103
1104        serialize_as!(char_non_escaped: 'h' => "h");
1105        serialize_as!(char_lt:   '<' => "&lt;");
1106        serialize_as!(char_gt:   '>' => "&gt;");
1107        serialize_as!(char_amp:  '&' => "&amp;");
1108        serialize_as!(char_apos: '\'' => "&apos;");
1109        serialize_as!(char_quot: '"' => "&quot;");
1110
1111        serialize_as!(str_non_escaped: "non-escaped-string" => "non-escaped-string");
1112        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped&#32;&amp;&#32;string&apos;&gt;");
1113
1114        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1115            => Unsupported("`serialize_bytes` not supported yet"));
1116
1117        serialize_as!(option_none: Option::<&str>::None => "");
1118        serialize_as!(option_some: Some("non-escaped-string") => "non-escaped-string");
1119
1120        err!(unit: ()
1121            => Unsupported("cannot serialize unit type `()` as an `xs:list` item"));
1122        err!(unit_struct: Unit
1123            => Unsupported("cannot serialize unit struct `Unit` as an `xs:list` item"));
1124
1125        serialize_as!(enum_unit: Enum::Unit => "Unit");
1126        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1127
1128        serialize_as!(newtype: Newtype(42) => "42");
1129        err!(enum_newtype: Enum::Newtype(42)
1130            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an `xs:list` item"));
1131
1132        err!(seq: vec![1, 2, 3]
1133            => Unsupported("cannot serialize sequence as an `xs:list` item"));
1134        err!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1135            => Unsupported("cannot serialize tuple as an `xs:list` item"));
1136        err!(tuple_struct: Tuple("first", 42)
1137            => Unsupported("cannot serialize tuple struct `Tuple` as an `xs:list` item"));
1138        err!(enum_tuple: Enum::Tuple("first", 42)
1139            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an `xs:list` item"));
1140
1141        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1142            => Unsupported("cannot serialize map as an `xs:list` item"));
1143        err!(struct_: Struct { key: "answer", val: 42 }
1144            => Unsupported("cannot serialize struct `Struct` as an `xs:list` item"));
1145        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1146            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an `xs:list` item"));
1147    }
1148
1149    mod simple_type {
1150        use super::*;
1151
1152        /// Checks that given `$data` successfully serialized as `$expected`
1153        macro_rules! serialize_as {
1154            ($name:ident: $data:expr => $expected:literal) => {
1155                #[test]
1156                fn $name() {
1157                    let ser = SimpleTypeSerializer {
1158                        writer: String::new(),
1159                        target: QuoteTarget::Text,
1160                        level: QuoteLevel::Full,
1161                    };
1162
1163                    let buffer = $data.serialize(ser).expect("serialization should succeed");
1164                    assert_eq!(buffer, $expected);
1165                }
1166            };
1167        }
1168
1169        /// Checks that attempt to serialize given `$data` results to a
1170        /// serialization error `$kind` with `$reason`
1171        macro_rules! err {
1172            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1173                #[test]
1174                fn $name() {
1175                    let mut buffer = String::new();
1176                    let ser = SimpleTypeSerializer {
1177                        writer: &mut buffer,
1178                        target: QuoteTarget::Text,
1179                        level: QuoteLevel::Full,
1180                    };
1181
1182                    match $data.serialize(ser).expect_err("serialization should fail") {
1183                        SeError::$kind(e) => assert_eq!(e, $reason),
1184                        e => panic!(
1185                            "Expected `Err({}({}))`, but got `{:?}`",
1186                            stringify!($kind),
1187                            $reason,
1188                            e
1189                        ),
1190                    }
1191                    assert_eq!(buffer, "");
1192                }
1193            };
1194        }
1195
1196        serialize_as!(false_: false => "false");
1197        serialize_as!(true_:  true  => "true");
1198
1199        serialize_as!(i8_:    -42i8                => "-42");
1200        serialize_as!(i16_:   -4200i16             => "-4200");
1201        serialize_as!(i32_:   -42000000i32         => "-42000000");
1202        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
1203        serialize_as!(isize_: -42000000isize       => "-42000000");
1204
1205        serialize_as!(u8_:    42u8                => "42");
1206        serialize_as!(u16_:   4200u16             => "4200");
1207        serialize_as!(u32_:   42000000u32         => "42000000");
1208        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
1209        serialize_as!(usize_: 42000000usize       => "42000000");
1210
1211        serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1212        serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1213
1214        serialize_as!(f32_: 4.2f32 => "4.2");
1215        serialize_as!(f64_: 4.2f64 => "4.2");
1216
1217        serialize_as!(char_non_escaped: 'h' => "h");
1218        serialize_as!(char_lt:   '<' => "&lt;");
1219        serialize_as!(char_gt:   '>' => "&gt;");
1220        serialize_as!(char_amp:  '&' => "&amp;");
1221        serialize_as!(char_apos: '\'' => "&apos;");
1222        serialize_as!(char_quot: '"' => "&quot;");
1223
1224        serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
1225        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1226
1227        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1228            => Unsupported("`serialize_bytes` not supported yet"));
1229
1230        serialize_as!(option_none: Option::<&str>::None => "");
1231        serialize_as!(option_some: Some("non-escaped string") => "non-escaped string");
1232
1233        serialize_as!(unit: () => "");
1234        serialize_as!(unit_struct: Unit => "");
1235
1236        serialize_as!(enum_unit: Enum::Unit => "Unit");
1237        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1238
1239        serialize_as!(newtype: Newtype(42) => "42");
1240        err!(enum_newtype: Enum::Newtype(42)
1241            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an attribute or text content value"));
1242
1243        serialize_as!(seq: vec![1, 2, 3] => "1 2 3");
1244        serialize_as!(seq_empty: Vec::<usize>::new() => "");
1245        serialize_as!(seq_with_1_empty_str: vec![""] => "");
1246        serialize_as!(seq_with_2_empty_strs: vec!["", ""] => "");
1247        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1248            => "&lt;&quot;&amp;&apos;&gt; with&#9;&#10;&#13;&#32;spaces 3");
1249        serialize_as!(tuple_struct: Tuple("first", 42) => "first 42");
1250        err!(enum_tuple: Enum::Tuple("first", 42)
1251            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an attribute or text content value"));
1252
1253        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1254            => Unsupported("cannot serialize map as an attribute or text content value"));
1255        err!(struct_: Struct { key: "answer", val: 42 }
1256            => Unsupported("cannot serialize struct `Struct` as an attribute or text content value"));
1257        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1258            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an attribute or text content value"));
1259    }
1260
1261    mod simple_seq {
1262        use super::*;
1263
1264        #[test]
1265        fn empty_seq() {
1266            let mut buffer = String::new();
1267            let ser = SimpleSeq {
1268                writer: &mut buffer,
1269                target: QuoteTarget::Text,
1270                level: QuoteLevel::Full,
1271                is_empty: true,
1272            };
1273
1274            SerializeSeq::end(ser).expect("serialization should succeed");
1275            assert_eq!(buffer, "");
1276        }
1277
1278        #[test]
1279        fn all_items_empty() {
1280            let mut buffer = String::new();
1281            let mut ser = SimpleSeq {
1282                writer: &mut buffer,
1283                target: QuoteTarget::Text,
1284                level: QuoteLevel::Full,
1285                is_empty: true,
1286            };
1287
1288            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1289            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1290            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1291            SerializeSeq::end(ser).expect("serialization should succeed");
1292            assert_eq!(buffer, "");
1293        }
1294
1295        #[test]
1296        fn some_items_empty1() {
1297            let mut buffer = String::new();
1298            let mut ser = SimpleSeq {
1299                writer: &mut buffer,
1300                target: QuoteTarget::Text,
1301                level: QuoteLevel::Full,
1302                is_empty: true,
1303            };
1304
1305            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1306            SerializeSeq::serialize_element(&mut ser, &1).expect("serialization should succeed");
1307            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1308            SerializeSeq::end(ser).expect("serialization should succeed");
1309            assert_eq!(buffer, "1");
1310        }
1311
1312        #[test]
1313        fn some_items_empty2() {
1314            let mut buffer = String::new();
1315            let mut ser = SimpleSeq {
1316                writer: &mut buffer,
1317                target: QuoteTarget::Text,
1318                level: QuoteLevel::Full,
1319                is_empty: true,
1320            };
1321
1322            SerializeSeq::serialize_element(&mut ser, &1).expect("serialization should succeed");
1323            SerializeSeq::serialize_element(&mut ser, "").expect("serialization should succeed");
1324            SerializeSeq::serialize_element(&mut ser, &2).expect("serialization should succeed");
1325            SerializeSeq::end(ser).expect("serialization should succeed");
1326            assert_eq!(buffer, "1 2");
1327        }
1328
1329        #[test]
1330        fn items() {
1331            let mut buffer = String::new();
1332            let mut ser = SimpleSeq {
1333                writer: &mut buffer,
1334                target: QuoteTarget::Text,
1335                level: QuoteLevel::Full,
1336                is_empty: true,
1337            };
1338
1339            SerializeSeq::serialize_element(&mut ser, &1).expect("serialization should succeed");
1340            SerializeSeq::serialize_element(&mut ser, &2).expect("serialization should succeed");
1341            SerializeSeq::serialize_element(&mut ser, &3).expect("serialization should succeed");
1342            SerializeSeq::end(ser).expect("serialization should succeed");
1343            assert_eq!(buffer, "1 2 3");
1344        }
1345    }
1346
1347    mod cdata {
1348        use super::*;
1349
1350        macro_rules! serialize_as_cdata {
1351            ($name:ident: $data:expr => $expected:literal) => {
1352                #[test]
1353                fn $name() {
1354                    let ser = SimpleTypeSerializer {
1355                        writer: String::new(),
1356                        target: QuoteTarget::CData,
1357                        level: QuoteLevel::Full,
1358                    };
1359
1360                    let buffer = $data.serialize(ser).expect("serialization should succeed");
1361                    assert_eq!(buffer, $expected);
1362                }
1363            };
1364        }
1365
1366        serialize_as_cdata!(empty_string: "" => "");
1367        serialize_as_cdata!(simple_text: "Hello World" => "<![CDATA[Hello World]]>");
1368        serialize_as_cdata!(with_markup: "<tag>content</tag>" => "<![CDATA[<tag>content</tag>]]>");
1369        serialize_as_cdata!(with_ampersand: "Tom & Jerry" => "<![CDATA[Tom & Jerry]]>");
1370        serialize_as_cdata!(with_quotes: r#"He said "Hello""# => r#"<![CDATA[He said "Hello"]]>"#);
1371        serialize_as_cdata!(all_xml_chars: "<>&\"'" => "<![CDATA[<>&\"']]>");
1372
1373        serialize_as_cdata!(with_cdata_end: "foo]]>bar" => "<![CDATA[foo]]]]><![CDATA[>bar]]>");
1374        serialize_as_cdata!(multiple_cdata_ends: "a]]>b]]>c" => "<![CDATA[a]]]]><![CDATA[>b]]]]><![CDATA[>c]]>");
1375        serialize_as_cdata!(starts_with_cdata_end: "]]>hello" => "<![CDATA[]]]]><![CDATA[>hello]]>");
1376        serialize_as_cdata!(ends_with_cdata_end: "hello]]>" => "<![CDATA[hello]]]]><![CDATA[>]]>");
1377        serialize_as_cdata!(only_cdata_end: "]]>" => "<![CDATA[]]]]><![CDATA[>]]>");
1378
1379        serialize_as_cdata!(seq_basic: vec!["foo", "bar", "baz"] => "<![CDATA[foo bar baz]]>");
1380        serialize_as_cdata!(seq_with_space: vec!["hello world", "hello\tworld", "world"] => "<![CDATA[hello world hello\tworld world]]>");
1381        serialize_as_cdata!(seq_with_markup_chars: vec!["<tag>", "&entity", "\"quoted\""] => "<![CDATA[<tag> &entity \"quoted\"]]>");
1382        serialize_as_cdata!(seq_with_cdata_end_split: vec!["foo]]>bar", "test"] => "<![CDATA[foo]]]]><![CDATA[>bar test]]>");
1383        serialize_as_cdata!(tuple_cdata: ("first", 42, "third") => "<![CDATA[first 42 third]]>");
1384    }
1385}