1// Copyright (c) 2020 lumi <lumi@pew.im>
2// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
3// Copyright (c) 2020 Bastien Orivel <eijebong+minidom@bananium.fr>
4// Copyright (c) 2020 Astro <astro@spaceboyz.net>
5// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
6// Copyright (c) 2020 Yue Liu <amznyue@amazon.com>
7// Copyright (c) 2020 Matt Bilker <me@mbilker.us>
8//
9// This Source Code Form is subject to the terms of the Mozilla Public
10// License, v. 2.0. If a copy of the MPL was not distributed with this
11// file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
13use crate::element::Element;
14use crate::error::Error;
15
16const TEST_STRING: &'static [u8] = br#"<root xmlns='root_ns' a="b" xml:lang="en">meow<child c="d"/><child xmlns='child_ns' d="e" xml:lang="fr"/>nya</root>"#;
17
18fn build_test_tree() -> Element {
19 let mut root = Element::builder("root", "root_ns")
20 .attr("xml:lang", "en")
21 .attr("a", "b")
22 .build();
23 root.append_text_node("meow");
24 let child = Element::builder("child", "root_ns").attr("c", "d").build();
25 root.append_child(child);
26 let other_child = Element::builder("child", "child_ns")
27 .attr("d", "e")
28 .attr("xml:lang", "fr")
29 .build();
30 root.append_child(other_child);
31 root.append_text_node("nya");
32 root
33}
34
35#[test]
36fn reader_works() {
37 assert_eq!(
38 Element::from_reader(TEST_STRING).unwrap(),
39 build_test_tree()
40 );
41}
42
43#[test]
44fn reader_deduplicate_prefixes() {
45 // The reader shouldn't complain that "child" doesn't have a namespace. It should reuse the
46 // parent ns with the same prefix.
47 let _: Element = r#"<root xmlns="ns1"><child/></root>"#.parse().unwrap();
48 let _: Element = r#"<p1:root xmlns:p1="ns1"><p1:child/></p1:root>"#.parse().unwrap();
49 let _: Element = r#"<root xmlns="ns1"><child xmlns:p1="ns2"><p1:grandchild/></child></root>"#
50 .parse()
51 .unwrap();
52
53 match r#"<p1:root xmlns:p1="ns1"><child/></p1:root>"#.parse::<Element>() {
54 Err(Error::MissingNamespace) => (),
55 Err(err) => panic!("No or wrong error: {:?}", err),
56 Ok(elem) => panic!(
57 "Got Element: {}; was expecting Error::MissingNamespace",
58 String::from(&elem)
59 ),
60 }
61}
62
63#[test]
64fn reader_no_deduplicate_sibling_prefixes() {
65 // The reader shouldn't reuse the sibling's prefixes
66 match r#"<root xmlns="ns1"><p1:child1 xmlns:p1="ns2"/><p1:child2/></root>"#.parse::<Element>() {
67 Err(Error::MissingNamespace) => (),
68 Err(err) => panic!("No or wrong error: {:?}", err),
69 Ok(elem) => panic!(
70 "Got Element:\n{:?}\n{}\n; was expecting Error::MissingNamespace",
71 elem,
72 String::from(&elem)
73 ),
74 }
75}
76
77#[test]
78fn test_real_data() {
79 let correction = Element::builder("replace", "urn:xmpp:message-correct:0").build();
80 let body = Element::builder("body", "jabber:client").build();
81 let message = Element::builder("message", "jabber:client")
82 .append(body)
83 .append(correction)
84 .build();
85 let stream = Element::builder("stream", "http://etherx.jabber.org/streams")
86 .prefix(
87 Some(String::from("stream")),
88 "http://etherx.jabber.org/streams",
89 )
90 .unwrap()
91 .prefix(None, "jabber:client")
92 .unwrap()
93 .append(message)
94 .build();
95 println!("{}", String::from(&stream));
96
97 let jid = Element::builder("jid", "urn:xmpp:presence:0").build();
98 let nick = Element::builder("nick", "urn:xmpp:presence:0").build();
99 let mix = Element::builder("mix", "urn:xmpp:presence:0")
100 .append(jid)
101 .append(nick)
102 .build();
103 let show = Element::builder("show", "jabber:client").build();
104 let status = Element::builder("status", "jabber:client").build();
105 let presence = Element::builder("presence", "jabber:client")
106 .append(show)
107 .append(status)
108 .append(mix)
109 .build();
110 let item = Element::builder("item", "http://jabber.org/protocol/pubsub")
111 .append(presence)
112 .build();
113 let items = Element::builder("items", "http://jabber.org/protocol/pubsub")
114 .append(item)
115 .build();
116 let pubsub = Element::builder("pubsub", "http://jabber.org/protocol/pubsub")
117 .append(items)
118 .build();
119 let iq = Element::builder("iq", "jabber:client")
120 .append(pubsub)
121 .build();
122 let stream = Element::builder("stream", "http://etherx.jabber.org/streams")
123 .prefix(
124 Some(String::from("stream")),
125 "http://etherx.jabber.org/streams",
126 )
127 .unwrap()
128 .prefix(None, "jabber:client")
129 .unwrap()
130 .append(iq)
131 .build();
132
133 println!("{}", String::from(&stream));
134}
135
136#[test]
137fn writer_works() {
138 let root = build_test_tree();
139 let mut writer = Vec::new();
140 {
141 root.write_to(&mut writer).unwrap();
142 }
143 assert_eq!(writer, TEST_STRING);
144}
145
146#[test]
147fn writer_with_decl_works() {
148 let root = build_test_tree();
149 let mut writer = Vec::new();
150 {
151 root.write_to_decl(&mut writer).unwrap();
152 }
153 let result = format!(
154 "<?xml version='1.0' encoding='utf-8'?>\n{}",
155 String::from_utf8(TEST_STRING.to_owned()).unwrap()
156 );
157 assert_eq!(String::from_utf8(writer).unwrap(), result);
158}
159
160#[test]
161fn writer_with_prefix() {
162 let root = Element::builder("root", "ns1")
163 .prefix(Some(String::from("p1")), "ns1")
164 .unwrap()
165 .prefix(None, "ns2")
166 .unwrap()
167 .build();
168 assert_eq!(
169 String::from(&root),
170 r#"<p1:root xmlns='ns2' xmlns:p1='ns1'/>"#,
171 );
172}
173
174#[test]
175fn writer_no_prefix_namespace() {
176 let root = Element::builder("root", "ns1").build();
177 // TODO: Note that this isn't exactly equal to a None prefix. it's just that the None prefix is
178 // the most obvious when it's not already used. Maybe fix tests so that it only checks that the
179 // prefix used equals the one declared for the namespace.
180 assert_eq!(String::from(&root), r#"<root xmlns='ns1'/>"#);
181}
182
183#[test]
184fn writer_no_prefix_namespace_child() {
185 let child = Element::builder("child", "ns1").build();
186 let root = Element::builder("root", "ns1").append(child).build();
187 // TODO: Same remark as `writer_no_prefix_namespace`.
188 assert_eq!(String::from(&root), r#"<root xmlns='ns1'><child/></root>"#);
189
190 let child = Element::builder("child", "ns2")
191 .prefix(None, "ns3")
192 .unwrap()
193 .build();
194 let root = Element::builder("root", "ns1").append(child).build();
195 // TODO: Same remark as `writer_no_prefix_namespace`.
196 assert_eq!(
197 String::from(&root),
198 r#"<root xmlns='ns1'><tns0:child xmlns='ns3' xmlns:tns0='ns2'/></root>"#
199 );
200}
201
202#[test]
203fn writer_prefix_namespace_child() {
204 let child = Element::builder("child", "ns1").build();
205 let root = Element::builder("root", "ns1")
206 .prefix(Some(String::from("p1")), "ns1")
207 .unwrap()
208 .append(child)
209 .build();
210 assert_eq!(
211 String::from(&root),
212 r#"<p1:root xmlns:p1='ns1'><p1:child/></p1:root>"#
213 );
214}
215
216#[test]
217fn writer_with_prefix_deduplicate() {
218 let child = Element::builder("child", "ns1")
219 // .prefix(Some(String::from("p1")), "ns1")
220 .build();
221 let root = Element::builder("root", "ns1")
222 .prefix(Some(String::from("p1")), "ns1")
223 .unwrap()
224 .prefix(None, "ns2")
225 .unwrap()
226 .append(child)
227 .build();
228 assert_eq!(
229 String::from(&root),
230 r#"<p1:root xmlns='ns2' xmlns:p1='ns1'><p1:child/></p1:root>"#,
231 );
232
233 // Ensure descendants don't just reuse ancestors' prefixes that have been shadowed in between
234 let grandchild = Element::builder("grandchild", "ns1").build();
235 let child = Element::builder("child", "ns2").append(grandchild).build();
236 let root = Element::builder("root", "ns1").append(child).build();
237 assert_eq!(
238 String::from(&root),
239 r#"<root xmlns='ns1'><child xmlns='ns2'><grandchild xmlns='ns1'/></child></root>"#,
240 );
241}
242
243#[test]
244fn writer_escapes_attributes() {
245 let root = Element::builder("root", "ns1")
246 .attr("a", "\"Air\" quotes")
247 .build();
248 let mut writer = Vec::new();
249 {
250 root.write_to(&mut writer).unwrap();
251 }
252 assert_eq!(
253 String::from_utf8(writer).unwrap(),
254 r#"<root xmlns='ns1' a=""Air" quotes"/>"#
255 );
256}
257
258#[test]
259fn writer_escapes_text() {
260 let root = Element::builder("root", "ns1").append("<3").build();
261 let mut writer = Vec::new();
262 {
263 root.write_to(&mut writer).unwrap();
264 }
265 assert_eq!(
266 String::from_utf8(writer).unwrap(),
267 r#"<root xmlns='ns1'><3</root>"#
268 );
269}
270
271#[test]
272fn builder_works() {
273 let elem = Element::builder("a", "b")
274 .attr("c", "d")
275 .append(Element::builder("child", "b"))
276 .append("e")
277 .build();
278 assert_eq!(elem.name(), "a");
279 assert_eq!(elem.ns(), "b".to_owned());
280 assert_eq!(elem.attr("c"), Some("d"));
281 assert_eq!(elem.attr("x"), None);
282 assert_eq!(elem.text(), "e");
283 assert!(elem.has_child("child", "b"));
284 assert!(elem.is("a", "b"));
285}
286
287#[test]
288fn children_iter_works() {
289 let root = build_test_tree();
290 let mut iter = root.children();
291 assert!(iter.next().unwrap().is("child", "root_ns"));
292 assert!(iter.next().unwrap().is("child", "child_ns"));
293 assert_eq!(iter.next(), None);
294}
295
296#[test]
297fn get_child_works() {
298 let root = build_test_tree();
299 assert_eq!(root.get_child("child", "inexistent_ns"), None);
300 assert_eq!(root.get_child("not_a_child", "root_ns"), None);
301 assert!(root
302 .get_child("child", "root_ns")
303 .unwrap()
304 .is("child", "root_ns"));
305 assert!(root
306 .get_child("child", "child_ns")
307 .unwrap()
308 .is("child", "child_ns"));
309 assert_eq!(
310 root.get_child("child", "root_ns").unwrap().attr("c"),
311 Some("d")
312 );
313 assert_eq!(
314 root.get_child("child", "child_ns").unwrap().attr("d"),
315 Some("e")
316 );
317}
318
319#[test]
320fn namespace_propagation_works() {
321 let mut root = Element::builder("root", "root_ns").build();
322 let mut child = Element::bare("child", "root_ns");
323 let grandchild = Element::bare("grandchild", "root_ns");
324 child.append_child(grandchild);
325 root.append_child(child);
326
327 assert_eq!(root.get_child("child", "root_ns").unwrap().ns(), root.ns());
328 assert_eq!(
329 root.get_child("child", "root_ns")
330 .unwrap()
331 .get_child("grandchild", "root_ns")
332 .unwrap()
333 .ns(),
334 root.ns()
335 );
336}
337
338#[test]
339fn two_elements_with_same_arguments_different_order_are_equal() {
340 let elem1: Element = "<a b='a' c='' xmlns='ns1'/>".parse().unwrap();
341 let elem2: Element = "<a c='' b='a' xmlns='ns1'/>".parse().unwrap();
342 assert_eq!(elem1, elem2);
343
344 let elem1: Element = "<a b='a' c='' xmlns='ns1'/>".parse().unwrap();
345 let elem2: Element = "<a c='d' b='a' xmlns='ns1'/>".parse().unwrap();
346 assert_ne!(elem1, elem2);
347}
348
349#[test]
350fn namespace_attributes_works() {
351 let root = Element::from_reader(TEST_STRING).unwrap();
352 assert_eq!("en", root.attr("xml:lang").unwrap());
353 assert_eq!(
354 "fr",
355 root.get_child("child", "child_ns")
356 .unwrap()
357 .attr("xml:lang")
358 .unwrap()
359 );
360}
361
362#[test]
363fn wrongly_closed_elements_error() {
364 let elem1 = "<a xmlns='ns1'></b>".parse::<Element>();
365 assert!(elem1.is_err());
366 let elem1 = "<a xmlns='ns1'></c></a>".parse::<Element>();
367 assert!(elem1.is_err());
368 let elem1 = "<a xmlns='ns1'><c xmlns='ns1'><d xmlns='ns1'/></c></a>".parse::<Element>();
369 assert!(elem1.is_ok());
370}
371
372#[test]
373fn namespace_simple() {
374 let elem: Element = "<message xmlns='jabber:client'/>".parse().unwrap();
375 assert_eq!(elem.name(), "message");
376 assert_eq!(elem.ns(), "jabber:client".to_owned());
377}
378
379#[test]
380fn namespace_prefixed() {
381 let elem: Element = "<stream:features xmlns:stream='http://etherx.jabber.org/streams'/>"
382 .parse()
383 .unwrap();
384 assert_eq!(elem.name(), "features");
385 assert_eq!(elem.ns(), "http://etherx.jabber.org/streams".to_owned(),);
386}
387
388#[test]
389fn namespace_inherited_simple() {
390 let elem: Element = "<stream xmlns='jabber:client'><message xmlns='jabber:client' /></stream>"
391 .parse()
392 .unwrap();
393 assert_eq!(elem.name(), "stream");
394 assert_eq!(elem.ns(), "jabber:client".to_owned());
395 let child = elem.children().next().unwrap();
396 assert_eq!(child.name(), "message");
397 assert_eq!(child.ns(), "jabber:client".to_owned());
398}
399
400#[test]
401fn namespace_inherited_prefixed1() {
402 let elem: Element = "<stream:features xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client'><message xmlns='jabber:client' /></stream:features>"
403 .parse().unwrap();
404 assert_eq!(elem.name(), "features");
405 assert_eq!(elem.ns(), "http://etherx.jabber.org/streams".to_owned(),);
406 let child = elem.children().next().unwrap();
407 assert_eq!(child.name(), "message");
408 assert_eq!(child.ns(), "jabber:client".to_owned());
409}
410
411#[test]
412fn namespace_inherited_prefixed2() {
413 let elem: Element = "<stream xmlns='http://etherx.jabber.org/streams' xmlns:jabber='jabber:client'><jabber:message xmlns:jabber='jabber:client' /></stream>"
414 .parse().unwrap();
415 assert_eq!(elem.name(), "stream");
416 assert_eq!(elem.ns(), "http://etherx.jabber.org/streams".to_owned(),);
417 let child = elem.children().next().unwrap();
418 assert_eq!(child.name(), "message");
419 assert_eq!(child.ns(), "jabber:client".to_owned());
420}
421
422#[test]
423fn fail_comments() {
424 let elem: Result<Element, Error> = "<foo xmlns='ns1'><!-- bar --></foo>".parse();
425 match elem {
426 Err(_) => (),
427 _ => panic!(),
428 };
429}
430
431#[test]
432fn xml_error() {
433 match "<a xmlns='ns1'></b>".parse::<Element>() {
434 Err(crate::error::Error::XmlError(rxml::Error::Xml(
435 rxml::error::XmlError::ElementMismatch,
436 ))) => (),
437 err => panic!("No or wrong error: {:?}", err),
438 }
439
440 match "<a xmlns='ns1'></".parse::<Element>() {
441 Err(crate::error::Error::XmlError(rxml::Error::Xml(
442 rxml::error::XmlError::InvalidEof(_),
443 ))) => (),
444 err => panic!("No or wrong error: {:?}", err),
445 }
446}
447
448#[test]
449fn missing_namespace_error() {
450 match "<a/>".parse::<Element>() {
451 Err(crate::error::Error::MissingNamespace) => (),
452 err => panic!("No or wrong error: {:?}", err),
453 }
454}
455
456#[test]
457fn misserialisation() {
458 let xml =
459 "<jitsi_participant_codecType xmlns='jabber:client'>vp9</jitsi_participant_codecType>";
460 //let elem = xml.parse::<Element>().unwrap();
461 let elem = Element::builder("jitsi_participant_codecType", "jabber:client")
462 .append("vp9")
463 .build();
464 let data = String::from(&elem);
465 assert_eq!(xml, data);
466}