propname tests

This commit is contained in:
Quentin 2024-03-01 15:32:40 +01:00
parent 2b30c97084
commit c15f8856a8
Signed by: quentin
GPG key ID: E9602264D639FF68
2 changed files with 165 additions and 23 deletions

View file

@ -61,6 +61,7 @@ impl<C: Context> QuickWritable<C> for PropFind<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("propfind"); let start = ctx.create_dav_element("propfind");
let end = start.to_end(); let end = start.to_end();
let ctx = ctx.child();
xml.write_event_async(Event::Start(start.clone())).await?; xml.write_event_async(Event::Start(start.clone())).await?;
match self { match self {
@ -129,9 +130,18 @@ impl<C: Context> QuickWritable<C> for Prop<C> {
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.write_event_async(Event::Start(start.clone())).await?;
for property in &self.0 { match self {
property.write(xml, ctx.child()).await?; Self::Name(many_names) => {
for propname in many_names {
propname.write(xml, ctx.child()).await?;
} }
},
Self::Value(many_values) => {
for propval in many_values {
propval.write(xml, ctx.child()).await?;
}
}
};
xml.write_event_async(Event::End(end)).await?; xml.write_event_async(Event::End(end)).await?;
Ok(()) Ok(())
@ -154,7 +164,7 @@ impl<C: Context> QuickWritable<C> for Href {
impl<C: Context> QuickWritable<C> for Response<C> { impl<C: Context> QuickWritable<C> for Response<C> {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("href"); let start = ctx.create_dav_element("response");
let end = start.to_end(); let end = start.to_end();
xml.write_event_async(Event::Start(start.clone())).await?; xml.write_event_async(Event::Start(start.clone())).await?;
@ -463,6 +473,7 @@ impl<C: Context> QuickWritable<C> for LockType {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("locktype"); let start = ctx.create_dav_element("locktype");
let end = start.to_end(); let end = start.to_end();
let ctx = ctx.child();
xml.write_event_async(Event::Start(start.clone())).await?; xml.write_event_async(Event::Start(start.clone())).await?;
match self { match self {
@ -476,6 +487,7 @@ impl<C: Context> QuickWritable<C> for LockScope {
async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> { async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
let start = ctx.create_dav_element("lockscope"); let start = ctx.create_dav_element("lockscope");
let end = start.to_end(); let end = start.to_end();
let ctx = ctx.child();
xml.write_event_async(Event::Start(start.clone())).await?; xml.write_event_async(Event::Start(start.clone())).await?;
match self { match self {
@ -627,36 +639,163 @@ mod tests {
/// 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
#[tokio::test] async fn serialize<C: Context, Q: QuickWritable<C>>(ctx: C, elem: &Q) -> String {
async fn test_href() {
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 mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
elem.write(&mut writer, ctx).await.expect("xml serialization");
let ctx = NoExtension { root: false };
Href("/SOGo/dav/so/".into()).write(&mut writer, ctx).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();
assert_eq!(buffer.as_slice(), &b"<D:href>/SOGo/dav/so/</D:href>"[..]); return got.into()
}
#[tokio::test]
async fn basic_href() {
let got = serialize(
NoExtension { root: false },
&Href("/SOGo/dav/so/".into())
).await;
let expected = "<D:href>/SOGo/dav/so/</D:href>";
assert_eq!(&got, expected);
} }
#[tokio::test] #[tokio::test]
async fn test_multistatus() { async fn basic_multistatus() {
let mut buffer = Vec::new(); let got = serialize(
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer); NoExtension { root: true },
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4); &Multistatus {
responses: vec![],
let ctx = NoExtension { root: true }; responsedescription: Some(ResponseDescription("Hello world".into()))
let xml = Multistatus { responses: vec![], responsedescription: Some(ResponseDescription("Hello world".into())) }; },
xml.write(&mut writer, ctx).await.expect("xml serialization"); ).await;
tokio_buffer.flush().await.expect("tokio buffer flush");
let expected = r#"<D:multistatus xmlns:D="DAV:"> let expected = r#"<D:multistatus xmlns:D="DAV:">
<D:responsedescription>Hello world</D:responsedescription> <D:responsedescription>Hello world</D:responsedescription>
</D:multistatus>"#; </D:multistatus>"#;
let got = std::str::from_utf8(buffer.as_slice()).unwrap();
assert_eq!(got, expected); assert_eq!(&got, expected);
}
#[tokio::test]
async fn rfc_error_delete_locked() {
let got = serialize(
NoExtension { root: true },
&Error(vec![
Violation::LockTokenSubmitted(vec![
Href("/locked/".into())
])
]),
).await;
let expected = r#"<D:error xmlns:D="DAV:">
<D:lock-token-submitted>
<D:href>/locked/</D:href>
</D:lock-token-submitted>
</D:error>"#;
assert_eq!(&got, expected);
}
#[tokio::test]
async fn rfc_propname_req() {
let got = serialize(
NoExtension { root: true },
&PropFind::PropName,
).await;
let expected = r#"<D:propfind xmlns:D="DAV:">
<D:propname/>
</D:propfind>"#;
assert_eq!(&got, expected);
}
#[tokio::test]
async fn rfc_propname_res() {
let got = serialize(
NoExtension { root: true },
&Multistatus {
responses: vec![
Response {
href: Href("http://www.example.com/container/".into()),
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat {
prop: Prop::Name(vec![
PropertyRequest::CreationDate,
PropertyRequest::DisplayName,
PropertyRequest::ResourceType,
PropertyRequest::SupportedLock,
]),
status: Status(http::status::StatusCode::OK),
error: None,
responsedescription: None,
}]),
error: None,
responsedescription: None,
location: None,
},
Response {
href: Href("http://www.example.com/container/front.html".into()),
status_or_propstat: StatusOrPropstat::PropStat(vec![PropStat {
prop: Prop::Name(vec![
PropertyRequest::CreationDate,
PropertyRequest::DisplayName,
PropertyRequest::GetContentLength,
PropertyRequest::GetContentType,
PropertyRequest::GetEtag,
PropertyRequest::GetLastModified,
PropertyRequest::ResourceType,
PropertyRequest::SupportedLock,
]),
status: Status(http::status::StatusCode::OK),
error: None,
responsedescription: None,
}]),
error: None,
responsedescription: None,
location: None,
},
],
responsedescription: None,
},
).await;
let expected = r#"<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/container/</D:href>
<D:propstat>
<D:prop>
<D:creationdate/>
<D:displayname/>
<D:resourcetype/>
<D:supportedlock/>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.example.com/container/front.html</D:href>
<D:propstat>
<D:prop>
<D:creationdate/>
<D:displayname/>
<D:getcontentlength/>
<D:getcontenttype/>
<D:getetag/>
<D:getlastmodified/>
<D:resourcetype/>
<D:supportedlock/>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>"#;
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
} }
} }

View file

@ -372,7 +372,10 @@ pub struct Owner {
/// text or mixed content. /// text or mixed content.
/// ///
/// <!ELEMENT prop ANY > /// <!ELEMENT prop ANY >
pub struct Prop<T: Extension>(pub Vec<Property<T>>); pub enum Prop<T: Extension> {
Name(Vec<PropertyRequest<T>>),
Value(Vec<Property<T>>),
}
/// 14.19. propertyupdate XML Element /// 14.19. propertyupdate XML Element
/// ///