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)]