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 into exactCorrespondence, 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 the assertions array 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_since onward

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 year
  • eventNotExists — the event must not be present in the calendar for the given year
  • hasExpectedDate — the event's date must match the expected_value
  • eventExists 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

  1. Create a new JSON file in jsondata/tests/ following the naming convention {EventKey}Test.json (or {calendar_id}_{EventKey}Test.json for calendar-specific tests)

  2. Define the test structure with the appropriate test_type

  3. 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
  4. 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