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 std::convert::TryFrom;
8
9use minidom::Element;
10use chrono::prelude::*;
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 Error = 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 Into<Element> for Delay {
49 fn into(self) -> Element {
50 Element::builder("delay")
51 .ns(ns::DELAY)
52 .attr("from", self.from.and_then(|value| Some(String::from(value))))
53 .attr("stamp", self.stamp.to_rfc3339())
54 .append(self.data)
55 .build()
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use std::str::FromStr;
62 use super::*;
63
64 #[test]
65 fn test_simple() {
66 let elem: Element = "<delay xmlns='urn:xmpp:delay' from='capulet.com' stamp='2002-09-10T23:08:25Z'/>".parse().unwrap();
67 let delay = Delay::try_from(elem).unwrap();
68 assert_eq!(delay.from, Some(Jid::from_str("capulet.com").unwrap()));
69 assert_eq!(delay.stamp.year(), 2002);
70 assert_eq!(delay.stamp.month(), 9);
71 assert_eq!(delay.stamp.day(), 10);
72 assert_eq!(delay.stamp.hour(), 23);
73 assert_eq!(delay.stamp.minute(), 08);
74 assert_eq!(delay.stamp.second(), 25);
75 assert_eq!(delay.stamp.nanosecond(), 0);
76 assert_eq!(delay.stamp.timezone(), FixedOffset::east(0));
77 assert_eq!(delay.data, None);
78 }
79
80 #[test]
81 fn test_unknown() {
82 let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
83 let error = Delay::try_from(elem).unwrap_err();
84 let message = match error {
85 Error::ParseError(string) => string,
86 _ => panic!(),
87 };
88 assert_eq!(message, "This is not a delay element.");
89 }
90
91 #[test]
92 fn test_invalid_child() {
93 let elem: Element = "<delay xmlns='urn:xmpp:delay'><coucou/></delay>".parse().unwrap();
94 let error = Delay::try_from(elem).unwrap_err();
95 let message = match error {
96 Error::ParseError(string) => string,
97 _ => panic!(),
98 };
99 assert_eq!(message, "Unknown child in delay element.");
100 }
101
102 #[test]
103 fn test_serialise() {
104 let elem: Element = "<delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:08:25+00:00'/>".parse().unwrap();
105 let delay = Delay {
106 from: None,
107 stamp: DateTime::parse_from_rfc3339("2002-09-10T23:08:25Z").unwrap(),
108 data: None,
109 };
110 let elem2 = delay.into();
111 assert_eq!(elem, elem2);
112 }
113
114 #[test]
115 fn test_serialise_data() {
116 let elem: Element = "<delay xmlns='urn:xmpp:delay' from='juliet@example.org' stamp='2002-09-10T23:08:25+00:00'>Reason</delay>".parse().unwrap();
117 let delay = Delay {
118 from: Some(Jid::from_str("juliet@example.org").unwrap()),
119 stamp: DateTime::parse_from_rfc3339("2002-09-10T23:08:25Z").unwrap(),
120 data: Some(String::from("Reason")),
121 };
122 let elem2 = delay.into();
123 assert_eq!(elem, elem2);
124 }
125}