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 / derived_test.go
derived_test.go 4.5K
1package sheet23import (4 "bytes"5 "strings"6 "testing"7)89// A derived cell of every value, format, inferred format and mark comes10// back from the store as it went in, kept in a slot unless it has a11// note, and the store counts the pivot's results it holds.12func TestSlotDerived(t *testing.T) {13 st := newCellStore()14 a := Addr{Col: 2, Row: 700}15 values := []Value{num(1.5), num(-0.25), boolean(true), boolean(false), {Kind: Text, Str: "north"},16 {Kind: Text, Str: "=not a formula"}, {Kind: Text, Str: "12"}, ErrRef, ErrDiv0, {Kind: Text}}17 for _, v := range values {18 for _, pivot := range []bool{true, false} {19 for _, note := range []string{"", "a note"} {20 c := &Cell{Input: derivedInput(v), Value: v, Format: Preset(FmtCurrency), Note: note, derived: pivot, spilled: !pivot}21 if !pivot {22 c.auto = Preset(FmtPercent)23 }24 c.Style.Bold = pivot25 checkDerived(t, &st, a, c)26 }27 }28 }29 st.delete(a)30 if st.len() != 0 || st.pivots != 0 || len(st.strs.index) != 0 || len(st.rich) != len(st.richFree) {31 t.Errorf("left: %d stored, %d pivot cells, %d strings, %d rich", st.len(), st.pivots, len(st.strs.index), len(st.rich)-len(st.richFree))32 }33}3435// checkDerived stores the derived cell c at a and reads it back.36func checkDerived(t *testing.T, st *cellStore, a Addr, c *Cell) {37 t.Helper()38 want := c.clone()39 st.set(a, c)40 checkSame(t, st.get(a), want)41 if rich := st.richAt(a) != nil; rich != (want.Note != "") {42 t.Errorf("%+v: rich %v", want, rich)43 }44 if got := st.filledAt(a); got != !want.Blank() {45 t.Errorf("%+v: filled %v", want, got)46 }47 if !st.holds(a, st.get(a)) {48 t.Errorf("%+v: doesn't hold its own view", want)49 }50 if n := len(collect(st.pivotKeys())); n != st.pivots || (n == 1) != want.derived {51 t.Errorf("%+v: %d pivot cells found, %d counted", want, n, st.pivots)52 }53}5455func collect(seq func(func(Addr) bool)) []Addr {56 var out []Addr57 seq(func(a Addr) bool { out = append(out, a); return true })58 return out59}6061// Spilled cells are slots, and read as they did as Cells: values of each62// kind, the anchor's inferred format, values when copied, skipped by63// Replace and left out of the file.64func TestSpillCompact(t *testing.T) {65 s := sheetOf(t, map[string]string{66 "A1": "$5", "A2": "$6", "A3": "x",67 "B1": "=ARRAYFORMULA(A1:A2*2)",68 "C1": `=ARRAYFORMULA(IF(SEQUENCE(3)=2, "none", SEQUENCE(3)))`,69 "D1": "=SEQUENCE(2)>1",70 "E1": "=1/(SEQUENCE(2)-2)",71 })72 wantShown(t, s, map[string]string{"B2": "12", "C2": "none", "C3": "3", "D2": "TRUE", "E2": "#DIV/0!"})73 for _, a := range []string{"B2", "C2", "C3", "D2", "E2"} {74 if s.cells.richAt(at(a)) != nil {75 t.Errorf("%s is a whole Cell", a)76 }77 if c := s.Cell(at(a)); !c.Spilled() || c.Input != derivedInput(c.Value) {78 t.Errorf("%s = %+v", a, c)79 }80 }81 if f := s.DisplayFormat(at("B2")); f.Kind != FmtCurrency {82 t.Errorf("B2's format %v, want the anchor's currency", f)83 }84 found, err := s.Find("none", FindOptions{})85 if err != nil || len(found) != 1 || found[0] != at("C2") {86 t.Errorf("Find found %v %v, want the spilled C2", found, err)87 }88 if changed, err := s.Replace(at("C2"), "none", "x", FindOptions{}); changed || err != nil {89 t.Errorf("Replace changed a spilled cell: %v %v", changed, err)90 }91 clip := s.Copy(rect("E1:E2"))92 if _, err := s.Paste(clip, rect("G1:G1"), false); err != nil {93 t.Fatal(err)94 }95 if c := s.Cell(at("G2")); c.Spilled() || c.Value.String() != "#DIV/0!" {96 t.Errorf("pasted spilled error = %+v", c)97 }98 var buf bytes.Buffer99 if err := s.Book().Write(&buf); err != nil {100 t.Fatal(err)101 }102 if strings.Contains(buf.String(), `"B2"`) || strings.Contains(buf.String(), `"D2"`) {103 t.Errorf("spilled cells saved:\n%s", buf.String())104 }105}106107// A pivot's results are slots, found again when they shrink.108func TestPivotCompact(t *testing.T) {109 src := sheetOf(t, map[string]string{"A1": "Region", "B1": "Sales", "A2": "north", "B2": "10", "A3": "south", "B3": "5", "A4": "east", "B4": "7"})110 r := rect("A1:B4")111 p := NewPivot(src, r)112 p.Rows = []PivotGroup{{Col: 0}}113 p.Values = []PivotValue{{Col: 1, Summarize: SumBy}}114 pv, err := src.Book().CreatePivot(src, r, "", p)115 if err != nil {116 t.Fatal(err)117 }118 n := pv.cells.pivots119 if n == 0 || len(pv.cells.rich) != len(pv.cells.richFree) {120 t.Fatalf("%d pivot cells, %d rich", n, len(pv.cells.rich)-len(pv.cells.richFree))121 }122 if err := src.Set(at("A4"), "north"); err != nil {123 t.Fatal(err)124 }125 if pv.cells.pivots >= n {126 t.Errorf("%d pivot cells after a group went, had %d", pv.cells.pivots, n)127 }128 if got := len(collect(pv.cells.pivotKeys())); got != pv.cells.pivots {129 t.Errorf("%d pivot cells found, %d counted", got, pv.cells.pivots)130 }131}