jingle_ibb.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;
  8use std::str::FromStr;
  9
 10use minidom::Element;
 11
 12use error::Error;
 13
 14use ns;
 15
 16use ibb::Stanza;
 17
 18#[derive(Debug, Clone)]
 19pub struct Transport {
 20    pub block_size: u16,
 21    pub sid: String,
 22    pub stanza: Stanza,
 23}
 24
 25fn optional_attr<T: FromStr>(root: &Element, attr: &str) -> Option<T> {
 26    root.attr(attr)
 27        .and_then(|value| value.parse().ok())
 28}
 29
 30fn required_attr<T: FromStr>(root: &Element, attr: &str, err: Error) -> Result<T, Error> {
 31    optional_attr(root, attr).ok_or(err)
 32}
 33
 34impl<'a> TryFrom<&'a Element> for Transport {
 35    type Error = Error;
 36
 37    fn try_from(elem: &'a Element) -> Result<Transport, Error> {
 38        if elem.is("transport", ns::JINGLE_IBB) {
 39            for _ in elem.children() {
 40                return Err(Error::ParseError("Unknown child in JingleIBB element."));
 41            }
 42            let block_size = required_attr(elem, "block-size", Error::ParseError("Required attribute 'block-size' missing in JingleIBB element."))?;
 43            let sid = required_attr(elem, "sid", Error::ParseError("Required attribute 'sid' missing in JingleIBB element."))?;
 44            let stanza = elem.attr("stanza")
 45                             .unwrap_or("iq")
 46                             .parse()?;
 47            Ok(Transport {
 48                block_size: block_size,
 49                sid: sid,
 50                stanza: stanza
 51            })
 52        } else {
 53            Err(Error::ParseError("This is not an JingleIBB element."))
 54        }
 55    }
 56}
 57
 58impl<'a> Into<Element> for &'a Transport {
 59    fn into(self) -> Element {
 60        Element::builder("transport")
 61                .ns(ns::JINGLE_IBB)
 62                .attr("block-size", format!("{}", self.block_size))
 63                .attr("sid", self.sid.clone())
 64                .attr("stanza", self.stanza.clone())
 65                .build()
 66    }
 67}
 68
 69#[cfg(test)]
 70mod tests {
 71    use super::*;
 72
 73    #[test]
 74    fn test_simple() {
 75        let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='3' sid='coucou'/>".parse().unwrap();
 76        let transport = Transport::try_from(&elem).unwrap();
 77        assert_eq!(transport.block_size, 3);
 78        assert_eq!(transport.sid, "coucou");
 79        assert_eq!(transport.stanza, Stanza::Iq);
 80    }
 81
 82    #[test]
 83    fn test_invalid() {
 84        let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1'/>".parse().unwrap();
 85        let error = Transport::try_from(&elem).unwrap_err();
 86        let message = match error {
 87            Error::ParseError(string) => string,
 88            _ => panic!(),
 89        };
 90        assert_eq!(message, "Required attribute 'block-size' missing in JingleIBB element.");
 91
 92        // TODO: maybe make a better error message here.
 93        let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='-5'/>".parse().unwrap();
 94        let error = Transport::try_from(&elem).unwrap_err();
 95        let message = match error {
 96            Error::ParseError(string) => string,
 97            _ => panic!(),
 98        };
 99        assert_eq!(message, "Required attribute 'block-size' missing in JingleIBB element.");
100
101        let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='128'/>".parse().unwrap();
102        let error = Transport::try_from(&elem).unwrap_err();
103        let message = match error {
104            Error::ParseError(string) => string,
105            _ => panic!(),
106        };
107        assert_eq!(message, "Required attribute 'sid' missing in JingleIBB element.");
108    }
109
110    #[test]
111    fn test_invalid_stanza() {
112        let elem: Element = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='128' sid='coucou' stanza='fdsq'/>".parse().unwrap();
113        let error = Transport::try_from(&elem).unwrap_err();
114        let message = match error {
115            Error::ParseError(string) => string,
116            _ => panic!(),
117        };
118        assert_eq!(message, "Invalid 'stanza' attribute.");
119    }
120}