diff --git a/Cargo.toml b/Cargo.toml index 59a8a89..d8b0826 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,4 @@ sha-1 = "0.3.0" sha2 = "0.5.0" sha3 = "0.5.0" blake2 = "0.5.0" +chrono = "0.3.1" diff --git a/src/error.rs b/src/error.rs index 2f7b254..899e25f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,7 @@ use std::string; use base64; use minidom; use jid; +use chrono; #[derive(Debug)] pub enum Error { @@ -22,6 +23,7 @@ pub enum Error { ParseIntError(num::ParseIntError), ParseStringError(string::ParseError), JidParseError(jid::JidParseError), + ChronoParseError(chrono::ParseError), } impl From for Error { @@ -59,3 +61,9 @@ impl From for Error { Error::JidParseError(err) } } + +impl From for Error { + fn from(err: chrono::ParseError) -> Error { + Error::ChronoParseError(err) + } +} diff --git a/src/idle.rs b/src/idle.rs index 2800a0e..ba13bd8 100644 --- a/src/idle.rs +++ b/src/idle.rs @@ -7,16 +7,15 @@ use std::convert::TryFrom; use minidom::Element; +use chrono::prelude::*; use error::Error; use ns; -type Date = String; - #[derive(Debug, Clone)] pub struct Idle { - pub since: Date, + pub since: DateTime, } impl TryFrom for Idle { @@ -29,7 +28,7 @@ impl TryFrom for Idle { for _ in elem.children() { return Err(Error::ParseError("Unknown child in idle element.")); } - let since = get_attr!(elem, "since", required); + let since = get_attr!(elem, "since", required, since, DateTime::parse_from_rfc3339(since)?); Ok(Idle { since: since }) } } @@ -38,7 +37,7 @@ impl Into for Idle { fn into(self) -> Element { Element::builder("idle") .ns(ns::IDLE) - .attr("since", self.since.clone()) + .attr("since", self.since.to_rfc3339()) .build() } } @@ -46,6 +45,7 @@ impl Into for Idle { #[cfg(test)] mod tests { use super::*; + use std::error::Error as StdError; #[test] fn test_simple() { @@ -75,10 +75,67 @@ mod tests { assert_eq!(message, "Required attribute 'since' missing."); } + #[test] + fn test_invalid_date() { + // There is no thirteenth month. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "input is out of range"); + + // Timezone ≥24:00 aren’t allowed. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "input is out of range"); + + // Timezone without the : separator aren’t allowed. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "input contains invalid characters"); + + // No seconds, error message could be improved. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "input contains invalid characters"); + + // TODO: maybe we’ll want to support this one, as per XEP-0082 §4. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "input contains invalid characters"); + + // No timezone. + let elem: Element = "".parse().unwrap(); + let error = Idle::try_from(elem).unwrap_err(); + let message = match error { + Error::ChronoParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message.description(), "premature end of input"); + } + #[test] fn test_serialise() { let elem: Element = "".parse().unwrap(); - let idle = Idle { since: Date::from("2017-05-21T20:19:55+01:00") }; + let idle = Idle { since: DateTime::parse_from_rfc3339("2017-05-21T20:19:55+01:00").unwrap() }; let elem2 = idle.into(); assert_eq!(elem, elem2); } diff --git a/src/lib.rs b/src/lib.rs index 363dfec..50ed56e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ extern crate sha_1; extern crate sha2; extern crate sha3; extern crate blake2; +extern crate chrono; macro_rules! get_attr { ($elem:ident, $attr:tt, $type:tt) => (