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
|
package cli
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/lukaszkasprzak/lectio/internal/bible"
"github.com/lukaszkasprzak/lectio/internal/config"
)
func TestRunLiturgy(t *testing.T) {
dir := t.TempDir()
t.Setenv("LECTIO_CONFIG", filepath.Join(dir, "config.ini"))
cfg, err := config.Load()
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if code := runLiturgy(cfg, "2025-08-15", &buf, &buf); code != 0 {
t.Fatalf("exit code %d", code)
}
out := buf.String()
if !strings.Contains(out, "2025-08-15") {
t.Errorf("missing date:\n%s", out)
}
if !strings.Contains(strings.ToLower(out), "solemnity") || !strings.Contains(out, "Assumption") {
t.Errorf("2025-08-15 should be the Assumption solemnity:\n%s", out)
}
if !strings.Contains(out, "gospel (") {
t.Errorf("proper reading not shown:\n%s", out)
}
}
func TestRunLiturgyTraditionalComputesEF(t *testing.T) {
dir := t.TempDir()
t.Setenv("LECTIO_CONFIG", filepath.Join(dir, "config.ini"))
os.WriteFile(filepath.Join(dir, "config.ini"), []byte("lectionary = traditional\n"), 0o644)
cfg, err := config.Load()
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if code := runLiturgy(cfg, "2025-08-15", &buf, &buf); code != 0 {
t.Fatalf("EF compute failed (%d):\n%s", code, buf.String())
}
out := buf.String()
// EF: Assumption is I class, and 2025-08-15 is in Time after Pentecost (not OF "ordinary").
if !strings.Contains(out, "Assumption") || !strings.Contains(out, "I class") {
t.Errorf("expected EF Assumption (I class):\n%s", out)
}
if !strings.Contains(out, "time-after-pentecost") {
t.Errorf("expected EF season time-after-pentecost:\n%s", out)
}
}
func TestVernacularVersionResolver(t *testing.T) {
// pl has no autoselect-eligible corpus (the built-in Wujek sets
// autoselect=false), so Polish always falls back to Latin regardless of
// which optional corpora are embedded -- pure logic, keep it running.
if got := vernacularVersion(config.Config{UILanguage: "pl"}); got != "vul" {
t.Fatalf("pl should fall back to Latin: %q", got)
}
// Both the explicit reading_version passthrough and the en->drb autoselect
// resolve through bible.Meta("drb") (Config.ReadingCorpus), so they need the
// optional drb corpus embedded.
t.Run("drb", func(t *testing.T) {
requireCorpus(t, "drb")
if got := vernacularVersion(config.Config{ReadingVersion: "drb"}); got != "drb" {
t.Fatalf("explicit: %q", got)
}
if got := vernacularVersion(config.Config{UILanguage: "en"}); got != "drb" {
t.Fatalf("en should be drb: %q", got)
}
})
}
// requireCorpus skips the test when corpus `code` is not embedded in this
// build. The optional corpora (wuj, drb, grb) compile in only with
// `-tags fullbible` (or when dropped into the user corpora dir); mirrors the
// helper in internal/bible so these tests run under fullbible and skip -- not
// fail -- on the default vul-only build.
func requireCorpus(t *testing.T, code string) {
t.Helper()
if _, ok := bible.Meta(code); !ok {
t.Skipf("corpus %q not embedded; build with -tags fullbible", code)
}
}
func TestVersionDisplayNameFallsBackToCorpusMeta(t *testing.T) {
bible.SetUserCorporaDir("../bible/testdata/corpora")
t.Cleanup(func() { bible.SetUserCorporaDir("") })
// "good" is a user fixture with no i18n entry; its sidecar Name must
// surface instead of the bare code.
if got := versionDisplayName("en", "good"); got != "Good Test Corpus" {
t.Fatalf("expected sidecar Name fallback, got %q", got)
}
// a known i18n code still uses the localized chrome label.
if got := versionDisplayName("en", "drb"); got == "drb" {
t.Fatalf("expected localized label, got bare code %q", got)
}
// a totally unknown code with no sidecar falls back to the bare code.
if got := versionDisplayName("en", "zzz-nope"); got != "zzz-nope" {
t.Fatalf("expected bare-code fallback, got %q", got)
}
}
func TestRunLiturgyUserLayer(t *testing.T) {
dir := t.TempDir()
t.Setenv("LECTIO_CONFIG", filepath.Join(dir, "config.ini"))
// a local layer adds a solemnity on 2025-08-11 (an ordinary Monday), and use it.
os.MkdirAll(filepath.Join(dir, "calendars"), 0o755)
os.WriteFile(filepath.Join(dir, "calendars", "local.ini"),
[]byte("[layer]\nid = local\ntype = particular\n\n[patron]\ndate = 08-11\nrank = solemnity\nclass = saint\ncolour = red\nname.en = Local Patron\n"), 0o644)
os.WriteFile(filepath.Join(dir, "config.ini"), []byte("use = local\n"), 0o644)
cfg, err := config.Load()
if err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if code := runLiturgy(cfg, "2025-08-11", &buf, &buf); code != 0 {
t.Fatalf("exit %d", code)
}
if !strings.Contains(buf.String(), "Local Patron") {
t.Fatalf("user layer's solemnity not observed:\n%s", buf.String())
}
}
|