2018-01-19 17:32:54 +08:00
|
|
|
package excelize
|
|
|
|
|
2018-12-27 18:51:44 +08:00
|
|
|
import (
|
2019-03-21 11:41:46 +08:00
|
|
|
"fmt"
|
2019-09-01 12:30:14 +08:00
|
|
|
"path/filepath"
|
2021-02-22 20:04:13 +08:00
|
|
|
"reflect"
|
2020-04-10 00:04:23 +08:00
|
|
|
"strconv"
|
2021-02-22 20:04:13 +08:00
|
|
|
"strings"
|
2020-08-15 00:09:50 +08:00
|
|
|
"sync"
|
2018-12-27 18:51:44 +08:00
|
|
|
"testing"
|
2019-10-26 20:55:24 +08:00
|
|
|
"time"
|
2018-12-27 18:51:44 +08:00
|
|
|
|
2021-07-06 00:31:04 +08:00
|
|
|
_ "image/jpeg"
|
|
|
|
|
2018-12-27 18:51:44 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
2018-01-19 17:32:54 +08:00
|
|
|
|
2020-08-15 00:09:50 +08:00
|
|
|
func TestConcurrency(t *testing.T) {
|
2021-07-04 12:13:06 +08:00
|
|
|
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
|
|
|
|
assert.NoError(t, err)
|
2020-08-15 00:09:50 +08:00
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
for i := 1; i <= 5; i++ {
|
|
|
|
wg.Add(1)
|
2021-02-15 00:09:35 +08:00
|
|
|
go func(val int, t *testing.T) {
|
2021-07-04 12:13:06 +08:00
|
|
|
// Concurrency set cell value
|
2021-02-15 00:09:35 +08:00
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("A%d", val), val))
|
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("B%d", val), strconv.Itoa(val)))
|
2021-07-07 00:57:43 +08:00
|
|
|
// Concurrency get cell value
|
2021-02-15 00:09:35 +08:00
|
|
|
_, err := f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
|
|
|
|
assert.NoError(t, err)
|
2021-07-07 00:57:43 +08:00
|
|
|
// Concurrency set rows
|
|
|
|
assert.NoError(t, f.SetSheetRow("Sheet1", "B6", &[]interface{}{" Hello",
|
|
|
|
[]byte("World"), 42, int8(1<<8/2 - 1), int16(1<<16/2 - 1), int32(1<<32/2 - 1),
|
|
|
|
int64(1<<32/2 - 1), float32(42.65418), float64(-42.65418), float32(42), float64(42),
|
|
|
|
uint(1<<32 - 1), uint8(1<<8 - 1), uint16(1<<16 - 1), uint32(1<<32 - 1),
|
|
|
|
uint64(1<<32 - 1), true, complex64(5 + 10i)}))
|
|
|
|
// Concurrency create style
|
|
|
|
style, err := f.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// Concurrency set cell style
|
|
|
|
assert.NoError(t, f.SetCellStyle("Sheet1", "A3", "A3", style))
|
2021-07-06 00:31:04 +08:00
|
|
|
// Concurrency add picture
|
|
|
|
assert.NoError(t, f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"),
|
2021-07-28 00:38:09 +08:00
|
|
|
`{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/xuri/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`))
|
2021-07-04 12:13:06 +08:00
|
|
|
// Concurrency get cell picture
|
|
|
|
name, raw, err := f.GetPicture("Sheet1", "A1")
|
|
|
|
assert.Equal(t, "", name)
|
|
|
|
assert.Nil(t, raw)
|
|
|
|
assert.NoError(t, err)
|
2021-07-05 00:03:56 +08:00
|
|
|
// Concurrency iterate rows
|
|
|
|
rows, err := f.Rows("Sheet1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for rows.Next() {
|
|
|
|
_, err := rows.Columns()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
// Concurrency iterate columns
|
|
|
|
cols, err := f.Cols("Sheet1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for rows.Next() {
|
|
|
|
_, err := cols.Rows()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
2021-07-04 12:13:06 +08:00
|
|
|
|
2020-08-15 00:09:50 +08:00
|
|
|
wg.Done()
|
2021-02-15 00:09:35 +08:00
|
|
|
}(i, t)
|
2020-08-15 00:09:50 +08:00
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
val, err := f.GetCellValue("Sheet1", "A1")
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
assert.Equal(t, "1", val)
|
2021-07-07 00:57:43 +08:00
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestConcurrency.xlsx")))
|
2020-08-15 00:09:50 +08:00
|
|
|
}
|
|
|
|
|
2018-01-19 17:32:54 +08:00
|
|
|
func TestCheckCellInArea(t *testing.T) {
|
2019-12-14 19:57:37 +08:00
|
|
|
f := NewFile()
|
2018-01-19 17:32:54 +08:00
|
|
|
expectedTrueCellInAreaList := [][2]string{
|
2018-01-31 11:12:43 +08:00
|
|
|
{"c2", "A1:AAZ32"},
|
|
|
|
{"B9", "A1:B9"},
|
|
|
|
{"C2", "C2:C2"},
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, expectedTrueCellInArea := range expectedTrueCellInAreaList {
|
|
|
|
cell := expectedTrueCellInArea[0]
|
|
|
|
area := expectedTrueCellInArea[1]
|
2019-12-14 19:57:37 +08:00
|
|
|
ok, err := f.checkCellInArea(cell, area)
|
2019-03-23 20:08:06 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Truef(t, ok,
|
2018-12-27 18:51:44 +08:00
|
|
|
"Expected cell %v to be in area %v, got false\n", cell, area)
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
expectedFalseCellInAreaList := [][2]string{
|
2018-01-31 11:12:43 +08:00
|
|
|
{"c2", "A4:AAZ32"},
|
|
|
|
{"C4", "D6:A1"}, // weird case, but you never know
|
|
|
|
{"AEF42", "BZ40:AEF41"},
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, expectedFalseCellInArea := range expectedFalseCellInAreaList {
|
|
|
|
cell := expectedFalseCellInArea[0]
|
|
|
|
area := expectedFalseCellInArea[1]
|
2019-12-14 19:57:37 +08:00
|
|
|
ok, err := f.checkCellInArea(cell, area)
|
2019-03-23 20:08:06 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Falsef(t, ok,
|
2018-12-27 18:51:44 +08:00
|
|
|
"Expected cell %v not to be inside of area %v, but got true\n", cell, area)
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
Huge refactorig for consistent col/row numbering (#356)
* Huge refactorig for consistent col/row numbering
Started from simply changing ToALphaString()/TitleToNumber() logic and related fixes.
But have to go deeper, do fixes, after do related fixes and again and again.
Major improvements:
1. Tests made stronger again (But still be weak).
2. "Empty" returns for incorrect input replaces with panic.
3. Check for correct col/row/cell naming & addressing by default.
4. Removed huge amount of duplicated code.
5. Removed ToALphaString(), TitleToNumber() and it helpers functions at all,
and replaced with SplitCellName(), JoinCellName(), ColumnNameToNumber(), ColumnNumberToName(), CellNameToCoordinates(), CoordinatesToCellName().
6. Minor fixes for internal variable naming for code readability (ex. col, row for input params, colIdx, rowIdx for slice indexes etc).
* Formatting fixes
2019-03-20 00:14:41 +08:00
|
|
|
|
2019-12-14 19:57:37 +08:00
|
|
|
ok, err := f.checkCellInArea("A1", "A:B")
|
|
|
|
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
assert.False(t, ok)
|
|
|
|
|
|
|
|
ok, err = f.checkCellInArea("AA0", "Z0:AB1")
|
2019-03-23 20:08:06 +08:00
|
|
|
assert.EqualError(t, err, `cannot convert cell "AA0" to coordinates: invalid cell name "AA0"`)
|
|
|
|
assert.False(t, ok)
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
2019-03-21 11:41:46 +08:00
|
|
|
|
|
|
|
func TestSetCellFloat(t *testing.T) {
|
|
|
|
sheet := "Sheet1"
|
|
|
|
t.Run("with no decimal", func(t *testing.T) {
|
|
|
|
f := NewFile()
|
2019-12-24 01:09:28 +08:00
|
|
|
assert.NoError(t, f.SetCellFloat(sheet, "A1", 123.0, -1, 64))
|
|
|
|
assert.NoError(t, f.SetCellFloat(sheet, "A2", 123.0, 1, 64))
|
2019-03-23 20:08:06 +08:00
|
|
|
val, err := f.GetCellValue(sheet, "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "123", val, "A1 should be 123")
|
|
|
|
val, err = f.GetCellValue(sheet, "A2")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "123.0", val, "A2 should be 123.0")
|
2019-03-21 11:41:46 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("with a decimal and precision limit", func(t *testing.T) {
|
|
|
|
f := NewFile()
|
2019-12-24 01:09:28 +08:00
|
|
|
assert.NoError(t, f.SetCellFloat(sheet, "A1", 123.42, 1, 64))
|
2019-03-23 20:08:06 +08:00
|
|
|
val, err := f.GetCellValue(sheet, "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "123.4", val, "A1 should be 123.4")
|
2019-03-21 11:41:46 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("with a decimal and no limit", func(t *testing.T) {
|
|
|
|
f := NewFile()
|
2019-12-24 01:09:28 +08:00
|
|
|
assert.NoError(t, f.SetCellFloat(sheet, "A1", 123.42, -1, 64))
|
2019-03-23 20:08:06 +08:00
|
|
|
val, err := f.GetCellValue(sheet, "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "123.42", val, "A1 should be 123.42")
|
2019-03-21 11:41:46 +08:00
|
|
|
})
|
2019-10-26 20:55:24 +08:00
|
|
|
f := NewFile()
|
|
|
|
assert.EqualError(t, f.SetCellFloat(sheet, "A", 123.42, -1, 64), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSetCellValue(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Now().UTC()), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Duration(1e13)), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
}
|
|
|
|
|
2020-10-04 21:07:39 +08:00
|
|
|
func TestSetCellValues(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
err := f.SetCellValue("Sheet1", "A1", time.Date(2010, time.December, 31, 0, 0, 0, 0, time.UTC))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
v, err := f.GetCellValue("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
2021-04-20 23:20:46 +08:00
|
|
|
assert.Equal(t, v, "12/31/10 00:00")
|
2020-10-04 21:07:39 +08:00
|
|
|
|
|
|
|
// test date value lower than min date supported by Excel
|
|
|
|
err = f.SetCellValue("Sheet1", "A1", time.Date(1600, time.December, 31, 0, 0, 0, 0, time.UTC))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2021-01-20 00:14:21 +08:00
|
|
|
v, err = f.GetCellValue("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, v, "1600-12-31T00:00:00Z")
|
2020-10-04 21:07:39 +08:00
|
|
|
}
|
|
|
|
|
2019-10-26 20:55:24 +08:00
|
|
|
func TestSetCellBool(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
}
|
|
|
|
|
2020-06-27 00:02:47 +08:00
|
|
|
func TestGetCellValue(t *testing.T) {
|
|
|
|
// Test get cell value without r attribute of the row.
|
|
|
|
f := NewFile()
|
2020-11-18 22:08:40 +08:00
|
|
|
sheetData := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>%s</sheetData></worksheet>`
|
2021-08-22 13:36:56 +08:00
|
|
|
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="3"><c t="str"><v>A3</v></c></row><row><c t="str"><v>A4</v></c><c t="str"><v>B4</v></c></row><row r="7"><c t="str"><v>A7</v></c><c t="str"><v>B7</v></c></row><row><c t="str"><v>A8</v></c><c t="str"><v>B8</v></c></row>`)))
|
2020-06-27 00:02:47 +08:00
|
|
|
f.checked = nil
|
|
|
|
cells := []string{"A3", "A4", "B4", "A7", "B7"}
|
|
|
|
rows, err := f.GetRows("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{nil, nil, {"A3"}, {"A4", "B4"}, nil, nil, {"A7", "B7"}, {"A8", "B8"}}, rows)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for _, cell := range cells {
|
|
|
|
value, err := f.GetCellValue("Sheet1", cell)
|
|
|
|
assert.Equal(t, cell, value)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
2020-06-28 00:02:32 +08:00
|
|
|
cols, err := f.GetCols("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{{"", "", "A3", "A4", "", "", "A7", "A8"}, {"", "", "", "B4", "", "", "B7", "B8"}}, cols)
|
|
|
|
assert.NoError(t, err)
|
2021-08-22 13:36:56 +08:00
|
|
|
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="str"><v>A2</v></c></row><row r="2"><c r="B2" t="str"><v>B2</v></c></row>`)))
|
2020-11-18 22:08:40 +08:00
|
|
|
f.checked = nil
|
|
|
|
cell, err := f.GetCellValue("Sheet1", "A2")
|
|
|
|
assert.Equal(t, "A2", cell)
|
|
|
|
assert.NoError(t, err)
|
2021-08-22 13:36:56 +08:00
|
|
|
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="str"><v>A2</v></c></row><row r="2"><c r="B2" t="str"><v>B2</v></c></row>`)))
|
2020-11-18 22:08:40 +08:00
|
|
|
f.checked = nil
|
|
|
|
rows, err = f.GetRows("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{nil, {"A2", "B2"}}, rows)
|
|
|
|
assert.NoError(t, err)
|
2021-08-22 13:36:56 +08:00
|
|
|
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="1"><c r="A1" t="str"><v>A1</v></c></row><row r="1"><c r="B1" t="str"><v>B1</v></c></row>`)))
|
2020-11-18 22:08:40 +08:00
|
|
|
f.checked = nil
|
|
|
|
rows, err = f.GetRows("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{{"A1", "B1"}}, rows)
|
|
|
|
assert.NoError(t, err)
|
2021-08-22 13:36:56 +08:00
|
|
|
|
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row><c t="str"><v>A3</v></c></row><row><c t="str"><v>A4</v></c><c t="str"><v>B4</v></c></row><row r="7"><c t="str"><v>A7</v></c><c t="str"><v>B7</v></c></row><row><c t="str"><v>A8</v></c><c t="str"><v>B8</v></c></row>`)))
|
|
|
|
f.checked = nil
|
|
|
|
rows, err = f.GetRows("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{{"A3"}, {"A4", "B4"}, nil, nil, nil, nil, {"A7", "B7"}, {"A8", "B8"}}, rows)
|
|
|
|
assert.NoError(t, err)
|
2021-08-23 00:15:43 +08:00
|
|
|
|
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="0"><c r="H6" t="str"><v>H6</v></c><c r="A1" t="str"><v>r0A6</v></c><c r="F4" t="str"><v>F4</v></c></row><row><c r="A1" t="str"><v>A6</v></c><c r="B1" t="str"><v>B6</v></c><c r="C1" t="str"><v>C6</v></c></row><row r="3"><c r="A3"><v>100</v></c><c r="B3" t="str"><v>B3</v></c></row>`)))
|
|
|
|
f.checked = nil
|
|
|
|
cell, err = f.GetCellValue("Sheet1", "H6")
|
|
|
|
assert.Equal(t, "H6", cell)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rows, err = f.GetRows("Sheet1")
|
|
|
|
assert.Equal(t, [][]string{
|
|
|
|
{"A6", "B6", "C6"},
|
|
|
|
nil,
|
|
|
|
{"100", "B3"},
|
|
|
|
{"", "", "", "", "", "F4"},
|
|
|
|
nil,
|
|
|
|
{"", "", "", "", "", "", "", "H6"},
|
|
|
|
}, rows)
|
|
|
|
assert.NoError(t, err)
|
2020-06-27 00:02:47 +08:00
|
|
|
}
|
|
|
|
|
2021-09-09 23:43:16 +08:00
|
|
|
func TestGetCellType(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
cellType, err := f.GetCellType("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, CellTypeUnset, cellType)
|
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", "A1", "A1"))
|
|
|
|
cellType, err = f.GetCellType("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, CellTypeString, cellType)
|
|
|
|
_, err = f.GetCellType("Sheet1", "A")
|
|
|
|
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
}
|
|
|
|
|
2019-10-26 20:55:24 +08:00
|
|
|
func TestGetCellFormula(t *testing.T) {
|
2019-12-22 00:02:09 +08:00
|
|
|
// Test get cell formula on not exist worksheet.
|
2019-10-26 20:55:24 +08:00
|
|
|
f := NewFile()
|
2019-12-22 00:02:09 +08:00
|
|
|
_, err := f.GetCellFormula("SheetN", "A1")
|
|
|
|
assert.EqualError(t, err, "sheet SheetN is not exist")
|
|
|
|
|
|
|
|
// Test get cell formula on no formula cell.
|
2019-12-24 01:09:28 +08:00
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
|
2019-12-22 00:02:09 +08:00
|
|
|
_, err = f.GetCellFormula("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
2021-08-15 01:19:49 +08:00
|
|
|
|
|
|
|
// Test get cell shared formula
|
|
|
|
f = NewFile()
|
|
|
|
sheetData := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"><c r="A1"><v>1</v></c><c r="B1"><f>2*A1</f></c></row><row r="2"><c r="A2"><v>2</v></c><c r="B2"><f t="shared" ref="B2:B7" si="0">%s</f></c></row><row r="3"><c r="A3"><v>3</v></c><c r="B3"><f t="shared" si="0"/></c></row><row r="4"><c r="A4"><v>4</v></c><c r="B4"><f t="shared" si="0"/></c></row><row r="5"><c r="A5"><v>5</v></c><c r="B5"><f t="shared" si="0"/></c></row><row r="6"><c r="A6"><v>6</v></c><c r="B6"><f t="shared" si="0"/></c></row><row r="7"><c r="A7"><v>7</v></c><c r="B7"><f t="shared" si="0"/></c></row></sheetData></worksheet>`
|
|
|
|
|
|
|
|
for sharedFormula, expected := range map[string]string{
|
|
|
|
`2*A2`: `2*A3`,
|
|
|
|
`2*A1A`: `2*A2A`,
|
|
|
|
`2*$A$2+LEN("")`: `2*$A$2+LEN("")`,
|
|
|
|
} {
|
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, sharedFormula)))
|
|
|
|
formula, err := f.GetCellFormula("Sheet1", "B3")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, expected, formula)
|
|
|
|
}
|
|
|
|
|
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="2"><c r="B2"><f t="shared" si="0"></f></c></row></sheetData></worksheet>`))
|
|
|
|
formula, err := f.GetCellFormula("Sheet1", "B2")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "", formula)
|
2019-10-26 20:55:24 +08:00
|
|
|
}
|
|
|
|
|
2019-03-21 11:41:46 +08:00
|
|
|
func ExampleFile_SetCellFloat() {
|
|
|
|
f := NewFile()
|
2019-03-21 14:09:25 +08:00
|
|
|
var x = 3.14159265
|
2019-12-24 01:09:28 +08:00
|
|
|
if err := f.SetCellFloat("Sheet1", "A1", x, 2, 64); err != nil {
|
2020-02-19 00:08:10 +08:00
|
|
|
fmt.Println(err)
|
2019-12-24 01:09:28 +08:00
|
|
|
}
|
2019-03-23 20:08:06 +08:00
|
|
|
val, _ := f.GetCellValue("Sheet1", "A1")
|
|
|
|
fmt.Println(val)
|
2019-03-21 11:41:46 +08:00
|
|
|
// Output: 3.14
|
|
|
|
}
|
2019-04-16 14:50:16 +08:00
|
|
|
|
|
|
|
func BenchmarkSetCellValue(b *testing.B) {
|
|
|
|
values := []string{"First", "Second", "Third", "Fourth", "Fifth", "Sixth"}
|
|
|
|
cols := []string{"A", "B", "C", "D", "E", "F"}
|
|
|
|
f := NewFile()
|
|
|
|
b.ResetTimer()
|
2020-04-10 00:04:23 +08:00
|
|
|
for i := 1; i <= b.N; i++ {
|
2019-04-16 14:50:16 +08:00
|
|
|
for j := 0; j < len(values); j++ {
|
2020-04-10 00:04:23 +08:00
|
|
|
if err := f.SetCellValue("Sheet1", cols[j]+strconv.Itoa(i), values[j]); err != nil {
|
2019-12-24 01:09:28 +08:00
|
|
|
b.Error(err)
|
|
|
|
}
|
2019-04-16 14:50:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-01 12:30:14 +08:00
|
|
|
|
|
|
|
func TestOverflowNumericCell(t *testing.T) {
|
|
|
|
f, err := OpenFile(filepath.Join("test", "OverflowNumericCell.xlsx"))
|
|
|
|
if !assert.NoError(t, err) {
|
|
|
|
t.FailNow()
|
|
|
|
}
|
2019-09-02 21:52:55 +08:00
|
|
|
val, err := f.GetCellValue("Sheet1", "A1")
|
2019-09-01 12:30:14 +08:00
|
|
|
assert.NoError(t, err)
|
2019-09-02 21:52:55 +08:00
|
|
|
// GOARCH=amd64 - all ok; GOARCH=386 - actual: "-2147483648"
|
2019-09-01 12:30:14 +08:00
|
|
|
assert.Equal(t, "8595602512225", val, "A1 should be 8595602512225")
|
|
|
|
}
|
2021-09-03 22:51:56 +08:00
|
|
|
|
|
|
|
func TestSetCellFormula(t *testing.T) {
|
|
|
|
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
|
|
|
|
if !assert.NoError(t, err) {
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "B19", "SUM(Sheet2!D2,Sheet2!D11)"))
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)"))
|
|
|
|
|
|
|
|
// Test set cell formula with illegal rows number.
|
|
|
|
assert.EqualError(t, f.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)"), `cannot convert cell "C" to coordinates: invalid cell name "C"`)
|
|
|
|
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
|
|
|
|
|
|
|
|
f, err = OpenFile(filepath.Join("test", "CalcChain.xlsx"))
|
|
|
|
if !assert.NoError(t, err) {
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
// Test remove cell formula.
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "A1", ""))
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula2.xlsx")))
|
|
|
|
// Test remove all cell formula.
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "B1", ""))
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula3.xlsx")))
|
|
|
|
|
|
|
|
// Test set shared formula for the cells.
|
|
|
|
f = NewFile()
|
|
|
|
for r := 1; r <= 5; r++ {
|
|
|
|
assert.NoError(t, f.SetSheetRow("Sheet1", fmt.Sprintf("A%d", r), &[]interface{}{r, r + 1}))
|
|
|
|
}
|
|
|
|
formulaType, ref := STCellFormulaTypeShared, "C1:C5"
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", "=A1+B1", FormulaOpts{Ref: &ref, Type: &formulaType}))
|
|
|
|
sharedFormulaSpreadsheet := filepath.Join("test", "TestSetCellFormula4.xlsx")
|
|
|
|
assert.NoError(t, f.SaveAs(sharedFormulaSpreadsheet))
|
|
|
|
|
|
|
|
f, err = OpenFile(sharedFormulaSpreadsheet)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ref = "D1:D5"
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "D1", "=A1+C1", FormulaOpts{Ref: &ref, Type: &formulaType}))
|
|
|
|
ref = ""
|
|
|
|
assert.EqualError(t, f.SetCellFormula("Sheet1", "D1", "=A1+C1", FormulaOpts{Ref: &ref, Type: &formulaType}), ErrParameterInvalid.Error())
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula5.xlsx")))
|
2021-09-05 11:59:50 +08:00
|
|
|
|
|
|
|
// Test set table formula for the cells.
|
|
|
|
f = NewFile()
|
|
|
|
for idx, row := range [][]interface{}{{"A", "B", "C"}, {1, 2}} {
|
|
|
|
assert.NoError(t, f.SetSheetRow("Sheet1", fmt.Sprintf("A%d", idx+1), &row))
|
|
|
|
}
|
|
|
|
assert.NoError(t, f.AddTable("Sheet1", "A1", "C2", `{"table_name":"Table1","table_style":"TableStyleMedium2"}`))
|
|
|
|
formulaType = STCellFormulaTypeDataTable
|
|
|
|
assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=SUM(Table1[[A]:[B]])", FormulaOpts{Type: &formulaType}))
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula6.xlsx")))
|
2021-09-03 22:51:56 +08:00
|
|
|
}
|
|
|
|
|
2021-02-22 20:04:13 +08:00
|
|
|
func TestGetCellRichText(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
|
|
|
|
runsSource := []RichTextRun{
|
|
|
|
{
|
|
|
|
Text: "a\n",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "b",
|
|
|
|
Font: &Font{
|
|
|
|
Underline: "single",
|
|
|
|
Color: "ff0000",
|
|
|
|
Bold: true,
|
|
|
|
Italic: true,
|
|
|
|
Family: "Times New Roman",
|
|
|
|
Size: 100,
|
|
|
|
Strike: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", runsSource))
|
2020-04-06 00:23:27 +08:00
|
|
|
|
2021-02-22 20:04:13 +08:00
|
|
|
runs, err := f.GetCellRichText("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, runsSource[0].Text, runs[0].Text)
|
|
|
|
assert.Nil(t, runs[0].Font)
|
|
|
|
assert.NotNil(t, runs[1].Font)
|
|
|
|
|
|
|
|
runsSource[1].Font.Color = strings.ToUpper(runsSource[1].Font.Color)
|
|
|
|
assert.True(t, reflect.DeepEqual(runsSource[1].Font, runs[1].Font), "should get the same font")
|
|
|
|
|
|
|
|
// Test get cell rich text when string item index overflow
|
2021-07-05 00:03:56 +08:00
|
|
|
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
|
|
|
|
assert.True(t, ok)
|
|
|
|
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "2"
|
2021-02-22 20:04:13 +08:00
|
|
|
runs, err = f.GetCellRichText("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 0, len(runs))
|
|
|
|
// Test get cell rich text when string item index is negative
|
2021-07-05 00:03:56 +08:00
|
|
|
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
|
|
|
|
assert.True(t, ok)
|
|
|
|
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "-1"
|
2021-02-22 20:04:13 +08:00
|
|
|
runs, err = f.GetCellRichText("Sheet1", "A1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 0, len(runs))
|
|
|
|
// Test get cell rich text on invalid string item index
|
2021-07-05 00:03:56 +08:00
|
|
|
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
|
|
|
|
assert.True(t, ok)
|
|
|
|
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "x"
|
2021-02-22 20:04:13 +08:00
|
|
|
_, err = f.GetCellRichText("Sheet1", "A1")
|
|
|
|
assert.EqualError(t, err, "strconv.Atoi: parsing \"x\": invalid syntax")
|
|
|
|
// Test set cell rich text on not exists worksheet
|
|
|
|
_, err = f.GetCellRichText("SheetN", "A1")
|
|
|
|
assert.EqualError(t, err, "sheet SheetN is not exist")
|
|
|
|
// Test set cell rich text with illegal cell coordinates
|
|
|
|
_, err = f.GetCellRichText("Sheet1", "A")
|
|
|
|
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
|
|
|
}
|
2020-04-06 00:23:27 +08:00
|
|
|
func TestSetCellRichText(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
assert.NoError(t, f.SetRowHeight("Sheet1", 1, 35))
|
|
|
|
assert.NoError(t, f.SetColWidth("Sheet1", "A", "A", 44))
|
|
|
|
richTextRun := []RichTextRun{
|
|
|
|
{
|
2020-08-22 18:58:43 +08:00
|
|
|
Text: "bold",
|
2020-04-06 00:23:27 +08:00
|
|
|
Font: &Font{
|
|
|
|
Bold: true,
|
|
|
|
Color: "2354e8",
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: " and ",
|
|
|
|
Font: &Font{
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "italic ",
|
|
|
|
Font: &Font{
|
|
|
|
Bold: true,
|
|
|
|
Color: "e83723",
|
|
|
|
Italic: true,
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "text with color and font-family,",
|
|
|
|
Font: &Font{
|
|
|
|
Bold: true,
|
|
|
|
Color: "2354e8",
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "\r\nlarge text with ",
|
|
|
|
Font: &Font{
|
|
|
|
Size: 14,
|
|
|
|
Color: "ad23e8",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "strike",
|
|
|
|
Font: &Font{
|
|
|
|
Color: "e89923",
|
|
|
|
Strike: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: " and ",
|
|
|
|
Font: &Font{
|
|
|
|
Size: 14,
|
|
|
|
Color: "ad23e8",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "underline.",
|
|
|
|
Font: &Font{
|
|
|
|
Color: "23e833",
|
|
|
|
Underline: "single",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", richTextRun))
|
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A2", richTextRun))
|
|
|
|
style, err := f.NewStyle(&Style{
|
|
|
|
Alignment: &Alignment{
|
|
|
|
WrapText: true,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "A1", style))
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellRichText.xlsx")))
|
|
|
|
// Test set cell rich text on not exists worksheet
|
|
|
|
assert.EqualError(t, f.SetCellRichText("SheetN", "A1", richTextRun), "sheet SheetN is not exist")
|
|
|
|
// Test set cell rich text with illegal cell coordinates
|
|
|
|
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
2021-07-31 14:20:29 +08:00
|
|
|
richTextRun = []RichTextRun{{Text: strings.Repeat("s", TotalCellChars+1)}}
|
|
|
|
// Test set cell rich text with characters over the maximum limit
|
|
|
|
assert.EqualError(t, f.SetCellRichText("Sheet1", "A1", richTextRun), ErrCellCharsLength.Error())
|
2020-04-06 00:23:27 +08:00
|
|
|
}
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2020-12-12 16:17:00 +08:00
|
|
|
func TestFormattedValue2(t *testing.T) {
|
2020-10-04 21:07:39 +08:00
|
|
|
f := NewFile()
|
2021-09-05 11:59:50 +08:00
|
|
|
v := f.formattedValue(0, "43528", false)
|
2020-10-04 21:07:39 +08:00
|
|
|
assert.Equal(t, "43528", v)
|
|
|
|
|
2021-09-05 11:59:50 +08:00
|
|
|
v = f.formattedValue(15, "43528", false)
|
2020-10-04 21:07:39 +08:00
|
|
|
assert.Equal(t, "43528", v)
|
|
|
|
|
2021-09-05 11:59:50 +08:00
|
|
|
v = f.formattedValue(1, "43528", false)
|
2020-10-04 21:07:39 +08:00
|
|
|
assert.Equal(t, "43528", v)
|
|
|
|
customNumFmt := "[$-409]MM/DD/YYYY"
|
|
|
|
_, err := f.NewStyle(&Style{
|
|
|
|
CustomNumFmt: &customNumFmt,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2021-09-05 11:59:50 +08:00
|
|
|
v = f.formattedValue(1, "43528", false)
|
2020-10-04 21:07:39 +08:00
|
|
|
assert.Equal(t, "03/04/2019", v)
|
2020-10-19 23:55:54 +08:00
|
|
|
|
|
|
|
// formatted value with no built-in number format ID
|
|
|
|
numFmtID := 5
|
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: &numFmtID,
|
|
|
|
})
|
2021-09-05 11:59:50 +08:00
|
|
|
v = f.formattedValue(2, "43528", false)
|
2020-12-12 16:17:00 +08:00
|
|
|
assert.Equal(t, "43528", v)
|
|
|
|
|
|
|
|
// formatted value with invalid number format ID
|
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: nil,
|
|
|
|
})
|
2021-09-05 11:59:50 +08:00
|
|
|
_ = f.formattedValue(3, "43528", false)
|
2020-12-12 16:17:00 +08:00
|
|
|
|
|
|
|
// formatted value with empty number format
|
|
|
|
f.Styles.NumFmts = nil
|
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: &numFmtID,
|
|
|
|
})
|
2021-09-05 11:59:50 +08:00
|
|
|
v = f.formattedValue(1, "43528", false)
|
2020-10-19 23:55:54 +08:00
|
|
|
assert.Equal(t, "43528", v)
|
2020-10-04 21:07:39 +08:00
|
|
|
}
|