cat / 012
clone

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

cat/module-path
012 / internal / ui / protect_test.go
protect_test.go 3.7K
1package ui23import (4 "strings"5 "testing"67 tea "charm.land/bubbletea/v2"89 "src.rest/cat/012/internal/sheet"10 "src.rest/cat/012/internal/ui/choicebar"11)1213func TestProtectRangeWarns(t *testing.T) {14 m := newModel()15 press(t, m, "<shift+down>", "<shift+right>")16 m.runCommand("data.protect_range")17 if l := line(m, contextLine); !strings.HasPrefix(l, "Describe A1:B2 (optional):") {18 t.Fatalf("prompt %q", l)19 }20 press(t, m, "Inputs", "<enter>")21 if ps := m.sheet.Protections(); len(ps) != 1 || ps[0].Desc != "Inputs" || ps[0].Range != rectOf("A1:B2") {22 t.Fatalf("protections %+v", ps)23 }24 // Typing into a protected cell asks first; Esc backs out.25 press(t, m, "<esc>", "7")26 if l := line(m, contextLine); !strings.Contains(l, "A1:B2 is protected.") || !strings.Contains(l, "Edit anyway") {27 t.Fatalf("no warning: %q", l)28 }29 if !strings.Contains(line(m, m.height-1), "Inputs") {30 t.Errorf("status %q", line(m, m.height-1))31 }32 press(t, m, "<esc>")33 if m.mode != modeReady || m.sheet.Value(addr("A1")).Kind != sheet.Empty {34 t.Fatalf("Esc went on: mode %v, A1 %v", m.mode, m.sheet.Value(addr("A1")))35 }36 // Enter goes on with the keystroke that asked.37 press(t, m, "7", "<enter>")38 if m.mode != modeEnter || m.line.Text() != "7" {39 t.Fatalf("after Enter: mode %v, %q", m.mode, m.line.Text())40 }41 press(t, m, "<enter>")42 if m.sheet.Value(addr("A1")).Num != 7 {43 t.Fatalf("A1 = %v", m.sheet.Value(addr("A1")))44 }45 // Commands ask through what they edit; outside, nothing asks.46 press(t, m, "<up>")47 m.runCommand("clear")48 if _, ok := m.overlay.(*choicebar.Bar); !ok {49 t.Fatal("clear didn't ask")50 }51 press(t, m, "<enter>")52 if m.sheet.Value(addr("A1")).Kind != sheet.Empty {53 t.Errorf("clear after Enter: %v", m.sheet.Value(addr("A1")))54 }55 press(t, m, "<right>", "<right>", "5", "<enter>")56 if m.sheet.Value(addr("C1")).Num != 5 {57 t.Errorf("C1 = %v", m.sheet.Value(addr("C1")))58 }59 // Inserting rows above moves the range without asking.60 press(t, m, "<up>")61 m.runCommand("insert.row_above")62 if m.overlay != nil || m.sheet.Protections()[0].Range != rectOf("A2:B3") {63 t.Errorf("insert: overlay %T, %+v", m.overlay, m.sheet.Protections())64 }65 // Pasted text into the range asks too.66 press(t, m, "<left>", "<left>", "<down>")67 send(m, tea.PasteMsg{Content: "1\t2"})68 if _, ok := m.overlay.(*choicebar.Bar); !ok {69 t.Fatal("paste didn't ask")70 }71 press(t, m, "<enter>")72 if m.sheet.Value(addr("B2")).Num != 2 {73 t.Errorf("B2 = %v", m.sheet.Value(addr("B2")))74 }75 m.runCommand("data.unprotect")76 if len(m.sheet.Protections()) != 0 {77 t.Errorf("unprotect left %+v", m.sheet.Protections())78 }79}8081func TestProtectSheetAndPicker(t *testing.T) {82 m := tallModel()83 m.Update(teaSize(100, 30))84 m.runCommand("data.protect")85 s := screen(m)86 if !strings.Contains(s, "Protected sheets and ranges") || !strings.Contains(s, "+ Protect the sheet") {87 t.Fatalf("picker:\n%s", s)88 }89 press(t, m, "<down>", "<enter>", "<enter>")90 if ps := m.sheet.Protections(); len(ps) != 1 || !ps[0].Sheet {91 t.Fatalf("protections %+v", ps)92 }93 // Back in the picker; the sheet's protection is listed.94 if !strings.Contains(screen(m), "whole sheet") {95 t.Fatalf("picker after adding:\n%s", screen(m))96 }97 press(t, m, "<esc>")98 // Anything on a protected sheet asks, inserting rows included.99 m.runCommand("insert.row_above")100 if _, ok := m.overlay.(*choicebar.Bar); !ok || !strings.Contains(line(m, contextLine), "Sheet1 is protected.") {101 t.Fatalf("insert didn't ask: %q", line(m, contextLine))102 }103 press(t, m, "<esc>")104 m.runCommand("data.protect")105 press(t, m, "<down>", "<down>", "<ctrl+d>")106 if len(m.sheet.Protections()) != 0 || !strings.Contains(screen(m), "Removed the protection of the sheet") {107 t.Errorf("remove: %+v\n%s", m.sheet.Protections(), screen(m))108 }109}