Restored WebDAV encoder tests

This commit is contained in:
Quentin 2024-03-05 16:26:15 +01:00
parent 8e5d8a8aaa
commit f376e88c73
Signed by: quentin
GPG key ID: E9602264D639FF68
2 changed files with 26 additions and 39 deletions

View file

@ -640,16 +640,20 @@ impl<E: Extension> QWrite for Violation<E> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::dav::realization::Core;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
/// To run only the unit tests and avoid the behavior ones: /// To run only the unit tests and avoid the behavior ones:
/// cargo test --bin aerogramme /// cargo test --bin aerogramme
async fn serialize<C: Context, Q: QuickWritable<C>>(ctx: C, elem: &Q) -> String { async fn serialize(elem: &impl QWrite) -> String {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer); let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4); let q = quick_xml::writer::Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
elem.write(&mut writer, ctx).await.expect("xml serialization"); 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"); tokio_buffer.flush().await.expect("tokio buffer flush");
let got = std::str::from_utf8(buffer.as_slice()).unwrap(); let got = std::str::from_utf8(buffer.as_slice()).unwrap();
@ -660,20 +664,17 @@ mod tests {
async fn basic_href() { async fn basic_href() {
let got = serialize( let got = serialize(
NoExtension { root: false },
&Href("/SOGo/dav/so/".into()) &Href("/SOGo/dav/so/".into())
).await; ).await;
let expected = "<D:href>/SOGo/dav/so/</D:href>"; let expected = r#"<D:href xmlns:D="DAV:">/SOGo/dav/so/</D:href>"#;
assert_eq!(&got, expected); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
#[tokio::test] #[tokio::test]
async fn basic_multistatus() { async fn basic_multistatus() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &Multistatus::<Core> {
&Multistatus {
responses: vec![], responses: vec![],
responsedescription: Some(ResponseDescription("Hello world".into())) responsedescription: Some(ResponseDescription("Hello world".into()))
}, },
@ -683,15 +684,14 @@ mod tests {
<D:responsedescription>Hello world</D:responsedescription> <D:responsedescription>Hello world</D:responsedescription>
</D:multistatus>"#; </D:multistatus>"#;
assert_eq!(&got, expected); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
#[tokio::test] #[tokio::test]
async fn rfc_error_delete_locked() { async fn rfc_error_delete_locked() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &Error::<Core>(vec![
&Error(vec![
Violation::LockTokenSubmitted(vec![ Violation::LockTokenSubmitted(vec![
Href("/locked/".into()) Href("/locked/".into())
]) ])
@ -704,28 +704,26 @@ mod tests {
</D:lock-token-submitted> </D:lock-token-submitted>
</D:error>"#; </D:error>"#;
assert_eq!(&got, expected); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
#[tokio::test] #[tokio::test]
async fn rfc_propname_req() { async fn rfc_propname_req() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &PropFind::<Core>::PropName,
&PropFind::PropName,
).await; ).await;
let expected = r#"<D:propfind xmlns:D="DAV:"> let expected = r#"<D:propfind xmlns:D="DAV:">
<D:propname/> <D:propname/>
</D:propfind>"#; </D:propfind>"#;
assert_eq!(&got, expected); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
#[tokio::test] #[tokio::test]
async fn rfc_propname_res() { async fn rfc_propname_res() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &Multistatus::<Core> {
&Multistatus {
responses: vec![ responses: vec![
Response { Response {
href: Href("http://www.example.com/container/".into()), href: Href("http://www.example.com/container/".into()),
@ -808,8 +806,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_allprop_req() { async fn rfc_allprop_req() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &PropFind::<Core>::AllProp(None),
&PropFind::AllProp(None),
).await; ).await;
let expected = r#"<D:propfind xmlns:D="DAV:"> let expected = r#"<D:propfind xmlns:D="DAV:">
@ -823,8 +820,7 @@ mod tests {
async fn rfc_allprop_res() { async fn rfc_allprop_res() {
use chrono::{DateTime,FixedOffset,TimeZone}; use chrono::{DateTime,FixedOffset,TimeZone};
let got = serialize( let got = serialize(
NoExtension { root: true }, &Multistatus::<Core> {
&Multistatus {
responses: vec![ responses: vec![
Response { Response {
href: Href("/container/".into()), href: Href("/container/".into()),
@ -966,12 +962,10 @@ mod tests {
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n"); assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
#[tokio::test] #[tokio::test]
async fn rfc_allprop_include() { async fn rfc_allprop_include() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &PropFind::<Core>::AllProp(Some(Include(vec![
&PropFind::AllProp(Some(Include(vec![
PropertyRequest::DisplayName, PropertyRequest::DisplayName,
PropertyRequest::ResourceType, PropertyRequest::ResourceType,
]))), ]))),
@ -991,8 +985,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_propertyupdate() { async fn rfc_propertyupdate() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &PropertyUpdate::<Core>(vec![
&PropertyUpdate(vec![
PropertyUpdateItem::Set(Set(PropValue(vec![ PropertyUpdateItem::Set(Set(PropValue(vec![
Property::GetContentLanguage("fr-FR".into()), Property::GetContentLanguage("fr-FR".into()),
]))), ]))),
@ -1021,8 +1014,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_delete_locked2() { async fn rfc_delete_locked2() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &Multistatus::<Core> {
&Multistatus {
responses: vec![Response { responses: vec![Response {
href: Href("http://www.example.com/container/resource3".into()), href: Href("http://www.example.com/container/resource3".into()),
status_or_propstat: StatusOrPropstat::Status(Status(http::status::StatusCode::from_u16(423).unwrap())), status_or_propstat: StatusOrPropstat::Status(Status(http::status::StatusCode::from_u16(423).unwrap())),
@ -1050,7 +1042,6 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_simple_lock_request() { async fn rfc_simple_lock_request() {
let got = serialize( let got = serialize(
NoExtension { root: true },
&LockInfo { &LockInfo {
lockscope: LockScope::Exclusive, lockscope: LockScope::Exclusive,
locktype: LockType::Write, locktype: LockType::Write,
@ -1076,8 +1067,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn rfc_simple_lock_response() { async fn rfc_simple_lock_response() {
let got = serialize( let got = serialize(
NoExtension { root: true }, &PropValue::<Core>(vec![
&PropValue(vec![
Property::LockDiscovery(vec![ActiveLock { Property::LockDiscovery(vec![ActiveLock {
lockscope: LockScope::Exclusive, lockscope: LockScope::Exclusive,
locktype: LockType::Write, locktype: LockType::Write,

View file

@ -1,4 +1,3 @@
use std::collections::HashMap;
use tokio::io::{AsyncWrite, AsyncBufRead}; use tokio::io::{AsyncWrite, AsyncBufRead};
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText}; use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText};
use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*}; use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*};
@ -21,7 +20,7 @@ pub trait QRead<T> {
/// Transform a Rust object into an XML stream of characters /// Transform a Rust object into an XML stream of characters
pub struct Writer<T: IWrite> { pub struct Writer<T: IWrite> {
pub q: quick_xml::writer::Writer<T>, pub q: quick_xml::writer::Writer<T>,
root: bool, pub ns_to_apply: Vec<(String, String)>,
} }
impl<T: IWrite> Writer<T> { impl<T: IWrite> Writer<T> {
pub fn create_dav_element(&mut self, name: &str) -> BytesStart<'static> { pub fn create_dav_element(&mut self, name: &str) -> BytesStart<'static> {
@ -33,11 +32,9 @@ impl<T: IWrite> Writer<T> {
fn create_ns_element(&mut self, ns: &str, name: &str) -> BytesStart<'static> { fn create_ns_element(&mut self, ns: &str, name: &str) -> BytesStart<'static> {
let mut start = BytesStart::new(format!("{}:{}", ns, name)); let mut start = BytesStart::new(format!("{}:{}", ns, name));
//@FIXME not what we want if !self.ns_to_apply.is_empty() {
if self.root { start.extend_attributes(self.ns_to_apply.iter().map(|(k, n)| (k.as_str(), n.as_str())));
start.push_attribute(("xmlns:D", "DAV:")); self.ns_to_apply.clear()
start.push_attribute(("xmlns:C", "urn:ietf:params:xml:ns:caldav"));
self.root = false;
} }
start start
} }