Add the iCalendar round-trip
Parsing goes through icalendar's low-level parser, which keeps properties in order and keeps repeated ones. Writing is ours: that crate's writer escapes a whole property value as text, so CATEGORIES:Work,Personal would go out as one category named "Work,Personal" to every other client. Anything the model does not interpret is carried rather than dropped -- X-MOZ-LASTACK, X-EVOLUTION-ALARM-UID, ACKNOWLEDGED, the X-MICROSOFT-CDO set, unrecognised ATTENDEE parameters, and whole VTODO/VJOURNAL components. A calendar has several clients writing to it and this one is not the authority on which properties matter. VTIMEZONE is modelled properly, and TZID is stored exactly as written: Exchange names its zones "Pacific Standard Time", which no IANA lookup resolves, and normalising at parse time would make the document unrepresentable. Mapping to a real zone belongs at the point of use. Tested against a golden corpus captured from the live Baikal (seven producing clients over five years) and a published Outlook feed, scrubbed of private content with the structure left byte-for-byte. Eight hand-written fixtures cover what neither server had: DURATION, floating times, RDATE, DST boundaries, leap day, and the full escape set. The contract is that parse -> write -> parse is stable, plus a check that no property name loses occurrences across the trip, since a parser that dropped ATTENDEE entirely would round-trip perfectly and still be wrong.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# Golden-file corpus
|
||||
|
||||
Every file here is real iCalendar data unless it sits under `synthetic/`. The point of the corpus
|
||||
is that `runway-core` is tested against what servers and clients actually emit, not against what
|
||||
the RFC says they should.
|
||||
|
||||
The contract each file must satisfy is in `tests/ical.rs`: **parse → serialise → parse must be
|
||||
stable**, and the second parse must equal the first. A file that cannot round-trip is a bug in the
|
||||
parser or the writer, never a reason to edit the file.
|
||||
|
||||
## Provenance
|
||||
|
||||
`baikal/` — captured from a live Baikal (SabreDAV) server holding six calendars written by seven
|
||||
different clients over five years. One file per CalDAV resource, exactly as the server returned it
|
||||
in a `calendar-query` REPORT.
|
||||
|
||||
| File | What it covers |
|
||||
|---|---|
|
||||
| `davx5-allday-weekly-alarm.ics` | `VALUE=DATE` all-day series, `RRULE`, one `VALARM` |
|
||||
| `davx5-zoned-two-alarms-vtimezone.ics` | `TZID=America/New_York`, **two** `VALARM`s, `VTIMEZONE` emitted *after* the `VEVENT` |
|
||||
| `evolution-x-lic-error.ics` | `X-LIC-ERROR` baked in by libical, `ACKNOWLEDGED`, `X-EVOLUTION-ALARM-UID`, `TRIGGER;RELATED=START` |
|
||||
| `thunderbird-google-invite-attendees.ics` | three `ATTENDEE`s with `CUTYPE`/`PARTSTAT`/`X-NUM-GUESTS`, `RRULE` with `COUNT`, `Europe/Zurich` |
|
||||
| `thunderbird-x-moz-props.ics` | `X-MOZ-GENERATION`, `X-MOZ-LASTACK` — vendor state that must survive a round-trip |
|
||||
| `outlook-invite-quoted-cn.ics` | `ORGANIZER`/`ATTENDEE` with a **quoted `CN` containing a comma**, `LANGUAGE` parameters, `X-MICROSOFT-CDO-*` |
|
||||
| `runway-v1-unfolded-line.ics` | **v1's own broken output**, still stored on the server: a 248-octet unfolded `DESCRIPTION` (RFC violation) and `CREATED` with no `Z` |
|
||||
|
||||
`outlook/` — captured from a published Outlook/Exchange `.ics` feed (252 events, 103 UIDs), trimmed
|
||||
to seven components that carry the interesting structure.
|
||||
|
||||
| Covers |
|
||||
|---|
|
||||
| **Windows timezone names** (`TZID=Pacific Standard Time`), not IANA — with the matching `VTIMEZONE` definitions, whose `DTSTART:16010101T020000` is year **1601** |
|
||||
| A master with four `RECURRENCE-ID` overrides, one of which moves the occurrence to a **different day** |
|
||||
| An **orphan override**: a `RECURRENCE-ID` whose master lies outside the feed window and must still render |
|
||||
| `EXDATE` with **many comma-separated values on one line** |
|
||||
| `METHOD:PUBLISH`, `X-WR-CALNAME`, and the full `X-MICROSOFT-*` set |
|
||||
|
||||
`synthetic/` — hand-authored, because nothing in the real corpus exercises these: `DURATION`
|
||||
instead of `DTEND`, floating (zoneless) times, `RDATE` on an event, a CalDAV resource bundling a
|
||||
master with its override, a DST spring-forward series, a leap-day series, and the complete set of
|
||||
RFC 5545 text escapes with non-ASCII.
|
||||
|
||||
## Scrubbing
|
||||
|
||||
The real files have been scrubbed. Structure is preserved **exactly** — property names, parameters,
|
||||
property order, component nesting, every datetime, `TZID`, `RRULE`, `EXDATE`, `RECURRENCE-ID`,
|
||||
`SEQUENCE` and `X-` property is byte-for-byte what the server sent. Only human-readable content was
|
||||
replaced: `SUMMARY`, `DESCRIPTION`, `LOCATION`, display names, email addresses and URLs, each with
|
||||
synthetic text of comparable shape that keeps the RFC 5545 escaping in play. `UID`s were replaced by
|
||||
a stable hash that preserves their original *format*, so master/override linkage inside a series
|
||||
still holds.
|
||||
|
||||
`runway-v1-unfolded-line.ics` is deliberately **not** refolded: its over-long line is the defect
|
||||
under test.
|
||||
Reference in New Issue
Block a user