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
|
package tui
import (
"errors"
"strings"
"testing"
"github.com/lukaszkasprzak/lectio/internal/config"
"github.com/lukaszkasprzak/lectio/internal/liturgy"
)
func TestVersionCycle(t *testing.T) {
m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl"}, "", "")
if m.version() != "pl" {
t.Fatalf("start = %q", m.version())
}
m = m.cycleVersion(+1)
if m.version() != "wuj" {
t.Errorf("after tab = %q", m.version())
}
m = m.cycleVersion(-1)
if m.version() != "pl" {
t.Errorf("after shift-tab = %q", m.version())
}
}
func TestOfflineDropsPL(t *testing.T) {
m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl", Offline: true}, "", "")
for _, v := range m.versions {
if v == "pl" {
t.Error("offline model kept pl")
}
}
}
// TestBodyLinesLocalisesMessages checks that the loading/no-readings/error
// messages follow cfg.UILanguage.
func TestBodyLinesLocalisesMessages(t *testing.T) {
en := Model{cfg: config.Config{UILanguage: "en"}, loading: true}
if lines := en.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "loading") {
t.Errorf("en loading bodyLines = %v, want it to contain %q", lines, "loading")
}
pl := Model{cfg: config.Config{UILanguage: "pl"}, loading: true}
if lines := pl.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "ładowanie") {
t.Errorf("pl loading bodyLines = %v, want it to contain %q", lines, "ładowanie")
}
enEmpty := Model{cfg: config.Config{UILanguage: "en"}, date: "2026-07-22"}
if lines := enEmpty.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "no readings for") {
t.Errorf("en no-readings bodyLines = %v, want it to contain %q", lines, "no readings for")
}
}
// TestBodyLinesSingleSpaceConcatenation is a regression test for the
// i18n-migration whitespace bug: i18n.UI.NoReadingsFor/ErrorPrefix must
// carry exactly one trailing space, since bodyLines concatenates the date/
// error string directly onto them with no separator of its own -- the
// pre-i18n TUI code produced "błąd: " + err / "brak czytań na " + date (one
// space), and the i18n fields regressed to two.
func TestBodyLinesSingleSpaceConcatenation(t *testing.T) {
enEmpty := Model{cfg: config.Config{UILanguage: "en"}, date: "2026-07-22"}
lines := enEmpty.bodyLines(80)
if len(lines) == 0 || !strings.Contains(lines[0], "no readings for 2026-07-22") {
t.Errorf("en no-readings bodyLines[0] = %q, want it to contain %q (single space)", lines[0], "no readings for 2026-07-22")
}
if strings.Contains(lines[0], "for 2026") {
t.Errorf("en no-readings bodyLines[0] = %q, has 2+ spaces before the date", lines[0])
}
plEmpty := Model{cfg: config.Config{UILanguage: "pl"}, date: "2026-07-22"}
lines = plEmpty.bodyLines(80)
if len(lines) == 0 || !strings.Contains(lines[0], "brak czytań na 2026-07-22") {
t.Errorf("pl no-readings bodyLines[0] = %q, want it to contain %q (single space)", lines[0], "brak czytań na 2026-07-22")
}
errText := "boom"
enErr := Model{cfg: config.Config{UILanguage: "en"}, err: errors.New(errText)}
lines = enErr.bodyLines(80)
if len(lines) == 0 || !strings.Contains(lines[0], "error: "+errText) {
t.Errorf("en error bodyLines[0] = %q, want it to contain %q (single space)", lines[0], "error: "+errText)
}
if strings.Contains(lines[0], "error: ") {
t.Errorf("en error bodyLines[0] = %q, has 2+ spaces after \"error:\"", lines[0])
}
plErr := Model{cfg: config.Config{UILanguage: "pl"}, err: errors.New(errText)}
lines = plErr.bodyLines(80)
if len(lines) == 0 || !strings.Contains(lines[0], "błąd: "+errText) {
t.Errorf("pl error bodyLines[0] = %q, want it to contain %q (single space)", lines[0], "błąd: "+errText)
}
if strings.Contains(lines[0], "błąd: ") {
t.Errorf("pl error bodyLines[0] = %q, has 2+ spaces after \"błąd:\"", lines[0])
}
}
// TestBodyLinesLocalisesHeading checks that a modern-lectionary section
// heading's label word follows cfg.UILanguage while the citation stays
// exactly as scraped (render.LocalizeHeading, brief §3b).
func TestBodyLinesLocalisesHeading(t *testing.T) {
sec := liturgy.Section{Heading: "Ewangelia (J 20, 1. 11-18)", PartID: "ewangelia"}
en := Model{cfg: config.Config{UILanguage: "en", Lectionary: "new"}, sections: []liturgy.Section{sec}}
body := strings.Join(en.bodyLines(80), "\n")
if !strings.Contains(body, "Gospel (J 20, 1. 11-18)") {
t.Errorf("en bodyLines missing localised heading: %q", body)
}
pl := Model{cfg: config.Config{UILanguage: "pl", Lectionary: "new"}, sections: []liturgy.Section{sec}}
body = strings.Join(pl.bodyLines(80), "\n")
if !strings.Contains(body, "Ewangelia (J 20, 1. 11-18)") {
t.Errorf("pl bodyLines missing unchanged heading: %q", body)
}
}
// TestFooterKeysLocalised checks the footer keybar text follows
// cfg.UILanguage.
func TestFooterKeysLocalised(t *testing.T) {
en := Model{cfg: config.Config{UILanguage: "en"}, date: "2026-07-22"}
if out := en.View(); !strings.Contains(out, "q quit") {
t.Errorf("en View() footer missing %q: %q", "q quit", out)
}
pl := Model{cfg: config.Config{UILanguage: "pl"}, date: "2026-07-22"}
if out := pl.View(); !strings.Contains(out, "q wyjście") {
t.Errorf("pl View() footer missing %q: %q", "q wyjście", out)
}
}
|