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
|
package caldata
import (
"strings"
"testing"
"time"
"github.com/lukaszkasprzak/lectio/internal/calendar"
)
func TestOFReadingsByCycle(t *testing.T) {
// A synthetic OF day keyed christ-the-king-A must resolve to Matt 25.
day := calendar.LiturgicalDay{
Observed: calendar.Celebration{Slug: "christ-the-king", Layer: "temporal"},
SundayCycle: "A",
Weekday: time.Sunday,
}
sel := calendar.Selection{Form: "new"}
rs := Readings(sel, nil, time.Date(2026, 11, 22, 0, 0, 0, 0, time.UTC), day)
var gospel string
for _, r := range rs {
if r.Part == "gospel" {
gospel = r.Citation
}
}
// The gospel of Christ the King (cycle A) is Matthew 25:31-46. The citation
// may spell Matthew as "Mat"/"Matt" (niedziela/ToEnglishRef) or "Matthew"
// (catholic-resources.org); all resolve to Matthew via books.ini.
if !strings.Contains(gospel, "25:31-46") ||
!(strings.HasPrefix(gospel, "Mat 25") || strings.HasPrefix(gospel, "Matt 25") || strings.HasPrefix(gospel, "Matthew 25")) {
t.Fatalf("christ-the-king-A gospel = %q, want Matthew 25:31-46", gospel)
}
}
func TestOFReadings2026Sunday(t *testing.T) {
// End-to-end: the real engine + embedded table resolve a 2026 (cycle A)
// Sunday's first + gospel.
sel := calendar.DefaultSelection() // Form defaults to the OF ("new")
layers := []calendar.Layer{Universal()}
d := time.Date(2026, 6, 7, 0, 0, 0, 0, time.UTC) // Ordinary Sunday 10, cycle A
day := calendar.Compute(d, sel, layers)
rs := Readings(sel, layers, d, day)
var hasFirst, hasGospel bool
for _, r := range rs {
if r.Part == "first" && r.Citation != "" {
hasFirst = true
}
if r.Part == "gospel" && r.Citation != "" {
hasGospel = true
}
}
if !hasFirst || !hasGospel {
t.Fatalf("2026-06-07 OF readings missing first/gospel: %+v (slug %s cycle %s)",
rs, day.Observed.Slug, day.SundayCycle)
}
}
func TestOFWeekdayEmpty(t *testing.T) {
day := calendar.LiturgicalDay{
Observed: calendar.Celebration{Slug: "ordinary-weekday", Layer: "temporal"},
Weekday: time.Wednesday, // no SundayCycle key -> deferred phase -> empty
}
if rs := Readings(calendar.Selection{Form: "new"}, nil, time.Now().UTC(), day); len(rs) != 0 {
t.Fatalf("weekday should be empty, got %v", rs)
}
}
func TestOFSundayCompleteReadings(t *testing.T) {
// Every OF Sunday/solemnity Mass has a SECOND reading; the niedziela harvest
// had dropped it on 271 entries, restored from catholic-resources.org.
for _, tc := range []struct{ slug, cycle string }{
{"ordinary-sunday-11", "A"}, {"trinity-sunday", "A"},
{"palm-sunday", "B"}, {"pentecost", "C"},
} {
day := calendar.LiturgicalDay{
Observed: calendar.Celebration{Slug: tc.slug, Layer: "temporal"},
SundayCycle: tc.cycle, Weekday: time.Sunday,
}
parts := map[string]bool{}
for _, r := range Readings(calendar.Selection{Form: "new"}, nil, time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC), day) {
parts[r.Part] = true
}
if !parts["first"] || !parts["second"] || !parts["gospel"] {
t.Errorf("%s-%s: got parts %v, want first+second+gospel", tc.slug, tc.cycle, parts)
}
}
}
func TestOFSeasonalFerials(t *testing.T) {
// Seasonal weekday ferials re-sourced from catholic-resources.org: an Easter
// weekday no longer contaminated, the Easter octave (was missing), and the
// date-based late-Advent days (Dec 17-24, keyed by date not by Advent week).
for _, tc := range []struct{ key, firstHas string }{
{"easter-3-mon-I", "Acts 6:8-15"}, // had 1 Cor 15 (contamination)
{"easter-octave-mon-I", "Acts 2:14"}, // was absent
{"advent-dec-17-I", "Genesis 49"},
{"advent-dec-24-I", "2 Samuel 7"},
} {
var first string
for _, r := range TemporalReadings("new", tc.key) {
if r.Part == "first" {
first = r.Citation
}
}
if !strings.Contains(first, tc.firstHas) {
t.Errorf("%s: first = %q, want containing %q", tc.key, first, tc.firstHas)
}
}
}
|