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
7#![deny(missing_docs)]
8
9use try_from::TryFrom;
10
11use minidom::Element;
12
13use error::Error;
14
15use ns;
16
17/// Enum representing chatstate elements part of the
18/// `http://jabber.org/protocol/chatstates` namespace.
19#[derive(Debug, Clone)]
20pub enum ChatState {
21 /// `<active xmlns='http://jabber.org/protocol/chatstates'/>`
22 Active,
23
24 /// `<composing xmlns='http://jabber.org/protocol/chatstates'/>`
25 Composing,
26
27 /// `<gone xmlns='http://jabber.org/protocol/chatstates'/>`
28 Gone,
29
30 /// `<inactive xmlns='http://jabber.org/protocol/chatstates'/>`
31 Inactive,
32
33 /// `<paused xmlns='http://jabber.org/protocol/chatstates'/>`
34 Paused,
35}
36
37impl TryFrom<Element> for ChatState {
38 type Err = Error;
39
40 fn try_from(elem: Element) -> Result<ChatState, Error> {
41 if !elem.has_ns(ns::CHATSTATES) {
42 return Err(Error::ParseError("This is not a chatstate element."));
43 }
44 for _ in elem.children() {
45 return Err(Error::ParseError("Unknown child in chatstate element."));
46 }
47 for _ in elem.attrs() {
48 return Err(Error::ParseError("Unknown attribute in chatstate element."));
49 }
50 Ok(match elem.name() {
51 "active" => ChatState::Active,
52 "composing" => ChatState::Composing,
53 "gone" => ChatState::Gone,
54 "inactive" => ChatState::Inactive,
55 "paused" => ChatState::Paused,
56 _ => return Err(Error::ParseError("This is not a chatstate element.")),
57 })
58 }
59}
60
61impl From<ChatState> for Element {
62 fn from(chatstate: ChatState) -> Element {
63 Element::builder(match chatstate {
64 ChatState::Active => "active",
65 ChatState::Composing => "composing",
66 ChatState::Gone => "gone",
67 ChatState::Inactive => "inactive",
68 ChatState::Paused => "paused",
69 }).ns(ns::CHATSTATES)
70 .build()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_simple() {
80 let elem: Element = "<active xmlns='http://jabber.org/protocol/chatstates'/>".parse().unwrap();
81 ChatState::try_from(elem).unwrap();
82 }
83
84 #[test]
85 fn test_invalid() {
86 let elem: Element = "<coucou xmlns='http://jabber.org/protocol/chatstates'/>".parse().unwrap();
87 let error = ChatState::try_from(elem).unwrap_err();
88 let message = match error {
89 Error::ParseError(string) => string,
90 _ => panic!(),
91 };
92 assert_eq!(message, "This is not a chatstate element.");
93 }
94
95 #[test]
96 fn test_invalid_child() {
97 let elem: Element = "<gone xmlns='http://jabber.org/protocol/chatstates'><coucou/></gone>".parse().unwrap();
98 let error = ChatState::try_from(elem).unwrap_err();
99 let message = match error {
100 Error::ParseError(string) => string,
101 _ => panic!(),
102 };
103 assert_eq!(message, "Unknown child in chatstate element.");
104 }
105
106 #[test]
107 fn test_invalid_attribute() {
108 let elem: Element = "<inactive xmlns='http://jabber.org/protocol/chatstates' coucou=''/>".parse().unwrap();
109 let error = ChatState::try_from(elem).unwrap_err();
110 let message = match error {
111 Error::ParseError(string) => string,
112 _ => panic!(),
113 };
114 assert_eq!(message, "Unknown attribute in chatstate element.");
115 }
116
117 #[test]
118 fn test_serialise() {
119 let chatstate = ChatState::Active;
120 let elem: Element = chatstate.into();
121 assert!(elem.is("active", ns::CHATSTATES));
122 }
123}