1 mod common;
2 
3 use common::init_logger;
4 use serde::{de, ser, Deserialize, Serialize};
5 use serde_xml_rs::{from_str, Error};
6 use std::fmt::Debug;
7 
8 #[derive(PartialEq, Debug, Serialize, Deserialize)]
9 enum Animal {
10     Dog,
11     Frog(String),
12     Ant(Simple),
13     Cat { age: usize, name: String },
14 }
15 
16 #[derive(PartialEq, Debug, Serialize, Deserialize)]
17 struct Simple {
18     a: (),
19     b: usize,
20     c: String,
21     d: Option<String>,
22 }
23 
24 #[derive(PartialEq, Debug, Serialize, Deserialize)]
25 struct Inner {
26     a: (),
27     b: (usize, String, i8),
28     c: Vec<String>,
29 }
30 
31 #[derive(PartialEq, Debug, Serialize, Deserialize)]
32 struct Outer {
33     inner: Option<Inner>,
34 }
35 
test_parse_ok<'de, 'a, T>(errors: &[(&'a str, T)]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,36 fn test_parse_ok<'de, 'a, T>(errors: &[(&'a str, T)])
37 where
38     T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,
39 {
40     for &(s, ref value) in errors {
41         let v: T = from_str(s).unwrap();
42         assert_eq!(v, *value);
43 
44         // // Make sure we can deserialize into an `Element`.
45         // let xml_value: Element = from_str(s).unwrap();
46 
47         // // Make sure we can deserialize from an `Element`.
48         // let v: T = from_value(xml_value.clone()).unwrap();
49         // assert_eq!(v, *value);
50     }
51 }
52 
test_parse_err<'de, 'a, T>(errors: &[&'a str]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,53 fn test_parse_err<'de, 'a, T>(errors: &[&'a str])
54 where
55     T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,
56 {
57     for &s in errors {
58         assert!(match from_str::<T>(s) {
59             Err(Error::Syntax { source: _ }) => true,
60             _ => false,
61         });
62     }
63 }
64 
65 #[test]
test_namespaces()66 fn test_namespaces() {
67     init_logger();
68     #[derive(PartialEq, Serialize, Deserialize, Debug)]
69     struct Envelope {
70         subject: String,
71     }
72     let s = r#"
73     <?xml version="1.0" encoding="UTF-8"?>
74     <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
75         <gesmes:subject>Reference rates</gesmes:subject>
76     </gesmes:Envelope>"#;
77     test_parse_ok(&[(
78         s,
79         Envelope {
80             subject: "Reference rates".to_string(),
81         },
82     )]);
83 }
84 
85 #[test]
test_doctype()86 fn test_doctype() {
87     init_logger();
88     #[derive(PartialEq, Serialize, Deserialize, Debug)]
89     struct Envelope {
90         subject: String,
91     }
92 
93     test_parse_ok(&[
94         (
95             r#"
96             <?xml version="1.0" encoding="UTF-8"?>
97             <!DOCTYPE Envelope>
98             <Envelope>
99             <subject>Reference rates</subject>
100             </Envelope>"#,
101             Envelope {
102                 subject: "Reference rates".to_string(),
103             },
104         ),
105         (
106             r#"
107             <?xml version="1.0" encoding="UTF-8"?>
108             <!DOCTYPE Envelope[]>
109             <Envelope>
110             <subject>Reference rates</subject>
111             </Envelope>"#,
112             Envelope {
113                 subject: "Reference rates".to_string(),
114             },
115         ),
116         (
117             r#"
118             <?xml version="1.0" encoding="UTF-8"?>
119             <!DOCTYPE Envelope [
120                 <!ELEMENT subject (#PCDATA)>
121             ] >
122             <Envelope>
123             <subject>Reference rates</subject>
124             </Envelope>"#,
125             Envelope {
126                 subject: "Reference rates".to_string(),
127             },
128         ),
129     ]);
130 }
131 
132 #[test]
133 #[ignore] // FIXME
test_forwarded_namespace()134 fn test_forwarded_namespace() {
135     #[derive(PartialEq, Serialize, Deserialize, Debug)]
136     struct Graphml {
137         #[serde(rename = "xsi:schemaLocation")]
138         schema_location: String,
139     }
140     let s = r#"
141     <?xml version="1.0" encoding="UTF-8"?>
142     <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
143         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
144         xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
145         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
146 
147 
148     </graphml>"#;
149     test_parse_ok(&[(
150         s,
151         Graphml {
152             schema_location: "http://graphml.graphdrawing.org/xmlns
153         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"
154                 .to_string(),
155         },
156     )]);
157 }
158 
159 #[test]
160 #[ignore] // FIXME
test_parse_string_not_trim()161 fn test_parse_string_not_trim() {
162     init_logger();
163 
164     test_parse_ok(&[("<bla>     </bla>", "     ".to_string())]);
165 }
166 
167 #[test]
168 #[ignore] // FIXME
test_parse_enum()169 fn test_parse_enum() {
170     use self::Animal::*;
171     init_logger();
172 
173     test_parse_ok(&[
174         ("<Animal xsi:type=\"Dog\"/>", Dog),
175         (
176             "<Animal xsi:type=\"Frog\">Quak</Animal>",
177             Frog("Quak".to_string()),
178         ),
179         (
180             "<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b><d>Foo</d></Animal>",
181             Ant(Simple {
182                 a: (),
183                 b: 15,
184                 c: "bla".to_string(),
185                 d: Some("Foo".to_string()),
186             }),
187         ),
188         (
189             "<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b></Animal>",
190             Ant(Simple {
191                 a: (),
192                 b: 15,
193                 c: "bla".to_string(),
194                 d: None,
195             }),
196         ),
197         (
198             "<Animal xsi:type=\"Cat\"><age>42</age><name>Shere Khan</name></Animal>",
199             Cat {
200                 age: 42,
201                 name: "Shere Khan".to_string(),
202             },
203         ),
204     ]);
205 
206     #[derive(PartialEq, Debug, Serialize, Deserialize)]
207     struct Helper {
208         x: Animal,
209     }
210 
211     test_parse_ok(&[
212         ("<Helper><x xsi:type=\"Dog\"/></Helper>", Helper { x: Dog }),
213         (
214             "<Helper><x xsi:type=\"Frog\">Quak</Animal></Helper>",
215             Helper {
216                 x: Frog("Quak".to_string()),
217             },
218         ),
219         (
220             "<Helper><x xsi:type=\"Cat\">
221                 <age>42</age>
222                 <name>Shere Khan</name>
223             </x></Helper>",
224             Helper {
225                 x: Cat {
226                     age: 42,
227                     name: "Shere Khan".to_string(),
228                 },
229             },
230         ),
231     ]);
232 }
233 
234 #[test]
test_parse_struct()235 fn test_parse_struct() {
236     init_logger();
237 
238     test_parse_ok(&[
239         (
240             "<Simple>
241                 <c>abc</c>
242                 <a/>
243                 <b>2</b>
244             </Simple>",
245             Simple {
246                 a: (),
247                 b: 2,
248                 c: "abc".to_string(),
249                 d: None,
250             },
251         ),
252         (
253             "<Simple><!-- this is a comment -->
254                 <c>abc</c>
255                 <a/>
256                 <b>2</b>
257             </Simple>",
258             Simple {
259                 a: (),
260                 b: 2,
261                 c: "abc".to_string(),
262                 d: None,
263             },
264         ),
265         (
266             "<Simple d=\"Foo\"><!-- this is a comment -->
267                 <c>abc</c>
268                 <a/>
269                 <b>2</b>
270             </Simple>",
271             Simple {
272                 a: (),
273                 b: 2,
274                 c: "abc".to_string(),
275                 d: Some("Foo".to_string()),
276             },
277         ),
278     ]);
279 }
280 
281 #[test]
282 #[ignore] // FIXME
test_option_not_trim()283 fn test_option_not_trim() {
284     init_logger();
285     test_parse_ok(&[("<a> </a>", Some(" ".to_string()))]);
286 }
287 
288 #[test]
test_amoskvin()289 fn test_amoskvin() {
290     init_logger();
291     #[derive(Debug, Deserialize, PartialEq, Serialize)]
292     struct Root {
293         foo: Vec<Foo>,
294     }
295 
296     #[derive(Debug, Deserialize, PartialEq, Serialize)]
297     struct Foo {
298         a: String,
299         b: Option<String>,
300     }
301     test_parse_ok(&[(
302         "
303 <root>
304 <foo>
305  <a>Hello</a>
306  <b>World</b>
307 </foo>
308 <foo>
309  <a>Hi</a>
310 </foo>
311 </root>",
312         Root {
313             foo: vec![
314                 Foo {
315                     a: "Hello".to_string(),
316                     b: Some("World".to_string()),
317                 },
318                 Foo {
319                     a: "Hi".to_string(),
320                     b: None,
321                 },
322             ],
323         },
324     )]);
325 }
326 
327 #[test]
328 #[ignore] // FIXME
test_nicolai86()329 fn test_nicolai86() {
330     init_logger();
331     #[derive(Serialize, Deserialize, PartialEq, Debug)]
332     struct TheSender {
333         name: String,
334     }
335 
336     #[derive(Serialize, Deserialize, PartialEq, Debug)]
337     struct CurrencyCube {
338         currency: String,
339         rate: String,
340     }
341 
342     #[derive(Serialize, Deserialize, PartialEq, Debug)]
343     #[allow(non_snake_case)]
344     struct InnerCube {
345         Cube: Vec<CurrencyCube>,
346     }
347 
348     #[derive(Serialize, Deserialize, PartialEq, Debug)]
349     #[allow(non_snake_case)]
350     struct OuterCube {
351         Cube: Vec<InnerCube>,
352     }
353 
354     #[derive(Serialize, Deserialize, PartialEq, Debug)]
355     #[allow(non_snake_case)]
356     struct Envelope {
357         subject: String,
358         Sender: TheSender,
359         Cube: OuterCube,
360     }
361     test_parse_ok(&[
362         (
363             r#"
364             <?xml version="1.0" encoding="UTF-8"?>
365             <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
366                 <gesmes:subject>Reference rates</gesmes:subject>
367                 <gesmes:Sender>
368                     <gesmes:name>European Central Bank</gesmes:name>
369                 </gesmes:Sender>
370                 <Cube> </Cube>
371             </gesmes:Envelope>"#,
372             Envelope {
373                 subject: "Reference rates".to_string(),
374                 Sender: TheSender {
375                     name: "European Central Bank".to_string(),
376                 },
377                 Cube: OuterCube { Cube: vec![] },
378             },
379         ),
380         (
381             r#"
382             <?xml version="1.0" encoding="UTF-8"?>
383             <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
384                 <gesmes:subject>Reference rates</gesmes:subject>
385                 <gesmes:Sender>
386                     <gesmes:name>European Central Bank</gesmes:name>
387                 </gesmes:Sender>
388                 <Cube><Cube>
389                     <Cube currency='GBP' rate='0.81725'/>
390                     <Cube currency='Latinum' rate='999999'/>
391                 </Cube></Cube>
392             </gesmes:Envelope>"#,
393             Envelope {
394                 subject: "Reference rates".to_string(),
395                 Sender: TheSender {
396                     name: "European Central Bank".to_string(),
397                 },
398                 Cube: OuterCube {
399                     Cube: vec![InnerCube {
400                         Cube: vec![
401                             CurrencyCube {
402                                 currency: "GBP".to_string(),
403                                 rate: "0.81725".to_string(),
404                             },
405                             CurrencyCube {
406                                 currency: "Latinum".to_string(),
407                                 rate: "999999".to_string(),
408                             },
409                         ],
410                     }],
411                 },
412             },
413         ),
414     ]);
415 }
416 
417 #[test]
test_hugo_duncan2()418 fn test_hugo_duncan2() {
419     init_logger();
420     let s = r#"
421     <?xml version="1.0" encoding="UTF-8"?>
422     <DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
423         <requestId>8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1</requestId>
424         <vpcSet>
425             <item>
426                 <vpcId>vpc-ba0d18d8</vpcId>
427                 <state>available</state>
428             </item>
429         </vpcSet>
430     </DescribeVpcsResponse>"#;
431     #[derive(PartialEq, Debug, Serialize, Deserialize)]
432     #[allow(non_snake_case)]
433     struct VpcSet {
434         vpcId: String,
435         state: String,
436     }
437 
438     #[derive(PartialEq, Debug, Serialize)]
439     struct ItemVec<T>(Vec<T>);
440 
441     impl<'de, T: de::Deserialize<'de>> de::Deserialize<'de> for ItemVec<T> {
442         fn deserialize<D>(deserializer: D) -> Result<ItemVec<T>, D::Error>
443         where
444             D: de::Deserializer<'de>,
445         {
446             #[derive(PartialEq, Debug, Serialize, Deserialize)]
447             struct Helper<U> {
448                 item: Vec<U>,
449             }
450             let h: Helper<_> = de::Deserialize::deserialize(deserializer)?;
451             Ok(ItemVec(h.item))
452         }
453     }
454     #[derive(PartialEq, Debug, Serialize, Deserialize)]
455     #[allow(non_snake_case)]
456     struct DescribeVpcsResponse {
457         requestId: String,
458         vpcSet: ItemVec<VpcSet>,
459     }
460     test_parse_ok(&[(
461         s,
462         DescribeVpcsResponse {
463             requestId: "8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1".to_string(),
464             vpcSet: ItemVec(vec![VpcSet {
465                 vpcId: "vpc-ba0d18d8".to_string(),
466                 state: "available".to_string(),
467             }]),
468         },
469     )]);
470 }
471 
472 #[test]
test_hugo_duncan()473 fn test_hugo_duncan() {
474     init_logger();
475     let s = "
476         <?xml version=\"1.0\" encoding=\"UTF-8\"?>
477         <DescribeInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2014-10-01/\">
478             <requestId>9474f558-10a5-42e8-84d1-f9ee181fe943</requestId>
479             <reservationSet/>
480         </DescribeInstancesResponse>
481     ";
482     #[derive(PartialEq, Debug, Serialize, Deserialize)]
483     #[allow(non_snake_case)]
484     struct DescribeInstancesResponse {
485         requestId: String,
486         reservationSet: (),
487     }
488     test_parse_ok(&[(
489         s,
490         DescribeInstancesResponse {
491             requestId: "9474f558-10a5-42e8-84d1-f9ee181fe943".to_string(),
492             reservationSet: (),
493         },
494     )]);
495 }
496 
497 #[test]
test_parse_xml_value()498 fn test_parse_xml_value() {
499     init_logger();
500     #[derive(Eq, Debug, PartialEq, Deserialize, Serialize)]
501     struct Test {
502         #[serde(rename = "$value")]
503         myval: String,
504     }
505     test_parse_ok(&[(
506         "<Test>abc</Test>",
507         Test {
508             myval: "abc".to_string(),
509         },
510     )]);
511 }
512 
513 #[test]
514 #[ignore] // FIXME
test_parse_complexstruct()515 fn test_parse_complexstruct() {
516     init_logger();
517 
518     test_parse_ok(&[
519         (
520             "<Outer>
521                 <inner>
522                     <b>2</b>
523                     <b>boom</b>
524                     <b>88</b>
525                 </inner>
526             </Outer>",
527             Outer {
528                 inner: Some(Inner {
529                     a: (),
530                     b: (2, "boom".to_string(), 88),
531                     c: vec![],
532                 }),
533             },
534         ),
535         (
536             "<Outer>
537                 <inner>
538                     <c>abc</c>
539                     <c>xyz</c>
540                     <a/>
541                     <b>2</b>
542                     <b>boom</b>
543                     <b>88</b>
544                 </inner>
545             </Outer>",
546             Outer {
547                 inner: Some(Inner {
548                     a: (),
549                     b: (2, "boom".to_string(), 88),
550                     c: vec!["abc".to_string(), "xyz".to_string()],
551                 }),
552             },
553         ),
554         ("<Outer/>", Outer { inner: None }),
555     ]);
556 }
557 
558 #[test]
test_parse_attributes()559 fn test_parse_attributes() {
560     init_logger();
561 
562     #[derive(PartialEq, Debug, Serialize, Deserialize)]
563     struct A {
564         a1: String,
565         #[serde(rename = "$value")]
566         a2: i32,
567     }
568 
569     test_parse_ok(&[(
570         r#"<A a1="What is the answer to the ultimate question?">42</A>"#,
571         A {
572             a1: "What is the answer to the ultimate question?".to_string(),
573             a2: 42,
574         },
575     )]);
576 
577     #[derive(PartialEq, Debug, Serialize, Deserialize)]
578     struct B {
579         b1: String,
580         b2: i32,
581     }
582 
583     test_parse_ok(&[(
584         r#"<B b1="What is the answer to the ultimate question?" b2="42"/>"#,
585         B {
586             b1: "What is the answer to the ultimate question?".to_string(),
587             b2: 42,
588         },
589     )]);
590 
591     #[derive(PartialEq, Debug, Serialize, Deserialize)]
592     struct C {
593         c1: B,
594     }
595 
596     test_parse_ok(&[
597         (
598             r#"<C><c1 b1="What is the answer to the ultimate question?" b2="42"/></C>"#,
599             C {
600                 c1: B {
601                     b1: "What is the answer to the ultimate question?".to_string(),
602                     b2: 42,
603                 },
604             },
605         ),
606         (
607             r#"<C><c1 b1="What is the answer to the ultimate question?" b2="42"/> </C>"#,
608             C {
609                 c1: B {
610                     b1: "What is the answer to the ultimate question?".to_string(),
611                     b2: 42,
612                 },
613             },
614         ),
615         (
616             r#"<C>  <c1 b1="What is the answer to the ultimate question?" b2="42">
617         </c1> </C>"#,
618             C {
619                 c1: B {
620                     b1: "What is the answer to the ultimate question?".to_string(),
621                     b2: 42,
622                 },
623             },
624         ),
625     ]);
626 
627     #[derive(PartialEq, Debug, Serialize, Deserialize)]
628     struct D {
629         d1: Option<A>,
630     }
631     test_parse_ok(&[(
632         r#"<D><d1 a1="What is the answer to the ultimate question?">42</d1></D>"#,
633         D {
634             d1: Some(A {
635                 a1: "What is the answer to the ultimate question?".to_string(),
636                 a2: 42,
637             }),
638         },
639     )]);
640 }
641 
642 #[test]
643 #[ignore] // FIXME
test_parse_hierarchies()644 fn test_parse_hierarchies() {
645     init_logger();
646     #[derive(PartialEq, Debug, Serialize, Deserialize)]
647     struct A {
648         a1: String,
649         a2: (String, String),
650     }
651     #[derive(PartialEq, Debug, Serialize, Deserialize)]
652     struct B {
653         b1: A,
654         b2: (A, A),
655     }
656     #[derive(PartialEq, Debug, Serialize, Deserialize)]
657     struct C {
658         c1: B,
659         c2: Vec<B>,
660     }
661 
662     test_parse_ok(&[
663         (
664             "<C><c1>
665             <b1>
666                 <a1>No</a1>
667                 <a2>Maybe</a2>
668                 <a2>Yes</a2>
669             </b1>
670             <b2>
671                 <a1>Red</a1>
672                 <a2>Green</a2>
673                 <a2>Blue</a2>
674             </b2>
675             <b2>
676                 <a1>London</a1>
677                 <a2>Berlin</a2>
678                 <a2>Paris</a2>
679             </b2>
680         </c1></C>",
681             C {
682                 c1: B {
683                     b1: A {
684                         a1: "No".to_string(),
685                         a2: ("Maybe".to_string(), "Yes".to_string()),
686                     },
687                     b2: (
688                         A {
689                             a1: "Red".to_string(),
690                             a2: ("Green".to_string(), "Blue".to_string()),
691                         },
692                         A {
693                             a1: "London".to_string(),
694                             a2: ("Berlin".to_string(), "Paris".to_string()),
695                         },
696                     ),
697                 },
698                 c2: vec![],
699             },
700         ),
701         (
702             "<C><c1>
703             <b2>
704                 <a2>Green</a2>
705                 <a2>Blue</a2>
706                 <a1>Red</a1>
707             </b2>
708             <b2>
709                 <a2>Berlin</a2>
710                 <a2>Paris</a2>
711                 <a1>London</a1>
712             </b2>
713             <b1>
714                 <a2>Maybe</a2>
715                 <a2>Yes</a2>
716                 <a1>No</a1>
717             </b1>
718         </c1></C>",
719             C {
720                 c1: B {
721                     b1: A {
722                         a1: "No".to_string(),
723                         a2: ("Maybe".to_string(), "Yes".to_string()),
724                     },
725                     b2: (
726                         A {
727                             a1: "Red".to_string(),
728                             a2: ("Green".to_string(), "Blue".to_string()),
729                         },
730                         A {
731                             a1: "London".to_string(),
732                             a2: ("Berlin".to_string(), "Paris".to_string()),
733                         },
734                     ),
735                 },
736                 c2: vec![],
737             },
738         ),
739     ]);
740 }
741 
742 #[test]
unknown_field()743 fn unknown_field() {
744     #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)]
745     struct A {
746         other: Vec<Other>,
747     }
748 
749     #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)]
750     struct Other {
751         d: i32,
752     }
753     test_parse_ok(&[(
754         "<a>
755                <b>
756                  <c>5</c>
757                </b>
758                <other>
759                  <d>6</d>
760                </other>
761             </a>",
762         A {
763             other: vec![Other { d: 6 }],
764         },
765     )]);
766 }
767 
768 // #[test]
769 // fn eoz() {
770 //     use std::io::Read;
771 //     let mut file = std::fs::File::open("Report_test.2.xml").unwrap();
772 //     let mut s = String::new();
773 //     file.read_to_string(&mut s).unwrap();
774 
775 //     let _xml_value: Element = from_str(&s).unwrap();
776 // }
777 
778 #[test]
test_parse_unfinished()779 fn test_parse_unfinished() {
780     test_parse_err::<Simple>(&["<Simple>
781             <c>abc</c>
782             <a/>
783             <b>2</b>
784             <d/>"]);
785 }
786 
787 #[test]
test_things_qc_found()788 fn test_things_qc_found() {
789     test_parse_err::<u32>(&["<\u{0}:/"]);
790 }
791 
792 #[test]
futile()793 fn futile() {
794     init_logger();
795     #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
796     struct Object {
797         id: u8,
798         name: String,
799         x: u8,
800         y: u8,
801         width: u8,
802         height: u8,
803         ellipse: Option<()>,
804     }
805 
806     test_parse_ok(&[
807         (
808             r###"
809             <object id="11" name="testEllipse" x="102" y="38" width="21" height="14">
810               <ellipse/>
811             </object>
812             "###,
813             Object {
814                 id: 11,
815                 name: "testEllipse".to_owned(),
816                 x: 102,
817                 y: 38,
818                 width: 21,
819                 height: 14,
820                 ellipse: Some(()),
821             },
822         ),
823         (
824             r###"
825             <object id="11" name="testEllipse" x="102" y="38" width="21" height="14">
826             </object>
827             "###,
828             Object {
829                 id: 11,
830                 name: "testEllipse".to_owned(),
831                 x: 102,
832                 y: 38,
833                 width: 21,
834                 height: 14,
835                 ellipse: None,
836             },
837         ),
838     ]);
839 }
840 
841 #[test]
futile2()842 fn futile2() {
843     init_logger();
844     #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
845     struct Null;
846 
847     #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
848     struct Object {
849         field: Option<Null>,
850     }
851 
852     #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
853     struct Stuff {
854         stuff_field: Option<Object>,
855     }
856 
857     test_parse_ok(&[
858         (
859             r###"
860             <object>
861               <field/>
862             </object>
863             "###,
864             Object { field: Some(Null) },
865         ),
866         (
867             r###"
868             <object>
869             </object>
870             "###,
871             Object { field: None },
872         ),
873     ]);
874 
875     test_parse_ok(&[
876         (
877             r###"
878             <object>
879               <stuff_field/>
880             </object>
881             "###,
882             Stuff {
883                 stuff_field: Some(Object { field: None }),
884             },
885         ),
886         (
887             r###"
888             <object>
889               <stuff_field>
890                 <field/>
891               </stuff_field>
892             </object>
893             "###,
894             Stuff {
895                 stuff_field: Some(Object { field: Some(Null) }),
896             },
897         ),
898         (
899             r###"
900             <object>
901             </object>
902             "###,
903             Stuff { stuff_field: None },
904         ),
905         (
906             r###"
907             <object/>
908             "###,
909             Stuff { stuff_field: None },
910         ),
911     ]);
912 }
913 
914 #[test]
newtype_struct()915 fn newtype_struct() {
916     #[derive(PartialEq, Debug, Serialize, Deserialize)]
917     struct Wrapper(String);
918 
919     test_parse_ok(&[(
920         r###"<wrapper>Content</wrapper>"###,
921         Wrapper("Content".into()),
922     )]);
923 }
924