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