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