mirror of
https://github.com/lennart-k/rustical.git
synced 2026-01-30 04:38:19 +00:00
carddav: Try out some tests with insta
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1789,6 +1789,17 @@ version = "0.1.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
|
checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "insta"
|
||||||
|
version = "1.44.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"once_cell",
|
||||||
|
"similar",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
@@ -3142,6 +3153,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"ical",
|
"ical",
|
||||||
|
"insta",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"rustical_dav",
|
"rustical_dav",
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ ece = { version = "2.3", default-features = false, features = [
|
|||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
async-std = { version = "1.13", features = ["attributes"] }
|
async-std = { version = "1.13", features = ["attributes"] }
|
||||||
similar-asserts = "1.7"
|
similar-asserts = "1.7"
|
||||||
|
insta = "1.44"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustical_store.workspace = true
|
rustical_store.workspace = true
|
||||||
|
|||||||
@@ -35,3 +35,6 @@ percent-encoding.workspace = true
|
|||||||
ical.workspace = true
|
ical.workspace = true
|
||||||
strum.workspace = true
|
strum.workspace = true
|
||||||
strum_macros.workspace = true
|
strum_macros.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
insta.workspace = true
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ mod service;
|
|||||||
pub use service::*;
|
pub use service::*;
|
||||||
mod prop;
|
mod prop;
|
||||||
pub use prop::*;
|
pub use prop::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PrincipalResource {
|
pub struct PrincipalResource {
|
||||||
principal: Principal,
|
pub principal: Principal,
|
||||||
members: Vec<String>,
|
pub members: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResourceName for PrincipalResource {
|
impl ResourceName for PrincipalResource {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use rustical_dav::{
|
|||||||
};
|
};
|
||||||
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName, Debug)]
|
||||||
#[xml(unit_variants_ident = "PrincipalPropName")]
|
#[xml(unit_variants_ident = "PrincipalPropName")]
|
||||||
pub enum PrincipalProp {
|
pub enum PrincipalProp {
|
||||||
// WebDAV Access Control (RFC 3744)
|
// WebDAV Access Control (RFC 3744)
|
||||||
@@ -27,10 +27,10 @@ pub enum PrincipalProp {
|
|||||||
PrincipalAddress(Option<HrefElement>),
|
PrincipalAddress(Option<HrefElement>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct AddressbookHomeSet(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
pub struct AddressbookHomeSet(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName, Debug)]
|
||||||
#[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)]
|
#[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)]
|
||||||
pub enum PrincipalPropWrapper {
|
pub enum PrincipalPropWrapper {
|
||||||
Principal(PrincipalProp),
|
Principal(PrincipalProp),
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
source: crates/carddav/src/principal/tests.rs
|
||||||
|
expression: response
|
||||||
|
---
|
||||||
|
ResponseElement {
|
||||||
|
href: "/carddav/principal/user/",
|
||||||
|
status: None,
|
||||||
|
propstat: [
|
||||||
|
Normal(
|
||||||
|
PropstatElement {
|
||||||
|
prop: PropTagWrapper(
|
||||||
|
[
|
||||||
|
Principal(
|
||||||
|
PrincipalUrl(
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/user/",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
GroupMembership(
|
||||||
|
GroupMembership(
|
||||||
|
[
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/group/",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
GroupMemberSet(
|
||||||
|
GroupMemberSet(
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
AlternateUriSet,
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
PrincipalCollectionSet(
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
AddressbookHomeSet(
|
||||||
|
AddressbookHomeSet(
|
||||||
|
[
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/group/",
|
||||||
|
},
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/user/",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Principal(
|
||||||
|
PrincipalAddress(
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Common(
|
||||||
|
Resourcetype(
|
||||||
|
Resourcetype(
|
||||||
|
[
|
||||||
|
ResourcetypeInner(
|
||||||
|
Some(
|
||||||
|
Namespace("DAV:"),
|
||||||
|
),
|
||||||
|
"collection",
|
||||||
|
),
|
||||||
|
ResourcetypeInner(
|
||||||
|
Some(
|
||||||
|
Namespace("DAV:"),
|
||||||
|
),
|
||||||
|
"principal",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Common(
|
||||||
|
Displayname(
|
||||||
|
Some(
|
||||||
|
"user",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Common(
|
||||||
|
CurrentUserPrincipal(
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/user/",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Common(
|
||||||
|
CurrentUserPrivilegeSet(
|
||||||
|
UserPrivilegeSet {
|
||||||
|
privileges: {
|
||||||
|
All,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Common(
|
||||||
|
Owner(
|
||||||
|
Some(
|
||||||
|
HrefElement {
|
||||||
|
href: "/carddav/principal/user/",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
source: crates/carddav/src/principal/tests.rs
|
||||||
|
expression: response.serialize_to_string().unwrap()
|
||||||
|
---
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<response xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
<propstat>
|
||||||
|
<prop>
|
||||||
|
<principal-URL>
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
</principal-URL>
|
||||||
|
<group-membership>
|
||||||
|
<href>/carddav/principal/group/</href>
|
||||||
|
</group-membership>
|
||||||
|
<group-member-set>
|
||||||
|
</group-member-set>
|
||||||
|
<alternate-URI-set/>
|
||||||
|
<principal-collection-set>
|
||||||
|
<href>/carddav/principal/</href>
|
||||||
|
</principal-collection-set>
|
||||||
|
<CARD:addressbook-home-set>
|
||||||
|
<href>/carddav/principal/group/</href>
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
</CARD:addressbook-home-set>
|
||||||
|
<resourcetype>
|
||||||
|
<collection/>
|
||||||
|
<principal/>
|
||||||
|
</resourcetype>
|
||||||
|
<displayname>user</displayname>
|
||||||
|
<current-user-principal>
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
</current-user-principal>
|
||||||
|
<current-user-privilege-set>
|
||||||
|
<privilege>
|
||||||
|
<all/>
|
||||||
|
</privilege>
|
||||||
|
</current-user-privilege-set>
|
||||||
|
<owner>
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
</owner>
|
||||||
|
</prop>
|
||||||
|
<status>HTTP/1.1 200 OK</status>
|
||||||
|
</propstat>
|
||||||
|
</response>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
source: crates/carddav/src/principal/tests.rs
|
||||||
|
expression: propfind
|
||||||
|
---
|
||||||
|
PropfindElement {
|
||||||
|
prop: Allprop,
|
||||||
|
include: None,
|
||||||
|
}
|
||||||
41
crates/carddav/src/principal/tests.rs
Normal file
41
crates/carddav/src/principal/tests.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
use rustical_dav::resource::Resource;
|
||||||
|
use rustical_store::auth::Principal;
|
||||||
|
use rustical_xml::XmlSerializeRoot;
|
||||||
|
|
||||||
|
use crate::{CardDavPrincipalUri, principal::PrincipalResource};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_propfind() {
|
||||||
|
let propfind = PrincipalResource::parse_propfind(
|
||||||
|
r#"<?xml version="1.0" encoding="UTF-8"?><propfind xmlns="DAV:"><allprop/></propfind>"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
insta::assert_debug_snapshot!(propfind);
|
||||||
|
|
||||||
|
let principal = Principal {
|
||||||
|
id: "user".to_string(),
|
||||||
|
displayname: None,
|
||||||
|
principal_type: rustical_store::auth::PrincipalType::Individual,
|
||||||
|
password: None,
|
||||||
|
memberships: vec!["group".to_string()],
|
||||||
|
};
|
||||||
|
|
||||||
|
let resource = PrincipalResource {
|
||||||
|
principal: principal.clone(),
|
||||||
|
members: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = resource
|
||||||
|
.propfind(
|
||||||
|
&format!("/carddav/principal/{}", principal.id),
|
||||||
|
&propfind.prop,
|
||||||
|
propfind.include.as_ref(),
|
||||||
|
&CardDavPrincipalUri("/carddav"),
|
||||||
|
&principal,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
insta::assert_debug_snapshot!(response);
|
||||||
|
insta::assert_snapshot!(response.serialize_to_string().unwrap());
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Debug, Clone, PropName, EnumVariants)]
|
||||||
#[xml(unit_variants_ident = "CommonPropertiesPropName")]
|
#[xml(unit_variants_ident = "CommonPropertiesPropName")]
|
||||||
pub enum CommonPropertiesProp {
|
pub enum CommonPropertiesProp {
|
||||||
// WebDAV (RFC 2518)
|
// WebDAV (RFC 2518)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::xml::HrefElement;
|
use crate::xml::HrefElement;
|
||||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
||||||
|
|
||||||
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)]
|
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub Vec<HrefElement>);
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use headers::{CacheControl, ContentType, HeaderMapExt};
|
|||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use quick_xml::name::Namespace;
|
use quick_xml::name::Namespace;
|
||||||
use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot};
|
use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot};
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
#[derive(XmlSerialize)]
|
#[derive(XmlSerialize, Debug)]
|
||||||
pub struct PropTagWrapper<T: XmlSerialize>(#[xml(flatten, ty = "untagged")] pub Vec<T>);
|
pub struct PropTagWrapper<T: XmlSerialize>(#[xml(flatten, ty = "untagged")] pub Vec<T>);
|
||||||
|
|
||||||
// RFC 2518
|
// RFC 2518
|
||||||
@@ -30,7 +30,7 @@ fn xml_serialize_status(
|
|||||||
XmlSerialize::serialize(&format!("HTTP/1.1 {status}"), ns, tag, namespaces, writer)
|
XmlSerialize::serialize(&format!("HTTP/1.1 {status}"), ns, tag, namespaces, writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(XmlSerialize)]
|
#[derive(XmlSerialize, Debug)]
|
||||||
#[xml(untagged)]
|
#[xml(untagged)]
|
||||||
pub enum PropstatWrapper<T: XmlSerialize> {
|
pub enum PropstatWrapper<T: XmlSerialize> {
|
||||||
Normal(PropstatElement<PropTagWrapper<T>>),
|
Normal(PropstatElement<PropTagWrapper<T>>),
|
||||||
@@ -40,7 +40,7 @@ pub enum PropstatWrapper<T: XmlSerialize> {
|
|||||||
// RFC 2518
|
// RFC 2518
|
||||||
// <!ELEMENT response (href, ((href*, status)|(propstat+)),
|
// <!ELEMENT response (href, ((href*, status)|(propstat+)),
|
||||||
// responsedescription?) >
|
// responsedescription?) >
|
||||||
#[derive(XmlSerialize, XmlRootTag)]
|
#[derive(XmlSerialize, XmlRootTag, Debug)]
|
||||||
#[xml(ns = "crate::namespace::NS_DAV", root = "response")]
|
#[xml(ns = "crate::namespace::NS_DAV", root = "response")]
|
||||||
#[xml(ns_prefix(
|
#[xml(ns_prefix(
|
||||||
crate::namespace::NS_DAV = "",
|
crate::namespace::NS_DAV = "",
|
||||||
|
|||||||
Reference in New Issue
Block a user