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 crate::date::DateTime;
8use crate::presence::PresencePayload;
9
10generate_element!(
11 /// Represents the last time the user interacted with their system.
12 Idle, "idle", IDLE,
13 attributes: [
14 /// The time at which the user stopped interacting.
15 since: Required<DateTime> = "since",
16 ]
17);
18
19impl PresencePayload for Idle {}
20
21#[cfg(test)]
22mod tests {
23 use super::*;
24 use crate::util::error::Error;
25 use minidom::Element;
26 use std::error::Error as StdError;
27 use std::str::FromStr;
28 use std::convert::TryFrom;
29
30 #[test]
31 fn test_size() {
32 assert_size!(Idle, 16);
33 }
34
35 #[test]
36 fn test_simple() {
37 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-21T20:19:55+01:00'/>"
38 .parse()
39 .unwrap();
40 Idle::try_from(elem).unwrap();
41 }
42
43 #[test]
44 fn test_invalid_child() {
45 let elem: Element = "<idle xmlns='urn:xmpp:idle:1'><coucou/></idle>"
46 .parse()
47 .unwrap();
48 let error = Idle::try_from(elem).unwrap_err();
49 let message = match error {
50 Error::ParseError(string) => string,
51 _ => panic!(),
52 };
53 assert_eq!(message, "Unknown child in idle element.");
54 }
55
56 #[test]
57 fn test_invalid_id() {
58 let elem: Element = "<idle xmlns='urn:xmpp:idle:1'/>".parse().unwrap();
59 let error = Idle::try_from(elem).unwrap_err();
60 let message = match error {
61 Error::ParseError(string) => string,
62 _ => panic!(),
63 };
64 assert_eq!(message, "Required attribute 'since' missing.");
65 }
66
67 #[test]
68 fn test_invalid_date() {
69 // There is no thirteenth month.
70 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-13-01T12:23:34Z'/>"
71 .parse()
72 .unwrap();
73 let error = Idle::try_from(elem).unwrap_err();
74 let message = match error {
75 Error::ChronoParseError(string) => string,
76 _ => panic!(),
77 };
78 assert_eq!(message.description(), "input is out of range");
79
80 // Timezone ≥24:00 aren’t allowed.
81 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02+25:00'/>"
82 .parse()
83 .unwrap();
84 let error = Idle::try_from(elem).unwrap_err();
85 let message = match error {
86 Error::ChronoParseError(string) => string,
87 _ => panic!(),
88 };
89 assert_eq!(message.description(), "input is out of range");
90
91 // Timezone without the : separator aren’t allowed.
92 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02+0100'/>"
93 .parse()
94 .unwrap();
95 let error = Idle::try_from(elem).unwrap_err();
96 let message = match error {
97 Error::ChronoParseError(string) => string,
98 _ => panic!(),
99 };
100 assert_eq!(message.description(), "input contains invalid characters");
101
102 // No seconds, error message could be improved.
103 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11+01:00'/>"
104 .parse()
105 .unwrap();
106 let error = Idle::try_from(elem).unwrap_err();
107 let message = match error {
108 Error::ChronoParseError(string) => string,
109 _ => panic!(),
110 };
111 assert_eq!(message.description(), "input contains invalid characters");
112
113 // TODO: maybe we’ll want to support this one, as per XEP-0082 §4.
114 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='20170527T12:11:02+01:00'/>"
115 .parse()
116 .unwrap();
117 let error = Idle::try_from(elem).unwrap_err();
118 let message = match error {
119 Error::ChronoParseError(string) => string,
120 _ => panic!(),
121 };
122 assert_eq!(message.description(), "input contains invalid characters");
123
124 // No timezone.
125 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02'/>"
126 .parse()
127 .unwrap();
128 let error = Idle::try_from(elem).unwrap_err();
129 let message = match error {
130 Error::ChronoParseError(string) => string,
131 _ => panic!(),
132 };
133 assert_eq!(message.description(), "premature end of input");
134 }
135
136 #[test]
137 fn test_serialise() {
138 let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-21T20:19:55+01:00'/>"
139 .parse()
140 .unwrap();
141 let idle = Idle {
142 since: DateTime::from_str("2017-05-21T20:19:55+01:00").unwrap(),
143 };
144 let elem2 = idle.into();
145 assert_eq!(elem, elem2);
146 }
147}