tests.rs

  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='&#34;Air&#34; 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'>&lt;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}