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 #[cfg(not(feature = "disable-validation"))]
62 use crate::util::error::Error;
63 use crate::Element;
64 use std::convert::TryFrom;
65
66 #[cfg(target_pointer_width = "32")]
67 #[test]
68 fn test_size() {
69 assert_size!(Metadata, 12);
70 assert_size!(Info, 64);
71 assert_size!(Data, 12);
72 }
73
74 #[cfg(target_pointer_width = "64")]
75 #[test]
76 fn test_size() {
77 assert_size!(Metadata, 24);
78 assert_size!(Info, 120);
79 assert_size!(Data, 24);
80 }
81
82 #[test]
83 fn test_simple() {
84 let elem: Element = "<metadata xmlns='urn:xmpp:avatar:metadata'>
85 <info bytes='12345' width='64' height='64'
86 id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'
87 type='image/png'/>
88 </metadata>"
89 .parse()
90 .unwrap();
91 let metadata = Metadata::try_from(elem).unwrap();
92 assert_eq!(metadata.infos.len(), 1);
93 let info = &metadata.infos[0];
94 assert_eq!(info.bytes, 12345);
95 assert_eq!(info.width, Some(64));
96 assert_eq!(info.height, Some(64));
97 assert_eq!(info.id.algo, Algo::Sha_1);
98 assert_eq!(info.type_, "image/png");
99 assert_eq!(info.url, None);
100 assert_eq!(
101 info.id.hash,
102 [
103 17, 31, 75, 60, 80, 215, 176, 223, 114, 157, 41, 155, 198, 248, 233, 239, 144, 102,
104 151, 31
105 ]
106 );
107
108 let elem: Element = "<data xmlns='urn:xmpp:avatar:data'>AAAA</data>"
109 .parse()
110 .unwrap();
111 let data = Data::try_from(elem).unwrap();
112 assert_eq!(data.data, b"\0\0\0");
113 }
114
115 #[cfg(not(feature = "disable-validation"))]
116 #[test]
117 fn test_invalid() {
118 let elem: Element = "<data xmlns='urn:xmpp:avatar:data' id='coucou'/>"
119 .parse()
120 .unwrap();
121 let error = Data::try_from(elem).unwrap_err();
122 let message = match error {
123 Error::ParseError(string) => string,
124 _ => panic!(),
125 };
126 assert_eq!(message, "Unknown attribute in data element.")
127 }
128}