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