Merge branch 'feature/fix-standard-deviance-in-jingle' into 'main'

Fix two places where we deviate from XEP-0166

See merge request xmpp-rs/xmpp-rs!305
This commit is contained in:
Jonas Schäfer 2024-04-17 16:33:05 +00:00
commit 5020f6f174
1 changed files with 34 additions and 27 deletions

View File

@ -14,7 +14,6 @@ use crate::ns;
use crate::util::error::Error;
use crate::Element;
use jid::Jid;
use std::collections::BTreeMap;
use std::fmt;
use std::str::FromStr;
@ -461,8 +460,6 @@ impl From<Reason> for Element {
}
}
type Lang = String;
/// Informs the recipient of something.
#[derive(Debug, Clone, PartialEq)]
pub struct ReasonElement {
@ -470,15 +467,18 @@ pub struct ReasonElement {
pub reason: Reason,
/// A human-readable description of this reason.
pub texts: BTreeMap<Lang, String>,
pub text: Option<String>,
/// A machine-readable extension of the reason.
// using a box here to save a significant amount of bytes in the common
// (absent) case.
pub other: Option<Box<Element>>,
}
impl fmt::Display for ReasonElement {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", Element::from(self.reason.clone()).name())?;
if let Some(text) = self.texts.get("en") {
write!(fmt, ": {}", text)?;
} else if let Some(text) = self.texts.get("") {
if let Some(text) = self.text.as_ref() {
write!(fmt, ": {}", text)?;
}
Ok(())
@ -492,17 +492,16 @@ impl TryFrom<Element> for ReasonElement {
check_self!(elem, "reason", JINGLE);
check_no_attributes!(elem, "reason");
let mut reason = None;
let mut texts = BTreeMap::new();
let mut text = None;
let mut other = None;
for child in elem.children() {
if child.is("text", ns::JINGLE) {
check_no_children!(child, "text");
check_no_unknown_attributes!(child, "text", ["xml:lang"]);
let lang = get_attr!(elem, "xml:lang", Default);
if texts.insert(lang, child.text()).is_some() {
return Err(Error::ParseError(
"Text element present twice for the same xml:lang.",
));
if text.is_some() {
return Err(Error::ParseError("Multiple reason texts."));
}
text = Some(child.text());
} else if child.has_ns(ns::JINGLE) {
if reason.is_some() {
return Err(Error::ParseError(
@ -512,12 +511,18 @@ impl TryFrom<Element> for ReasonElement {
check_no_children!(child, "reason");
check_no_attributes!(child, "reason");
reason = Some(child.name().parse()?);
} else if other.is_none() {
other = Some(Box::new(child.clone()));
} else {
return Err(Error::ParseError("Reason contains a foreign element."));
}
}
let reason = reason.ok_or(Error::ParseError("Reason doesnt contain a valid reason."))?;
Ok(ReasonElement { reason, texts })
Ok(ReasonElement {
reason,
text,
other,
})
}
}
@ -525,11 +530,13 @@ impl From<ReasonElement> for Element {
fn from(reason: ReasonElement) -> Element {
Element::builder("reason", ns::JINGLE)
.append(Element::from(reason.reason))
.append_all(reason.texts.into_iter().map(|(lang, text)| {
Element::builder("text", ns::JINGLE)
.attr("xml:lang", lang)
.append(text)
}))
.append_all(
reason
.text
.into_iter()
.map(|text| Element::builder("text", ns::JINGLE).append(text)),
)
.append_all(reason.other.into_iter().map(|other| *other))
.build()
}
}
@ -690,9 +697,9 @@ mod tests {
assert_size!(ContentId, 12);
assert_size!(Content, 216);
assert_size!(Reason, 1);
assert_size!(ReasonElement, 16);
assert_size!(ReasonElement, 20);
assert_size!(SessionId, 12);
assert_size!(Jingle, 104);
assert_size!(Jingle, 108);
}
#[cfg(target_pointer_width = "64")]
@ -709,9 +716,9 @@ mod tests {
#[cfg(feature = "stable")]
assert_size!(Content, 440);
assert_size!(Reason, 1);
assert_size!(ReasonElement, 32);
assert_size!(ReasonElement, 40);
assert_size!(SessionId, 24);
assert_size!(Jingle, 208);
assert_size!(Jingle, 216);
}
#[test]
@ -823,13 +830,13 @@ mod tests {
let jingle = Jingle::try_from(elem).unwrap();
let reason = jingle.reason.unwrap();
assert_eq!(reason.reason, Reason::Success);
assert_eq!(reason.texts, BTreeMap::new());
assert_eq!(reason.text, None);
let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><reason><success/><text>coucou</text></reason></jingle>".parse().unwrap();
let jingle = Jingle::try_from(elem).unwrap();
let reason = jingle.reason.unwrap();
assert_eq!(reason.reason, Reason::Success);
assert_eq!(reason.texts.get(""), Some(&String::from("coucou")));
assert_eq!(reason.text, Some(String::from("coucou")));
}
#[test]
@ -856,7 +863,7 @@ mod tests {
Error::ParseError(string) => string,
_ => panic!(),
};
assert_eq!(message, "Reason contains a foreign element.");
assert_eq!(message, "Reason doesnt contain a valid reason.");
let elem: Element = "<jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' sid='coucou'><reason><decline/></reason><reason/></jingle>".parse().unwrap();
let error = Jingle::try_from(elem).unwrap_err();
@ -872,7 +879,7 @@ mod tests {
Error::ParseError(string) => string,
_ => panic!(),
};
assert_eq!(message, "Text element present twice for the same xml:lang.");
assert_eq!(message, "Multiple reason texts.");
}
#[test]