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}