idle.rs

  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}