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 / sheet / find_test.go
find_test.go 3.8K
1package sheet23import (4 "slices"5 "testing"6)78func findSheet() *Sheet {9 s := New()10 for a, in := range map[string]string{11 "A1": "Rent", "B1": "1450",12 "A2": "rental car", "B2": "=B1*2",13 "A3": "'2900", "B3": "=SUM(B1:B2)",14 "C1": "Rent", "C2": "Total rent: $5",15 } {16 s.Set(at(a), in)17 }18 return s19}2021func names(as []Addr) []string {22 out := make([]string, len(as))23 for i, a := range as {24 out[i] = a.String()25 }26 return out27}2829func TestFind(t *testing.T) {30 s := findSheet()31 b1b2 := NewRect(at("B1"), at("B2"))32 tests := []struct {33 query string34 o FindOptions35 want []string36 }{37 {"rent", FindOptions{}, []string{"A1", "C1", "A2", "C2"}}, // reading order38 {"Rent", FindOptions{MatchCase: true}, []string{"A1", "C1"}},39 {"rent", FindOptions{WholeCell: true}, []string{"A1", "C1"}},40 {"2900", FindOptions{}, []string{"B2", "A3"}}, // formula results and forced text41 {"B1", FindOptions{}, nil}, // formula text isn't searched by default42 {"B1", FindOptions{InFormulas: true}, []string{"B2", "B3"}},43 {`^r\w+`, FindOptions{Regex: true}, []string{"A1", "C1", "A2"}},44 {"$5", FindOptions{}, []string{"C2"}}, // plain queries are literal45 {"1450", FindOptions{Within: &b1b2}, []string{"B1"}},46 {"", FindOptions{}, nil},47 }48 for _, tt := range tests {49 got, err := s.Find(tt.query, tt.o)50 if err != nil {51 t.Errorf("Find(%q): %v", tt.query, err)52 continue53 }54 if !slices.Equal(names(got), tt.want) {55 t.Errorf("Find(%q, %+v) = %v, want %v", tt.query, tt.o, names(got), tt.want)56 }57 }58 if _, err := s.Find("(", FindOptions{Regex: true}); err == nil {59 t.Error("invalid regex accepted")60 }61}6263func TestReplace(t *testing.T) {64 s := findSheet()65 n, err := s.ReplaceAll("rent", "Lease", FindOptions{})66 if err != nil || n != 4 {67 t.Fatalf("ReplaceAll = %d, %v", n, err)68 }69 for a, want := range map[string]string{"A1": "Lease", "A2": "Leaseal car", "C2": "Total Lease: $5"} {70 if got := s.Cell(at(a)).Input; got != want {71 t.Errorf("%s = %q, want %q", a, got, want)72 }73 }7475 // Formulas only change when searching within them, and keep working.76 if n, _ := s.ReplaceAll("B1", "A9", FindOptions{}); n != 0 {77 t.Errorf("replaced %d formula results", n)78 }79 s.Set(at("A9"), "10")80 if n, _ := s.ReplaceAll("B1", "A9", FindOptions{InFormulas: true}); n != 2 {81 t.Errorf("replaced %d formulas", n)82 }83 if got := s.Value(at("B2")).Num; got != 20 {84 t.Errorf("B2 = %v after rewriting its reference", got)85 }8687 // Regex groups; forced text stays text; literal $ in plain mode.88 s.Set(at("D1"), "2026-09-26")89 s.Replace(at("D1"), `(\d+)-(\d+)-(\d+)`, "$3/$2/$1", FindOptions{Regex: true})90 if got := s.Cell(at("D1")).Input; got != "26/09/2026" {91 t.Errorf("regex replace = %q", got)92 }93 s.Replace(at("A3"), "2900", "3000", FindOptions{})94 if c := s.Cell(at("A3")); c.Input != "'3000" || c.Value.Kind != Text {95 t.Errorf("forced text = %+v", c)96 }97 s.Set(at("C1"), "Rent due")98 s.Replace(at("C1"), "Rent", "$1", FindOptions{})99 if got := s.Cell(at("C1")).Input; got != "$1 due" {100 t.Errorf("plain replacement = %q, want a literal $1", got)101 }102103 // A replacement that breaks a formula is an error and changes nothing.104 s.Set(at("E1"), "=SUM(B1:B2)")105 if _, err := s.Replace(at("E1"), ")", "", FindOptions{InFormulas: true}); err == nil {106 t.Error("broken formula accepted")107 }108 if got := s.Cell(at("E1")).Input; got != "=SUM(B1:B2)" {109 t.Errorf("E1 changed to %q", got)110 }111}112113func TestReplaceAllIsOneUndoStep(t *testing.T) {114 s := findSheet()115 if n, err := s.ReplaceAll("rent", "Lease", FindOptions{}); n != 4 || err != nil {116 t.Fatalf("ReplaceAll = %d, %v", n, err)117 }118 if _, ok := s.Undo(); !ok {119 t.Fatal("nothing to undo")120 }121 for a, want := range map[string]string{"A1": "Rent", "A2": "rental car", "C1": "Rent", "C2": "Total rent: $5"} {122 if got := s.Cell(at(a)).Input; got != want {123 t.Errorf("%s = %q after undo, want %q", a, got, want)124 }125 }126}