From ed34fd574b4fc2e0a52c655ececddd1be29b271e Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 24 Jul 2026 12:26:23 +0200 Subject: reader: lectio-ui --reader fuzzy book picker + chapter reader over the corpora; v0.8.0 --- internal/tui/reader_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 internal/tui/reader_test.go (limited to 'internal/tui/reader_test.go') diff --git a/internal/tui/reader_test.go b/internal/tui/reader_test.go new file mode 100644 index 0000000..167e546 --- /dev/null +++ b/internal/tui/reader_test.go @@ -0,0 +1,100 @@ +package tui + +import ( + "strings" + "testing" + + tea "github.com/charmbracelet/bubbletea" + + "github.com/lukaszkasprzak/lectio/internal/bible" + "github.com/lukaszkasprzak/lectio/internal/config" +) + +func enReader(t *testing.T) ReaderModel { + t.Helper() + tbl, err := bible.LoadBookTable(nil) + if err != nil { + t.Fatal(err) + } + cfg := config.Default() + cfg.UILanguage = "en" + cfg.SiglaStyle = "english" + cfg.Versions = []string{"bt", "wuj", "vul", "grb", "drb"} + return NewReader(cfg, tbl) +} + +func key(m ReaderModel, k tea.KeyMsg) ReaderModel { + nm, _ := m.Update(k) + return nm.(ReaderModel) +} + +func runes(s string) tea.KeyMsg { return tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(s)} } + +func TestReaderInit(t *testing.T) { + m := enReader(t) + if m.mode != modePick { + t.Errorf("mode = %v want modePick", m.mode) + } + if len(m.matches) != len(m.books) || len(m.books) != 73 { + t.Errorf("matches=%d books=%d", len(m.matches), len(m.books)) + } + if len(m.versions) == 0 || m.versions[0] == "bt" { + t.Errorf("versions = %v (bt must be excluded, non-empty)", m.versions) + } +} + +func TestReaderFilterAndOpen(t *testing.T) { + m := enReader(t) + nm, _ := m.Update(tea.WindowSizeMsg{Width: 80, Height: 24}) + m = nm.(ReaderModel) + m = key(m, runes("jn")) + if len(m.matches) == 0 || m.books[m.matches[0]].Canonical != "John" { + t.Fatalf("filter 'jn' top = %v", m.books[m.matches[m.pickSel]]) + } + m = key(m, tea.KeyMsg{Type: tea.KeyEnter}) + if m.mode != modeRead { + t.Fatalf("did not enter read mode") + } + if m.books[m.bookIdx].Canonical != "John" || len(m.verses) == 0 { + t.Errorf("opened book=%q verses=%d", m.books[m.bookIdx].Canonical, len(m.verses)) + } + if !strings.Contains(m.View(), "1") { // chapter 1 header + t.Errorf("read view missing chapter:\n%s", m.View()) + } +} + +func TestReaderChapterAndVersion(t *testing.T) { + m := enReader(t) + nm, _ := m.Update(tea.WindowSizeMsg{Width: 80, Height: 24}) + m = nm.(ReaderModel) + m = key(m, runes("jn")) + m = key(m, tea.KeyMsg{Type: tea.KeyEnter}) + firstChap := m.chapters[m.chapPos] + m = key(m, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("n")}) // next chapter + if m.chapters[m.chapPos] <= firstChap { + t.Errorf("chapter did not advance: %d -> %d", firstChap, m.chapters[m.chapPos]) + } + v0 := m.verIdx + m = key(m, tea.KeyMsg{Type: tea.KeyTab}) + if m.verIdx == v0 { + t.Errorf("version did not cycle") + } + // esc returns to picker + m = key(m, tea.KeyMsg{Type: tea.KeyEsc}) + if m.mode != modePick { + t.Errorf("esc did not return to picker") + } +} + +func TestReaderFuzzyScore(t *testing.T) { + if s, ok := fuzzyScore("gen", "Gen Genesis"); !ok || s < 500 { + t.Errorf("substring score = %d,%v", s, ok) + } + if _, ok := fuzzyScore("xyz", "Gen Genesis"); ok { + t.Error("xyz should not match Genesis") + } + // subsequence: g..s..s across the string + if _, ok := fuzzyScore("gss", "Gen Genesis"); !ok { + t.Error("gss should subsequence-match") + } +} -- cgit v1.3