Liturgical event tests - Liturgical-Calendar/LiturgicalCalendarAPI GitHub Wiki
Liturgical event tests verify the liturgical correctness of the calendar output: that events fall on the right dates, respect precedence rules, appear only in the years they should, and are correctly moved when they coincide with higher-ranking celebrations. These are distinct from the code-quality unit tests that exercise the API's PHP classes and HTTP routes.
Overview
Test definitions live as JSON files in jsondata/tests/ within the
LiturgicalCalendarAPI repository.
Each file defines assertions about a single liturgical event across one or more calendar years.
These definitions can be created and managed through the
Unit Test interface frontend.
See Unit Test server and interface for details on that frontend and its WebSocket backend.
The API exposes a /tests/ discovery endpoint that lists all available test definitions, making them
consumable by the frontend interface.
File location and naming
Test files are stored in:
jsondata/tests/
├── MaryMotherChurchTest.json
├── NativityJohnBaptistTest.json
├── PrayerUnbornTest.json
├── StJaneFrancesDeChantalTest.json
└── rotter_nl_HLaurentiusdiakenenmartelaarpatroonvanhetbisdomTest.json
File names must end in *Test.json. The name typically matches the event_key of the event being tested.
For diocesan or national events, the name is prefixed with the calendar identifier
(e.g., rotter_nl_ for the Diocese of Rotterdam in the Netherlands).
JSON structure
Every test definition is a JSON object with these top-level properties:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Identifier for the test (matches the filename) |
event_key |
string | yes | The liturgical event key as used in the API response |
description |
string | yes | Human-readable explanation of what the test verifies |
test_type |
string | yes | One of the three test types (see below) |
year_since |
number | no | Starting year (required for exactCorrespondenceSince) |
year_until |
number | no | Final year (required for exactCorrespondenceUntil) |
applies_to |
object | no | Restricts the test to a specific calendar (see below) |
assertions |
array | yes | Array of assertion objects (see below) |
Test types
Note: a fourth type,
variableCorrespondence, was merged intoexactCorrespondence, since the two had become structurally and behaviorally identical: in both cases each assertion independently defines what is expected for its year, and only the years explicitly listed in theassertionsarray are tested. See LiturgicalCalendarAPI#704.
exactCorrespondence
The event is tested only against the years listed in the assertions array. Each assertion
independently defines what is expected for its year: either the event exists and falls on an expected
date (eventExists AND hasExpectedDate), or the event does not exist at all (eventNotExists).
This type is appropriate when the event's behavior in the significant years does not follow a simple
"since year X" or "until year X" boundary.
Example use case: The Nativity of John the Baptist normally falls on June 24, but when it coincides with the Solemnity of the Sacred Heart, it is moved to June 23. The test lists only the years where this coincidence occurs:
{
"name": "NativityJohnBaptistTest",
"event_key": "NativityJohnBaptist",
"description": "When the Nativity of John the Baptist coincides with the Sacred Heart, is it moved to June 23?",
"test_type": "exactCorrespondence",
"assertions": [
{
"year": 2022,
"expected_value": "2022-06-23T00:00:00+00:00",
"assert": "eventExists AND hasExpectedDate",
"assertion": "Nativity of John the Baptist should be moved to June 23"
},
{
"year": 2033,
"expected_value": "2033-06-23T00:00:00+00:00",
"assert": "eventExists AND hasExpectedDate",
"assertion": "Nativity of John the Baptist should be moved to June 23"
}
]
}
Example with non-existence assertions: Saint Jane Frances de Chantal was moved from December 12 to August 12 in the 2002 Roman Missal. Before 2002, the memorial fell on December 12 but was suppressed when that date fell on a Sunday. After 2002, it falls on August 12 but is similarly suppressed on Sundays:
{
"name": "StJaneFrancesDeChantalTest",
"event_key": "StJaneFrancesDeChantal",
"description": "Saint Jane Frances de Chantal was moved from December 12 to August 12 in the 2002 Roman Missal...",
"test_type": "exactCorrespondence",
"assertions": [
{
"year": 2001,
"expected_value": "2001-12-12T00:00:00+00:00",
"assert": "eventExists AND hasExpectedDate",
"assertion": "should fall on expected date December 12"
},
{
"year": 2002,
"expected_value": "2002-08-12T00:00:00+00:00",
"assert": "eventExists AND hasExpectedDate",
"assertion": "should fall on expected date August 12"
},
{
"year": 1971,
"expected_value": null,
"assert": "eventNotExists",
"assertion": "should not exist, December 12th is a Sunday"
},
{
"year": 2012,
"expected_value": null,
"assert": "eventNotExists",
"assertion": "should not exist, August 12th is a Sunday"
}
]
}
exactCorrespondenceSince
The event was introduced starting from a specific year (typically by a Decree of the Dicastery for Divine Worship). The test verifies that:
- The event does not exist in calendar years before
year_since - The event exists on the expected date in calendar years from
year_sinceonward
The year_since property is required for this test type.
Example use case: The memorial of Mary Mother of the Church was added in 2018 by Decree, on the Monday after Pentecost. It should not appear in calendars before 2018:
{
"name": "MaryMotherChurchTest",
"event_key": "MaryMotherChurch",
"description": "The memorial 'Mary Mother of the Church' was added in 2018...",
"test_type": "exactCorrespondenceSince",
"year_since": 2018,
"assertions": [
{
"year": 2015,
"expected_value": null,
"assert": "eventNotExists",
"assertion": "Should not exist before the year 2018"
},
{
"year": 2018,
"expected_value": "2018-05-21T00:00:00+00:00",
"assert": "eventExists AND hasExpectedDate",
"assertion": "Should be created on the expected date"
}
]
}
exactCorrespondenceUntil
The event was celebrated only up to a specific year (for example, an event suppressed or replaced in a
later edition of the Roman Missal). This is the mirror of exactCorrespondenceSince. The test verifies
that:
- The event exists on the expected date in calendar years up to and including
year_until - The event does not exist in calendar years after
year_until
The year_until property is required for this test type.
Assertion object structure
Each object in the assertions array has these properties:
| Property | Type | Required | Description |
|---|---|---|---|
year |
number | yes | The calendar year to test against |
expected_value |
string or null | yes | Expected RFC 3339 datetime, or null for non-existence |
assert |
string | yes | The assertion type (see below) |
assertion |
string | yes | Human-readable description shown in the test UI |
comment |
string | no | Additional context explaining why the year is significant |
Assertion types
eventExists— the event must be present in the calendar for the given yeareventNotExists— the event must not be present in the calendar for the given yearhasExpectedDate— the event's date must match theexpected_valueeventExists AND hasExpectedDate— the event must both exist and fall on the expected date
When assert is eventNotExists, the expected_value should be null.
Date format
Expected dates use the RFC 3339 format: YYYY-MM-DDTHH:mm:ss+00:00
The time component is always 00:00:00 and the timezone is always UTC (+00:00), since liturgical events
are all-day events.
Scoping tests to specific calendars
By default, a test applies to the General Roman Calendar. To scope a test to a national or diocesan
calendar, add the applies_to property:
National calendar:
{
"applies_to": {
"national_calendar": "US"
}
}
Diocesan calendar:
{
"applies_to": {
"diocesan_calendar": "rotter_nl"
}
}
The value must match the calendar key as returned by the /calendars metadata endpoint.
What to test
Liturgical event tests are most valuable for verifying:
- Decree-based events — events introduced by a Decree of the Dicastery for Divine Worship should not exist in years before the decree
- Precedence rules — when a memorial or feast coincides with a Sunday or higher-ranking celebration, it should be suppressed or moved to the correct date
- Date changes across editions — events whose date was changed between editions of the Roman Missal should fall on the old date before the edition year and on the new date from that year onward
- National/diocesan patron feasts — patron saints elevated to a feast in a particular diocese should be moved when they fall on a Sunday in Ordinary Time
Creating a new test
-
Create a new JSON file in
jsondata/tests/following the naming convention{EventKey}Test.json(or{calendar_id}_{EventKey}Test.jsonfor calendar-specific tests) -
Define the test structure with the appropriate
test_type -
Add assertions covering the significant years:
- For
exactCorrespondence: include years representing each distinct behavior pattern (date deviating from the norm, suppression by a higher-ranking celebration, etc.) - For
exactCorrespondenceSince: include at least a few years before the decree and the first few years after - For
exactCorrespondenceUntil: include the last few years the event was celebrated and a few years after its suppression
- For
-
The test will be automatically picked up by the
/tests/discovery endpoint and appear in the Unit Test interface
Testing: ← [How to write unit tests]] ](/Liturgical-Calendar/LiturgicalCalendarAPI/wiki/[[Home) | Unit Test server and interface →