1// Copyright (c) 2019 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 crate::hashes::Sha1HexAttribute;
8use crate::pubsub::PubSubPayload;
9use crate::util::helpers::WhitespaceAwareBase64;
10
11generate_element!(
12 /// Communicates information about an avatar.
13 Metadata, "metadata", AVATAR_METADATA,
14 children: [
15 /// List of information elements describing this avatar.
16 infos: Vec<Info> = ("info", AVATAR_METADATA) => Info
17 ]
18);
19
20impl PubSubPayload for Metadata {}
21
22generate_element!(
23 /// Communicates avatar metadata.
24 Info, "info", AVATAR_METADATA,
25 attributes: [
26 /// The size of the image data in bytes.
27 bytes: Required<u16> = "bytes",
28
29 /// The width of the image in pixels.
30 width: Option<u16> = "width",
31
32 /// The height of the image in pixels.
33 height: Option<u16> = "height",
34
35 /// The SHA-1 hash of the image data for the specified content-type.
36 id: Required<Sha1HexAttribute> = "id",
37
38 /// The IANA-registered content type of the image data.
39 type_: Required<String> = "type",
40
41 /// The http: or https: URL at which the image data file is hosted.
42 url: Option<String> = "url",
43 ]
44);
45
46generate_element!(
47 /// The actual avatar data.
48 Data, "data", AVATAR_DATA,
49 text: (
50 /// Vector of bytes representing the avatar’s image.
51 data: WhitespaceAwareBase64<Vec<u8>>
52 )
53);
54
55impl PubSubPayload for Data {}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use crate::hashes::Algo;
61 use crate::util::error::Error;
62 use minidom::Element;
63 use std::convert::TryFrom;
64
65 #[cfg(target_pointer_width = "32")]
66 #[test]
67 fn test_size() {
68 assert_size!(Metadata, 12);
69 assert_size!(Info, 64);
70 assert_size!(Data, 12);
71 }
72
73 #[cfg(target_pointer_width = "64")]
74 #[test]
75 fn test_size() {
76 assert_size!(Metadata, 24);
77 assert_size!(Info, 120);
78 assert_size!(Data, 24);
79 }
80
81 #[test]
82 fn test_simple() {
83 let elem: Element = "<metadata xmlns='urn:xmpp:avatar:metadata'>
84 <info bytes='12345' width='64' height='64'
85 id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'
86 type='image/png'/>
87 </metadata>"
88 .parse()
89 .unwrap();
90 let metadata = Metadata::try_from(elem).unwrap();
91 assert_eq!(metadata.infos.len(), 1);
92 let info = &metadata.infos[0];
93 assert_eq!(info.bytes, 12345);
94 assert_eq!(info.width, Some(64));
95 assert_eq!(info.height, Some(64));
96 assert_eq!(info.id.algo, Algo::Sha_1);
97 assert_eq!(info.type_, "image/png");
98 assert_eq!(info.url, None);
99 assert_eq!(
100 info.id.hash,
101 [
102 17, 31, 75, 60, 80, 215, 176, 223, 114, 157, 41, 155, 198, 248, 233, 239, 144, 102,
103 151, 31
104 ]
105 );
106
107 let elem: Element = "<data xmlns='urn:xmpp:avatar:data'>AAAA</data>"
108 .parse()
109 .unwrap();
110 let data = Data::try_from(elem).unwrap();
111 assert_eq!(data.data, b"\0\0\0");
112 }
113
114 #[cfg(not(feature = "disable-validation"))]
115 #[test]
116 fn test_invalid() {
117 let elem: Element = "<data xmlns='urn:xmpp:avatar:data' id='coucou'/>"
118 .parse()
119 .unwrap();
120 let error = Data::try_from(elem).unwrap_err();
121 let message = match error {
122 Error::ParseError(string) => string,
123 _ => panic!(),
124 };
125 assert_eq!(message, "Unknown attribute in data element.")
126 }
127}