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 / fileio / xlsxlayout_test.go
xlsxlayout_test.go 5.1K
1package fileio23import (4 "context"5 "path/filepath"6 "slices"7 "testing"89 "github.com/xuri/excelize/v2"1011 "src.rest/cat/012/internal/sheet"12)1314func rangeOf(t testing.TB, s string) sheet.Rect {15 t.Helper()16 r, ok := sheet.ParseRange(s)17 if !ok {18 t.Fatalf("bad range %q", s)19 }20 return r21}2223// Wrapping, borders, heights and merges go out to Excel and come back.24func TestXLSXLayoutRoundTrip(t *testing.T) {25 src := build(t, map[string]string{"A1": "Title", "A2": "a long text that wraps", "B2": "2"})26 src.Merge(rangeOf(t, "A1:C1"), sheet.MergeAll)27 src.SetStyle(rangeOf(t, "A2"), func(st *sheet.Style) { st.Wrap = sheet.WrapOn })28 src.SetBorders(rangeOf(t, "A2:C3"), sheet.BorderAll, sheet.LineThin)29 src.SetBorders(rangeOf(t, "A2:C3"), sheet.BorderOuter, sheet.LineThick)30 src.SetBorders(rangeOf(t, "B2"), sheet.BorderBottom, sheet.LineDouble)31 src.SetBorderStroke(rangeOf(t, "C3"), sheet.BorderRight, sheet.Stroke{Line: sheet.LineThick, Color: sheet.ColorGreen})32 src.SetStyle(rangeOf(t, "B2"), func(st *sheet.Style) { st.VAlign = sheet.VAlignTop })33 src.SetRowHeight(4, 4, 3)3435 name := filepath.Join(t.TempDir(), "layout.xlsx")36 if _, err := Export(context.Background(), name, XLSX, SnapBook(src), ExportOptions{}); err != nil {37 t.Fatal(err)38 }39 x, err := excelize.OpenFile(name)40 if err != nil {41 t.Fatal(err)42 }43 ws := x.GetSheetName(0)44 if mc, _ := x.GetMergeCells(ws); len(mc) != 1 || mc[0].GetStartAxis() != "A1" || mc[0].GetEndAxis() != "C1" {45 t.Errorf("merges in Excel: %v", mc)46 }47 if h, _ := x.GetRowHeight(ws, 5); h != 45 {48 t.Errorf("row 5 is %v points", h)49 }50 id, _ := x.GetCellStyle(ws, "C3") // a blank cell drawing lines51 st, _ := x.GetStyle(id)52 if st == nil || len(st.Border) == 0 {53 t.Errorf("C3's borders didn't go to Excel: %+v", st)54 }55 id, _ = x.GetCellStyle(ws, "A2")56 if st, _ = x.GetStyle(id); st == nil || st.Alignment == nil || !st.Alignment.WrapText {57 t.Errorf("A2 doesn't wrap in Excel: %+v", st)58 }59 id, _ = x.GetCellStyle(ws, "B2")60 if st, _ = x.GetStyle(id); st == nil || st.Alignment == nil || st.Alignment.Vertical != "top" {61 t.Errorf("B2 isn't at the top in Excel: %+v", st)62 }63 x.Close()6465 res, err := Import(context.Background(), name, Options{})66 if err != nil {67 t.Fatal(err)68 }69 got := res.Sheet70 if !slices.Equal(got.Merges(), src.Merges()) {71 t.Errorf("merges %v", got.Merges())72 }73 if h, _ := got.RowHeight(4); h != 3 {74 t.Errorf("row 5 height %d", h)75 }76 for _, a := range []string{"A2", "B2", "C2", "A3", "B3", "C3", "B4"} {77 if g, w := got.CellStyle(addr(t, a)), src.CellStyle(addr(t, a)); g != w {78 t.Errorf("%s style %+v, want %+v", a, g, w)79 }80 }81}8283// What Excel writes: its other line styles, heights it fitted itself84// (not read) and ones set by hand, and merged cells.85func TestXLSXLayoutImport(t *testing.T) {86 p := oneSheetParts("", `<row r="1" ht="45" customHeight="1"><c r="A1" s="1"><v>1</v></c><c r="B1" s="2"/></row>`+87 `<row r="2" ht="60"><c r="A2" s="3" t="inlineStr"><is><t>fits</t></is></c></row>`+88 `<row r="3" ht="15.75" customHeight="1"><c r="A3" s="1"/><c r="D3"><v>4</v></c></row>`)89 p["xl/styles.xml"] = `<styleSheet ` + mainNS + `><fonts count="1"><font/></fonts>` +90 `<borders count="3"><border><left/><right/><top/><bottom/></border>` +91 `<border><left style="hair"><color auto="1"/></left><right style="mediumDashed"><color rgb="FF808080"/></right>` +92 `<top style="double"><color rgb="FFFF0000"/></top><bottom style="thick"><color theme="4"/></bottom></border>` +93 `<border><left style="dashDot"/></border></borders>` +94 `<cellXfs count="4"><xf numFmtId="0" fontId="0" borderId="0"/><xf numFmtId="0" fontId="0" borderId="1" applyBorder="1"/>` +95 `<xf numFmtId="0" fontId="0" borderId="2"/><xf numFmtId="0" fontId="0" borderId="0"><alignment wrapText="1" vertical="center"/></xf></cellXfs></styleSheet>`96 p["xl/worksheets/sheet1.xml"] = p["xl/worksheets/sheet1.xml"][:len(p["xl/worksheets/sheet1.xml"])-len(`</worksheet>`)] +97 `<mergeCells count="2"><mergeCell ref="B2:C3"/><mergeCell ref="$E$5:$E$9"/></mergeCells></worksheet>`98 name := writeParts(t, t.TempDir(), "excel.xlsx", p)99 res, err := Import(context.Background(), name, Options{})100 if err != nil {101 t.Fatal(err)102 }103 s := res.Sheet104 // Colors come in as the nearest named one; grays as the text's ink.105 want := sheet.BordersOf(sheet.LineDouble, sheet.LineThick, sheet.LineThin, sheet.LineThick).106 WithColor(sheet.EdgeTop, sheet.ColorRed).WithColor(sheet.EdgeBottom, sheet.ColorBlue)107 if got := s.CellStyle(addr(t, "A1")).Borders; got != want {108 t.Errorf("A1 borders %x, want %x", uint32(got), uint32(want))109 }110 if v := s.CellStyle(addr(t, "A2")).VAlign; v != sheet.VAlignMiddle {111 t.Errorf("vertical center read as %v", v)112 }113 if got := s.CellStyle(addr(t, "B1")).Borders.Left(); got != sheet.LineThin {114 t.Errorf("a blank cell's border after the row's values: %v", got)115 }116 if s.CellStyle(addr(t, "A2")).Wrap != sheet.WrapOn {117 t.Error("wrapText not read")118 }119 if h, ok := s.RowHeight(0); !ok || h != 3 {120 t.Errorf("row 1 height %d, %v", h, ok)121 }122 for _, row := range []int{1, 2} {123 if _, ok := s.RowHeight(row); ok {124 t.Errorf("row %d has a height", row+1)125 }126 }127 if got := s.Merges(); len(got) != 2 || got[1] != rangeOf(t, "E5:E9") {128 t.Errorf("merges %v", got)129 }130}