diff --git a/src/dav/encoder.rs b/src/dav/encoder.rs index 745c396..c0a5332 100644 --- a/src/dav/encoder.rs +++ b/src/dav/encoder.rs @@ -640,16 +640,20 @@ impl QWrite for Violation { #[cfg(test)] mod tests { use super::*; + use crate::dav::realization::Core; use tokio::io::AsyncWriteExt; /// To run only the unit tests and avoid the behavior ones: /// cargo test --bin aerogramme - async fn serialize>(ctx: C, elem: &Q) -> String { + async fn serialize(elem: &impl QWrite) -> String { let mut buffer = Vec::new(); let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer); - let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4); - elem.write(&mut writer, ctx).await.expect("xml serialization"); + let q = quick_xml::writer::Writer::new_with_indent(&mut tokio_buffer, b' ', 4); + let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()) ]; + let mut writer = Writer { q, ns_to_apply }; + + elem.qwrite(&mut writer).await.expect("xml serialization"); tokio_buffer.flush().await.expect("tokio buffer flush"); let got = std::str::from_utf8(buffer.as_slice()).unwrap(); @@ -660,20 +664,17 @@ mod tests { async fn basic_href() { let got = serialize( - NoExtension { root: false }, &Href("/SOGo/dav/so/".into()) ).await; - let expected = "/SOGo/dav/so/"; + let expected = r#"/SOGo/dav/so/"#; - assert_eq!(&got, expected); + assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } - #[tokio::test] async fn basic_multistatus() { let got = serialize( - NoExtension { root: true }, - &Multistatus { + &Multistatus:: { responses: vec![], responsedescription: Some(ResponseDescription("Hello world".into())) }, @@ -683,15 +684,14 @@ mod tests { Hello world "#; - assert_eq!(&got, expected); + assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } #[tokio::test] async fn rfc_error_delete_locked() { let got = serialize( - NoExtension { root: true }, - &Error(vec![ + &Error::(vec![ Violation::LockTokenSubmitted(vec![ Href("/locked/".into()) ]) @@ -704,28 +704,26 @@ mod tests { "#; - assert_eq!(&got, expected); + assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } #[tokio::test] async fn rfc_propname_req() { let got = serialize( - NoExtension { root: true }, - &PropFind::PropName, + &PropFind::::PropName, ).await; let expected = r#" "#; - assert_eq!(&got, expected); + assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } #[tokio::test] async fn rfc_propname_res() { let got = serialize( - NoExtension { root: true }, - &Multistatus { + &Multistatus:: { responses: vec![ Response { href: Href("http://www.example.com/container/".into()), @@ -808,8 +806,7 @@ mod tests { #[tokio::test] async fn rfc_allprop_req() { let got = serialize( - NoExtension { root: true }, - &PropFind::AllProp(None), + &PropFind::::AllProp(None), ).await; let expected = r#" @@ -823,8 +820,7 @@ mod tests { async fn rfc_allprop_res() { use chrono::{DateTime,FixedOffset,TimeZone}; let got = serialize( - NoExtension { root: true }, - &Multistatus { + &Multistatus:: { responses: vec![ Response { href: Href("/container/".into()), @@ -966,12 +962,10 @@ mod tests { assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); } - #[tokio::test] async fn rfc_allprop_include() { let got = serialize( - NoExtension { root: true }, - &PropFind::AllProp(Some(Include(vec![ + &PropFind::::AllProp(Some(Include(vec![ PropertyRequest::DisplayName, PropertyRequest::ResourceType, ]))), @@ -991,8 +985,7 @@ mod tests { #[tokio::test] async fn rfc_propertyupdate() { let got = serialize( - NoExtension { root: true }, - &PropertyUpdate(vec![ + &PropertyUpdate::(vec![ PropertyUpdateItem::Set(Set(PropValue(vec![ Property::GetContentLanguage("fr-FR".into()), ]))), @@ -1021,8 +1014,7 @@ mod tests { #[tokio::test] async fn rfc_delete_locked2() { let got = serialize( - NoExtension { root: true }, - &Multistatus { + &Multistatus:: { responses: vec![Response { href: Href("http://www.example.com/container/resource3".into()), status_or_propstat: StatusOrPropstat::Status(Status(http::status::StatusCode::from_u16(423).unwrap())), @@ -1050,7 +1042,6 @@ mod tests { #[tokio::test] async fn rfc_simple_lock_request() { let got = serialize( - NoExtension { root: true }, &LockInfo { lockscope: LockScope::Exclusive, locktype: LockType::Write, @@ -1076,8 +1067,7 @@ mod tests { #[tokio::test] async fn rfc_simple_lock_response() { let got = serialize( - NoExtension { root: true }, - &PropValue(vec![ + &PropValue::(vec![ Property::LockDiscovery(vec![ActiveLock { lockscope: LockScope::Exclusive, locktype: LockType::Write, diff --git a/src/dav/xml.rs b/src/dav/xml.rs index 777f99e..495c9a5 100644 --- a/src/dav/xml.rs +++ b/src/dav/xml.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use tokio::io::{AsyncWrite, AsyncBufRead}; use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*}; @@ -21,7 +20,7 @@ pub trait QRead { /// Transform a Rust object into an XML stream of characters pub struct Writer { pub q: quick_xml::writer::Writer, - root: bool, + pub ns_to_apply: Vec<(String, String)>, } impl Writer { pub fn create_dav_element(&mut self, name: &str) -> BytesStart<'static> { @@ -33,11 +32,9 @@ impl Writer { fn create_ns_element(&mut self, ns: &str, name: &str) -> BytesStart<'static> { let mut start = BytesStart::new(format!("{}:{}", ns, name)); - //@FIXME not what we want - if self.root { - start.push_attribute(("xmlns:D", "DAV:")); - start.push_attribute(("xmlns:C", "urn:ietf:params:xml:ns:caldav")); - self.root = false; + if !self.ns_to_apply.is_empty() { + start.extend_attributes(self.ns_to_apply.iter().map(|(k, n)| (k.as_str(), n.as_str()))); + self.ns_to_apply.clear() } start }