fixtures: add a contact per BDAY form
Which of these vCard 4.0 and Apple date forms macOS and iOS actually
accept is empirical, and `rake dev` serves this book to a real client.

Assisted-by: Claude Opus 5 via Claude Code
Claude-Session: https://claude.ai/code/session_01SZGjJaJGVMs3w2bohXtcn9
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
change xuztuwuztrsxwoyrylqkxsnoplmropum
commit cadd5873e6ae5ed487c261ea8e489c9457e8c38a
author Alpha Chen <alpha@kejadlen.dev>
date
parent nwymrzou
diff --git a/test/fixtures/cards/bday-basic-noyear.vcf b/test/fixtures/cards/bday-basic-noyear.vcf
new file mode 100644
index 0000000..9dc35dc
--- /dev/null
+++ b/test/fixtures/cards/bday-basic-noyear.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Basic No-Year;;;
+FN:Basic No-Year Birthday
+BDAY:--0412
+UID:bday-basic-noyear
+END:VCARD
diff --git a/test/fixtures/cards/bday-complete.vcf b/test/fixtures/cards/bday-complete.vcf
new file mode 100644
index 0000000..97263ec
--- /dev/null
+++ b/test/fixtures/cards/bday-complete.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Complete;;;
+FN:Complete Birthday
+BDAY:1985-04-12
+UID:bday-complete
+END:VCARD
diff --git a/test/fixtures/cards/bday-datetime.vcf b/test/fixtures/cards/bday-datetime.vcf
new file mode 100644
index 0000000..d64a94d
--- /dev/null
+++ b/test/fixtures/cards/bday-datetime.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Date-Time;;;
+FN:Date-Time Birthday
+BDAY:1985-04-12T23:10:00Z
+UID:bday-datetime
+END:VCARD
diff --git a/test/fixtures/cards/bday-day-only.vcf b/test/fixtures/cards/bday-day-only.vcf
new file mode 100644
index 0000000..1acf866
--- /dev/null
+++ b/test/fixtures/cards/bday-day-only.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Day Only;;;
+FN:Day Only Birthday
+BDAY:---12
+UID:bday-day-only
+END:VCARD
diff --git a/test/fixtures/cards/bday-extended-noyear.vcf b/test/fixtures/cards/bday-extended-noyear.vcf
new file mode 100644
index 0000000..e9087ba
--- /dev/null
+++ b/test/fixtures/cards/bday-extended-noyear.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Extended No-Year;;;
+FN:Extended No-Year Birthday
+BDAY:--04-12
+UID:bday-extended-noyear
+END:VCARD
diff --git a/test/fixtures/cards/bday-omit-year.vcf b/test/fixtures/cards/bday-omit-year.vcf
new file mode 100644
index 0000000..2e6ecdc
--- /dev/null
+++ b/test/fixtures/cards/bday-omit-year.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Omit-Year;;;
+FN:Omit-Year Birthday
+BDAY;X-APPLE-OMIT-YEAR=1604:1604-04-12
+UID:bday-omit-year
+END:VCARD
diff --git a/test/fixtures/cards/bday-year-month.vcf b/test/fixtures/cards/bday-year-month.vcf
new file mode 100644
index 0000000..8e7ef75
--- /dev/null
+++ b/test/fixtures/cards/bday-year-month.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Year-Month;;;
+FN:Year-Month Birthday
+BDAY:1985-04
+UID:bday-year-month
+END:VCARD
diff --git a/test/fixtures/cards/bday-year-only.vcf b/test/fixtures/cards/bday-year-only.vcf
new file mode 100644
index 0000000..3b9ef7d
--- /dev/null
+++ b/test/fixtures/cards/bday-year-only.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Birthday;Year Only;;;
+FN:Year Only Birthday
+BDAY:1985
+UID:bday-year-only
+END:VCARD
diff --git a/test/fixtures/macos-exchange/05-propfind-addressbook-ctag/response b/test/fixtures/macos-exchange/05-propfind-addressbook-ctag/response
index 69507d5..924225b 100644
--- a/test/fixtures/macos-exchange/05-propfind-addressbook-ctag/response
+++ b/test/fixtures/macos-exchange/05-propfind-addressbook-ctag/response
@@ -16,8 +16,8 @@ Content-Type: text/xml
           <d:report><d:sync-collection/></d:report>
         </d:supported-report>
       </d:supported-report-set>
-      <cs:getctag>b42a5c0d98f526c874f2a1d84bcefada2e16f8b8bc89e3c221c16e9170e39809</cs:getctag>
-      <d:sync-token>http://pro-tacts/sync/b42a5c0d98f526c874f2a1d84bcefada2e16f8b8bc89e3c221c16e9170e39809</d:sync-token>
+      <cs:getctag>ef8eddac0927936788c8997a6faedb70b86480fc67475851dcb15013ddc230c9</cs:getctag>
+      <d:sync-token>http://pro-tacts/sync/ef8eddac0927936788c8997a6faedb70b86480fc67475851dcb15013ddc230c9</d:sync-token>
       <d:current-user-privilege-set>
         <d:privilege><d:read/></d:privilege>
         <d:privilege><d:write/></d:privilege>
