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 first = set.first.clone()
92 .map(|first| Element::builder("first")
93 .ns(ns::RSM)
94 .attr("index", set.first_index)
95 .append(first)
96 .build());
97 Element::builder("set")
98 .ns(ns::RSM)
99 .append(set.after.map(|after| Element::builder("after").ns(ns::RSM).append(after).build()))
100 .append(set.before.map(|before| Element::builder("before").ns(ns::RSM).append(before).build()))
101 .append(set.count.map(|count| Element::builder("count").ns(ns::RSM).append(format!("{}", count)).build()))
102 .append(first)
103 .append(set.index.map(|index| Element::builder("index").ns(ns::RSM).append(format!("{}", index)).build()))
104 .append(set.last.map(|last| Element::builder("last").ns(ns::RSM).append(last).build()))
105 .append(set.max.map(|max| Element::builder("max").ns(ns::RSM).append(format!("{}", max)).build()))
106 .build()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use compare_elements::NamespaceAwareCompare;
114
115 #[test]
116 fn test_simple() {
117 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
118 let set = Set::try_from(elem).unwrap();
119 assert_eq!(set.after, None);
120 assert_eq!(set.before, None);
121 assert_eq!(set.count, None);
122 match set.first {
123 Some(_) => panic!(),
124 None => (),
125 }
126 assert_eq!(set.index, None);
127 assert_eq!(set.last, None);
128 assert_eq!(set.max, None);
129 }
130
131 #[test]
132 fn test_unknown() {
133 let elem: Element = "<replace xmlns='urn:xmpp:message-correct:0'/>".parse().unwrap();
134 let error = Set::try_from(elem).unwrap_err();
135 let message = match error {
136 Error::ParseError(string) => string,
137 _ => panic!(),
138 };
139 assert_eq!(message, "This is not a RSM element.");
140 }
141
142 #[test]
143 fn test_invalid_child() {
144 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><coucou/></set>".parse().unwrap();
145 let error = Set::try_from(elem).unwrap_err();
146 let message = match error {
147 Error::ParseError(string) => string,
148 _ => panic!(),
149 };
150 assert_eq!(message, "Unknown child in set element.");
151 }
152
153 #[test]
154 fn test_serialise() {
155 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'/>".parse().unwrap();
156 let rsm = Set {
157 after: None,
158 before: None,
159 count: None,
160 first: None,
161 first_index: None,
162 index: None,
163 last: None,
164 max: None,
165 };
166 let elem2 = rsm.into();
167 assert_eq!(elem, elem2);
168 }
169
170 #[test]
171 fn test_first_index() {
172 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><first index='4'>coucou</first></set>".parse().unwrap();
173 let elem1 = elem.clone();
174 let set = Set::try_from(elem).unwrap();
175 assert_eq!(set.first, Some(String::from("coucou")));
176 assert_eq!(set.first_index, Some(4));
177
178 let set2 = Set {
179 after: None,
180 before: None,
181 count: None,
182 first: Some(String::from("coucou")),
183 first_index: Some(4),
184 index: None,
185 last: None,
186 max: None,
187 };
188 let elem2 = set2.into();
189 assert!(elem1.compare_to(&elem2));
190 }
191}