stanza_id.rs

  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 std::convert::TryFrom;
  8
  9use minidom::Element;
 10use jid::Jid;
 11
 12use error::Error;
 13
 14use ns;
 15
 16#[derive(Debug, Clone)]
 17pub enum StanzaId {
 18    StanzaId {
 19        id: String,
 20        by: Jid,
 21    },
 22    OriginId {
 23        id: String,
 24    },
 25}
 26
 27impl<'a> TryFrom<&'a Element> for StanzaId {
 28    type Error = Error;
 29
 30    fn try_from(elem: &'a Element) -> Result<StanzaId, Error> {
 31        let is_stanza_id = elem.is("stanza-id", ns::SID);
 32        if !is_stanza_id && !elem.is("origin-id", ns::SID) {
 33            return Err(Error::ParseError("This is not a stanza-id or origin-id element."));
 34        }
 35        for _ in elem.children() {
 36            return Err(Error::ParseError("Unknown child in stanza-id or origin-id element."));
 37        }
 38        let id = match elem.attr("id") {
 39            Some(id) => id.to_owned(),
 40            None => return Err(Error::ParseError("No 'id' attribute present in stanza-id or origin-id.")),
 41        };
 42        Ok(if is_stanza_id {
 43            let by = match elem.attr("by") {
 44                Some(by) => by.parse().unwrap(),
 45                None => return Err(Error::ParseError("No 'by' attribute present in stanza-id.")),
 46            };
 47            StanzaId::StanzaId { id, by }
 48        } else {
 49            StanzaId::OriginId { id }
 50        })
 51    }
 52}
 53
 54impl<'a> Into<Element> for &'a StanzaId {
 55    fn into(self) -> Element {
 56        match *self {
 57            StanzaId::StanzaId { ref id, ref by } => {
 58                Element::builder("stanza-id")
 59                        .ns(ns::SID)
 60                        .attr("id", id.clone())
 61                        .attr("by", String::from(by.clone()))
 62                        .build()
 63            },
 64            StanzaId::OriginId { ref id } => {
 65                Element::builder("origin-id")
 66                        .ns(ns::SID)
 67                        .attr("id", id.clone())
 68                        .build()
 69            },
 70        }
 71    }
 72}
 73
 74#[cfg(test)]
 75mod tests {
 76    use super::*;
 77    use std::str::FromStr;
 78
 79    #[test]
 80    fn test_simple() {
 81        let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou' by='coucou@coucou'/>".parse().unwrap();
 82        let stanza_id = StanzaId::try_from(&elem).unwrap();
 83        if let StanzaId::StanzaId { id, by } = stanza_id {
 84            assert_eq!(id, String::from("coucou"));
 85            assert_eq!(by, Jid::from_str("coucou@coucou").unwrap());
 86        } else {
 87            panic!();
 88        }
 89
 90        let elem: Element = "<origin-id xmlns='urn:xmpp:sid:0' id='coucou'/>".parse().unwrap();
 91        let stanza_id = StanzaId::try_from(&elem).unwrap();
 92        if let StanzaId::OriginId { id } = stanza_id {
 93            assert_eq!(id, String::from("coucou"));
 94        } else {
 95            panic!();
 96        }
 97    }
 98
 99    #[test]
100    fn test_invalid_child() {
101        let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0'><coucou/></stanza-id>".parse().unwrap();
102        let error = StanzaId::try_from(&elem).unwrap_err();
103        let message = match error {
104            Error::ParseError(string) => string,
105            _ => panic!(),
106        };
107        assert_eq!(message, "Unknown child in stanza-id or origin-id element.");
108    }
109
110    #[test]
111    fn test_invalid_id() {
112        let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0'/>".parse().unwrap();
113        let error = StanzaId::try_from(&elem).unwrap_err();
114        let message = match error {
115            Error::ParseError(string) => string,
116            _ => panic!(),
117        };
118        assert_eq!(message, "No 'id' attribute present in stanza-id or origin-id.");
119    }
120
121    #[test]
122    fn test_invalid_by() {
123        let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou'/>".parse().unwrap();
124        let error = StanzaId::try_from(&elem).unwrap_err();
125        let message = match error {
126            Error::ParseError(string) => string,
127            _ => panic!(),
128        };
129        assert_eq!(message, "No 'by' attribute present in stanza-id.");
130    }
131
132    #[test]
133    fn test_serialise() {
134        let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou' by='coucou@coucou'/>".parse().unwrap();
135        let stanza_id = StanzaId::StanzaId { id: String::from("coucou"), by: Jid::from_str("coucou@coucou").unwrap() };
136        let elem2 = (&stanza_id).into();
137        assert_eq!(elem, elem2);
138    }
139}