1 use serde::Deserialize;
2 use serde_derive::Deserialize;
3 use serde_xml_rs::{from_str, Deserializer};
4 use simple_logger::SimpleLogger;
5
init_logger()6 fn init_logger() {
7 let _ = SimpleLogger::new().init();
8 }
9
10 #[derive(Debug, Deserialize, PartialEq)]
11 struct Item {
12 name: String,
13 source: String,
14 }
15
16 #[test]
simple_struct_from_attributes()17 fn simple_struct_from_attributes() {
18 init_logger();
19
20 let s = r##"
21 <item name="hello" source="world.rs" />
22 "##;
23
24 let item: Item = from_str(s).unwrap();
25
26 assert_eq!(
27 item,
28 Item {
29 name: "hello".to_string(),
30 source: "world.rs".to_string(),
31 }
32 );
33 }
34
35 #[test]
multiple_roots_attributes()36 fn multiple_roots_attributes() {
37 init_logger();
38
39 let s = r##"
40 <item name="hello" source="world.rs" />
41 <item name="hello" source="world.rs" />
42 "##;
43
44 let item: Vec<Item> = from_str(s).unwrap();
45
46 assert_eq!(
47 item,
48 vec![
49 Item {
50 name: "hello".to_string(),
51 source: "world.rs".to_string(),
52 },
53 Item {
54 name: "hello".to_string(),
55 source: "world.rs".to_string(),
56 },
57 ]
58 );
59 }
60
61 #[test]
simple_struct_from_attribute_and_child()62 fn simple_struct_from_attribute_and_child() {
63 init_logger();
64
65 let s = r##"
66 <item name="hello">
67 <source>world.rs</source>
68 </item>
69 "##;
70
71 let item: Item = from_str(s).unwrap();
72
73 assert_eq!(
74 item,
75 Item {
76 name: "hello".to_string(),
77 source: "world.rs".to_string(),
78 }
79 );
80 }
81
82 #[derive(Debug, Deserialize, PartialEq)]
83 struct Project {
84 name: String,
85
86 #[serde(rename = "item", default)]
87 items: Vec<Item>,
88 }
89
90 #[test]
nested_collection()91 fn nested_collection() {
92 init_logger();
93
94 let s = r##"
95 <project name="my_project">
96 <item name="hello1" source="world1.rs" />
97 <item name="hello2" source="world2.rs" />
98 </project>
99 "##;
100
101 let project: Project = from_str(s).unwrap();
102
103 assert_eq!(
104 project,
105 Project {
106 name: "my_project".to_string(),
107 items: vec![
108 Item {
109 name: "hello1".to_string(),
110 source: "world1.rs".to_string(),
111 },
112 Item {
113 name: "hello2".to_string(),
114 source: "world2.rs".to_string(),
115 },
116 ],
117 }
118 );
119 }
120
121 #[derive(Debug, Deserialize, PartialEq)]
122 enum MyEnum {
123 A(String),
124 B { name: String, flag: bool },
125 C,
126 }
127
128 #[derive(Debug, Deserialize, PartialEq)]
129 struct MyEnums {
130 #[serde(rename = "$value")]
131 items: Vec<MyEnum>,
132 }
133
134 #[test]
collection_of_enums()135 fn collection_of_enums() {
136 init_logger();
137
138 let s = r##"
139 <enums>
140 <A>test</A>
141 <B name="hello" flag="true" />
142 <C />
143 </enums>
144 "##;
145
146 let project: MyEnums = from_str(s).unwrap();
147
148 assert_eq!(
149 project,
150 MyEnums {
151 items: vec![
152 MyEnum::A("test".to_string()),
153 MyEnum::B {
154 name: "hello".to_string(),
155 flag: true,
156 },
157 MyEnum::C,
158 ],
159 }
160 );
161 }
162
163 #[test]
out_of_order_collection()164 fn out_of_order_collection() {
165 #[derive(Debug, Deserialize, PartialEq)]
166 struct Collection {
167 a: Vec<A>,
168 b: Vec<B>,
169 c: C,
170 }
171
172 #[derive(Debug, Deserialize, PartialEq)]
173 struct A {
174 name: String,
175 }
176
177 #[derive(Debug, Deserialize, PartialEq)]
178 struct B {
179 name: String,
180 }
181
182 #[derive(Debug, Deserialize, PartialEq)]
183 struct C {
184 name: String,
185 }
186
187 init_logger();
188
189 let in_xml = r#"
190 <collection>
191 <a name="a1" />
192 <a name="a2" />
193 <b name="b1" />
194 <a name="a3" />
195 <c name="c" />
196 <b name="b2" />
197 <a name="a4" />
198 </collection>
199 "#;
200
201 let should_be = Collection {
202 a: vec![
203 A { name: "a1".into() },
204 A { name: "a2".into() },
205 A { name: "a3".into() },
206 A { name: "a4".into() },
207 ],
208 b: vec![B { name: "b1".into() }, B { name: "b2".into() }],
209 c: C { name: "c".into() },
210 };
211
212 let mut de = Deserializer::new_from_reader(in_xml.as_bytes()).non_contiguous_seq_elements(true);
213 let actual = Collection::deserialize(&mut de).unwrap();
214
215 assert_eq!(should_be, actual);
216 }
217
218 #[test]
nested_out_of_order_collection()219 fn nested_out_of_order_collection() {
220 #[derive(Debug, Deserialize, PartialEq)]
221 struct OuterCollection {
222 a: A,
223 inner: Vec<InnerCollection>,
224 }
225
226 #[derive(Debug, Deserialize, PartialEq)]
227 struct InnerCollection {
228 b: Vec<B>,
229 c: Vec<C>,
230 }
231
232 #[derive(Debug, Deserialize, PartialEq)]
233 struct A {
234 name: String,
235 }
236
237 #[derive(Debug, Deserialize, PartialEq)]
238 struct B {
239 name: String,
240 }
241
242 #[derive(Debug, Deserialize, PartialEq)]
243 struct C {
244 name: String,
245 }
246
247 init_logger();
248
249 let in_xml = r#"
250 <collection>
251 <inner>
252 <b name="b1" />
253 <c name="c1" />
254 <b name="b2" />
255 <c name="c2" />
256 </inner>
257 <a name="a" />
258 <inner>
259 <c name="c3" />
260 <b name="b3" />
261 <c name="c4" />
262 <b name="b4" />
263 </inner>
264 </collection>
265 "#;
266
267 let should_be = OuterCollection {
268 a: A { name: "a".into() },
269 inner: vec![
270 InnerCollection {
271 b: vec![B { name: "b1".into() }, B { name: "b2".into() }],
272 c: vec![C { name: "c1".into() }, C { name: "c2".into() }],
273 },
274 InnerCollection {
275 b: vec![B { name: "b3".into() }, B { name: "b4".into() }],
276 c: vec![C { name: "c3".into() }, C { name: "c4".into() }],
277 },
278 ],
279 };
280
281 let mut de = Deserializer::new_from_reader(in_xml.as_bytes()).non_contiguous_seq_elements(true);
282 let actual = OuterCollection::deserialize(&mut de).unwrap();
283
284 assert_eq!(should_be, actual);
285 }
286
287 #[test]
out_of_order_tuple()288 fn out_of_order_tuple() {
289 #[derive(Debug, Deserialize, PartialEq)]
290 struct Collection {
291 val: (A, B, C),
292 other: A,
293 }
294
295 #[derive(Debug, Deserialize, PartialEq)]
296 struct A {
297 name_a: String,
298 }
299
300 #[derive(Debug, Deserialize, PartialEq)]
301 struct B {
302 name_b: String,
303 }
304
305 #[derive(Debug, Deserialize, PartialEq)]
306 struct C {
307 name_c: String,
308 }
309
310 init_logger();
311
312 let in_xml = r#"
313 <collection>
314 <val name_a="a1" />
315 <val name_b="b" />
316 <other name_a="a2" />
317 <val name_c="c" />
318 </collection>
319 "#;
320
321 let should_be = Collection {
322 val: (
323 A {
324 name_a: "a1".into(),
325 },
326 B { name_b: "b".into() },
327 C { name_c: "c".into() },
328 ),
329 other: A {
330 name_a: "a2".into(),
331 },
332 };
333
334 let mut de = Deserializer::new_from_reader(in_xml.as_bytes()).non_contiguous_seq_elements(true);
335 let actual = Collection::deserialize(&mut de).unwrap();
336
337 assert_eq!(should_be, actual);
338 }
339
340 /// Ensure that identically-named elements at different depths are not deserialized as if they were
341 /// at the same depth.
342 #[test]
nested_collection_repeated_elements()343 fn nested_collection_repeated_elements() {
344 #[derive(Debug, Deserialize, PartialEq)]
345 struct OuterCollection {
346 a: Vec<A>,
347 inner: Inner,
348 }
349
350 #[derive(Debug, Deserialize, PartialEq)]
351 struct Inner {
352 a: A,
353 }
354
355 #[derive(Debug, Deserialize, PartialEq)]
356 struct A {
357 name: String,
358 }
359
360 init_logger();
361
362 let in_xml = r#"
363 <collection>
364 <a name="a1" />
365 <inner>
366 <a name="a2" />
367 </inner>
368 <a name="a3" />
369 </collection>
370 "#;
371
372 let should_be = OuterCollection {
373 a: vec![A { name: "a1".into() }, A { name: "a3".into() }],
374 inner: Inner {
375 a: A { name: "a2".into() },
376 },
377 };
378
379 let mut de = Deserializer::new_from_reader(in_xml.as_bytes()).non_contiguous_seq_elements(true);
380 let actual = OuterCollection::deserialize(&mut de).unwrap();
381
382 assert_eq!(should_be, actual);
383 }
384