1 #[macro_use]
2 extern crate yaserde_derive;
3 
4 use std::io::Read;
5 use yaserde::de::from_str;
6 use yaserde::YaDeserialize;
7 
8 macro_rules! convert_and_validate {
9   ($content: expr, $struct: tt, $model: expr) => {
10     let loaded: Result<$struct, String> = from_str($content);
11     assert_eq!(loaded, Ok($model));
12   };
13 }
14 
15 #[test]
de_basic()16 fn de_basic() {
17   #[derive(YaDeserialize, PartialEq, Debug)]
18   #[yaserde(root = "book")]
19   pub struct Book {
20     author: String,
21     title: String,
22   }
23 
24   let content =
25     "<book><author>Antoine de Saint-Exupéry</author><title>Little prince</title></book>";
26   convert_and_validate!(
27     content,
28     Book,
29     Book {
30       author: String::from("Antoine de Saint-Exupéry"),
31       title: String::from("Little prince"),
32     }
33   );
34 
35   let content =
36     "<book><title>Little prince</title><author>Antoine de Saint-Exupéry</author></book>";
37   convert_and_validate!(
38     content,
39     Book,
40     Book {
41       author: String::from("Antoine de Saint-Exupéry"),
42       title: String::from("Little prince"),
43     }
44   );
45 }
46 
47 #[test]
de_multiple_segments()48 fn de_multiple_segments() {
49   mod other_mod {
50     use std::io::Read;
51     use yaserde::YaDeserialize;
52 
53     #[derive(YaDeserialize, PartialEq, Debug, Default)]
54     pub struct Page {
55       pub number: i32,
56       pub text: std::string::String,
57     }
58   }
59 
60   #[derive(YaDeserialize, PartialEq, Debug)]
61   #[yaserde(root = "book")]
62   pub struct Book {
63     author: std::string::String,
64     title: std::string::String,
65     page: other_mod::Page,
66   }
67 
68   let content = r#"
69       <book>
70         <author>Antoine de Saint-Exupéry</author>
71         <title>Little prince</title>
72         <page>
73           <number>40</number>
74           <text>The Earth is not just an ordinary planet!</text>
75         </page>
76       </book>
77     "#;
78 
79   convert_and_validate!(
80     content,
81     Book,
82     Book {
83       author: String::from("Antoine de Saint-Exupéry"),
84       title: String::from("Little prince"),
85       page: other_mod::Page {
86         number: 40,
87         text: String::from("The Earth is not just an ordinary planet!"),
88       },
89     }
90   );
91 }
92 
93 #[test]
de_list_of_items()94 fn de_list_of_items() {
95   #[derive(YaDeserialize, PartialEq, Debug)]
96   #[yaserde(root = "library")]
97   pub struct Library {
98     books: Vec<String>,
99   }
100 
101   let content = "<library><books>Little Prince</books><books>Harry Potter</books></library>";
102   convert_and_validate!(
103     content,
104     Library,
105     Library {
106       books: vec![String::from("Little Prince"), String::from("Harry Potter")],
107     }
108   );
109 
110   #[derive(YaDeserialize, PartialEq, Debug)]
111   #[yaserde(root = "libraries")]
112   pub struct Libraries {
113     library: Vec<Library>,
114   }
115 
116   let content = "<libraries><library><books>Little Prince</books></library><library><books>Harry Potter</books></library></libraries>";
117   convert_and_validate!(
118     content,
119     Libraries,
120     Libraries {
121       library: vec![
122         Library {
123           books: vec![String::from("Little Prince")],
124         },
125         Library {
126           books: vec![String::from("Harry Potter")],
127         },
128       ],
129     }
130   );
131 }
132 
133 #[test]
de_attributes()134 fn de_attributes() {
135   #[derive(YaDeserialize, PartialEq, Debug)]
136   #[yaserde(root = "base")]
137   pub struct XmlStruct {
138     #[yaserde(attribute)]
139     item: String,
140     sub: SubStruct,
141   }
142 
143   #[derive(YaDeserialize, PartialEq, Debug)]
144   #[yaserde(root = "sub")]
145   pub struct SubStruct {
146     #[yaserde(attribute)]
147     subitem: String,
148   }
149 
150   impl Default for SubStruct {
151     fn default() -> SubStruct {
152       SubStruct {
153         subitem: "".to_string(),
154       }
155     }
156   }
157 
158   let content = "<base item=\"something\"><sub subitem=\"sub-something\"></sub></base>";
159   convert_and_validate!(
160     content,
161     XmlStruct,
162     XmlStruct {
163       item: "something".to_string(),
164       sub: SubStruct {
165         subitem: "sub-something".to_string(),
166       },
167     }
168   );
169 }
170 
171 #[test]
de_attributes_complex()172 fn de_attributes_complex() {
173   mod other_mod {
174     use super::*;
175 
176     #[derive(YaDeserialize, PartialEq, Debug)]
177     pub enum AttrEnum {
178       #[yaserde(rename = "variant 1")]
179       Variant1,
180       #[yaserde(rename = "variant 2")]
181       Variant2,
182     }
183 
184     impl Default for AttrEnum {
185       fn default() -> AttrEnum {
186         AttrEnum::Variant1
187       }
188     }
189   }
190 
191   #[derive(Default, YaDeserialize, PartialEq, Debug)]
192   pub struct Struct {
193     #[yaserde(attribute)]
194     attr_option_string: Option<std::string::String>,
195     #[yaserde(attribute)]
196     attr_option_enum: Option<other_mod::AttrEnum>,
197   }
198 
199   convert_and_validate!(
200     r#"<Struct />"#,
201     Struct,
202     Struct {
203       attr_option_string: None,
204       attr_option_enum: None
205     }
206   );
207 
208   convert_and_validate!(
209     r#"<Struct attr_option_string="some value" attr_option_enum="variant 2" />"#,
210     Struct,
211     Struct {
212       attr_option_string: Some("some value".to_string()),
213       attr_option_enum: Some(other_mod::AttrEnum::Variant2)
214     }
215   );
216 }
217 
218 #[test]
de_rename()219 fn de_rename() {
220   #[derive(YaDeserialize, PartialEq, Debug)]
221   #[yaserde(root = "base")]
222   pub struct XmlStruct {
223     #[yaserde(attribute, rename = "Item")]
224     item: String,
225     #[yaserde(rename = "sub")]
226     sub_struct: SubStruct,
227     #[yaserde(rename = "maj.min.bug")]
228     with_dots: String,
229   }
230 
231   #[derive(YaDeserialize, PartialEq, Debug)]
232   #[yaserde(root = "sub")]
233   pub struct SubStruct {
234     #[yaserde(attribute, rename = "sub_item")]
235     subitem: String,
236   }
237 
238   impl Default for SubStruct {
239     fn default() -> SubStruct {
240       SubStruct {
241         subitem: "".to_string(),
242       }
243     }
244   }
245 
246   let content = "<base Item=\"something\"><sub sub_item=\"sub_something\"></sub><maj.min.bug>2.0.1</maj.min.bug></base>";
247   convert_and_validate!(
248     content,
249     XmlStruct,
250     XmlStruct {
251       item: "something".to_string(),
252       sub_struct: SubStruct {
253         subitem: "sub_something".to_string(),
254       },
255       with_dots: "2.0.1".into()
256     }
257   );
258 }
259 
260 #[test]
de_text_content_with_attributes()261 fn de_text_content_with_attributes() {
262   #[derive(YaDeserialize, PartialEq, Debug)]
263   #[yaserde(root = "base")]
264   pub struct XmlStruct {
265     #[yaserde(attribute, rename = "Item")]
266     item: String,
267     #[yaserde(rename = "sub")]
268     sub_struct: SubStruct,
269   }
270 
271   #[derive(YaDeserialize, PartialEq, Debug)]
272   #[yaserde(root = "sub")]
273   pub struct SubStruct {
274     #[yaserde(attribute, rename = "sub_item")]
275     subitem: String,
276     #[yaserde(text)]
277     text: String,
278   }
279 
280   impl Default for SubStruct {
281     fn default() -> SubStruct {
282       SubStruct {
283         subitem: "".to_string(),
284         text: "".to_string(),
285       }
286     }
287   }
288 
289   let content =
290     "<base Item=\"something\"><sub sub_item=\"sub_something\">text_content</sub></base>";
291   convert_and_validate!(
292     content,
293     XmlStruct,
294     XmlStruct {
295       item: "something".to_string(),
296       sub_struct: SubStruct {
297         subitem: "sub_something".to_string(),
298         text: "text_content".to_string(),
299       },
300     }
301   );
302 }
303 
304 #[test]
de_enum()305 fn de_enum() {
306   #[derive(YaDeserialize, PartialEq, Debug)]
307   #[yaserde(root = "base")]
308   pub struct XmlStruct {
309     background: Color,
310   }
311 
312   #[derive(YaDeserialize, PartialEq, Debug)]
313   #[yaserde(root = "base")]
314   pub struct Colors {
315     items: Vec<Color>,
316   }
317 
318   #[derive(YaDeserialize, PartialEq, Debug)]
319   #[yaserde(root = "color")]
320   pub enum Color {
321     White,
322     Black,
323   }
324 
325   impl Default for Color {
326     fn default() -> Color {
327       Color::White
328     }
329   }
330 
331   #[derive(YaDeserialize, PartialEq, Debug)]
332   pub struct RGBColor {
333     red: String,
334     green: String,
335     blue: String,
336   }
337 
338   impl Default for RGBColor {
339     fn default() -> RGBColor {
340       RGBColor {
341         red: "0".to_string(),
342         green: "0".to_string(),
343         blue: "0".to_string(),
344       }
345     }
346   }
347 
348   let content =
349     "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><background>Black</background></base>";
350   convert_and_validate!(
351     content,
352     XmlStruct,
353     XmlStruct {
354       background: Color::Black,
355     }
356   );
357 
358   let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><items>Black</items><items>White</items></base>";
359   convert_and_validate!(
360     content,
361     Colors,
362     Colors {
363       items: vec![Color::Black, Color::White],
364     }
365   );
366 }
367 
368 #[test]
de_attribute_enum()369 fn de_attribute_enum() {
370   #[derive(YaDeserialize, PartialEq, Debug)]
371   #[yaserde(root = "base")]
372   pub struct XmlStruct {
373     #[yaserde(attribute)]
374     background: Color,
375   }
376 
377   #[derive(YaDeserialize, PartialEq, Debug)]
378   #[yaserde(root = "color")]
379   pub enum Color {
380     White,
381     Black,
382   }
383 
384   impl Default for Color {
385     fn default() -> Color {
386       Color::White
387     }
388   }
389 
390   let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base background=\"Black\" />";
391   convert_and_validate!(
392     content,
393     XmlStruct,
394     XmlStruct {
395       background: Color::Black,
396     }
397   );
398 }
399 
400 #[test]
de_complex_enum()401 fn de_complex_enum() {
402   #[derive(YaDeserialize, PartialEq, Debug)]
403   pub struct XmlStruct {
404     background: Color,
405   }
406 
407   #[derive(YaDeserialize, PartialEq, Debug, Default)]
408   pub struct OtherStruct {
409     fi: i32,
410     se: i32,
411   }
412 
413   #[derive(YaDeserialize, PartialEq, Debug)]
414   pub enum Color {
415     White,
416     Black(String),
417     Orange(std::string::String),
418     Red(i32),
419     Green(OtherStruct),
420     Yellow(Option<String>),
421     Brown(Option<OtherStruct>),
422     Blue(Vec<String>),
423     Purple(Vec<i32>),
424     Magenta(Vec<OtherStruct>),
425     #[yaserde(rename = "NotSoCyan")]
426     Cyan(Vec<OtherStruct>),
427     #[yaserde(rename = "renamed.with.dots")]
428     Dotted(u32),
429   }
430 
431   impl Default for Color {
432     fn default() -> Color {
433       Color::White
434     }
435   }
436 
437   let content = r#"<?xml version="1.0" encoding="utf-8"?>
438     <base>
439       <background>
440         <Black>text</Black>
441       </background>
442     </base>
443   "#;
444   convert_and_validate!(
445     content,
446     XmlStruct,
447     XmlStruct {
448       background: Color::Black(String::from("text")),
449     }
450   );
451 
452   let content = r#"<?xml version="1.0" encoding="utf-8"?>
453     <base>
454       <background>
455         <Orange>text</Orange>
456       </background>
457     </base>
458   "#;
459   convert_and_validate!(
460     content,
461     XmlStruct,
462     XmlStruct {
463       background: Color::Orange(String::from("text")),
464     }
465   );
466 
467   let content = r#"<?xml version="1.0" encoding="utf-8"?>
468     <base>
469       <background>
470         <Red>56</Red>
471       </background>
472     </base>
473   "#;
474   convert_and_validate!(
475     content,
476     XmlStruct,
477     XmlStruct {
478       background: Color::Red(56),
479     }
480   );
481 
482   let content = r#"<?xml version="1.0" encoding="utf-8"?>
483     <base>
484       <background>
485         <Green>
486           <fi>12</fi>
487           <se>23</se>
488         </Green>
489       </background>
490     </base>
491   "#;
492   convert_and_validate!(
493     content,
494     XmlStruct,
495     XmlStruct {
496       background: Color::Green(OtherStruct { fi: 12, se: 23 }),
497     }
498   );
499 
500   let content = r#"<?xml version="1.0" encoding="utf-8"?>
501     <base>
502       <background>
503         <Yellow>text</Yellow>
504       </background>
505     </base>
506   "#;
507   convert_and_validate!(
508     content,
509     XmlStruct,
510     XmlStruct {
511       background: Color::Yellow(Some(String::from("text"))),
512     }
513   );
514 
515   let content = r#"<?xml version="1.0" encoding="utf-8"?>
516     <base>
517       <background>
518         <Brown>
519           <fi>12</fi>
520           <se>23</se>
521         </Brown>
522       </background>
523     </base>
524   "#;
525   convert_and_validate!(
526     content,
527     XmlStruct,
528     XmlStruct {
529       background: Color::Brown(Some(OtherStruct { fi: 12, se: 23 })),
530     }
531   );
532 
533   let content = r#"<?xml version="1.0" encoding="utf-8"?>
534     <base>
535       <background>
536         <Blue>abc</Blue>
537         <Blue>def</Blue>
538       </background>
539     </base>
540   "#;
541   convert_and_validate!(
542     content,
543     XmlStruct,
544     XmlStruct {
545       background: Color::Blue(vec![String::from("abc"), String::from("def")]),
546     }
547   );
548 
549   let content = r#"<?xml version="1.0" encoding="utf-8"?>
550     <base>
551       <background>
552         <Purple>12</Purple>
553         <Purple>43</Purple>
554       </background>
555     </base>
556   "#;
557   convert_and_validate!(
558     content,
559     XmlStruct,
560     XmlStruct {
561       background: Color::Purple(vec![12, 43]),
562     }
563   );
564 
565   let content = r#"<?xml version="1.0" encoding="utf-8"?>
566     <base>
567       <background>
568         <Magenta><fi>12</fi><se>23</se></Magenta>
569         <Magenta><fi>63</fi><se>98</se></Magenta>
570       </background>
571     </base>
572   "#;
573   convert_and_validate!(
574     content,
575     XmlStruct,
576     XmlStruct {
577       background: Color::Magenta(vec![
578         OtherStruct { fi: 12, se: 23 },
579         OtherStruct { fi: 63, se: 98 }
580       ]),
581     }
582   );
583 
584   let content = r#"<?xml version="1.0" encoding="utf-8"?>
585     <base xmlns:ns="http://www.sample.com/ns/domain">
586       <background>
587         <NotSoCyan><fi>12</fi><se>23</se></NotSoCyan>
588         <NotSoCyan><fi>63</fi><se>98</se></NotSoCyan>
589       </background>
590     </base>
591   "#;
592   convert_and_validate!(
593     content,
594     XmlStruct,
595     XmlStruct {
596       background: Color::Cyan(vec![
597         OtherStruct { fi: 12, se: 23 },
598         OtherStruct { fi: 63, se: 98 }
599       ])
600     }
601   );
602 
603   let content = r#"<?xml version="1.0" encoding="utf-8"?>
604     <base xmlns:ns="http://www.sample.com/ns/domain">
605       <background>
606         <renamed.with.dots>54</renamed.with.dots>
607       </background>
608     </base>
609   "#;
610   convert_and_validate!(
611     content,
612     XmlStruct,
613     XmlStruct {
614       background: Color::Dotted(54)
615     }
616   );
617 }
618 
619 #[test]
de_name_issue_21()620 fn de_name_issue_21() {
621   #[derive(YaDeserialize, PartialEq, Debug)]
622   #[yaserde(root = "book")]
623   pub struct Book {
624     name: String,
625   }
626 
627   let content = "<book><name>Little prince</name></book>";
628   convert_and_validate!(
629     content,
630     Book,
631     Book {
632       name: String::from("Little prince"),
633     }
634   );
635 }
636 
637 #[test]
de_custom()638 fn de_custom() {
639   #[derive(Default, PartialEq, Debug, YaDeserialize)]
640   struct Date {
641     #[yaserde(rename = "Year")]
642     year: i32,
643     #[yaserde(rename = "Month")]
644     month: i32,
645     #[yaserde(rename = "Day")]
646     day: Day,
647   }
648 
649   #[derive(Default, PartialEq, Debug)]
650   struct Day {
651     value: i32,
652   }
653 
654   impl YaDeserialize for Day {
655     fn deserialize<R: Read>(reader: &mut yaserde::de::Deserializer<R>) -> Result<Self, String> {
656       use std::str::FromStr;
657 
658       if let xml::reader::XmlEvent::StartElement { name, .. } = reader.peek()?.to_owned() {
659         let expected_name = String::from("Day");
660         if name.local_name != expected_name {
661           return Err(format!(
662             "Wrong StartElement name: {}, expected: {}",
663             name, expected_name
664           ));
665         }
666         let _next = reader.next_event();
667       } else {
668         return Err("StartElement missing".to_string());
669       }
670 
671       if let xml::reader::XmlEvent::Characters(text) = reader.peek()?.to_owned() {
672         Ok(Day {
673           value: 2 * i32::from_str(&text).unwrap(),
674         })
675       } else {
676         Err("Characters missing".to_string())
677       }
678     }
679   }
680 
681   let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Date><Year>2020</Year><Month>01</Month><Day>11</Day></Date>";
682   let model: Date = from_str(content).unwrap();
683 
684   assert_eq!(
685     model,
686     Date {
687       year: 2020,
688       month: 1,
689       day: Day { value: 11 * 2 }
690     }
691   );
692 }
693 
694 #[test]
de_subitem_issue_12()695 fn de_subitem_issue_12() {
696   #[derive(Default, PartialEq, Debug, YaDeserialize)]
697   pub struct Struct {
698     id: i32,
699   }
700 
701   convert_and_validate!(
702     r#"
703     <?xml version="1.0" encoding="utf-8"?>
704     <Struct>
705       <id>54</id>
706       <SubStruct>
707         <id>86</id>
708       </SubStruct>
709     </Struct>
710     "#,
711     Struct,
712     Struct { id: 54 }
713   );
714 }
715 
716 #[test]
de_subitem_issue_12_with_sub()717 fn de_subitem_issue_12_with_sub() {
718   #[derive(Default, PartialEq, Debug, YaDeserialize)]
719   pub struct SubStruct {
720     id: i32,
721   }
722 
723   #[derive(Default, PartialEq, Debug, YaDeserialize)]
724   pub struct Struct {
725     id: i32,
726     #[yaserde(rename = "SubStruct")]
727     sub: SubStruct,
728   }
729 
730   convert_and_validate!(
731     r#"
732     <?xml version="1.0" encoding="utf-8"?>
733     <Struct>
734       <id>54</id>
735       <SubStruct>
736         <id>86</id>
737       </SubStruct>
738     </Struct>
739     "#,
740     Struct,
741     Struct {
742       id: 54,
743       sub: SubStruct { id: 86 }
744     }
745   );
746 }
747 
748 #[test]
de_subitem_issue_12_attributes()749 fn de_subitem_issue_12_attributes() {
750   #[derive(Default, PartialEq, Debug, YaDeserialize)]
751   pub struct Struct {
752     #[yaserde(attribute)]
753     id: i32,
754   }
755 
756   convert_and_validate!(
757     r#"
758     <?xml version="1.0" encoding="utf-8"?>
759     <Struct id="54">
760       <SubStruct id="86" />
761     </Struct>
762     "#,
763     Struct,
764     Struct { id: 54 }
765   );
766 }
767 
768 #[test]
de_subitem_issue_12_attributes_with_sub()769 fn de_subitem_issue_12_attributes_with_sub() {
770   #[derive(Default, PartialEq, Debug, YaDeserialize)]
771   pub struct SubStruct {
772     #[yaserde(attribute)]
773     id: i32,
774   }
775 
776   #[derive(Default, PartialEq, Debug, YaDeserialize)]
777   pub struct Struct {
778     #[yaserde(attribute)]
779     id: i32,
780     sub1: SubStruct,
781     sub2: SubStruct,
782   }
783 
784   convert_and_validate!(
785     r#"
786     <?xml version="1.0" encoding="utf-8"?>
787     <Struct id="54">
788       <sub1 id="63" />
789       <sub2 id="72" />
790     </Struct>
791     "#,
792     Struct,
793     Struct {
794       id: 54,
795       sub1: SubStruct { id: 63 },
796       sub2: SubStruct { id: 72 }
797     }
798   );
799 }
800 
801 #[test]
de_same_field_name_sub()802 fn de_same_field_name_sub() {
803   #[derive(Default, PartialEq, Debug, YaDeserialize)]
804   pub struct SubStruct {
805     sub: Option<i32>,
806   }
807 
808   #[derive(Default, PartialEq, Debug, YaDeserialize)]
809   pub struct Struct {
810     sub: SubStruct,
811   }
812 
813   convert_and_validate!("<Struct><sub /></Struct>", Struct, Struct::default());
814 
815   convert_and_validate!(
816     "<Struct><sub><sub>42</sub></sub></Struct>",
817     Struct,
818     Struct {
819       sub: SubStruct { sub: Some(42) }
820     }
821   );
822 }
823 
824 #[test]
de_same_field_name_sub_sub()825 fn de_same_field_name_sub_sub() {
826   #[derive(Default, PartialEq, Debug, YaDeserialize)]
827   pub struct SubSubStruct {
828     sub: i32,
829   }
830 
831   #[derive(Default, PartialEq, Debug, YaDeserialize)]
832   pub struct SubStruct {
833     sub: Option<SubSubStruct>,
834   }
835 
836   #[derive(Default, PartialEq, Debug, YaDeserialize)]
837   pub struct Struct {
838     sub: SubStruct,
839   }
840 
841   convert_and_validate!("<Struct><sub /></Struct>", Struct, Struct::default());
842 
843   convert_and_validate!(
844     "<Struct><sub><sub><sub>42</sub></sub></sub></Struct>",
845     Struct,
846     Struct {
847       sub: SubStruct {
848         sub: Some(SubSubStruct { sub: 42 })
849       }
850     }
851   );
852 }
853