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 try_from::TryFrom;
8
9use minidom::Element;
10use chrono::{DateTime, FixedOffset};
11
12use error::Error;
13use jid::Jid;
14
15use ns;
16
17#[derive(Debug, Clone)]
18pub struct Delay {
19 pub from: Option<Jid>,
20 pub stamp: DateTime<FixedOffset>,
21 pub data: Option<String>,
22}
23
24impl TryFrom<Element> for Delay {
25 type Err = Error;
26
27 fn try_from(elem: Element) -> Result<Delay, Error> {
28 if !elem.is("delay", ns::DELAY) {
29 return Err(Error::ParseError("This is not a delay element."));
30 }
31 for _ in elem.children() {
32 return Err(Error::ParseError("Unknown child in delay element."));
33 }
34 let from = get_attr!(elem, "from", optional);
35 let stamp = get_attr!(elem, "stamp", required, stamp, DateTime::parse_from_rfc3339(stamp)?);
36 let data = match elem.text().as_ref() {
37 "" => None,
38 text => Some(text.to_owned()),
39 };
40 Ok(Delay {
41 from: from,
42 stamp: stamp,
43 data: data,
44 })
45 }
46}
47
48impl From<Delay> for Element {
49 fn from(delay: Delay) -> Element {
50 Element::builder("delay")
51 .ns(ns::DELAY)
52 .attr("from", delay.from)
53 .attr("stamp", delay.stamp.to_rfc3339())
54 .append(delay.data)
55 .build()
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use std::str::FromStr;
63 use chrono::{Datelike, Timelike};
64
65 #[test]
66 fn test_simple() {
67 let elem: Element = "<delay xmlns='urn:xmpp:delay' from='capulet.com' stamp='2002-09-10T23:08:25Z'/>".parse().unwrap();
68 let delay = Delay::try_from(elem).unwrap();
69 assert_eq!(delay.from, Some(Jid::from_str("capulet.com").unwrap()));
70 assert_eq!(delay.stamp.year(), 2002);
71 assert_eq!(delay.stamp.month(), 9);
72 assert_eq!(delay.stamp.day(), 10);
73 assert_eq!(delay.stamp.hour(), 23);
74 assert_eq!(delay.stamp.minute(), 08);
75 assert_eq!(delay.stamp.second(), 25);
76 assert_eq!(delay.stamp.nanosecond(), 0);
77 assert_eq!(delay.stamp.timezone(), FixedOffset::east(0));
78 assert_eq!(delay.data, None);
79 }
80
81 #[test]
82 fn test_unknown() {
83 let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
84 let error = Delay::try_from(elem).unwrap_err();
85 let message = match error {
86 Error::ParseError(string) => string,
87 _ => panic!(),
88 };
89 assert_eq!(message, "This is not a delay element.");
90 }
91
92 #[test]
93 fn test_invalid_child() {
94 let elem: Element = "<delay xmlns='urn:xmpp:delay'><coucou/></delay>".parse().unwrap();
95 let error = Delay::try_from(elem).unwrap_err();
96 let message = match error {
97 Error::ParseError(string) => string,
98 _ => panic!(),
99 };
100 assert_eq!(message, "Unknown child in delay element.");
101 }
102
103 #[test]
104 fn test_serialise() {
105 let elem: Element = "<delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:08:25+00:00'/>".parse().unwrap();
106 let delay = Delay {
107 from: None,
108 stamp: DateTime::parse_from_rfc3339("2002-09-10T23:08:25Z").unwrap(),
109 data: None,
110 };
111 let elem2 = delay.into();
112 assert_eq!(elem, elem2);
113 }
114
115 #[test]
116 fn test_serialise_data() {
117 let elem: Element = "<delay xmlns='urn:xmpp:delay' from='juliet@example.org' stamp='2002-09-10T23:08:25+00:00'>Reason</delay>".parse().unwrap();
118 let delay = Delay {
119 from: Some(Jid::from_str("juliet@example.org").unwrap()),
120 stamp: DateTime::parse_from_rfc3339("2002-09-10T23:08:25Z").unwrap(),
121 data: Some(String::from("Reason")),
122 };
123 let elem2 = delay.into();
124 assert_eq!(elem, elem2);
125 }
126}