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
  7#![deny(missing_docs)]
  8
  9use helpers::TrimmedPlainText;
 10
 11generate_element_with_text!(
 12    /// Represents an URI used in a media element.
 13    URI, "uri", MEDIA_ELEMENT,
 14    [
 15        /// The MIME type of the URI referenced.
 16        ///
 17        /// See the [IANA MIME Media Types Registry][1] for a list of
 18        /// registered types, but unregistered or yet-to-be-registered are
 19        /// accepted too.
 20        ///
 21        /// [1]: https://www.iana.org/assignments/media-types/media-types.xhtml
 22        type_: String = "type" => required
 23    ],
 24
 25    /// The actual URI contained.
 26    uri: TrimmedPlainText<String>
 27);
 28
 29generate_element!(
 30    /// References a media element, to be used in [data
 31    /// forms](../data_forms/index.html).
 32    MediaElement, "media", MEDIA_ELEMENT,
 33    attributes: [
 34        /// The recommended display width in pixels.
 35        width: Option<usize> = "width" => optional,
 36
 37        /// The recommended display height in pixels.
 38        height: Option<usize> = "height" => optional
 39    ],
 40    children: [
 41        /// A list of URIs referencing this media.
 42        uris: Vec<URI> = ("uri", MEDIA_ELEMENT) => URI
 43    ]
 44);
 45
 46#[cfg(test)]
 47mod tests {
 48    use super::*;
 49    use try_from::TryFrom;
 50    use minidom::Element;
 51    use error::Error;
 52    use data_forms::DataForm;
 53    use std::error::Error as StdError;
 54
 55    #[test]
 56    fn test_simple() {
 57        let elem: Element = "<media xmlns='urn:xmpp:media-element'/>".parse().unwrap();
 58        let media = MediaElement::try_from(elem).unwrap();
 59        assert!(media.width.is_none());
 60        assert!(media.height.is_none());
 61        assert!(media.uris.is_empty());
 62    }
 63
 64    #[test]
 65    fn test_width_height() {
 66        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='32' height='32'/>".parse().unwrap();
 67        let media = MediaElement::try_from(elem).unwrap();
 68        assert_eq!(media.width.unwrap(), 32);
 69        assert_eq!(media.height.unwrap(), 32);
 70    }
 71
 72    #[test]
 73    fn test_uri() {
 74        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'>https://example.org/</uri></media>".parse().unwrap();
 75        let media = MediaElement::try_from(elem).unwrap();
 76        assert_eq!(media.uris.len(), 1);
 77        assert_eq!(media.uris[0].type_, "text/html");
 78        assert_eq!(media.uris[0].uri, "https://example.org/");
 79    }
 80
 81    #[test]
 82    fn test_invalid_width_height() {
 83        let elem: Element = "<media xmlns='urn:xmpp:media-element' width=''/>".parse().unwrap();
 84        let error = MediaElement::try_from(elem).unwrap_err();
 85        let error = match error {
 86            Error::ParseIntError(error) => error,
 87            _ => panic!(),
 88        };
 89        assert_eq!(error.description(), "cannot parse integer from empty string");
 90
 91        let elem: Element = "<media xmlns='urn:xmpp:media-element' width='coucou'/>".parse().unwrap();
 92        let error = MediaElement::try_from(elem).unwrap_err();
 93        let error = match error {
 94            Error::ParseIntError(error) => error,
 95            _ => panic!(),
 96        };
 97        assert_eq!(error.description(), "invalid digit found in string");
 98
 99        let elem: Element = "<media xmlns='urn:xmpp:media-element' height=''/>".parse().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.description(), "cannot parse integer from empty string");
106
107        let elem: Element = "<media xmlns='urn:xmpp:media-element' height='-10'/>".parse().unwrap();
108        let error = MediaElement::try_from(elem).unwrap_err();
109        let error = match error {
110            Error::ParseIntError(error) => error,
111            _ => panic!(),
112        };
113        assert_eq!(error.description(), "invalid digit found in string");
114    }
115
116    #[test]
117    fn test_unknown_child() {
118        let elem: Element = "<media xmlns='urn:xmpp:media-element'><coucou/></media>".parse().unwrap();
119        let error = MediaElement::try_from(elem).unwrap_err();
120        let message = match error {
121            Error::ParseError(string) => string,
122            _ => panic!(),
123        };
124        assert_eq!(message, "Unknown child in media element.");
125    }
126
127    #[test]
128    fn test_bad_uri() {
129        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri>https://example.org/</uri></media>".parse().unwrap();
130        let error = MediaElement::try_from(elem).unwrap_err();
131        let message = match error {
132            Error::ParseError(string) => string,
133            _ => panic!(),
134        };
135        assert_eq!(message, "Required attribute 'type' missing.");
136
137        let elem: Element = "<media xmlns='urn:xmpp:media-element'><uri type='text/html'/></media>".parse().unwrap();
138        let error = MediaElement::try_from(elem).unwrap_err();
139        let message = match error {
140            Error::ParseError(string) => string,
141            _ => panic!(),
142        };
143        assert_eq!(message, "URI missing in uri.");
144    }
145
146    #[test]
147    fn test_xep_ex1() {
148        let elem: Element = r#"
149<media xmlns='urn:xmpp:media-element'>
150  <uri type='audio/x-wav'>
151    http://victim.example.com/challenges/speech.wav?F3A6292C
152  </uri>
153  <uri type='audio/ogg; codecs=speex'>
154    cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org
155  </uri>
156  <uri type='audio/mpeg'>
157    http://victim.example.com/challenges/speech.mp3?F3A6292C
158  </uri>
159</media>"#.parse().unwrap();
160        let media = MediaElement::try_from(elem).unwrap();
161        assert!(media.width.is_none());
162        assert!(media.height.is_none());
163        assert_eq!(media.uris.len(), 3);
164        assert_eq!(media.uris[0].type_, "audio/x-wav");
165        assert_eq!(media.uris[0].uri, "http://victim.example.com/challenges/speech.wav?F3A6292C");
166        assert_eq!(media.uris[1].type_, "audio/ogg; codecs=speex");
167        assert_eq!(media.uris[1].uri, "cid:sha1+a15a505e360702b79c75a5f67773072ed392f52a@bob.xmpp.org");
168        assert_eq!(media.uris[2].type_, "audio/mpeg");
169        assert_eq!(media.uris[2].uri, "http://victim.example.com/challenges/speech.mp3?F3A6292C");
170    }
171
172    #[test]
173    fn test_xep_ex2() {
174        let elem: Element = r#"
175<x xmlns='jabber:x:data' type='form'>
176  [ ... ]
177  <field var='ocr'>
178    <media xmlns='urn:xmpp:media-element'
179           height='80'
180           width='290'>
181      <uri type='image/jpeg'>
182        http://www.victim.com/challenges/ocr.jpeg?F3A6292C
183      </uri>
184      <uri type='image/jpeg'>
185        cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org
186      </uri>
187    </media>
188  </field>
189  [ ... ]
190</x>"#.parse().unwrap();
191        let form = DataForm::try_from(elem).unwrap();
192        assert_eq!(form.fields.len(), 1);
193        assert_eq!(form.fields[0].var, "ocr");
194        assert_eq!(form.fields[0].media[0].width, Some(290));
195        assert_eq!(form.fields[0].media[0].height, Some(80));
196        assert_eq!(form.fields[0].media[0].uris[0].type_, "image/jpeg");
197        assert_eq!(form.fields[0].media[0].uris[0].uri, "http://www.victim.com/challenges/ocr.jpeg?F3A6292C");
198        assert_eq!(form.fields[0].media[0].uris[1].type_, "image/jpeg");
199        assert_eq!(form.fields[0].media[0].uris[1].uri, "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org");
200    }
201}