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