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 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_: String = "type" => required
 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" => optional,
 35
 36        /// The recommended display height in pixels.
 37        height: Option<usize> = "height" => optional
 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 try_from::TryFrom;
 49    use minidom::Element;
 50    use error::Error;
 51    use data_forms::DataForm;
 52    use std::error::Error as StdError;
 53
 54    #[test]
 55    fn test_size() {
 56        assert_size!(URI, 48);
 57        assert_size!(MediaElement, 56);
 58    }
 59
 60    #[test]
 61    fn test_simple() {
 62        let elem: Element = "<media xmlns='urn:xmpp:media-element'/>".parse().unwrap();
 63        let media = MediaElement::try_from(elem).unwrap();
 64        assert!(media.width.is_none());
 65        assert!(media.height.is_none());
 66        assert!(media.uris.is_empty());
 67    }
 68
 69    #[test]
 70    fn test_width_height() {
 71        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='32' height='32'/>".parse().unwrap();
 72        let media = MediaElement::try_from(elem).unwrap();
 73        assert_eq!(media.width.unwrap(), 32);
 74        assert_eq!(media.height.unwrap(), 32);
 75    }
 76
 77    #[test]
 78    fn test_uri() {
 79        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'>https://example.org/</uri></media>".parse().unwrap();
 80        let media = MediaElement::try_from(elem).unwrap();
 81        assert_eq!(media.uris.len(), 1);
 82        assert_eq!(media.uris[0].type_, "text/html");
 83        assert_eq!(media.uris[0].uri, "https://example.org/");
 84    }
 85
 86    #[test]
 87    fn test_invalid_width_height() {
 88        let elem: Element = "<media xmlns='urn:xmpp:media-element' width=''/>".parse().unwrap();
 89        let error = MediaElement::try_from(elem).unwrap_err();
 90        let error = match error {
 91            Error::ParseIntError(error) => error,
 92            _ => panic!(),
 93        };
 94        assert_eq!(error.description(), "cannot parse integer from empty string");
 95
 96        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='coucou'/>".parse().unwrap();
 97        let error = MediaElement::try_from(elem).unwrap_err();
 98        let error = match error {
 99            Error::ParseIntError(error) => error,
100            _ => panic!(),
101        };
102        assert_eq!(error.description(), "invalid digit found in string");
103
104        let elem: Element = "<media xmlns='urn:xmpp:media-element' height=''/>".parse().unwrap();
105        let error = MediaElement::try_from(elem).unwrap_err();
106        let error = match error {
107            Error::ParseIntError(error) => error,
108            _ => panic!(),
109        };
110        assert_eq!(error.description(), "cannot parse integer from empty string");
111
112        let elem: Element = "<media xmlns='urn:xmpp:media-element' height='-10'/>".parse().unwrap();
113        let error = MediaElement::try_from(elem).unwrap_err();
114        let error = match error {
115            Error::ParseIntError(error) => error,
116            _ => panic!(),
117        };
118        assert_eq!(error.description(), "invalid digit found in string");
119    }
120
121    #[test]
122    fn test_unknown_child() {
123        let elem: Element = "<media xmlns='urn:xmpp:media-element'><coucou/></media>".parse().unwrap();
124        let error = MediaElement::try_from(elem).unwrap_err();
125        let message = match error {
126            Error::ParseError(string) => string,
127            _ => panic!(),
128        };
129        assert_eq!(message, "Unknown child in media element.");
130    }
131
132    #[test]
133    fn test_bad_uri() {
134        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri>https://example.org/</uri></media>".parse().unwrap();
135        let error = MediaElement::try_from(elem).unwrap_err();
136        let message = match error {
137            Error::ParseError(string) => string,
138            _ => panic!(),
139        };
140        assert_eq!(message, "Required attribute 'type' missing.");
141
142        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'/></media>".parse().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, "URI missing in uri.");
149    }
150
151    #[test]
152    fn test_xep_ex1() {
153        let elem: Element = r#"
154<media xmlns='urn:xmpp:media-element'>
155  <uri type='audio/x-wav'>
156    http://victim.example.com/challenges/speech.wav?F3A6292C
157  </uri>
158  <uri type='audio/ogg; codecs=speex'>
159    cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org
160  </uri>
161  <uri type='audio/mpeg'>
162    http://victim.example.com/challenges/speech.mp3?F3A6292C
163  </uri>
164</media>"#.parse().unwrap();
165        let media = MediaElement::try_from(elem).unwrap();
166        assert!(media.width.is_none());
167        assert!(media.height.is_none());
168        assert_eq!(media.uris.len(), 3);
169        assert_eq!(media.uris[0].type_, "audio/x-wav");
170        assert_eq!(media.uris[0].uri, "http://victim.example.com/challenges/speech.wav?F3A6292C");
171        assert_eq!(media.uris[1].type_, "audio/ogg; codecs=speex");
172        assert_eq!(media.uris[1].uri, "cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org");
173        assert_eq!(media.uris[2].type_, "audio/mpeg");
174        assert_eq!(media.uris[2].uri, "http://victim.example.com/challenges/speech.mp3?F3A6292C");
175    }
176
177    #[test]
178    fn test_xep_ex2() {
179        let elem: Element = r#"
180<x xmlns='jabber:x:data' type='form'>
181  [ ... ]
182  <field var='ocr'>
183    <media xmlns='urn:xmpp:media-element'
184           height='80'
185           width='290'>
186      <uri type='image/jpeg'>
187        http://www.victim.com/challenges/ocr.jpeg?F3A6292C
188      </uri>
189      <uri type='image/jpeg'>
190        cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org
191      </uri>
192    </media>
193  </field>
194  [ ... ]
195</x>"#.parse().unwrap();
196        let form = DataForm::try_from(elem).unwrap();
197        assert_eq!(form.fields.len(), 1);
198        assert_eq!(form.fields[0].var, "ocr");
199        assert_eq!(form.fields[0].media[0].width, Some(290));
200        assert_eq!(form.fields[0].media[0].height, Some(80));
201        assert_eq!(form.fields[0].media[0].uris[0].type_, "image/jpeg");
202        assert_eq!(form.fields[0].media[0].uris[0].uri, "http://www.victim.com/challenges/ocr.jpeg?F3A6292C");
203        assert_eq!(form.fields[0].media[0].uris[1].type_, "image/jpeg");
204        assert_eq!(form.fields[0].media[0].uris[1].uri, "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org");
205    }
206}