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