blob: 84ee0318800e453716a1d4b0a8884b4d975c0f81 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
module V = Rite_ef.Vocab_ef
let test_vocab_roundtrips () =
List.iter
(fun s ->
Alcotest.(check bool) "season string roundtrip" true
(V.season_of_string (V.season_to_string s) = Some s))
V.seasons;
List.iter
(fun r ->
Alcotest.(check bool) "rank string roundtrip" true
(V.rank_of_string (V.rank_to_string r) = Some r))
V.ranks;
Alcotest.(check int) "eight seasons" 8 (List.length V.seasons);
Alcotest.(check int) "four ranks" 4 (List.length V.ranks)
(* Slug words are lectio's lectionary-key vocabulary, deliberately distinct from
the season names (spec §4.4, plan correction 2). *)
let test_slug_words () =
Alcotest.(check string) "paschaltide slugs as easter" "easter" (V.season_slug_word V.Paschaltide);
Alcotest.(check string) "christmastide slugs as christmas" "christmas"
(V.season_slug_word V.Christmastide);
Alcotest.(check string) "season name differs" "paschaltide" (V.season_to_string V.Paschaltide)
module T = Rite_ef.Temporal_ef
module D = Colitur_kernel.Date
let d y m dd = match D.make ~year:y ~month:m ~day:dd with
| Ok t -> t | Error e -> Alcotest.failf "%s" e
let season_str dt = V.season_to_string (T.season dt)
let test_advent_start () =
(* Advent 2026 begins Sunday 29 November 2026. *)
Alcotest.(check string) "advent 2026" "2026-11-29" (D.to_iso8601 (T.advent_start 2026));
Alcotest.(check bool) "always a Sunday" true (D.weekday (T.advent_start 2026) = D.Sun)
let test_seasons () =
(* Easter 2026 is 5 April. *)
Alcotest.(check string) "1 Dec 2026" "advent" (season_str (d 2026 12 1));
Alcotest.(check string) "24 Dec 2026" "advent" (season_str (d 2026 12 24));
Alcotest.(check string) "25 Dec 2026" "christmastide" (season_str (d 2026 12 25));
(* RG 72-73: Christmas Time runs to 13 January INCLUSIVE -- the deliberate
divergence from lectio, which starts time-after-epiphany at 6 January. *)
Alcotest.(check string) "6 Jan 2026" "christmastide" (season_str (d 2026 1 6));
Alcotest.(check string) "13 Jan 2026" "christmastide" (season_str (d 2026 1 13));
Alcotest.(check string) "14 Jan 2026" "time-after-epiphany" (season_str (d 2026 1 14));
Alcotest.(check string) "Septuagesima 1 Feb 2026" "septuagesima" (season_str (d 2026 2 1));
Alcotest.(check string) "Ash Wed 18 Feb 2026" "lent" (season_str (d 2026 2 18));
Alcotest.(check string) "Passion Sun 22 Mar 2026" "passiontide" (season_str (d 2026 3 22));
(* Holy Saturday stays in Passiontide: the Vigil is a night Mass (spec §4.2). *)
Alcotest.(check string) "Holy Sat 4 Apr 2026" "passiontide" (season_str (d 2026 4 4));
Alcotest.(check string) "Easter 5 Apr 2026" "paschaltide" (season_str (d 2026 4 5));
Alcotest.(check string) "Sat after Pentecost 30 May 2026" "paschaltide" (season_str (d 2026 5 30));
Alcotest.(check string) "Trinity 31 May 2026" "time-after-pentecost" (season_str (d 2026 5 31))
let named_slug dt = match T.named dt with
| Some (_, slug, _, _, _) -> slug
| None -> "<none>"
let test_named_feasts () =
(* Easter 2026 = 5 April. *)
Alcotest.(check string) "nativity" "ef-nativity" (named_slug (d 2026 12 25));
Alcotest.(check string) "nativity vigil" "ef-nativity-vigil" (named_slug (d 2026 12 24));
Alcotest.(check string) "circumcision" "ef-circumcision" (named_slug (d 2026 1 1));
Alcotest.(check string) "epiphany" "ef-epiphany" (named_slug (d 2026 1 6));
Alcotest.(check string) "ash wednesday" "ef-ash-wednesday" (named_slug (d 2026 2 18));
Alcotest.(check string) "passion sunday" "ef-passion-sunday" (named_slug (d 2026 3 22));
Alcotest.(check string) "palm sunday" "ef-palm-sunday" (named_slug (d 2026 3 29));
Alcotest.(check string) "easter" "ef-easter-sunday" (named_slug (d 2026 4 5));
Alcotest.(check string) "low sunday" "ef-low-sunday" (named_slug (d 2026 4 12));
Alcotest.(check string) "ascension vigil" "ef-ascension-vigil" (named_slug (d 2026 5 13));
Alcotest.(check string) "ascension" "ef-ascension" (named_slug (d 2026 5 14));
Alcotest.(check string) "pentecost vigil" "ef-pentecost-vigil" (named_slug (d 2026 5 23));
Alcotest.(check string) "pentecost" "ef-pentecost" (named_slug (d 2026 5 24));
Alcotest.(check string) "trinity" "ef-trinity" (named_slug (d 2026 5 31));
Alcotest.(check string) "corpus christi" "ef-corpus-christi" (named_slug (d 2026 6 4));
Alcotest.(check string) "sacred heart" "ef-sacred-heart" (named_slug (d 2026 6 12));
Alcotest.(check string) "an ordinary day is not named" "<none>" (named_slug (d 2026 7 15))
let test_christ_the_king () =
(* 1960 calendar: the LAST Sunday of October, not the OF's last before Advent. *)
Alcotest.(check string) "2026" "2026-10-25" (D.to_iso8601 (T.christ_the_king 2026));
Alcotest.(check bool) "always a Sunday" true (D.weekday (T.christ_the_king 2026) = D.Sun);
Alcotest.(check string) "slug" "ef-christ-the-king" (named_slug (T.christ_the_king 2026))
let test_nativity_octave () =
Alcotest.(check string) "29 Dec" "ef-nativity-octave-day-5" (named_slug (d 2026 12 29));
Alcotest.(check string) "31 Dec" "ef-nativity-octave-day-7" (named_slug (d 2026 12 31))
let sunday_slug_of dt = match T.sunday_slug dt with Some s -> s | None -> "<none>"
let test_week_numbers () =
Alcotest.(check (option int)) "Advent I 2026" (Some 1) (T.week (T.advent_start 2026));
Alcotest.(check (option int)) "Advent II 2026" (Some 2)
(T.week (D.add_days (T.advent_start 2026) 7));
(* Weeks are Sunday-aligned: the Saturday of week 1 is still week 1. *)
Alcotest.(check (option int)) "Advent I Saturday" (Some 1)
(T.week (D.add_days (T.advent_start 2026) 6));
(* Time after Pentecost counts from Pentecost, so Trinity is week 1. *)
Alcotest.(check (option int)) "Trinity 2026 is week 1" (Some 1) (T.week (d 2026 5 31));
(* Christmastide has no numbered weeks. *)
Alcotest.(check (option int)) "Christmastide has no week" None (T.week (d 2026 12 30))
let test_sunday_slugs () =
Alcotest.(check string) "Advent I" "ef-advent-sunday-1" (sunday_slug_of (T.advent_start 2026));
Alcotest.(check string) "Lent I 2026 (22 Feb)" "ef-lent-sunday-1" (sunday_slug_of (d 2026 2 22));
(* Slugs use lectio's season words: Paschaltide slugs as "easter". *)
Alcotest.(check string) "Paschaltide III 2026 (19 Apr)" "ef-easter-sunday-3"
(sunday_slug_of (d 2026 4 19));
(* The Sunday within the Octave of the Nativity keeps lectio's key. *)
Alcotest.(check string) "27 Dec 2026" "ef-christmas-sunday-0" (sunday_slug_of (d 2026 12 27));
(* The Sunday falling 7-13 Jan is the 1st Sunday after Epiphany. Its season is
Christmastide (RG 72-73) but its lectionary key stays lectio's. *)
Alcotest.(check string) "11 Jan 2026" "ef-time-after-epiphany-sunday-1"
(sunday_slug_of (d 2026 1 11))
(* The resumed-Sunday tail: when Easter is early there are more than 23 Sundays
after Pentecost, and the surplus resume the Sundays after Epiphany that
Septuagesima cut short. 2038 has Easter on 25 April (the latest possible) and
1943-style early years have the most Sundays; 2035 (Easter 25 March) is an
early-Easter year with a long tail. *)
let test_resumed_sundays () =
let last_sunday_before_advent y = D.add_days (T.advent_start y) (-7) in
(* The last Sunday before Advent always keeps the 24th (Last) Mass. *)
Alcotest.(check string) "2035 last Sunday" "ef-time-after-pentecost-sunday-24"
(sunday_slug_of (last_sunday_before_advent 2035));
Alcotest.(check string) "2026 last Sunday" "ef-time-after-pentecost-sunday-24"
(sunday_slug_of (last_sunday_before_advent 2026));
(* In an early-Easter year the surplus Sundays route to Epiphany Masses. *)
let resumed =
List.filter_map
(fun n ->
let dt = D.add_days (T.advent_start 2035) (-7 - (7 * n)) in
let s = sunday_slug_of dt in
if String.length s >= 27 && String.sub s 0 27 = "ef-time-after-epiphany-sund" then Some s
else None)
[ 1; 2; 3; 4; 5 ]
in
Alcotest.(check bool) "2035 has resumed Epiphany Sundays" true (resumed <> [])
let suite_extra =
[ Alcotest.test_case "advent start" `Quick test_advent_start;
Alcotest.test_case "seasons" `Quick test_seasons;
Alcotest.test_case "named feasts" `Quick test_named_feasts;
Alcotest.test_case "christ the king" `Quick test_christ_the_king;
Alcotest.test_case "nativity octave" `Quick test_nativity_octave;
Alcotest.test_case "week numbers" `Quick test_week_numbers;
Alcotest.test_case "sunday slugs" `Quick test_sunday_slugs;
Alcotest.test_case "resumed sundays" `Quick test_resumed_sundays ]
let suite =
( "Rite_ef",
[ Alcotest.test_case "vocab roundtrips" `Quick test_vocab_roundtrips;
Alcotest.test_case "slug words" `Quick test_slug_words ]
@ suite_extra )
|