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