diff --git a/test/fixtures/macos-exchange/06-propfind-addressbook-listing/response b/test/fixtures/macos-exchange/06-propfind-addressbook-listing/response
index 3cff818..017bece 100644
--- a/test/fixtures/macos-exchange/06-propfind-addressbook-listing/response
+++ b/test/fixtures/macos-exchange/06-propfind-addressbook-listing/response
@@ -22,6 +22,78 @@ Content-Type: text/xml
     <d:status>HTTP/1.1 200 OK</d:status>
   </d:propstat>
 </d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-basic-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"98dbb3374e96a83578e334e9d8c5455721576795724e90f621d11a6b4662bc27"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-complete.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"a4e6b4c955cfcebf3431ab4ab547c64a6bf1983ceba7953a77074ec64c1d6fbd"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-datetime.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"348c560bf1811fc48380fac606cf7198333ae0746c4f5ba8cec7269474b13162"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-day-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"f5c9defba63b13fe74e2ad78270bf609957db631ff701aa9920fcd8aa5d8f28c"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-extended-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"433c9c285186c3a1cee60452295512a7f8e326e7b70c4670c399b235f9300a62"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-omit-year.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"55f079c8ad3ab5fce768ce51eecc2447ab3be4d24dbf84967a2360b780b58f9d"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-month.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"48a1e4a752c132571a33aec08edafe49d2b3b64a4b9658a7a41cac30e8bd7866"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"cc4ef0c4a6d004412a4b7f11dd05d66414204d822c9de0453eaafe164378b53e"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
 <d:response>
   <d:href>/dav/addressbook/oqmvpzooywwmtwwx.vcf</d:href>
   <d:propstat>
diff --git a/test/fixtures/macos-exchange/08-report-sync-collection/response b/test/fixtures/macos-exchange/08-report-sync-collection/response
index 3a7b1e1..4544c7f 100644
--- a/test/fixtures/macos-exchange/08-report-sync-collection/response
+++ b/test/fixtures/macos-exchange/08-report-sync-collection/response
@@ -21,6 +21,78 @@ Content-Type: text/xml
     <d:status>HTTP/1.1 200 OK</d:status>
   </d:propstat>
 </d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-basic-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"98dbb3374e96a83578e334e9d8c5455721576795724e90f621d11a6b4662bc27"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-complete.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"a4e6b4c955cfcebf3431ab4ab547c64a6bf1983ceba7953a77074ec64c1d6fbd"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-datetime.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"348c560bf1811fc48380fac606cf7198333ae0746c4f5ba8cec7269474b13162"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-day-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"f5c9defba63b13fe74e2ad78270bf609957db631ff701aa9920fcd8aa5d8f28c"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-extended-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"433c9c285186c3a1cee60452295512a7f8e326e7b70c4670c399b235f9300a62"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-omit-year.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"55f079c8ad3ab5fce768ce51eecc2447ab3be4d24dbf84967a2360b780b58f9d"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-month.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"48a1e4a752c132571a33aec08edafe49d2b3b64a4b9658a7a41cac30e8bd7866"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"cc4ef0c4a6d004412a4b7f11dd05d66414204d822c9de0453eaafe164378b53e"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
 <d:response>
   <d:href>/dav/addressbook/oqmvpzooywwmtwwx.vcf</d:href>
   <d:propstat>
diff --git a/test/fixtures/macos-exchange/09-propfind-addressbook-bootstrap/response b/test/fixtures/macos-exchange/09-propfind-addressbook-bootstrap/response
index b5c9a46..3d63a5f 100644
--- a/test/fixtures/macos-exchange/09-propfind-addressbook-bootstrap/response
+++ b/test/fixtures/macos-exchange/09-propfind-addressbook-bootstrap/response
@@ -16,8 +16,8 @@ Content-Type: text/xml
           <d:report><d:sync-collection/></d:report>
         </d:supported-report>
       </d:supported-report-set>
-      <cs:getctag>b42a5c0d98f526c874f2a1d84bcefada2e16f8b8bc89e3c221c16e9170e39809</cs:getctag>
-      <d:sync-token>http://pro-tacts/sync/b42a5c0d98f526c874f2a1d84bcefada2e16f8b8bc89e3c221c16e9170e39809</d:sync-token>
+      <cs:getctag>ef8eddac0927936788c8997a6faedb70b86480fc67475851dcb15013ddc230c9</cs:getctag>
+      <d:sync-token>http://pro-tacts/sync/ef8eddac0927936788c8997a6faedb70b86480fc67475851dcb15013ddc230c9</d:sync-token>
       <d:current-user-privilege-set>
         <d:privilege><d:read/></d:privilege>
         <d:privilege><d:write/></d:privilege>
@@ -47,6 +47,78 @@ Content-Type: text/xml
     <d:status>HTTP/1.1 200 OK</d:status>
   </d:propstat>
 </d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-basic-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"98dbb3374e96a83578e334e9d8c5455721576795724e90f621d11a6b4662bc27"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-complete.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"a4e6b4c955cfcebf3431ab4ab547c64a6bf1983ceba7953a77074ec64c1d6fbd"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-datetime.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"348c560bf1811fc48380fac606cf7198333ae0746c4f5ba8cec7269474b13162"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-day-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"f5c9defba63b13fe74e2ad78270bf609957db631ff701aa9920fcd8aa5d8f28c"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-extended-noyear.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"433c9c285186c3a1cee60452295512a7f8e326e7b70c4670c399b235f9300a62"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-omit-year.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"55f079c8ad3ab5fce768ce51eecc2447ab3be4d24dbf84967a2360b780b58f9d"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-month.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"48a1e4a752c132571a33aec08edafe49d2b3b64a4b9658a7a41cac30e8bd7866"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
+<d:response>
+  <d:href>/dav/addressbook/bday-year-only.vcf</d:href>
+  <d:propstat>
+    <d:prop>
+      <d:getetag>"cc4ef0c4a6d004412a4b7f11dd05d66414204d822c9de0453eaafe164378b53e"</d:getetag>
+    </d:prop>
+    <d:status>HTTP/1.1 200 OK</d:status>
+  </d:propstat>
+</d:response>
 <d:response>
   <d:href>/dav/addressbook/oqmvpzooywwmtwwx.vcf</d:href>
   <d:propstat>