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
|
package calendar_test
import (
"encoding/json"
"math"
"os"
"sort"
"testing"
"time"
"github.com/lukaszkasprzak/lectio/internal/caldata"
"github.com/lukaszkasprzak/lectio/internal/calendar"
)
type oracleDay struct {
Season string `json:"season"`
RankNum float64 `json:"rank_num"`
}
// classOf maps a Table band (1-13) to its calapi class (1, 2, or 3).
func classOf(band int) int {
switch {
case band <= 4:
return 1
case band <= 9:
return 2
default:
return 3
}
}
// mySeason maps the engine's season onto calapi's five-season vocabulary
// (calapi buckets the Triduum's Thu/Fri/Sat under "lent").
func mySeason(s calendar.Season) string {
if s == calendar.Triduum {
return "lent"
}
return string(s)
}
// TestOracle2020to2040 diffs the engine against calapi (calendarium-romanum).
// Season is asserted strictly (data-independent — it validates the whole
// temporal engine). Rank class is reported for information only, since a class
// mismatch usually means the initial embedded sanctoral simply lacks that saint.
func TestOracle2020to2040(t *testing.T) {
raw, err := os.ReadFile("testdata/oracle-2020-2040.json")
if err != nil {
t.Skip("oracle snapshot missing; run scripts/build-oracle.sh")
}
var oracle map[string]oracleDay
if err := json.Unmarshal(raw, &oracle); err != nil {
t.Fatal(err)
}
sel := calendar.DefaultSelection()
layers := []calendar.Layer{caldata.Universal()}
dates := make([]string, 0, len(oracle))
for date := range oracle {
dates = append(dates, date)
}
sort.Strings(dates)
var seasonMiss, classMiss, total int
shownS, shownC := 0, 0
for _, date := range dates {
want := oracle[date]
day, _ := time.Parse("2006-01-02", date)
got := calendar.Compute(day.UTC(), sel, layers)
total++
if mySeason(got.Season) != want.Season {
seasonMiss++
if shownS < 20 {
t.Errorf("%s: season got %q want %q", date, mySeason(got.Season), want.Season)
shownS++
}
}
wantClass := int(math.Floor(want.RankNum))
if classOf(got.ObservedBand) != wantClass && shownC < 15 {
classMiss++
t.Logf("[info] %s: rank class got %d (band %d) want %d — likely missing sanctoral data",
date, classOf(got.ObservedBand), got.ObservedBand, wantClass)
shownC++
} else if classOf(got.ObservedBand) != wantClass {
classMiss++
}
}
t.Logf("oracle: %d days, %d season mismatches, %d rank-class mismatches (info)", total, seasonMiss, classMiss)
if seasonMiss > 0 {
t.Fatalf("%d/%d season mismatches vs calapi — temporal engine is wrong", seasonMiss, total)
}
}
|