xmpp_parsers/
media_element.rs1use xso::{text::EmptyAsError, AsXml, FromXml};
8
9use crate::ns;
10
11#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
13#[xml(namespace = ns::MEDIA_ELEMENT, name = "uri")]
14pub struct Uri {
15 #[xml(attribute(name = "type"))]
23 pub type_: String,
24
25 #[xml(text(codec = EmptyAsError))]
27 pub uri: String,
28}
29
30#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
33#[xml(namespace = ns::MEDIA_ELEMENT, name = "media")]
34pub struct MediaElement {
35 #[xml(attribute(default))]
37 pub width: Option<usize>,
38
39 #[xml(attribute(default))]
41 pub height: Option<usize>,
42
43 #[xml(child(n = ..))]
45 pub uris: Vec<Uri>,
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::data_forms::DataForm;
52 use minidom::Element;
53 use xso::error::{Error, FromElementError};
54
55 #[cfg(target_pointer_width = "32")]
56 #[test]
57 fn test_size() {
58 assert_size!(Uri, 24);
59 assert_size!(MediaElement, 28);
60 }
61
62 #[cfg(target_pointer_width = "64")]
63 #[test]
64 fn test_size() {
65 assert_size!(Uri, 48);
66 assert_size!(MediaElement, 56);
67 }
68
69 #[test]
70 fn test_simple() {
71 let elem: Element = "<media xmlns='urn:xmpp:media-element'/>".parse().unwrap();
72 let media = MediaElement::try_from(elem).unwrap();
73 assert!(media.width.is_none());
74 assert!(media.height.is_none());
75 assert!(media.uris.is_empty());
76 }
77
78 #[test]
79 fn test_width_height() {
80 let elem: Element = "<media xmlns='urn:xmpp:media-element' width='32' height='32'/>"
81 .parse()
82 .unwrap();
83 let media = MediaElement::try_from(elem).unwrap();
84 assert_eq!(media.width.unwrap(), 32);
85 assert_eq!(media.height.unwrap(), 32);
86 }
87
88 #[test]
89 fn test_uri() {
90 let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'>https://example.org/</uri></media>".parse().unwrap();
91 let media = MediaElement::try_from(elem).unwrap();
92 assert_eq!(media.uris.len(), 1);
93 assert_eq!(media.uris[0].type_, "text/html");
94 assert_eq!(media.uris[0].uri, "https://example.org/");
95 }
96
97 #[test]
98 fn test_invalid_width_height() {
99 let elem: Element = "<media xmlns='urn:xmpp:media-element' width=''/>"
100 .parse()
101 .unwrap();
102 let error = MediaElement::try_from(elem).unwrap_err();
103 let error = match error {
104 FromElementError::Invalid(Error::TextParseError(error))
105 if error.is::<core::num::ParseIntError>() =>
106 {
107 error
108 }
109 _ => panic!(),
110 };
111 assert_eq!(error.to_string(), "cannot parse integer from empty string");
112
113 let elem: Element = "<media xmlns='urn:xmpp:media-element' width='coucou'/>"
114 .parse()
115 .unwrap();
116 let error = MediaElement::try_from(elem).unwrap_err();
117 let error = match error {
118 FromElementError::Invalid(Error::TextParseError(error))
119 if error.is::<core::num::ParseIntError>() =>
120 {
121 error
122 }
123 _ => panic!(),
124 };
125 assert_eq!(error.to_string(), "invalid digit found in string");
126
127 let elem: Element = "<media xmlns='urn:xmpp:media-element' height=''/>"
128 .parse()
129 .unwrap();
130 let error = MediaElement::try_from(elem).unwrap_err();
131 let error = match error {
132 FromElementError::Invalid(Error::TextParseError(error))
133 if error.is::<core::num::ParseIntError>() =>
134 {
135 error
136 }
137 _ => panic!(),
138 };
139 assert_eq!(error.to_string(), "cannot parse integer from empty string");
140
141 let elem: Element = "<media xmlns='urn:xmpp:media-element' height='-10'/>"
142 .parse()
143 .unwrap();
144 let error = MediaElement::try_from(elem).unwrap_err();
145 let error = match error {
146 FromElementError::Invalid(Error::TextParseError(error))
147 if error.is::<core::num::ParseIntError>() =>
148 {
149 error
150 }
151 _ => panic!(),
152 };
153 assert_eq!(error.to_string(), "invalid digit found in string");
154 }
155
156 #[test]
157 #[cfg_attr(feature = "disable-validation", should_panic = "Result::unwrap_err")]
158 fn test_unknown_child() {
159 let elem: Element = "<media xmlns='urn:xmpp:media-element'><coucou/></media>"
160 .parse()
161 .unwrap();
162 let error = MediaElement::try_from(elem).unwrap_err();
163 let message = match error {
164 FromElementError::Invalid(Error::Other(string)) => string,
165 _ => panic!(),
166 };
167 assert_eq!(message, "Unknown child in MediaElement element.");
168 }
169
170 #[test]
171 fn test_bad_uri() {
172 let elem: Element =
173 "<media xmlns='urn:xmpp:media-element'><uri>https://example.org/</uri></media>"
174 .parse()
175 .unwrap();
176 let error = MediaElement::try_from(elem).unwrap_err();
177 let message = match error {
178 FromElementError::Invalid(Error::Other(string)) => string,
179 _ => panic!(),
180 };
181 assert_eq!(
182 message,
183 "Required attribute field 'type_' on Uri element missing."
184 );
185
186 let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'/></media>"
187 .parse()
188 .unwrap();
189 let error = MediaElement::try_from(elem).unwrap_err();
190 let message = match error {
191 FromElementError::Invalid(Error::Other(string)) => string,
192 _ => panic!(),
193 };
194 assert_eq!(message, "Empty text node.");
195 }
196
197 #[test]
198 fn test_xep_ex1() {
199 let elem: Element = r#"<media xmlns='urn:xmpp:media-element'>
200 <uri type='audio/x-wav'>http://victim.example.com/challenges/speech.wav?F3A6292C</uri>
201 <uri type='audio/ogg; codecs=speex'>cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org</uri>
202 <uri type='audio/mpeg'>http://victim.example.com/challenges/speech.mp3?F3A6292C</uri>
203</media>"#
204 .parse()
205 .unwrap();
206 let media = MediaElement::try_from(elem).unwrap();
207 assert!(media.width.is_none());
208 assert!(media.height.is_none());
209 assert_eq!(media.uris.len(), 3);
210 assert_eq!(media.uris[0].type_, "audio/x-wav");
211 assert_eq!(
212 media.uris[0].uri,
213 "http://victim.example.com/challenges/speech.wav?F3A6292C"
214 );
215 assert_eq!(media.uris[1].type_, "audio/ogg; codecs=speex");
216 assert_eq!(
217 media.uris[1].uri,
218 "cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org"
219 );
220 assert_eq!(media.uris[2].type_, "audio/mpeg");
221 assert_eq!(
222 media.uris[2].uri,
223 "http://victim.example.com/challenges/speech.mp3?F3A6292C"
224 );
225 }
226
227 #[test]
228 fn test_xep_ex2() {
229 let elem: Element = r#"<x xmlns='jabber:x:data' type='form'>
230 [ ... ]
231 <field var='ocr'>
232 <media xmlns='urn:xmpp:media-element'
233 height='80'
234 width='290'>
235 <uri type='image/jpeg'>http://www.victim.com/challenges/ocr.jpeg?F3A6292C</uri>
236 <uri type='image/jpeg'>cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org</uri>
237 </media>
238 </field>
239 [ ... ]
240</x>"#
241 .parse()
242 .unwrap();
243 let form = DataForm::try_from(elem).unwrap();
244 assert_eq!(form.fields.len(), 1);
245 assert_eq!(form.fields[0].var.as_deref(), Some("ocr"));
246 assert_eq!(form.fields[0].media[0].width, Some(290));
247 assert_eq!(form.fields[0].media[0].height, Some(80));
248 assert_eq!(form.fields[0].media[0].uris[0].type_, "image/jpeg");
249 assert_eq!(
250 form.fields[0].media[0].uris[0].uri,
251 "http://www.victim.com/challenges/ocr.jpeg?F3A6292C"
252 );
253 assert_eq!(form.fields[0].media[0].uris[1].type_, "image/jpeg");
254 assert_eq!(
255 form.fields[0].media[0].uris[1].uri,
256 "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org"
257 );
258 }
259}