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