idle: Add the chrono dependency to actually parse dates.

This commit is contained in:
Emmanuel Gil Peyrot 2017-05-27 12:20:19 +01:00
parent dfdfd8cf71
commit 2c77c4f701
4 changed files with 73 additions and 6 deletions

View file

@ -18,3 +18,4 @@ sha-1 = "0.3.0"
sha2 = "0.5.0" sha2 = "0.5.0"
sha3 = "0.5.0" sha3 = "0.5.0"
blake2 = "0.5.0" blake2 = "0.5.0"
chrono = "0.3.1"

View file

@ -12,6 +12,7 @@ use std::string;
use base64; use base64;
use minidom; use minidom;
use jid; use jid;
use chrono;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -22,6 +23,7 @@ pub enum Error {
ParseIntError(num::ParseIntError), ParseIntError(num::ParseIntError),
ParseStringError(string::ParseError), ParseStringError(string::ParseError),
JidParseError(jid::JidParseError), JidParseError(jid::JidParseError),
ChronoParseError(chrono::ParseError),
} }
impl From<io::Error> for Error { impl From<io::Error> for Error {
@ -59,3 +61,9 @@ impl From<jid::JidParseError> for Error {
Error::JidParseError(err) Error::JidParseError(err)
} }
} }
impl From<chrono::ParseError> for Error {
fn from(err: chrono::ParseError) -> Error {
Error::ChronoParseError(err)
}
}

View file

@ -7,16 +7,15 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use minidom::Element; use minidom::Element;
use chrono::prelude::*;
use error::Error; use error::Error;
use ns; use ns;
type Date = String;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Idle { pub struct Idle {
pub since: Date, pub since: DateTime<FixedOffset>,
} }
impl TryFrom<Element> for Idle { impl TryFrom<Element> for Idle {
@ -29,7 +28,7 @@ impl TryFrom<Element> for Idle {
for _ in elem.children() { for _ in elem.children() {
return Err(Error::ParseError("Unknown child in idle element.")); 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 }) Ok(Idle { since: since })
} }
} }
@ -38,7 +37,7 @@ impl Into<Element> for Idle {
fn into(self) -> Element { fn into(self) -> Element {
Element::builder("idle") Element::builder("idle")
.ns(ns::IDLE) .ns(ns::IDLE)
.attr("since", self.since.clone()) .attr("since", self.since.to_rfc3339())
.build() .build()
} }
} }
@ -46,6 +45,7 @@ impl Into<Element> for Idle {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::error::Error as StdError;
#[test] #[test]
fn test_simple() { fn test_simple() {
@ -75,10 +75,67 @@ mod tests {
assert_eq!(message, "Required attribute 'since' missing."); assert_eq!(message, "Required attribute 'since' missing.");
} }
#[test]
fn test_invalid_date() {
// There is no thirteenth month.
let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-13-01T12:23:34Z'/>".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 arent allowed.
let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02+25:00'/>".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 arent allowed.
let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02+0100'/>".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 = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11+01:00'/>".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 well want to support this one, as per XEP-0082 §4.
let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='20170527T12:11:02+01:00'/>".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 = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-27T12:11:02'/>".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] #[test]
fn test_serialise() { fn test_serialise() {
let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-21T20:19:55+01:00'/>".parse().unwrap(); let elem: Element = "<idle xmlns='urn:xmpp:idle:1' since='2017-05-21T20:19:55+01:00'/>".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(); let elem2 = idle.into();
assert_eq!(elem, elem2); assert_eq!(elem, elem2);
} }

View file

@ -22,6 +22,7 @@ extern crate sha_1;
extern crate sha2; extern crate sha2;
extern crate sha3; extern crate sha3;
extern crate blake2; extern crate blake2;
extern crate chrono;
macro_rules! get_attr { macro_rules! get_attr {
($elem:ident, $attr:tt, $type:tt) => ( ($elem:ident, $attr:tt, $type:tt) => (