2017-05-28 16:30:43 +01:00
|
|
|
|
// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
|
|
|
|
|
//
|
|
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
2024-08-03 13:04:56 +02:00
|
|
|
|
use xso::{AsXml, FromXml};
|
|
|
|
|
|
|
2019-06-10 23:17:09 +02:00
|
|
|
|
use jid::BareJid;
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2024-08-03 13:04:56 +02:00
|
|
|
|
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
|
|
|
|
|
|
use crate::ns;
|
|
|
|
|
|
|
2018-07-31 23:47:55 +02:00
|
|
|
|
generate_elem_id!(
|
|
|
|
|
|
/// Represents a group a contact is part of.
|
2018-12-18 15:32:05 +01:00
|
|
|
|
Group,
|
|
|
|
|
|
"group",
|
|
|
|
|
|
ROSTER
|
2018-07-31 23:47:55 +02:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
generate_attribute!(
|
|
|
|
|
|
/// The state of your mutual subscription with a contact.
|
|
|
|
|
|
Subscription, "subscription", {
|
|
|
|
|
|
/// The user doesn’t have any subscription to this contact’s presence,
|
|
|
|
|
|
/// and neither does this contact.
|
|
|
|
|
|
None => "none",
|
|
|
|
|
|
|
|
|
|
|
|
/// Only this contact has a subscription with you, not the opposite.
|
|
|
|
|
|
From => "from",
|
|
|
|
|
|
|
|
|
|
|
|
/// Only you have a subscription with this contact, not the opposite.
|
|
|
|
|
|
To => "to",
|
|
|
|
|
|
|
|
|
|
|
|
/// Both you and your contact are subscribed to each other’s presence.
|
|
|
|
|
|
Both => "both",
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2018-07-31 23:47:55 +02:00
|
|
|
|
/// In a roster set, this asks the server to remove this contact item
|
|
|
|
|
|
/// from your roster.
|
|
|
|
|
|
Remove => "remove",
|
|
|
|
|
|
}, Default = None
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2019-01-07 16:49:33 +03:00
|
|
|
|
generate_attribute!(
|
|
|
|
|
|
/// The sub-state of subscription with a contact.
|
2019-01-12 22:51:02 +01:00
|
|
|
|
Ask, "ask", (
|
|
|
|
|
|
/// Pending sub-state of the 'none' subscription state.
|
|
|
|
|
|
Subscribe => "subscribe"
|
|
|
|
|
|
)
|
2019-01-07 16:49:33 +03:00
|
|
|
|
);
|
|
|
|
|
|
|
2024-08-08 18:30:14 +02:00
|
|
|
|
/// Contact from the user’s contact list.
|
|
|
|
|
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
|
|
|
|
#[xml(namespace = ns::ROSTER, name = "item")]
|
|
|
|
|
|
pub struct Item {
|
|
|
|
|
|
/// JID of this contact.
|
|
|
|
|
|
#[xml(attribute)]
|
|
|
|
|
|
pub jid: BareJid,
|
|
|
|
|
|
|
|
|
|
|
|
/// Name of this contact.
|
|
|
|
|
|
#[xml(attribute(default))]
|
|
|
|
|
|
pub name: Option<String>,
|
|
|
|
|
|
|
|
|
|
|
|
/// Subscription status of this contact.
|
|
|
|
|
|
#[xml(attribute(default))]
|
|
|
|
|
|
pub subscription: Subscription,
|
|
|
|
|
|
|
|
|
|
|
|
/// Indicates “Pending Out” sub-states for this contact.
|
|
|
|
|
|
#[xml(attribute(default))]
|
|
|
|
|
|
pub ask: Ask,
|
|
|
|
|
|
|
|
|
|
|
|
/// Groups this contact is part of.
|
|
|
|
|
|
#[xml(child(n = ..))]
|
|
|
|
|
|
pub groups: Vec<Group>,
|
2026-06-10 21:24:24 +00:00
|
|
|
|
|
|
|
|
|
|
/// Subscription pre-approval
|
|
|
|
|
|
#[xml(attribute(default))]
|
|
|
|
|
|
pub approved: Option<bool>,
|
2024-08-08 18:30:14 +02:00
|
|
|
|
}
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2024-08-03 13:04:56 +02:00
|
|
|
|
/// The contact list of the user.
|
|
|
|
|
|
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
|
|
|
|
|
|
#[xml(namespace = ns::ROSTER, name = "query")]
|
|
|
|
|
|
pub struct Roster {
|
|
|
|
|
|
/// Version of the contact list.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// This is an opaque string that should only be sent back to the server on
|
|
|
|
|
|
/// a new connection, if this client is storing the contact list between
|
|
|
|
|
|
/// connections.
|
|
|
|
|
|
#[xml(attribute(default))]
|
|
|
|
|
|
pub ver: Option<String>,
|
|
|
|
|
|
|
|
|
|
|
|
/// List of the contacts of the user.
|
|
|
|
|
|
#[xml(child(n = ..))]
|
|
|
|
|
|
pub items: Vec<Item>,
|
|
|
|
|
|
}
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2018-05-16 15:08:17 +02:00
|
|
|
|
impl IqGetPayload for Roster {}
|
|
|
|
|
|
impl IqSetPayload for Roster {}
|
|
|
|
|
|
impl IqResultPayload for Roster {}
|
|
|
|
|
|
|
2017-05-28 16:30:43 +01:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
use super::*;
|
2025-01-25 20:35:47 +01:00
|
|
|
|
use core::str::FromStr;
|
2024-07-24 20:28:22 +02:00
|
|
|
|
use minidom::Element;
|
2024-06-21 16:27:43 +02:00
|
|
|
|
use xso::error::{Error, FromElementError};
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2018-10-28 13:10:48 +01:00
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_size() {
|
|
|
|
|
|
assert_size!(Group, 12);
|
|
|
|
|
|
assert_size!(Subscription, 1);
|
2019-01-13 12:06:37 +01:00
|
|
|
|
assert_size!(Ask, 1);
|
2023-06-20 14:14:15 +02:00
|
|
|
|
assert_size!(Item, 44);
|
2018-10-28 13:10:48 +01:00
|
|
|
|
assert_size!(Roster, 24);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(target_pointer_width = "64")]
|
2018-10-26 14:26:16 +02:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_size() {
|
|
|
|
|
|
assert_size!(Group, 24);
|
|
|
|
|
|
assert_size!(Subscription, 1);
|
2019-01-13 12:06:37 +01:00
|
|
|
|
assert_size!(Ask, 1);
|
2023-06-20 14:08:58 +02:00
|
|
|
|
assert_size!(Item, 88);
|
2018-10-26 14:26:16 +02:00
|
|
|
|
assert_size!(Roster, 48);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-28 16:30:43 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_get() {
|
|
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster'/>".parse().unwrap();
|
|
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert!(roster.ver.is_none());
|
|
|
|
|
|
assert!(roster.items.is_empty());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_result() {
|
|
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster' ver='ver7'><item jid='nurse@example.com'/><item jid='romeo@example.net'/></query>".parse().unwrap();
|
|
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert_eq!(roster.ver, Some(String::from("ver7")));
|
|
|
|
|
|
assert_eq!(roster.items.len(), 2);
|
|
|
|
|
|
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster' ver='ver9'/>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert_eq!(roster.ver, Some(String::from("ver9")));
|
|
|
|
|
|
assert!(roster.items.is_empty());
|
|
|
|
|
|
|
2022-03-22 23:29:25 +01:00
|
|
|
|
let elem: Element = r#"<query xmlns='jabber:iq:roster' ver='ver11'>
|
2017-05-28 16:30:43 +01:00
|
|
|
|
<item jid='romeo@example.net'
|
|
|
|
|
|
name='Romeo'
|
|
|
|
|
|
subscription='both'>
|
|
|
|
|
|
<group>Friends</group>
|
|
|
|
|
|
</item>
|
|
|
|
|
|
<item jid='mercutio@example.com'
|
|
|
|
|
|
name='Mercutio'
|
|
|
|
|
|
subscription='from'/>
|
|
|
|
|
|
<item jid='benvolio@example.net'
|
|
|
|
|
|
name='Benvolio'
|
|
|
|
|
|
subscription='both'/>
|
2019-01-07 16:49:33 +03:00
|
|
|
|
<item jid='contact@example.org'
|
|
|
|
|
|
subscription='none'
|
|
|
|
|
|
ask='subscribe'
|
2026-06-10 21:24:24 +00:00
|
|
|
|
approved='true'
|
2019-01-07 16:49:33 +03:00
|
|
|
|
name='MyContact'>
|
|
|
|
|
|
<group>MyBuddies</group>
|
|
|
|
|
|
</item>
|
2017-05-28 16:30:43 +01:00
|
|
|
|
</query>
|
2018-12-18 15:32:05 +01:00
|
|
|
|
"#
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert_eq!(roster.ver, Some(String::from("ver11")));
|
2019-01-07 16:49:33 +03:00
|
|
|
|
assert_eq!(roster.items.len(), 4);
|
2023-06-20 14:07:50 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].jid,
|
|
|
|
|
|
BareJid::new("romeo@example.net").unwrap()
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
assert_eq!(roster.items[0].name, Some(String::from("Romeo")));
|
2017-10-10 17:40:29 +01:00
|
|
|
|
assert_eq!(roster.items[0].subscription, Subscription::Both);
|
2019-01-12 22:51:02 +01:00
|
|
|
|
assert_eq!(roster.items[0].ask, Ask::None);
|
2026-06-10 21:24:24 +00:00
|
|
|
|
assert_eq!(roster.items[0].approved, None);
|
2018-12-18 15:32:05 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].groups,
|
|
|
|
|
|
vec!(Group::from_str("Friends").unwrap())
|
|
|
|
|
|
);
|
2019-01-07 16:49:33 +03:00
|
|
|
|
|
2023-06-20 14:07:50 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[3].jid,
|
|
|
|
|
|
BareJid::new("contact@example.org").unwrap()
|
|
|
|
|
|
);
|
2019-01-07 16:49:33 +03:00
|
|
|
|
assert_eq!(roster.items[3].name, Some(String::from("MyContact")));
|
|
|
|
|
|
assert_eq!(roster.items[3].subscription, Subscription::None);
|
2019-01-12 22:51:02 +01:00
|
|
|
|
assert_eq!(roster.items[3].ask, Ask::Subscribe);
|
2026-06-10 21:24:24 +00:00
|
|
|
|
assert_eq!(roster.items[3].approved, Some(true));
|
2019-01-07 16:49:33 +03:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[3].groups,
|
|
|
|
|
|
vec!(Group::from_str("MyBuddies").unwrap())
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-25 23:27:38 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_multiple_groups() {
|
2019-12-07 20:37:33 +01:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster'><item jid='test@example.org'><group>A</group><group>B</group></item></query>"
|
2018-12-18 15:32:05 +01:00
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-06-25 23:27:38 +01:00
|
|
|
|
let elem1 = elem.clone();
|
|
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert!(roster.ver.is_none());
|
|
|
|
|
|
assert_eq!(roster.items.len(), 1);
|
2023-06-20 14:07:50 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].jid,
|
|
|
|
|
|
BareJid::new("test@example.org").unwrap()
|
|
|
|
|
|
);
|
2017-06-25 23:27:38 +01:00
|
|
|
|
assert_eq!(roster.items[0].name, None);
|
|
|
|
|
|
assert_eq!(roster.items[0].groups.len(), 2);
|
2017-07-29 05:36:59 +01:00
|
|
|
|
assert_eq!(roster.items[0].groups[0], Group::from_str("A").unwrap());
|
|
|
|
|
|
assert_eq!(roster.items[0].groups[1], Group::from_str("B").unwrap());
|
2017-06-25 23:27:38 +01:00
|
|
|
|
let elem2 = roster.into();
|
2019-11-29 14:33:17 +01:00
|
|
|
|
assert_eq!(elem1, elem2);
|
2017-06-25 23:27:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-28 16:30:43 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_set() {
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element =
|
|
|
|
|
|
"<query xmlns='jabber:iq:roster'><item jid='nurse@example.com'/></query>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert!(roster.ver.is_none());
|
|
|
|
|
|
assert_eq!(roster.items.len(), 1);
|
|
|
|
|
|
|
2022-03-22 23:29:25 +01:00
|
|
|
|
let elem: Element = r#"<query xmlns='jabber:iq:roster'>
|
2017-05-28 16:30:43 +01:00
|
|
|
|
<item jid='nurse@example.com'
|
|
|
|
|
|
name='Nurse'>
|
|
|
|
|
|
<group>Servants</group>
|
|
|
|
|
|
</item>
|
2022-03-22 23:29:25 +01:00
|
|
|
|
</query>"#
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert!(roster.ver.is_none());
|
|
|
|
|
|
assert_eq!(roster.items.len(), 1);
|
2023-06-20 14:07:50 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].jid,
|
|
|
|
|
|
BareJid::new("nurse@example.com").unwrap()
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
assert_eq!(roster.items[0].name, Some(String::from("Nurse")));
|
|
|
|
|
|
assert_eq!(roster.items[0].groups.len(), 1);
|
2018-12-18 15:32:05 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].groups[0],
|
|
|
|
|
|
Group::from_str("Servants").unwrap()
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2022-03-22 23:29:25 +01:00
|
|
|
|
let elem: Element = r#"<query xmlns='jabber:iq:roster'>
|
2017-05-28 16:30:43 +01:00
|
|
|
|
<item jid='nurse@example.com'
|
|
|
|
|
|
subscription='remove'/>
|
2022-03-22 23:29:25 +01:00
|
|
|
|
</query>"#
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let roster = Roster::try_from(elem).unwrap();
|
|
|
|
|
|
assert!(roster.ver.is_none());
|
|
|
|
|
|
assert_eq!(roster.items.len(), 1);
|
2023-06-20 14:07:50 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
roster.items[0].jid,
|
|
|
|
|
|
BareJid::new("nurse@example.com").unwrap()
|
|
|
|
|
|
);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
assert!(roster.items[0].name.is_none());
|
|
|
|
|
|
assert!(roster.items[0].groups.is_empty());
|
2017-10-10 17:40:29 +01:00
|
|
|
|
assert_eq!(roster.items[0].subscription, Subscription::Remove);
|
2017-05-28 16:30:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
Stop being pedantic by default
Up to now, the xmpp-rs projects have been very strict about incoming
data. This has served us, as developers of the libraries, well,
uncovering bugs in our and remote implementations which we could then
get fixed.
However, this behaviour is unexpected to users of the library. In the
XMPP world, unexpected child elements and attributes are generally
expected to be ignored. While this could be opted-into previously, the
feature flag for that sounded more dangerous than it was
("disable-validation"). In addition, the tribal knowledge needed to know
about that feature flag may not have reached some people who tried the
library and gave up because of that.
With this change, we make the non-pedantic behaviour the default. For
development and debugging purposes, users can always opt into the
pedantic behaviour as needed, using the newly-introduced `pedantic`
feature flags on all affected crates.
2026-03-27 12:07:53 +01:00
|
|
|
|
#[cfg(feature = "pedantic")]
|
2017-05-28 16:30:43 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_invalid() {
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster'><coucou/></query>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let error = Roster::try_from(elem).unwrap_err();
|
|
|
|
|
|
let message = match error {
|
2024-06-21 16:27:43 +02:00
|
|
|
|
FromElementError::Invalid(Error::Other(string)) => string,
|
2017-05-28 16:30:43 +01:00
|
|
|
|
_ => panic!(),
|
|
|
|
|
|
};
|
2024-08-03 13:04:56 +02:00
|
|
|
|
assert_eq!(message, "Unknown child in Roster element.");
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster' coucou=''/>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let error = Roster::try_from(elem).unwrap_err();
|
|
|
|
|
|
let message = match error {
|
2024-06-21 16:27:43 +02:00
|
|
|
|
FromElementError::Invalid(Error::Other(string)) => string,
|
2017-05-28 16:30:43 +01:00
|
|
|
|
_ => panic!(),
|
|
|
|
|
|
};
|
2024-08-03 13:04:56 +02:00
|
|
|
|
assert_eq!(message, "Unknown attribute in Roster element.");
|
2017-05-28 16:30:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
2024-12-20 08:57:46 +01:00
|
|
|
|
fn test_item_missing_jid() {
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster'><item/></query>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let error = Roster::try_from(elem).unwrap_err();
|
|
|
|
|
|
let message = match error {
|
2024-06-21 16:27:43 +02:00
|
|
|
|
FromElementError::Invalid(Error::Other(string)) => string,
|
2017-05-28 16:30:43 +01:00
|
|
|
|
_ => panic!(),
|
|
|
|
|
|
};
|
2024-08-08 18:30:14 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
message,
|
|
|
|
|
|
"Required attribute field 'jid' on Item element missing."
|
|
|
|
|
|
);
|
2024-12-20 08:57:46 +01:00
|
|
|
|
}
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2024-12-20 08:57:46 +01:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_item_invalid_jid() {
|
2024-08-08 18:30:14 +02:00
|
|
|
|
let elem: Element = "<query xmlns='jabber:iq:roster'><item jid=''/></query>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let error = Roster::try_from(elem).unwrap_err();
|
2024-08-08 18:30:14 +02:00
|
|
|
|
assert_eq!(
|
|
|
|
|
|
format!("{error}"),
|
2025-02-05 18:26:48 +01:00
|
|
|
|
"text parse error: domain doesn’t pass idna validation"
|
2024-08-08 18:30:14 +02:00
|
|
|
|
);
|
2024-12-20 08:57:46 +01:00
|
|
|
|
}
|
2017-05-28 16:30:43 +01:00
|
|
|
|
|
2024-12-20 08:57:46 +01:00
|
|
|
|
#[test]
|
Stop being pedantic by default
Up to now, the xmpp-rs projects have been very strict about incoming
data. This has served us, as developers of the libraries, well,
uncovering bugs in our and remote implementations which we could then
get fixed.
However, this behaviour is unexpected to users of the library. In the
XMPP world, unexpected child elements and attributes are generally
expected to be ignored. While this could be opted-into previously, the
feature flag for that sounded more dangerous than it was
("disable-validation"). In addition, the tribal knowledge needed to know
about that feature flag may not have reached some people who tried the
library and gave up because of that.
With this change, we make the non-pedantic behaviour the default. For
development and debugging purposes, users can always opt into the
pedantic behaviour as needed, using the newly-introduced `pedantic`
feature flags on all affected crates.
2026-03-27 12:07:53 +01:00
|
|
|
|
#[cfg_attr(not(feature = "pedantic"), should_panic = "Result::unwrap_err")]
|
2024-12-20 08:57:46 +01:00
|
|
|
|
fn test_item_unknown_child() {
|
2018-12-18 15:32:05 +01:00
|
|
|
|
let elem: Element =
|
|
|
|
|
|
"<query xmlns='jabber:iq:roster'><item jid='coucou'><coucou/></item></query>"
|
|
|
|
|
|
.parse()
|
|
|
|
|
|
.unwrap();
|
2017-05-28 16:30:43 +01:00
|
|
|
|
let error = Roster::try_from(elem).unwrap_err();
|
|
|
|
|
|
let message = match error {
|
2024-06-21 16:27:43 +02:00
|
|
|
|
FromElementError::Invalid(Error::Other(string)) => string,
|
2017-05-28 16:30:43 +01:00
|
|
|
|
_ => panic!(),
|
|
|
|
|
|
};
|
2024-08-08 18:30:14 +02:00
|
|
|
|
assert_eq!(message, "Unknown child in Item element.");
|
2017-05-28 16:30:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|