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