aboutsummaryrefslogtreecommitdiff
path: root/internal/calendar/precedence_ef_repro_test.go
blob: 09cadbd32d3d68015e62c4adec5491ef3bf73831 (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
package calendar_test

// Reproduction tests for three named EF precedence defects (colitur's
// differential/oracle audit against lectio's ~66-line EF precedence
// approximation, internal/calendar/precedence_ef.go). Each test fails before
// its fix and passes after -- see the report for the exact pre-fix failure
// message. These exercise the REAL tridentine sanctoral data
// (caldata.Tridentine()) through the public Compute entry point, since the
// bugs are about how real fixed-date feasts interact with the temporal
// calendar, not about precedenceEF's arithmetic in isolation (that is
// covered separately, package-internal, in precedence_ef_test.go).

import (
	"testing"
	"time"

	"github.com/lukaszkasprzak/lectio/internal/caldata"
	"github.com/lukaszkasprzak/lectio/internal/calendar"
)

func efCompute(date string) calendar.LiturgicalDay {
	sel := calendar.DefaultSelection()
	sel.Form = "old"
	d, _ := time.Parse("2006-01-02", date)
	return calendar.Compute(d.UTC(), sel, []calendar.Layer{caldata.Tridentine()})
}

// TestJosephYieldsToSundayOfLent: RG 91 entry 6 (Sundays of Lent, I class)
// vs entry 11 (I-class feasts of the universal Church not above) -- the
// Sunday holds; St Joseph (19 March) transfers to the next free day (RG 95,
// RG 96), landing on the 20th. Before the fix (defect 4: Sunday ranks), Lent
// Sundays were wrongly II class, so Joseph (I class) won outright every time
// this collision occurred.
func TestJosephYieldsToSundayOfLent(t *testing.T) {
	for _, year := range []string{"2006", "2017", "2023", "2028", "2034", "2045"} {
		sunday := efCompute(year + "-03-19")
		if sunday.Observed.Slug == "joseph-spouse-of-the-bl-virgin-mary" {
			t.Errorf("%s-03-19 observed = %q want the Lent Sunday (RG 91 entry 6 beats entry 11)", year, sunday.Observed.Slug)
		}
		next := efCompute(year + "-03-20")
		if next.Observed.Slug != "joseph-spouse-of-the-bl-virgin-mary" {
			t.Errorf("%s-03-20 observed = %q want joseph-spouse-of-the-bl-virgin-mary (transferred one day, RG 96)", year, next.Observed.Slug)
		}
	}
}

// TestTransferSkipsBothIAndIIClass: RG 96 -- an impeded I-class feast
// transfers to the next day that is NOT ITSELF I OR II CLASS (not merely "not
// I class"). 2011: the Sacred Heart (Friday after the Corpus Christi octave)
// falls on 1 July and impedes the Precious Blood (also 1 July, fixed). 2
// July is the Visitation (II class, fixed); 3 July is an ordinary II-class
// Sunday. Both must be skipped; the Precious Blood lands on 4 July, and the
// Visitation is observed, undisplaced, on its own day.
func TestTransferSkipsBothIAndIIClass(t *testing.T) {
	if got := efCompute("2011-07-01").Observed.Slug; got != "ef-sacred-heart" {
		t.Fatalf("2011-07-01 observed = %q want ef-sacred-heart", got)
	}
	if got := efCompute("2011-07-02").Observed.Slug; got != "visitation-of-the-blessed-virgin-mary" {
		t.Errorf("2011-07-02 observed = %q want visitation-of-the-blessed-virgin-mary (RG 96: the Precious Blood must skip past it, not displace it)", got)
	}
	if got := efCompute("2011-07-03").Observed.Slug; got != "ef-time-after-pentecost-sunday-3" {
		t.Errorf("2011-07-03 observed = %q want ef-time-after-pentecost-sunday-3 (an ordinary II-class Sunday also blocks a I-class transfer)", got)
	}
	if got := efCompute("2011-07-04").Observed.Slug; got != "precious-blood-of-our-lord-jesus-christ" {
		t.Errorf("2011-07-04 observed = %q want precious-blood-of-our-lord-jesus-christ (RG 96: first day that is neither I nor II class)", got)
	}
}

// TestMatthewBeatsSeptemberEmberWednesday: RG 91 -- St Matthew (21 September,
// II class) and the September Ember Wednesday are both II class; the table
// decides the tie. Entry 16 (II-class feasts of the universal Church) sits
// ABOVE entry 18 (II-class ferias, including the Ember days) -- the feast
// wins, the Ember feria is only commemorated.
func TestMatthewBeatsSeptemberEmberWednesday(t *testing.T) {
	// 21 September falls on the September Ember Wednesday whenever the third
	// Sunday of September is the 18th -- 2016 and 2022 both qualify.
	for _, date := range []string{"2016-09-21", "2022-09-21"} {
		day := efCompute(date)
		if day.Observed.Slug != "matthew" {
			t.Errorf("%s observed = %q want matthew (RG 91 entry 16 beats entry 18)", date, day.Observed.Slug)
		}
	}
}

// TestImmaculateConceptionBeatsAdventSunday: found, not named among the
// seven, while verifying defect 4 (Sunday ranks) against the real sanctoral
// data. RG 91 entry 4 (Immaculate Conception, Assumption BVM) sits ABOVE
// entry 6 (Sundays of Advent/Lent/Passiontide) -- unlike an ORDINARY
// I-class feast (entry 11, e.g. St Joseph), the Immaculate Conception
// (8 December) is not impeded by the Advent Sunday it falls on at all. Before
// defect 4's own fix, Advent Sundays were wrongly II class, so this was
// accidentally right (I class beats II class outright); once Sundays became
// I class the tie mattered for the first time.
func TestImmaculateConceptionBeatsAdventSunday(t *testing.T) {
	for _, year := range []string{"2013", "2019", "2024"} {
		day := efCompute(year + "-12-08")
		if day.Observed.Slug != "immaculate-conception-of-the-blessed-virgin-mary" {
			t.Errorf("%s-12-08 observed = %q want immaculate-conception-of-the-blessed-virgin-mary (RG 91 entry 4 beats entry 6)", year, day.Observed.Slug)
		}
	}
}

// TestVigilOfChristmasSurvivesAdventSunday: found, not named among the
// seven, while verifying defect 4 against the real sanctoral data -- and
// worse than a wrong winner. RG 91 entry 5 (Vigil & Octave day of the
// Nativity) also sits above entry 6, so the Vigil of Christmas (24 December)
// is not impeded by falling on Advent IV either. Without this, defect 4
// alone would have made the Advent Sunday win a genuine tie, sending the
// Vigil into transferIfImpededEF's forward walk -- which has no way to
// re-place a transfer that crosses the Dec31/Jan1 boundary (celebrationDate
// re-resolves a fixed date using the year of whatever day is being queried,
// so a walk landing in the following January can never match the query that
// produced it). The Vigil did not move to the wrong day; it vanished for the
// whole year.
func TestVigilOfChristmasSurvivesAdventSunday(t *testing.T) {
	for _, year := range []string{"2006", "2017", "2023", "2028"} {
		day := efCompute(year + "-12-24")
		if day.Observed.Slug != "vigil-of-christmas" {
			t.Errorf("%s-12-24 observed = %q want vigil-of-christmas (RG 91 entry 5 beats entry 6; must not vanish)", year, day.Observed.Slug)
		}
	}
}