diff --git a/src/jingle_ft.rs b/src/jingle_ft.rs index 85ac2df..1931aab 100644 --- a/src/jingle_ft.rs +++ b/src/jingle_ft.rs @@ -6,9 +6,12 @@ use try_from::TryFrom; +use std::collections::BTreeMap; +use std::str::FromStr; + use hashes::Hash; -use minidom::{Element, IntoElements, ElementEmitter}; +use minidom::{Element, IntoElements, IntoAttributeValue, ElementEmitter}; use chrono::{DateTime, FixedOffset}; use error::Error; @@ -35,12 +38,16 @@ impl IntoElements for Range { } } +type Lang = String; + +generate_id!(Desc); + #[derive(Debug, Clone)] pub struct File { pub date: Option>, pub media_type: Option, pub name: Option, - pub desc: Option, + pub descs: BTreeMap, pub size: Option, pub range: Option, pub hashes: Vec, @@ -98,7 +105,7 @@ impl TryFrom for Description { let mut date = None; let mut media_type = None; let mut name = None; - let mut desc = None; + let mut descs = BTreeMap::new(); let mut size = None; let mut range = None; let mut hashes = vec!(); @@ -123,10 +130,11 @@ impl TryFrom for Description { } name = Some(file_payload.text()); } else if file_payload.is("desc", ns::JINGLE_FT) { - if desc.is_some() { - return Err(Error::ParseError("File must not have more than one desc.")); + let lang = get_attr!(file_payload, "xml:lang", default); + let desc = Desc(file_payload.text()); + if descs.insert(lang, desc).is_some() { + return Err(Error::ParseError("Desc element present twice for the same xml:lang.")); } - desc = Some(file_payload.text()); } else if file_payload.is("size", ns::JINGLE_FT) { if size.is_some() { return Err(Error::ParseError("File must not have more than one size.")); @@ -163,7 +171,7 @@ impl TryFrom for Description { date: date, media_type: media_type, name: name, - desc: desc, + descs: descs, size: size, range: range, hashes: hashes, @@ -195,10 +203,11 @@ impl From for Element { .append(name) .build()); } - if let Some(desc) = file.desc { + for (lang, desc) in file.descs.into_iter() { root.append_child(Element::builder("desc") .ns(ns::JINGLE_FT) - .append(desc) + .attr("xml:lang", lang) + .append(desc.0) .build()); } if let Some(size) = file.size { @@ -250,11 +259,10 @@ mod tests { "#.parse().unwrap(); - let desc = Description::try_from(elem).unwrap(); assert_eq!(desc.file.media_type, Some(String::from("text/plain"))); assert_eq!(desc.file.name, Some(String::from("test.txt"))); - assert_eq!(desc.file.desc, None); + assert_eq!(desc.file.descs, BTreeMap::new()); assert_eq!(desc.file.date, Some(DateTime::parse_from_rfc3339("2015-07-26T21:46:00+01:00").unwrap())); assert_eq!(desc.file.size, Some(6144u64)); assert_eq!(desc.file.range, None); @@ -272,15 +280,51 @@ mod tests { "#.parse().unwrap(); - let desc = Description::try_from(elem).unwrap(); assert_eq!(desc.file.media_type, None); assert_eq!(desc.file.name, None); - assert_eq!(desc.file.desc, None); + assert_eq!(desc.file.descs, BTreeMap::new()); assert_eq!(desc.file.date, None); assert_eq!(desc.file.size, None); assert_eq!(desc.file.range, None); assert_eq!(desc.file.hashes[0].algo, Algo::Sha_1); assert_eq!(desc.file.hashes[0].hash, base64::decode("w0mcJylzCn+AfvuGdqkty2+KP48=").unwrap()); } + + #[test] + fn test_descs() { + let elem: Element = r#" + + + text/plain + Fichier secret ! + Secret file! + w0mcJylzCn+AfvuGdqkty2+KP48= + + +"#.parse().unwrap(); + let desc = Description::try_from(elem).unwrap(); + assert_eq!(desc.file.descs.keys().cloned().collect::>(), ["en", "fr"]); + assert_eq!(desc.file.descs["en"], Desc(String::from("Secret file!"))); + assert_eq!(desc.file.descs["fr"], Desc(String::from("Fichier secret !"))); + + let elem: Element = r#" + + + text/plain + Fichier secret ! + Secret file! + w0mcJylzCn+AfvuGdqkty2+KP48= + + +"#.parse().unwrap(); + let error = Description::try_from(elem).unwrap_err(); + let message = match error { + Error::ParseError(string) => string, + _ => panic!(), + }; + assert_eq!(message, "Desc element present twice for the same xml:lang."); + } }