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;
10
11use error::Error;
12
13use ns;
14
15#[derive(Debug, Clone)]
16pub struct Set {
17 pub after: Option<String>,
18 pub before: Option<String>,
19 pub count: Option<usize>,
20 pub first: Option<String>,
21 pub first_index: Option<usize>,
22 pub index: Option<usize>,
23 pub last: Option<String>,
24 pub max: Option<usize>,
25}
26
27impl TryFrom<Element> for Set {
28 type Err = Error;
29
30 fn try_from(elem: Element) -> Result<Set, Error> {
31 if !elem.is("set", ns::RSM) {
32 return Err(Error::ParseError("This is not a RSM element."));
33 }
34 let mut set = Set {
35 after: None,
36 before: None,
37 count: None,
38 first: None,
39 first_index: None,
40 index: None,
41 last: None,
42 max: None,
43 };
44 for child in elem.children() {
45 if child.is("after", ns::RSM) {
46 if set.after.is_some() {
47 return Err(Error::ParseError("Set can’t have more than one after."));
48 }
49 set.after = Some(child.text());
50 } else if child.is("before", ns::RSM) {
51 if set.before.is_some() {
52 return Err(Error::ParseError("Set can’t have more than one before."));
53 }
54 set.before = Some(child.text());
55 } else if child.is("count", ns::RSM) {
56 if set.count.is_some() {
57 return Err(Error::ParseError("Set can’t have more than one count."));
58 }
59 set.count = Some(child.text().parse()?);
60 } else if child.is("first", ns::RSM) {
61 if set.first.is_some() {
62 return Err(Error::ParseError("Set can’t have more than one first."));
63 }
64 set.first_index = get_attr!(child, "index", optional);
65 set.first = Some(child.text());
66 } else if child.is("index", ns::RSM) {
67 if set.index.is_some() {
68 return Err(Error::ParseError("Set can’t have more than one index."));
69 }
70 set.index = Some(child.text().parse()?);
71 } else if child.is("last", ns::RSM) {
72 if set.last.is_some() {
73 return Err(Error::ParseError("Set can’t have more than one last."));
74 }
75 set.last = Some(child.text());
76 } else if child.is("max", ns::RSM) {
77 if set.max.is_some() {
78 return Err(Error::ParseError("Set can’t have more than one max."));
79 }
80 set.max = Some(child.text().parse()?);
81 } else {
82 return Err(Error::ParseError("Unknown child in set element."));
83 }
84 }
85 Ok(set)
86 }
87}
88
89impl From<Set> for Element {
90 fn from(set: Set) -> Element {
91 let mut elem = Element::builder("set")
92 .ns(ns::RSM)
93 .build();
94 if set.after.is_some() {
95 elem.append_child(Element::builder("after").ns(ns::RSM).append(set.after).build());
96 }
97 if set.before.is_some() {
98 elem.append_child(Element::builder("before").ns(ns::RSM).append(set.before).build());
99 }
100 if let Some(count) = set.count {
101 elem.append_child(Element::builder("count").ns(ns::RSM).append(format!("{}", count)).build());
102 }
103 if set.first.is_some() {
104 elem.append_child(Element::builder("first")
105 .ns(ns::RSM)
106 .attr("index", set.first_index)
107 .append(set.first).build());
108 }
109 if let Some(index) = set.index {
110 elem.append_child(Element::builder("index").ns(ns::RSM).append(format!("{}", index)).build());
111 }
112 if set.last.is_some() {
113 elem.append_child(Element::builder("last").ns(ns::RSM).append(set.last).build());
114 }
115 if let Some(max) = set.max {
116 elem.append_child(Element::builder("max").ns(ns::RSM).append(format!("{}", max)).build());
117 }
118 elem
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use compare_elements::NamespaceAwareCompare;
126
127 #[test]
128 fn test_simple() {
129 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
130 let set = Set::try_from(elem).unwrap();
131 assert_eq!(set.after, None);
132 assert_eq!(set.before, None);
133 assert_eq!(set.count, None);
134 match set.first {
135 Some(_) => panic!(),
136 None => (),
137 }
138 assert_eq!(set.index, None);
139 assert_eq!(set.last, None);
140 assert_eq!(set.max, None);
141 }
142
143 #[test]
144 fn test_unknown() {
145 let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
146 let error = Set::try_from(elem).unwrap_err();
147 let message = match error {
148 Error::ParseError(string) => string,
149 _ => panic!(),
150 };
151 assert_eq!(message, "This is not a RSM element.");
152 }
153
154 #[test]
155 fn test_invalid_child() {
156 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><coucou/></set>".parse().unwrap();
157 let error = Set::try_from(elem).unwrap_err();
158 let message = match error {
159 Error::ParseError(string) => string,
160 _ => panic!(),
161 };
162 assert_eq!(message, "Unknown child in set element.");
163 }
164
165 #[test]
166 fn test_serialise() {
167 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
168 let rsm = Set {
169 after: None,
170 before: None,
171 count: None,
172 first: None,
173 first_index: None,
174 index: None,
175 last: None,
176 max: None,
177 };
178 let elem2 = rsm.into();
179 assert_eq!(elem, elem2);
180 }
181
182 #[test]
183 fn test_first_index() {
184 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><first index='4'>coucou</first></set>".parse().unwrap();
185 let elem1 = elem.clone();
186 let set = Set::try_from(elem).unwrap();
187 assert_eq!(set.first, Some(String::from("coucou")));
188 assert_eq!(set.first_index, Some(4));
189
190 let set2 = Set {
191 after: None,
192 before: None,
193 count: None,
194 first: Some(String::from("coucou")),
195 first_index: Some(4),
196 index: None,
197 last: None,
198 max: None,
199 };
200 let elem2 = set2.into();
201 assert!(elem1.compare_to(&elem2));
202 }
203}