cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

main
012 / internal / ui / evalview / evalview_test.go
evalview_test.go 3.7K
1package evalview23import (4 "strings"5 "testing"67 tea "charm.land/bubbletea/v2"8 "github.com/charmbracelet/x/ansi"910 "src.rest/cat/012/internal/locale"11 "src.rest/cat/012/internal/sheet"12 "src.rest/cat/012/internal/ui/theme"13)1415type fakeHost struct {16 th theme.Theme17 loc *locale.Locale18 w int19 closed bool20}2122func (h *fakeHost) Theme() *theme.Theme { return &h.th }23func (h *fakeHost) Size() (int, int) { return h.w, 24 }24func (h *fakeHost) Close() { h.closed = true }25func (h *fakeHost) Locale() *locale.Locale { return h.loc }26func named(code rune) tea.KeyPressMsg { return tea.KeyPressMsg{Code: code} }27func text(v *View) string { return ansi.Strip(strings.Join(v.Layout()[0].Lines, "\n")) }28func status(v *View) string { d, k := v.Status(); return ansi.Strip(d + " | " + k) }29func at(s string) sheet.Addr { a, _ := sheet.ParseAddr(s); return a }30func newHost(w int, l *locale.Locale) *fakeHost { return &fakeHost{th: theme.New(true), loc: l, w: w} }3132func book(t *testing.T) *sheet.Sheet {33 t.Helper()34 s := sheet.New()35 for a, in := range map[string]string{"A1": "1.5", "A2": "2", "B1": "=A1*2", "C1": "=SUM(B1,A2)"} {36 if err := s.Set(at(a), in); err != nil {37 t.Fatal(err)38 }39 }40 return s41}4243func TestEvaluate(t *testing.T) {44 s := book(t)45 h := newHost(60, locale.Canonical)46 v := New(h, s.EvaluateSteps(at("C1")))47 if got := text(v); !strings.Contains(got, "Evaluate C1") || !strings.Contains(got, "=SUM(B1,A2)") ||48 !strings.Contains(got, "Next B1 = 3") || !strings.Contains(got, "0 of 3") {49 t.Errorf("first:\n%s", got)50 }51 if got := status(v); !strings.Contains(got, "Enter evaluate") || !strings.Contains(got, "→ step in") {52 t.Errorf("status %q", got)53 }54 // Stepping into B1 shows its formula; stepping out puts its value in.55 v.Key(named(tea.KeyRight))56 if got := text(v); v.Depth() != 2 || !strings.Contains(got, "Evaluate C1 › B1") || !strings.Contains(got, "=A1*2") {57 t.Errorf("into B1:\n%s", got)58 }59 v.Key(named(tea.KeyEnter))60 v.Key(named(tea.KeyEnter))61 if got := text(v); !strings.Contains(got, "Value 3") || !strings.Contains(status(v), "Enter step out") {62 t.Errorf("B1 done:\n%s", got)63 }64 v.Key(named(tea.KeyEnter))65 if got := text(v); v.Depth() != 1 || !strings.Contains(got, "=SUM(3,A2)") || !strings.Contains(got, "Next A2 = 2") {66 t.Errorf("back out:\n%s", got)67 }68 v.Key(named(tea.KeyEnter))69 v.Key(named(tea.KeyEnter))70 if got := text(v); !strings.Contains(got, "Value 5") || !strings.Contains(status(v), "Enter restart") {71 t.Errorf("done:\n%s", got)72 }73 v.Key(named(tea.KeyEnter))74 if got := text(v); !strings.Contains(got, "0 of 3") {75 t.Errorf("restart:\n%s", got)76 }77 // Esc steps out, then closes.78 v.Key(named(tea.KeyRight))79 v.Key(named(tea.KeyEscape))80 if v.Depth() != 1 || h.closed {81 t.Error("Esc didn't step out")82 }83 v.Key(named(tea.KeyEscape))84 if !h.closed {85 t.Error("Esc didn't close")86 }87}8889// Formulas are written in the locale's syntax, and long ones wrap.90func TestEvaluateLocaleAndWrap(t *testing.T) {91 s := book(t)92 s.Set(at("D1"), "=A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1+A1")93 de, _ := locale.Lookup("de-DE")94 v := New(newHost(40, de), s.EvaluateSteps(at("C1")))95 v.Key(named(tea.KeyRight))96 v.Key(named(tea.KeyEnter))97 if got := text(v); !strings.Contains(got, "=1,5*2") {98 t.Errorf("de-DE:\n%s", got)99 }100 v = New(newHost(40, locale.Canonical), s.EvaluateSteps(at("D1")))101 lines := v.Layout()[0].Lines102 if len(lines) < 6 {103 t.Errorf("didn't wrap:\n%s", text(v))104 }105 for _, l := range lines {106 if ansi.StringWidth(l) != ansi.StringWidth(lines[0]) {107 t.Errorf("ragged box:\n%s", text(v))108 }109 }110}