From 61a8c32af45f4129a76027ac6abd536de5f5240e Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:22:04 +0100 Subject: [PATCH] add some more propfind regression tests --- Cargo.lock | 1 + crates/caldav/Cargo.toml | 1 + ...dav__principal__tests__propfind-2.snap.new | 137 ++++++++++++++++ ...dav__principal__tests__propfind-3.snap.new | 54 +++++++ ...aldav__principal__tests__propfind.snap.new | 9 ++ crates/caldav/src/principal/tests.rs | 8 +- crates/carddav/src/addressbook/mod.rs | 2 + crates/carddav/src/addressbook/prop.rs | 4 +- ...rddav__addressbook__tests__propfind-2.snap | 151 ++++++++++++++++++ ...rddav__addressbook__tests__propfind-3.snap | 59 +++++++ ...carddav__addressbook__tests__propfind.snap | 8 + crates/carddav/src/addressbook/tests.rs | 49 ++++++ crates/dav/src/extensions/synctoken.rs | 2 +- crates/dav_push/src/extension.rs | 2 +- crates/dav_push/src/prop.rs | 2 +- 15 files changed, 481 insertions(+), 8 deletions(-) create mode 100644 crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-2.snap.new create mode 100644 crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-3.snap.new create mode 100644 crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind.snap.new create mode 100644 crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-2.snap create mode 100644 crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-3.snap create mode 100644 crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind.snap create mode 100644 crates/carddav/src/addressbook/tests.rs diff --git a/Cargo.lock b/Cargo.lock index d876697..ae48c8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3115,6 +3115,7 @@ dependencies = [ "headers", "http", "ical", + "insta", "percent-encoding", "quick-xml", "rstest", diff --git a/crates/caldav/Cargo.toml b/crates/caldav/Cargo.toml index d73176d..ac3a37b 100644 --- a/crates/caldav/Cargo.toml +++ b/crates/caldav/Cargo.toml @@ -13,6 +13,7 @@ rustical_store_sqlite = { workspace = true, features = ["test"] } rstest.workspace = true async-std.workspace = true serde_json.workspace = true +insta.workspace = true [dependencies] axum.workspace = true diff --git a/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-2.snap.new b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-2.snap.new new file mode 100644 index 0000000..63e8965 --- /dev/null +++ b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-2.snap.new @@ -0,0 +1,137 @@ +--- +source: crates/caldav/src/principal/tests.rs +assertion_line: 92 +expression: response +--- +ResponseElement { + href: "/caldav/principal/user/", + status: None, + propstat: [ + Normal( + PropstatElement { + prop: PropTagWrapper( + [ + Principal( + CalendarUserType( + Individual, + ), + ), + Principal( + CalendarUserAddressSet( + HrefElement { + href: "/caldav/principal/user/", + }, + ), + ), + Principal( + PrincipalUrl( + HrefElement { + href: "/caldav/principal/user/", + }, + ), + ), + Principal( + GroupMembership( + GroupMembership( + [ + HrefElement { + href: "/caldav/principal/group/", + }, + ], + ), + ), + ), + Principal( + GroupMemberSet( + GroupMemberSet( + [], + ), + ), + ), + Principal( + AlternateUriSet, + ), + Principal( + SupportedReportSet( + SupportedReportSet { + supported_report: [ + ReportWrapper { + report: PrincipalMatch, + }, + ], + }, + ), + ), + Principal( + CalendarHomeSet( + CalendarHomeSet( + [ + HrefElement { + href: "/caldav/principal/group/", + }, + HrefElement { + href: "/caldav/principal/user/", + }, + ], + ), + ), + ), + Common( + Resourcetype( + Resourcetype( + [ + ResourcetypeInner( + Some( + Namespace("DAV:"), + ), + "collection", + ), + ResourcetypeInner( + Some( + Namespace("DAV:"), + ), + "principal", + ), + ], + ), + ), + ), + Common( + Displayname( + Some( + "user", + ), + ), + ), + Common( + CurrentUserPrincipal( + HrefElement { + href: "/caldav/principal/user/", + }, + ), + ), + Common( + CurrentUserPrivilegeSet( + UserPrivilegeSet { + privileges: { + All, + }, + }, + ), + ), + Common( + Owner( + Some( + HrefElement { + href: "/caldav/principal/user/", + }, + ), + ), + ), + ], + ), + status: 200, + }, + ), + ], +} diff --git a/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-3.snap.new b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-3.snap.new new file mode 100644 index 0000000..2c539be --- /dev/null +++ b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind-3.snap.new @@ -0,0 +1,54 @@ +--- +source: crates/caldav/src/principal/tests.rs +assertion_line: 93 +expression: response.serialize_to_string().unwrap() +--- + + + /caldav/principal/user/ + + + INDIVIDUAL + + /caldav/principal/user/ + + + /caldav/principal/user/ + + + /caldav/principal/group/ + + + + + + + + + + + + + /caldav/principal/group/ + /caldav/principal/user/ + + + + + + user + + /caldav/principal/user/ + + + + + + + + /caldav/principal/user/ + + + HTTP/1.1 200 OK + + diff --git a/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind.snap.new b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind.snap.new new file mode 100644 index 0000000..af92dd2 --- /dev/null +++ b/crates/caldav/src/principal/snapshots/rustical_caldav__principal__tests__propfind.snap.new @@ -0,0 +1,9 @@ +--- +source: crates/caldav/src/principal/tests.rs +assertion_line: 66 +expression: propfind +--- +PropfindElement { + prop: Allprop, + include: None, +} diff --git a/crates/caldav/src/principal/tests.rs b/crates/caldav/src/principal/tests.rs index 5bd3dac..75ac6c0 100644 --- a/crates/caldav/src/principal/tests.rs +++ b/crates/caldav/src/principal/tests.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use crate::{ CalDavPrincipalUri, principal::{PrincipalResource, PrincipalResourceService}, @@ -14,6 +12,7 @@ use rustical_store_sqlite::{ tests::{get_test_calendar_store, get_test_principal_store, get_test_subscription_store}, }; use rustical_xml::XmlSerializeRoot; +use std::sync::Arc; #[rstest] #[tokio::test] @@ -64,6 +63,8 @@ async fn test_propfind() { ) .unwrap(); + insta::assert_debug_snapshot!(propfind); + let principal = Principal { id: "user".to_string(), displayname: None, @@ -88,5 +89,6 @@ async fn test_propfind() { ) .unwrap(); - let _output = response.serialize_to_string().unwrap(); + insta::assert_debug_snapshot!(response); + insta::assert_snapshot!(response.serialize_to_string().unwrap()); } diff --git a/crates/carddav/src/addressbook/mod.rs b/crates/carddav/src/addressbook/mod.rs index f9a4117..5aa536e 100644 --- a/crates/carddav/src/addressbook/mod.rs +++ b/crates/carddav/src/addressbook/mod.rs @@ -3,3 +3,5 @@ pub mod prop; pub mod resource; mod service; pub use service::*; +#[cfg(test)] +pub mod tests; diff --git a/crates/carddav/src/addressbook/prop.rs b/crates/carddav/src/addressbook/prop.rs index 48165a2..898b01c 100644 --- a/crates/carddav/src/addressbook/prop.rs +++ b/crates/carddav/src/addressbook/prop.rs @@ -6,7 +6,7 @@ use rustical_dav_push::DavPushExtensionProp; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use strum_macros::VariantArray; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName, Debug)] #[xml(unit_variants_ident = "AddressbookPropName")] pub enum AddressbookProp { // CardDAV (RFC 6352) @@ -20,7 +20,7 @@ pub enum AddressbookProp { MaxResourceSize(i64), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName, Debug)] #[xml(unit_variants_ident = "AddressbookPropWrapperName", untagged)] pub enum AddressbookPropWrapper { Addressbook(AddressbookProp), diff --git a/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-2.snap b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-2.snap new file mode 100644 index 0000000..93499b2 --- /dev/null +++ b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-2.snap @@ -0,0 +1,151 @@ +--- +source: crates/carddav/src/addressbook/tests.rs +expression: response +--- +ResponseElement { + href: "/carddav/principal/user/yeet/", + status: None, + propstat: [ + Normal( + PropstatElement { + prop: PropTagWrapper( + [ + Addressbook( + AddressbookDescription( + None, + ), + ), + Addressbook( + SupportedAddressData( + SupportedAddressData { + address_data_type: [ + AddressDataType { + content_type: "text/vcard", + version: "3.0", + }, + AddressDataType { + content_type: "text/vcard", + version: "4.0", + }, + ], + }, + ), + ), + Addressbook( + SupportedReportSet( + SupportedReportSet { + supported_report: [ + ReportWrapper { + report: AddressbookMultiget, + }, + ReportWrapper { + report: SyncCollection, + }, + ], + }, + ), + ), + Addressbook( + MaxResourceSize( + 10000000, + ), + ), + SyncToken( + SyncToken( + "github.com/lennart-k/rustical/ns/0", + ), + ), + SyncToken( + Getctag( + "github.com/lennart-k/rustical/ns/0", + ), + ), + DavPush( + Transports( + Transports { + transports: [ + WebPush, + ], + }, + ), + ), + DavPush( + Topic( + "asdasd", + ), + ), + DavPush( + SupportedTriggers( + SupportedTriggers( + [ + ContentUpdate( + ContentUpdate( + One, + ), + ), + PropertyUpdate( + PropertyUpdate( + One, + ), + ), + ], + ), + ), + ), + Common( + Resourcetype( + Resourcetype( + [ + ResourcetypeInner( + Some( + Namespace("DAV:"), + ), + "collection", + ), + ResourcetypeInner( + Some( + Namespace("urn:ietf:params:xml:ns:carddav"), + ), + "addressbook", + ), + ], + ), + ), + ), + Common( + Displayname( + None, + ), + ), + Common( + CurrentUserPrincipal( + HrefElement { + href: "/carddav/principal/user/", + }, + ), + ), + Common( + CurrentUserPrivilegeSet( + UserPrivilegeSet { + privileges: { + All, + }, + }, + ), + ), + Common( + Owner( + Some( + HrefElement { + href: "/carddav/principal/user/", + }, + ), + ), + ), + ], + ), + status: 200, + }, + ), + ], +} diff --git a/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-3.snap b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-3.snap new file mode 100644 index 0000000..d58d2c2 --- /dev/null +++ b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind-3.snap @@ -0,0 +1,59 @@ +--- +source: crates/carddav/src/addressbook/tests.rs +expression: response.serialize_to_string().unwrap() +--- + + + /carddav/principal/user/yeet/ + + + + + + + + + + + + + + + + + + + 10000000 + github.com/lennart-k/rustical/ns/0 + github.com/lennart-k/rustical/ns/0 + + + + asdasd + + + 1 + + + 1 + + + + + + + + /carddav/principal/user/ + + + + + + + + /carddav/principal/user/ + + + HTTP/1.1 200 OK + + diff --git a/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind.snap b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind.snap new file mode 100644 index 0000000..c00515d --- /dev/null +++ b/crates/carddav/src/addressbook/snapshots/rustical_carddav__addressbook__tests__propfind.snap @@ -0,0 +1,8 @@ +--- +source: crates/carddav/src/addressbook/tests.rs +expression: propfind +--- +PropfindElement { + prop: Allprop, + include: None, +} diff --git a/crates/carddav/src/addressbook/tests.rs b/crates/carddav/src/addressbook/tests.rs new file mode 100644 index 0000000..8f49faf --- /dev/null +++ b/crates/carddav/src/addressbook/tests.rs @@ -0,0 +1,49 @@ +use crate::{CardDavPrincipalUri, addressbook::resource::AddressbookResource}; +use rustical_dav::resource::Resource; +use rustical_store::{Addressbook, auth::Principal}; +use rustical_xml::XmlSerializeRoot; + +#[test] +fn test_propfind() { + let propfind = AddressbookResource::parse_propfind( + r#""#, + ) + .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 addressbook = Addressbook { + id: "yeet".to_string(), + principal: "user".to_string(), + displayname: None, + description: None, + deleted_at: None, + synctoken: 0, + push_topic: "asdasd".to_string(), + }; + + let resource = AddressbookResource(addressbook.clone()); + let response = resource + .propfind( + &format!( + "/carddav/principal/{}/{}", + addressbook.principal, addressbook.id + ), + &propfind.prop, + propfind.include.as_ref(), + &CardDavPrincipalUri("/carddav"), + &principal, + ) + .unwrap(); + + insta::assert_debug_snapshot!(response); + insta::assert_snapshot!(response.serialize_to_string().unwrap()); +} diff --git a/crates/dav/src/extensions/synctoken.rs b/crates/dav/src/extensions/synctoken.rs index a75d1c4..6d90c43 100644 --- a/crates/dav/src/extensions/synctoken.rs +++ b/crates/dav/src/extensions/synctoken.rs @@ -1,6 +1,6 @@ use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants, Debug)] #[xml(unit_variants_ident = "SyncTokenExtensionPropName")] pub enum SyncTokenExtensionProp { // Collection Synchronization (RFC 6578) diff --git a/crates/dav_push/src/extension.rs b/crates/dav_push/src/extension.rs index 781b05e..a3901e7 100644 --- a/crates/dav_push/src/extension.rs +++ b/crates/dav_push/src/extension.rs @@ -2,7 +2,7 @@ use crate::{ContentUpdate, PropertyUpdate, SupportedTriggers, Transports, Trigge use rustical_dav::header::Depth; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants, Debug)] #[xml(unit_variants_ident = "DavPushExtensionPropName")] pub enum DavPushExtensionProp { // WebDav Push diff --git a/crates/dav_push/src/prop.rs b/crates/dav_push/src/prop.rs index fd681a0..ee3dd4e 100644 --- a/crates/dav_push/src/prop.rs +++ b/crates/dav_push/src/prop.rs @@ -22,7 +22,7 @@ impl Default for Transports { } } -#[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Clone)] +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Clone, Debug)] pub struct SupportedTriggers(#[xml(flatten, ty = "untagged")] pub Vec); #[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Debug, Clone)]