media_element.rs

  1// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7use crate::util::helpers::TrimmedPlainText;
  8
  9generate_element!(
 10    /// Represents an URI used in a media element.
 11    URI, "uri", MEDIA_ELEMENT,
 12    attributes: [
 13        /// The MIME type of the URI referenced.
 14        ///
 15        /// See the [IANA MIME Media Types Registry][1] for a list of
 16        /// registered types, but unregistered or yet-to-be-registered are
 17        /// accepted too.
 18        ///
 19        /// [1]: <https://www.iana.org/assignments/media-types/media-types.xhtml>
 20        type_: Required<String> = "type"
 21    ],
 22    text: (
 23        /// The actual URI contained.
 24        uri: TrimmedPlainText<String>
 25    )
 26);
 27
 28generate_element!(
 29    /// References a media element, to be used in [data
 30    /// forms](../data_forms/index.html).
 31    MediaElement, "media", MEDIA_ELEMENT,
 32    attributes: [
 33        /// The recommended display width in pixels.
 34        width: Option<usize> = "width",
 35
 36        /// The recommended display height in pixels.
 37        height: Option<usize> = "height"
 38    ],
 39    children: [
 40        /// A list of URIs referencing this media.
 41        uris: Vec<URI> = ("uri", MEDIA_ELEMENT) => URI
 42    ]
 43);
 44
 45#[cfg(test)]
 46mod tests {
 47    use super::*;
 48    use crate::data_forms::DataForm;
 49    use crate::util::error::Error;
 50    use crate::Element;
 51    use std::convert::TryFrom;
 52
 53    #[cfg(target_pointer_width = "32")]
 54    #[test]
 55    fn test_size() {
 56        assert_size!(URI, 24);
 57        assert_size!(MediaElement, 28);
 58    }
 59
 60    #[cfg(target_pointer_width = "64")]
 61    #[test]
 62    fn test_size() {
 63        assert_size!(URI, 48);
 64        assert_size!(MediaElement, 56);
 65    }
 66
 67    #[test]
 68    fn test_simple() {
 69        let elem: Element = "<media xmlns='urn:xmpp:media-element'/>".parse().unwrap();
 70        let media = MediaElement::try_from(elem).unwrap();
 71        assert!(media.width.is_none());
 72        assert!(media.height.is_none());
 73        assert!(media.uris.is_empty());
 74    }
 75
 76    #[test]
 77    fn test_width_height() {
 78        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='32' height='32'/>"
 79            .parse()
 80            .unwrap();
 81        let media = MediaElement::try_from(elem).unwrap();
 82        assert_eq!(media.width.unwrap(), 32);
 83        assert_eq!(media.height.unwrap(), 32);
 84    }
 85
 86    #[test]
 87    fn test_uri() {
 88        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'>https://example.org/</uri></media>".parse().unwrap();
 89        let media = MediaElement::try_from(elem).unwrap();
 90        assert_eq!(media.uris.len(), 1);
 91        assert_eq!(media.uris[0].type_, "text/html");
 92        assert_eq!(media.uris[0].uri, "https://example.org/");
 93    }
 94
 95    #[test]
 96    fn test_invalid_width_height() {
 97        let elem: Element = "<media xmlns='urn:xmpp:media-element' width=''/>"
 98            .parse()
 99            .unwrap();
100        let error = MediaElement::try_from(elem).unwrap_err();
101        let error = match error {
102            Error::ParseIntError(error) => error,
103            _ => panic!(),
104        };
105        assert_eq!(error.to_string(), "cannot parse integer from empty string");
106
107        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='coucou'/>"
108            .parse()
109            .unwrap();
110        let error = MediaElement::try_from(elem).unwrap_err();
111        let error = match error {
112            Error::ParseIntError(error) => error,
113            _ => panic!(),
114        };
115        assert_eq!(error.to_string(), "invalid digit found in string");
116
117        let elem: Element = "<media xmlns='urn:xmpp:media-element' height=''/>"
118            .parse()
119            .unwrap();
120        let error = MediaElement::try_from(elem).unwrap_err();
121        let error = match error {
122            Error::ParseIntError(error) => error,
123            _ => panic!(),
124        };
125        assert_eq!(error.to_string(), "cannot parse integer from empty string");
126
127        let elem: Element = "<media xmlns='urn:xmpp:media-element' height='-10'/>"
128            .parse()
129            .unwrap();
130        let error = MediaElement::try_from(elem).unwrap_err();
131        let error = match error {
132            Error::ParseIntError(error) => error,
133            _ => panic!(),
134        };
135        assert_eq!(error.to_string(), "invalid digit found in string");
136    }
137
138    #[test]
139    fn test_unknown_child() {
140        let elem: Element = "<media xmlns='urn:xmpp:media-element'><coucou/></media>"
141            .parse()
142            .unwrap();
143        let error = MediaElement::try_from(elem).unwrap_err();
144        let message = match error {
145            Error::ParseError(string) => string,
146            _ => panic!(),
147        };
148        assert_eq!(message, "Unknown child in media element.");
149    }
150
151    #[test]
152    fn test_bad_uri() {
153        let elem: Element =
154            "<media xmlns='urn:xmpp:media-element'><uri>https://example.org/</uri></media>"
155                .parse()
156                .unwrap();
157        let error = MediaElement::try_from(elem).unwrap_err();
158        let message = match error {
159            Error::ParseError(string) => string,
160            _ => panic!(),
161        };
162        assert_eq!(message, "Required attribute 'type' missing.");
163
164        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'/></media>"
165            .parse()
166            .unwrap();
167        let error = MediaElement::try_from(elem).unwrap_err();
168        let message = match error {
169            Error::ParseError(string) => string,
170            _ => panic!(),
171        };
172        assert_eq!(message, "URI missing in uri.");
173    }
174
175    #[test]
176    fn test_xep_ex1() {
177        let elem: Element = r#"<media xmlns='urn:xmpp:media-element'>
178  <uri type='audio/x-wav'>
179    http://victim.example.com/challenges/speech.wav?F3A6292C
180  </uri>
181  <uri type='audio/ogg; codecs=speex'>
182    cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org
183  </uri>
184  <uri type='audio/mpeg'>
185    http://victim.example.com/challenges/speech.mp3?F3A6292C
186  </uri>
187</media>"#
188            .parse()
189            .unwrap();
190        let media = MediaElement::try_from(elem).unwrap();
191        assert!(media.width.is_none());
192        assert!(media.height.is_none());
193        assert_eq!(media.uris.len(), 3);
194        assert_eq!(media.uris[0].type_, "audio/x-wav");
195        assert_eq!(
196            media.uris[0].uri,
197            "http://victim.example.com/challenges/speech.wav?F3A6292C"
198        );
199        assert_eq!(media.uris[1].type_, "audio/ogg; codecs=speex");
200        assert_eq!(
201            media.uris[1].uri,
202            "cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org"
203        );
204        assert_eq!(media.uris[2].type_, "audio/mpeg");
205        assert_eq!(
206            media.uris[2].uri,
207            "http://victim.example.com/challenges/speech.mp3?F3A6292C"
208        );
209    }
210
211    #[test]
212    fn test_xep_ex2() {
213        let elem: Element = r#"<x xmlns='jabber:x:data' type='form'>
214  [ ... ]
215  <field var='ocr'>
216    <media xmlns='urn:xmpp:media-element'
217           height='80'
218           width='290'>
219      <uri type='image/jpeg'>
220        http://www.victim.com/challenges/ocr.jpeg?F3A6292C
221      </uri>
222      <uri type='image/jpeg'>
223        cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org
224      </uri>
225    </media>
226  </field>
227  [ ... ]
228</x>"#
229            .parse()
230            .unwrap();
231        let form = DataForm::try_from(elem).unwrap();
232        assert_eq!(form.fields.len(), 1);
233        assert_eq!(form.fields[0].var, "ocr");
234        assert_eq!(form.fields[0].media[0].width, Some(290));
235        assert_eq!(form.fields[0].media[0].height, Some(80));
236        assert_eq!(form.fields[0].media[0].uris[0].type_, "image/jpeg");
237        assert_eq!(
238            form.fields[0].media[0].uris[0].uri,
239            "http://www.victim.com/challenges/ocr.jpeg?F3A6292C"
240        );
241        assert_eq!(form.fields[0].media[0].uris[1].type_, "image/jpeg");
242        assert_eq!(
243            form.fields[0].media[0].uris[1].uri,
244            "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org"
245        );
246    }
247}