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