269 lines
5.9 KiB
Go
269 lines
5.9 KiB
Go
|
package excelwriter_test
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"github.com/xuri/excelize/v2"
|
||
|
|
||
|
"gitlab.com/slon/shad-go/excelwriter"
|
||
|
)
|
||
|
|
||
|
const Sheet = "Sheet1"
|
||
|
|
||
|
type MyInt int
|
||
|
|
||
|
type Basic struct {
|
||
|
I int `xlsx:"i"`
|
||
|
UI uint `xlsx:"ui"`
|
||
|
I16 int16 `xlsx:"i_16"`
|
||
|
UI16 uint16 `xlsx:"ui_16"`
|
||
|
I32 int32 `xlsx:"i_32"`
|
||
|
UI32 uint32 `xlsx:"ui_32"`
|
||
|
I64 int64 `xlsx:"i_64"`
|
||
|
UI64 uint64 `xlsx:"ui_64"`
|
||
|
|
||
|
Float float32 `xlsx:"float"`
|
||
|
Double float64 `xlsx:"double"`
|
||
|
Bool bool `xlsx:"bool"`
|
||
|
String string `xlsx:"string"`
|
||
|
|
||
|
MyInt int `xlsx:"my_int"`
|
||
|
}
|
||
|
|
||
|
type Inner struct {
|
||
|
Name string `xlsx:"name"`
|
||
|
}
|
||
|
|
||
|
type TextInt int
|
||
|
|
||
|
func (i TextInt) MarshalText() ([]byte, error) {
|
||
|
return []byte("__" + fmt.Sprint(i) + "__"), nil
|
||
|
}
|
||
|
|
||
|
type TextStruct struct {
|
||
|
V string
|
||
|
}
|
||
|
|
||
|
func (s TextStruct) MarshalText() (text []byte, err error) {
|
||
|
return []byte("__" + s.V + "__"), nil
|
||
|
}
|
||
|
|
||
|
func TestWriter_basic(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet(Sheet)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
b := &Basic{
|
||
|
I: -1,
|
||
|
UI: 1,
|
||
|
I16: -16,
|
||
|
UI16: 16,
|
||
|
I32: -32,
|
||
|
UI32: 32,
|
||
|
I64: -64,
|
||
|
UI64: 64,
|
||
|
|
||
|
Float: -2.5,
|
||
|
Double: 5.5,
|
||
|
Bool: true,
|
||
|
String: "hello",
|
||
|
|
||
|
MyInt: 23,
|
||
|
}
|
||
|
require.NoError(t, w.WriteRow(b))
|
||
|
|
||
|
storeFile(t, f, "basic")
|
||
|
|
||
|
rows := readAll(t, f, true)
|
||
|
require.Equal(t, []string{"i", "ui", "i_16", "ui_16", "i_32", "ui_32", "i_64", "ui_64", "float", "double", "bool", "string", "my_int"}, rows[0])
|
||
|
require.Equal(t, []string{"-1", "1", "-16", "16", "-32", "32", "-64", "64", "-2.5", "5.5", "1", "hello", "23"}, rows[1])
|
||
|
}
|
||
|
|
||
|
func TestWriter_map(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet(Sheet)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
require.NoError(t, w.WriteRow(map[string]any{
|
||
|
"id": 29,
|
||
|
"name": "hello",
|
||
|
"title": "yo",
|
||
|
}))
|
||
|
|
||
|
require.NoError(t, w.WriteRow(map[string]any{}))
|
||
|
|
||
|
require.NoError(t, w.WriteRow(map[TextStruct]any{
|
||
|
{"id"}: 18,
|
||
|
{"name"}: "tm",
|
||
|
}))
|
||
|
|
||
|
storeFile(t, f, "map")
|
||
|
|
||
|
rows := readAll(t, f, true)
|
||
|
require.Equal(t, []string{"id", "name", "title", "__id__", "__name__"}, rows[0])
|
||
|
require.Equal(t, []string{"29", "hello", "yo"}, rows[1])
|
||
|
require.Equal(t, []string{"", "", "", "18", "tm"}, rows[2])
|
||
|
}
|
||
|
|
||
|
type E struct {
|
||
|
ID string `xlsx:"id"`
|
||
|
NoTag string
|
||
|
Skipped int `xlsx:"-"`
|
||
|
private float32 `xlsx:"private"`
|
||
|
|
||
|
TextInt TextInt `xlsx:"text-int"`
|
||
|
TextStruct TextStruct `xlsx:"text-struct"`
|
||
|
|
||
|
Struct Inner `xlsx:"inner"`
|
||
|
StructPtr *Inner `xlsx:"inner-ptr"`
|
||
|
|
||
|
Slice []int `xlsx:"slice"`
|
||
|
Array [2]int `xlsx:"arr"`
|
||
|
|
||
|
Map map[string]string `xlsx:"map"`
|
||
|
TMMap map[TextStruct]string `xlsx:"tm-map"`
|
||
|
|
||
|
F func() `xlsx:"func"`
|
||
|
Ch chan int `xlsx:"chan"`
|
||
|
}
|
||
|
|
||
|
func TestWriter_elaborate(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet("Sheet1")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
e := &E{
|
||
|
ID: "42",
|
||
|
NoTag: "no-tag",
|
||
|
Skipped: 29,
|
||
|
private: 2,
|
||
|
TextInt: 77,
|
||
|
TextStruct: TextStruct{V: "text-struct"},
|
||
|
Struct: Inner{Name: "inner"},
|
||
|
StructPtr: &Inner{Name: "inner-ptr"},
|
||
|
Slice: []int{1, 2, 3},
|
||
|
Array: [2]int{4, 5},
|
||
|
Map: map[string]string{"foo": "bar"},
|
||
|
TMMap: map[TextStruct]string{{"foo"}: "bar"},
|
||
|
F: func() { fmt.Println("hello") },
|
||
|
Ch: make(chan int, 10),
|
||
|
}
|
||
|
require.NoError(t, w.WriteRow(e))
|
||
|
|
||
|
storeFile(t, f, "elaborate")
|
||
|
|
||
|
rows := readAll(t, f, true)
|
||
|
require.Equal(t, []string{"id", "notag", "private", "text-int", "text-struct", "inner", "inner-ptr", "slice", "arr", "map", "tm-map"}, rows[0])
|
||
|
require.Equal(t, []string{"42", "no-tag", "2", "__77__", "__text-struct__", `{"Name":"inner"}`, `{"Name":"inner-ptr"}`, "[1,2,3]", "[4,5]", `{"foo":"bar"}`, `{"__foo__":"bar"}`}, rows[1])
|
||
|
}
|
||
|
|
||
|
func TestWriter_ptr(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet(Sheet)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
require.NoError(t, w.WriteRow(struct{ Name string }{"foo"}))
|
||
|
require.NoError(t, w.WriteRow(&struct{ Name string }{"bar"}))
|
||
|
require.NoError(t, w.WriteRow(map[string]string{"name": "baz"}))
|
||
|
require.NoError(t, w.WriteRow(&map[string]string{"name": "qux"}))
|
||
|
|
||
|
storeFile(t, f, "ptr")
|
||
|
|
||
|
rows := readAll(t, f, true)
|
||
|
require.Equal(t, []string{"name"}, rows[0])
|
||
|
require.Equal(t, []string{"foo"}, rows[1])
|
||
|
require.Equal(t, []string{"bar"}, rows[2])
|
||
|
require.Equal(t, []string{"baz"}, rows[3])
|
||
|
require.Equal(t, []string{"qux"}, rows[4])
|
||
|
}
|
||
|
|
||
|
func TestWriter_unsupported(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet("Sheet1")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
require.Error(t, w.WriteRow(2))
|
||
|
require.Error(t, w.WriteRow(nil))
|
||
|
var b *Basic
|
||
|
require.Error(t, w.WriteRow(b))
|
||
|
}
|
||
|
|
||
|
type S struct {
|
||
|
P float64 `xlsx:"percent,numfmt:9"`
|
||
|
D int `xlsx:"date,numfmt:15"`
|
||
|
D2 int `xlsx:",numfmt:15"`
|
||
|
T float64 `xlsx:"time,numfmt:22"`
|
||
|
Y int `xlsx:"jpy,numfmt:194"`
|
||
|
}
|
||
|
|
||
|
func TestWriter_style(t *testing.T) {
|
||
|
f := excelize.NewFile()
|
||
|
_, err := f.NewSheet("Sheet1")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
w := excelwriter.New(f)
|
||
|
|
||
|
s := &S{
|
||
|
P: 0.5,
|
||
|
D: 100,
|
||
|
D2: 100,
|
||
|
T: 100.5,
|
||
|
Y: 200,
|
||
|
}
|
||
|
require.NoError(t, w.WriteRow(s))
|
||
|
|
||
|
storeFile(t, f, "style")
|
||
|
|
||
|
rows := readAll(t, f, false)
|
||
|
require.Equal(t, []string{"percent", "date", "d2", "time", "jpy"}, rows[0])
|
||
|
require.Equal(t, []string{"50%", "9-Apr-00", "9-Apr-00", "4/9/00 12:00", "¥200.00"}, rows[1])
|
||
|
}
|
||
|
|
||
|
func readAll(t *testing.T, f *excelize.File, raw bool) [][]string {
|
||
|
t.Helper()
|
||
|
|
||
|
var out [][]string
|
||
|
|
||
|
rows, err := f.Rows(Sheet)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
var opts []excelize.Options
|
||
|
if raw {
|
||
|
opts = append(opts, excelize.Options{RawCellValue: true})
|
||
|
}
|
||
|
|
||
|
for i := 1; rows.Next(); i++ {
|
||
|
row, err := rows.Columns(opts...)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
out = append(out, row)
|
||
|
}
|
||
|
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func storeFile(t *testing.T, f *excelize.File, prefix string) {
|
||
|
t.Helper()
|
||
|
|
||
|
out, err := os.CreateTemp("/tmp", prefix+"-*.xlsx")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = f.WriteTo(out)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
t.Logf("stored file in %s", out.Name())
|
||
|
}
|