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"
|
2022-01-11 00:24:24 +08:00
|
|
|
"os"
|
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
|
2022-01-23 00:32:34 +08:00
|
|
|
assert.NoError(t, f.SetSheetRow("Sheet1", "B6", &[]interface{}{
|
|
|
|
" Hello",
|
2021-07-07 00:57:43 +08:00
|
|
|
[]byte("World"), 42, int8(1<<8/2 - 1), int16(1<<16/2 - 1), int32(1<<32/2 - 1),
|
2022-03-24 00:19:30 +08:00
|
|
|
int64(1<<32/2 - 1), float32(42.65418), -42.65418, float32(42), float64(42),
|
2021-07-07 00:57:43 +08:00
|
|
|
uint(1<<32 - 1), uint8(1<<8 - 1), uint16(1<<16 - 1), uint32(1<<32 - 1),
|
2022-01-23 00:32:34 +08:00
|
|
|
uint64(1<<32 - 1), true, complex64(5 + 10i),
|
|
|
|
}))
|
2021-07-07 00:57:43 +08:00
|
|
|
// 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)
|
|
|
|
}
|
2022-09-11 00:04:04 +08:00
|
|
|
// Concurrency set columns style
|
|
|
|
assert.NoError(t, f.SetColStyle("Sheet1", "C:E", style))
|
|
|
|
// Concurrency get columns style
|
|
|
|
styleID, err := f.GetColStyle("Sheet1", "D")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, style, styleID)
|
|
|
|
// Concurrency set columns width
|
|
|
|
assert.NoError(t, f.SetColWidth("Sheet1", "A", "B", 10))
|
|
|
|
// Concurrency get columns width
|
|
|
|
width, err := f.GetColWidth("Sheet1", "A")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, 10.0, width)
|
|
|
|
// Concurrency set columns visible
|
|
|
|
assert.NoError(t, f.SetColVisible("Sheet1", "A:B", true))
|
|
|
|
// Concurrency get columns visible
|
|
|
|
visible, err := f.GetColVisible("Sheet1", "A")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, true, visible)
|
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")))
|
2021-09-18 23:20:24 +08:00
|
|
|
assert.NoError(t, f.Close())
|
2020-08-15 00:09:50 +08:00
|
|
|
}
|
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
func TestCheckCellInRangeRef(t *testing.T) {
|
2019-12-14 19:57:37 +08:00
|
|
|
f := NewFile()
|
2022-09-28 00:04:17 +08:00
|
|
|
expectedTrueCellInRangeRefList := [][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
|
|
|
}
|
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
for _, expectedTrueCellInRangeRef := range expectedTrueCellInRangeRefList {
|
|
|
|
cell := expectedTrueCellInRangeRef[0]
|
|
|
|
reference := expectedTrueCellInRangeRef[1]
|
|
|
|
ok, err := f.checkCellInRangeRef(cell, reference)
|
2019-03-23 20:08:06 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Truef(t, ok,
|
2022-09-28 00:04:17 +08:00
|
|
|
"Expected cell %v to be in range reference %v, got false\n", cell, reference)
|
2018-01-19 17:32:54 +08:00
|
|
|
}
|
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
expectedFalseCellInRangeRefList := [][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
|
|
|
}
|
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
for _, expectedFalseCellInRangeRef := range expectedFalseCellInRangeRefList {
|
|
|
|
cell := expectedFalseCellInRangeRef[0]
|
|
|
|
reference := expectedFalseCellInRangeRef[1]
|
|
|
|
ok, err := f.checkCellInRangeRef(cell, reference)
|
2019-03-23 20:08:06 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Falsef(t, ok,
|
2022-09-28 00:04:17 +08:00
|
|
|
"Expected cell %v not to be inside of range reference %v, but got true\n", cell, reference)
|
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
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
ok, err := f.checkCellInRangeRef("A1", "A:B")
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2019-12-14 19:57:37 +08:00
|
|
|
assert.False(t, ok)
|
|
|
|
|
2022-09-28 00:04:17 +08:00
|
|
|
ok, err = f.checkCellInRangeRef("AA0", "Z0:AB1")
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, err, newCellNameToCoordinatesError("AA0", newInvalidCellNameError("AA0")).Error())
|
2019-03-23 20:08:06 +08:00
|
|
|
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)
|
2022-02-18 00:02:39 +08:00
|
|
|
assert.Equal(t, "123", val, "A2 should be 123")
|
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()
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, f.SetCellFloat(sheet, "A", 123.42, -1, 64), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2019-10-26 20:55:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSetCellValue(t *testing.T) {
|
|
|
|
f := NewFile()
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Now().UTC()), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Duration(1e13)), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2022-11-13 00:40:04 +08:00
|
|
|
// Test set cell value with column and row style inherit.
|
2022-05-15 15:38:40 +08:00
|
|
|
style1, err := f.NewStyle(&Style{NumFmt: 2})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
style2, err := f.NewStyle(&Style{NumFmt: 9})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NoError(t, f.SetColStyle("Sheet1", "B", style1))
|
|
|
|
assert.NoError(t, f.SetRowStyle("Sheet1", 1, 1, style2))
|
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", "B1", 0.5))
|
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", "B2", 0.5))
|
|
|
|
B1, err := f.GetCellValue("Sheet1", "B1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "50%", B1)
|
|
|
|
B2, err := f.GetCellValue("Sheet1", "B2")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "0.50", B2)
|
2022-11-12 00:02:11 +08:00
|
|
|
|
2022-11-13 00:40:04 +08:00
|
|
|
// Test set cell value with unsupported charset shared strings table.
|
2022-11-12 00:02:11 +08:00
|
|
|
f.SharedStrings = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", "A1"), "XML syntax error on line 1: invalid UTF-8")
|
2022-11-13 00:40:04 +08:00
|
|
|
// Test set cell value with unsupported charset workbook.
|
|
|
|
f.WorkBook = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", time.Now().UTC()), "XML syntax error on line 1: invalid UTF-8")
|
2019-10-26 20:55:24 +08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2022-11-13 00:40:04 +08:00
|
|
|
// Test date value lower than min date supported by Excel.
|
2020-10-04 21:07:39 +08:00
|
|
|
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()
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2019-10-26 20:55:24 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 00:09:35 +08:00
|
|
|
func TestSetCellTime(t *testing.T) {
|
|
|
|
date, err := time.Parse(time.RFC3339Nano, "2009-11-10T23:00:00Z")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for location, expected := range map[string]string{
|
|
|
|
"America/New_York": "40127.75",
|
|
|
|
"Asia/Shanghai": "40128.291666666664",
|
|
|
|
"Europe/London": "40127.958333333336",
|
|
|
|
"UTC": "40127.958333333336",
|
|
|
|
} {
|
|
|
|
timezone, err := time.LoadLocation(location)
|
|
|
|
assert.NoError(t, err)
|
2022-10-25 10:24:45 +08:00
|
|
|
c := &xlsxC{}
|
|
|
|
isNum, err := c.setCellTime(date.In(timezone), false)
|
2021-11-24 00:09:35 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, true, isNum)
|
2022-10-25 10:24:45 +08:00
|
|
|
assert.Equal(t, expected, c.V)
|
2021-11-24 00:09:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="3"><c t="inlineStr"><is><t>A3</t></is></c></row><row><c t="inlineStr"><is><t>A4</t></is></c><c t="inlineStr"><is><t>B4</t></is></c></row><row r="7"><c t="inlineStr"><is><t>A7</t></is></c><c t="inlineStr"><is><t>B7</t></is></c></row><row><c t="inlineStr"><is><t>A8</t></is></c><c t="inlineStr"><is><t>B8</t></is></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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="inlineStr"><is><t>A2</t></is></c></row><row r="2"><c r="B2" t="inlineStr"><is><t>B2</t></is></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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="inlineStr"><is><t>A2</t></is></c></row><row r="2"><c r="B2" t="inlineStr"><is><t>B2</t></is></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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="1"><c r="A1" t="inlineStr"><is><t>A1</t></is></c></row><row r="1"><c r="B1" t="inlineStr"><is><t>B1</t></is></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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row><c t="inlineStr"><is><t>A3</t></is></c></row><row><c t="inlineStr"><is><t>A4</t></is></c><c t="inlineStr"><is><t>B4</t></is></c></row><row r="7"><c t="inlineStr"><is><t>A7</t></is></c><c t="inlineStr"><is><t>B7</t></is></c></row><row><c t="inlineStr"><is><t>A8</t></is></c><c t="inlineStr"><is><t>B8</t></is></c></row>`)))
|
2021-08-22 13:36:56 +08:00
|
|
|
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")
|
2022-10-25 10:24:45 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="0"><c r="H6" t="inlineStr"><is><t>H6</t></is></c><c r="A1" t="inlineStr"><is><t>r0A6</t></is></c><c r="F4" t="inlineStr"><is><t>F4</t></is></c></row><row><c r="A1" t="inlineStr"><is><t>A6</t></is></c><c r="B1" t="inlineStr"><is><t>B6</t></is></c><c r="C1" t="inlineStr"><is><t>C6</t></is></c></row><row r="3"><c r="A3"><v>100</v></c><c r="B3" t="inlineStr"><is><t>B3</t></is></c></row>`)))
|
2021-08-23 00:15:43 +08:00
|
|
|
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)
|
2021-09-26 00:07:40 +08:00
|
|
|
|
|
|
|
f.Sheet.Delete("xl/worksheets/sheet1.xml")
|
2022-10-24 00:02:22 +08:00
|
|
|
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `
|
|
|
|
<row r="1"><c r="A1"><v>2422.3000000000002</v></c></row>
|
|
|
|
<row r="2"><c r="A2"><v>2422.3000000000002</v></c></row>
|
|
|
|
<row r="3"><c r="A3"><v>12.4</v></c></row>
|
|
|
|
<row r="4"><c r="A4"><v>964</v></c></row>
|
|
|
|
<row r="5"><c r="A5"><v>1101.5999999999999</v></c></row>
|
|
|
|
<row r="6"><c r="A6"><v>275.39999999999998</v></c></row>
|
|
|
|
<row r="7"><c r="A7"><v>68.900000000000006</v></c></row>
|
|
|
|
<row r="8"><c r="A8"><v>44385.208333333336</v></c></row>
|
|
|
|
<row r="9"><c r="A9"><v>5.0999999999999996</v></c></row>
|
|
|
|
<row r="10"><c r="A10"><v>5.1100000000000003</v></c></row>
|
|
|
|
<row r="11"><c r="A11"><v>5.0999999999999996</v></c></row>
|
|
|
|
<row r="12"><c r="A12"><v>5.1109999999999998</v></c></row>
|
|
|
|
<row r="13"><c r="A13"><v>5.1111000000000004</v></c></row>
|
|
|
|
<row r="14"><c r="A14"><v>2422.012345678</v></c></row>
|
|
|
|
<row r="15"><c r="A15"><v>2422.0123456789</v></c></row>
|
|
|
|
<row r="16"><c r="A16"><v>12.012345678901</v></c></row>
|
|
|
|
<row r="17"><c r="A17"><v>964</v></c></row>
|
|
|
|
<row r="18"><c r="A18"><v>1101.5999999999999</v></c></row>
|
|
|
|
<row r="19"><c r="A19"><v>275.39999999999998</v></c></row>
|
|
|
|
<row r="20"><c r="A20"><v>68.900000000000006</v></c></row>
|
|
|
|
<row r="21"><c r="A21"><v>8.8880000000000001E-2</v></c></row>
|
|
|
|
<row r="22"><c r="A22"><v>4.0000000000000003e-5</v></c></row>
|
|
|
|
<row r="23"><c r="A23"><v>2422.3000000000002</v></c></row>
|
|
|
|
<row r="24"><c r="A24"><v>1101.5999999999999</v></c></row>
|
|
|
|
<row r="25"><c r="A25"><v>275.39999999999998</v></c></row>
|
|
|
|
<row r="26"><c r="A26"><v>68.900000000000006</v></c></row>
|
|
|
|
<row r="27"><c r="A27"><v>1.1000000000000001</v></c></row>
|
2022-10-25 10:24:45 +08:00
|
|
|
<row r="28"><c r="A28" t="inlineStr"><is><t>1234567890123_4</t></is></c></row>
|
|
|
|
<row r="29"><c r="A29" t="inlineStr"><is><t>123456789_0123_4</t></is></c></row>
|
2022-10-24 00:02:22 +08:00
|
|
|
<row r="30"><c r="A30"><v>+0.0000000000000000002399999999999992E-4</v></c></row>
|
|
|
|
<row r="31"><c r="A31"><v>7.2399999999999992E-2</v></c></row>
|
|
|
|
<row r="32"><c r="A32" t="d"><v>20200208T080910.123</v></c></row>
|
|
|
|
<row r="33"><c r="A33" t="d"><v>20200208T080910,123</v></c></row>
|
|
|
|
<row r="34"><c r="A34" t="d"><v>20221022T150529Z</v></c></row>
|
|
|
|
<row r="35"><c r="A35" t="d"><v>2022-10-22T15:05:29Z</v></c></row>
|
|
|
|
<row r="36"><c r="A36" t="d"><v>2020-07-10 15:00:00.000</v></c></row>`)))
|
2021-09-26 00:07:40 +08:00
|
|
|
f.checked = nil
|
2022-10-24 00:02:22 +08:00
|
|
|
rows, err = f.GetCols("Sheet1")
|
|
|
|
assert.Equal(t, []string{
|
2021-10-15 21:45:46 +08:00
|
|
|
"2422.3",
|
|
|
|
"2422.3",
|
|
|
|
"12.4",
|
|
|
|
"964",
|
|
|
|
"1101.6",
|
|
|
|
"275.4",
|
|
|
|
"68.9",
|
|
|
|
"44385.2083333333",
|
|
|
|
"5.1",
|
|
|
|
"5.11",
|
|
|
|
"5.1",
|
|
|
|
"5.111",
|
|
|
|
"5.1111",
|
|
|
|
"2422.012345678",
|
|
|
|
"2422.0123456789",
|
|
|
|
"12.012345678901",
|
|
|
|
"964",
|
|
|
|
"1101.6",
|
|
|
|
"275.4",
|
|
|
|
"68.9",
|
|
|
|
"0.08888",
|
|
|
|
"0.00004",
|
|
|
|
"2422.3",
|
|
|
|
"1101.6",
|
|
|
|
"275.4",
|
|
|
|
"68.9",
|
|
|
|
"1.1",
|
2022-02-18 00:02:39 +08:00
|
|
|
"1234567890123_4",
|
|
|
|
"123456789_0123_4",
|
2022-09-28 00:04:17 +08:00
|
|
|
"2.39999999999999E-23",
|
|
|
|
"0.0724",
|
2022-10-24 00:02:22 +08:00
|
|
|
"43869.3397004977",
|
|
|
|
"43869.3397004977",
|
|
|
|
"44856.6288078704",
|
|
|
|
"44856.6288078704",
|
|
|
|
"2020-07-10 15:00:00.000",
|
|
|
|
}, rows[0])
|
2021-09-26 00:07:40 +08:00
|
|
|
assert.NoError(t, err)
|
2022-11-12 00:02:11 +08:00
|
|
|
|
|
|
|
// Test get cell value with unsupported charset shared strings table.
|
|
|
|
f.SharedStrings = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
|
|
|
_, value := f.GetCellValue("Sheet1", "A1")
|
|
|
|
assert.EqualError(t, value, "XML syntax error on line 1: invalid UTF-8")
|
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)
|
2022-10-25 10:24:45 +08:00
|
|
|
assert.Equal(t, CellTypeSharedString, cellType)
|
2021-09-09 23:43:16 +08:00
|
|
|
_, err = f.GetCellType("Sheet1", "A")
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2021-09-09 23:43:16 +08:00
|
|
|
}
|
|
|
|
|
2022-01-17 08:05:52 +08:00
|
|
|
func TestGetValueFrom(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
c := xlsxC{T: "s"}
|
2022-11-12 00:02:11 +08:00
|
|
|
sst, err := f.sharedStringsReader()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
value, err := c.getValueFrom(f, sst, false)
|
2022-01-17 08:05:52 +08:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "", value)
|
|
|
|
}
|
|
|
|
|
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")
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, err, "sheet SheetN does not exist")
|
2019-12-22 00:02:09 +08:00
|
|
|
|
|
|
|
// 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()
|
2022-01-23 00:32:34 +08:00
|
|
|
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-18 23:20:24 +08:00
|
|
|
assert.NoError(t, f.Close())
|
2019-09-01 12:30:14 +08:00
|
|
|
}
|
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.
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, f.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)"), newCellNameToCoordinatesError("C", newInvalidCellNameError("C")).Error())
|
2021-09-03 22:51:56 +08:00
|
|
|
|
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
|
2021-09-18 23:20:24 +08:00
|
|
|
assert.NoError(t, f.Close())
|
2021-09-03 22:51:56 +08:00
|
|
|
|
|
|
|
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")))
|
2021-09-18 23:20:24 +08:00
|
|
|
assert.NoError(t, f.Close())
|
2021-09-03 22:51:56 +08:00
|
|
|
|
|
|
|
// 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) {
|
2022-10-15 00:03:49 +08:00
|
|
|
f, theme := NewFile(), 1
|
2021-02-22 20:04:13 +08:00
|
|
|
|
|
|
|
runsSource := []RichTextRun{
|
|
|
|
{
|
|
|
|
Text: "a\n",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "b",
|
|
|
|
Font: &Font{
|
2022-10-15 00:03:49 +08:00
|
|
|
Underline: "single",
|
|
|
|
Color: "ff0000",
|
|
|
|
ColorTheme: &theme,
|
|
|
|
ColorTint: 0.5,
|
|
|
|
Bold: true,
|
|
|
|
Italic: true,
|
|
|
|
Family: "Times New Roman",
|
|
|
|
Size: 100,
|
|
|
|
Strike: true,
|
2021-02-22 20:04:13 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", runsSource))
|
2022-04-29 13:53:09 +08:00
|
|
|
assert.NoError(t, f.SetCellValue("Sheet1", "A2", false))
|
2020-04-06 00:23:27 +08:00
|
|
|
|
2022-04-29 13:53:09 +08:00
|
|
|
runs, err := f.GetCellRichText("Sheet1", "A2")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, []RichTextRun(nil), runs)
|
|
|
|
|
|
|
|
runs, err = f.GetCellRichText("Sheet1", "A1")
|
2021-02-22 20:04:13 +08:00
|
|
|
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")
|
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// 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))
|
2022-11-12 00:02:11 +08:00
|
|
|
// 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))
|
2022-11-12 00:02:11 +08:00
|
|
|
// 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")
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell rich text on not exists worksheet.
|
2021-02-22 20:04:13 +08:00
|
|
|
_, err = f.GetCellRichText("SheetN", "A1")
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, err, "sheet SheetN does not exist")
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell rich text with illegal cell reference.
|
2021-02-22 20:04:13 +08:00
|
|
|
_, err = f.GetCellRichText("Sheet1", "A")
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set rich text color theme without tint.
|
2022-10-15 00:03:49 +08:00
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTheme: &theme}}}))
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set rich text color tint without theme.
|
2022-10-15 00:03:49 +08:00
|
|
|
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTint: 0.5}}}))
|
2022-11-12 00:02:11 +08:00
|
|
|
|
|
|
|
// Test set cell rich text with unsupported charset shared strings table.
|
|
|
|
f.SharedStrings = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualError(t, f.SetCellRichText("Sheet1", "A1", runsSource), "XML syntax error on line 1: invalid UTF-8")
|
|
|
|
// Test get cell rich text with unsupported charset shared strings table.
|
|
|
|
f.SharedStrings = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.GetCellRichText("Sheet1", "A1")
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
2021-02-22 20:04:13 +08:00
|
|
|
}
|
2022-01-23 00:32:34 +08:00
|
|
|
|
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{
|
2022-10-24 00:02:22 +08:00
|
|
|
Bold: true,
|
|
|
|
Color: "2354e8",
|
|
|
|
ColorIndexed: 0,
|
|
|
|
Family: "Times New Roman",
|
2020-04-06 00:23:27 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: " and ",
|
|
|
|
Font: &Font{
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "italic ",
|
|
|
|
Font: &Font{
|
|
|
|
Bold: true,
|
|
|
|
Color: "e83723",
|
|
|
|
Italic: true,
|
|
|
|
Family: "Times New Roman",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-06-13 23:38:59 +08:00
|
|
|
Text: "text with color and font-family, ",
|
2020-04-06 00:23:27 +08:00
|
|
|
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,
|
|
|
|
},
|
|
|
|
},
|
2022-06-13 23:38:59 +08:00
|
|
|
{
|
|
|
|
Text: " superscript",
|
|
|
|
Font: &Font{
|
|
|
|
Color: "dbc21f",
|
|
|
|
VertAlign: "superscript",
|
|
|
|
},
|
|
|
|
},
|
2020-04-06 00:23:27 +08:00
|
|
|
{
|
|
|
|
Text: " and ",
|
|
|
|
Font: &Font{
|
2022-06-13 23:38:59 +08:00
|
|
|
Size: 14,
|
|
|
|
Color: "ad23e8",
|
|
|
|
VertAlign: "BASELINE",
|
2020-04-06 00:23:27 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-06-13 23:38:59 +08:00
|
|
|
Text: "underline",
|
2020-04-06 00:23:27 +08:00
|
|
|
Font: &Font{
|
|
|
|
Color: "23e833",
|
|
|
|
Underline: "single",
|
|
|
|
},
|
|
|
|
},
|
2022-06-13 23:38:59 +08:00
|
|
|
{
|
|
|
|
Text: " subscript.",
|
|
|
|
Font: &Font{
|
|
|
|
Color: "017505",
|
|
|
|
VertAlign: "subscript",
|
|
|
|
},
|
|
|
|
},
|
2020-04-06 00:23:27 +08:00
|
|
|
}
|
|
|
|
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")))
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell rich text on not exists worksheet.
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, f.SetCellRichText("SheetN", "A1", richTextRun), "sheet SheetN does not exist")
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell rich text with illegal cell reference.
|
2021-12-07 00:26:53 +08:00
|
|
|
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
2021-07-31 14:20:29 +08:00
|
|
|
richTextRun = []RichTextRun{{Text: strings.Repeat("s", TotalCellChars+1)}}
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell rich text with characters over the maximum limit.
|
2021-07-31 14:20:29 +08:00
|
|
|
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
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
func TestFormattedValue(t *testing.T) {
|
2020-10-04 21:07:39 +08:00
|
|
|
f := NewFile()
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err := f.formattedValue(0, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(15, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(1, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2020-10-04 21:07:39 +08:00
|
|
|
customNumFmt := "[$-409]MM/DD/YYYY"
|
2022-11-12 00:02:11 +08:00
|
|
|
_, err = f.NewStyle(&Style{
|
2020-10-04 21:07:39 +08:00
|
|
|
CustomNumFmt: &customNumFmt,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(1, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "03/04/2019", result)
|
2020-10-19 23:55:54 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test format value with no built-in number format ID.
|
2020-10-19 23:55:54 +08:00
|
|
|
numFmtID := 5
|
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: &numFmtID,
|
|
|
|
})
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(2, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2020-12-12 16:17:00 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test format value with invalid number format ID.
|
2020-12-12 16:17:00 +08:00
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: nil,
|
|
|
|
})
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(3, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2020-12-12 16:17:00 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test format value with empty number format.
|
2020-12-12 16:17:00 +08:00
|
|
|
f.Styles.NumFmts = nil
|
|
|
|
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
|
|
|
|
NumFmtID: &numFmtID,
|
|
|
|
})
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(1, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2022-08-24 00:00:47 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test format decimal value with build-in number format ID.
|
2022-08-24 00:00:47 +08:00
|
|
|
styleID, err := f.NewStyle(&Style{
|
|
|
|
NumFmt: 1,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err = f.formattedValue(styleID, "310.56", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "311", result)
|
2022-10-12 00:06:09 +08:00
|
|
|
|
|
|
|
for _, fn := range builtInNumFmtFunc {
|
|
|
|
assert.Equal(t, "0_0", fn("0_0", "", false))
|
|
|
|
}
|
2022-11-12 00:02:11 +08:00
|
|
|
|
2022-11-13 00:40:04 +08:00
|
|
|
// Test format value with unsupported charset workbook.
|
|
|
|
f.WorkBook = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.formattedValue(1, "43528", false)
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test format value with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.formattedValue(1, "43528", false)
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
2020-10-04 21:07:39 +08:00
|
|
|
}
|
2021-12-27 23:34:14 +08:00
|
|
|
|
2022-11-05 12:41:07 +08:00
|
|
|
func TestFormattedValueNilXfs(t *testing.T) {
|
|
|
|
// Set the CellXfs to nil and verify that the formattedValue function does not crash.
|
|
|
|
f := NewFile()
|
|
|
|
f.Styles.CellXfs = nil
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err := f.formattedValue(3, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2022-11-05 12:41:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormattedValueNilNumFmts(t *testing.T) {
|
|
|
|
// Set the NumFmts value to nil and verify that the formattedValue function does not crash.
|
|
|
|
f := NewFile()
|
|
|
|
f.Styles.NumFmts = nil
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err := f.formattedValue(3, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2022-11-05 12:41:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormattedValueNilWorkbook(t *testing.T) {
|
|
|
|
// Set the Workbook value to nil and verify that the formattedValue function does not crash.
|
|
|
|
f := NewFile()
|
|
|
|
f.WorkBook = nil
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err := f.formattedValue(3, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2022-11-05 12:41:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestFormattedValueNilWorkbookPr(t *testing.T) {
|
|
|
|
// Set the WorkBook.WorkbookPr value to nil and verify that the formattedValue function does not
|
|
|
|
// crash.
|
|
|
|
f := NewFile()
|
|
|
|
f.WorkBook.WorkbookPr = nil
|
2022-11-12 00:02:11 +08:00
|
|
|
result, err := f.formattedValue(3, "43528", false)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, "43528", result)
|
2022-11-05 12:41:07 +08:00
|
|
|
}
|
|
|
|
|
2021-12-27 23:34:14 +08:00
|
|
|
func TestSharedStringsError(t *testing.T) {
|
|
|
|
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
|
|
|
|
assert.NoError(t, err)
|
2022-01-11 00:24:24 +08:00
|
|
|
tempFile, ok := f.tempFiles.Load(defaultXMLPathSharedStrings)
|
|
|
|
assert.True(t, ok)
|
2022-01-09 00:20:42 +08:00
|
|
|
f.tempFiles.Store(defaultXMLPathSharedStrings, "")
|
2022-01-11 00:24:24 +08:00
|
|
|
assert.Equal(t, "1", f.getFromStringItem(1))
|
|
|
|
// Cleanup undelete temporary files
|
|
|
|
assert.NoError(t, os.Remove(tempFile.(string)))
|
2022-10-24 00:02:22 +08:00
|
|
|
// Test reload the file error on set cell value and rich text. The error message was different between macOS and Windows.
|
2021-12-27 23:34:14 +08:00
|
|
|
err = f.SetCellValue("Sheet1", "A19", "A19")
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
2022-01-09 00:20:42 +08:00
|
|
|
f.tempFiles.Store(defaultXMLPathSharedStrings, "")
|
2021-12-27 23:34:14 +08:00
|
|
|
err = f.SetCellRichText("Sheet1", "A19", []RichTextRun{})
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.NoError(t, f.Close())
|
2022-01-11 00:24:24 +08:00
|
|
|
|
|
|
|
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rows, err := f.Rows("Sheet1")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
const maxUint16 = 1<<16 - 1
|
2022-01-19 00:51:09 +08:00
|
|
|
currentRow := 0
|
2022-01-11 00:24:24 +08:00
|
|
|
for rows.Next() {
|
2022-01-19 00:51:09 +08:00
|
|
|
currentRow++
|
|
|
|
if currentRow == 19 {
|
2022-01-11 00:24:24 +08:00
|
|
|
_, err := rows.Columns()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
// Test get cell value from string item with invalid offset
|
|
|
|
f.sharedStringItem[1] = []uint{maxUint16 - 1, maxUint16}
|
|
|
|
assert.Equal(t, "1", f.getFromStringItem(1))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.NoError(t, rows.Close())
|
|
|
|
// Test shared string item temporary files has been closed before close the workbook
|
|
|
|
assert.NoError(t, f.sharedStringTemp.Close())
|
|
|
|
assert.Error(t, f.Close())
|
|
|
|
// Cleanup undelete temporary files
|
|
|
|
f.tempFiles.Range(func(k, v interface{}) bool {
|
|
|
|
return assert.NoError(t, os.Remove(v.(string)))
|
|
|
|
})
|
|
|
|
|
|
|
|
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rows, err = f.Rows("Sheet1")
|
|
|
|
assert.NoError(t, err)
|
2022-01-19 00:51:09 +08:00
|
|
|
currentRow = 0
|
2022-01-11 00:24:24 +08:00
|
|
|
for rows.Next() {
|
2022-01-19 00:51:09 +08:00
|
|
|
currentRow++
|
|
|
|
if currentRow == 19 {
|
2022-01-11 00:24:24 +08:00
|
|
|
_, err := rows.Columns()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.NoError(t, rows.Close())
|
|
|
|
assert.NoError(t, f.sharedStringTemp.Close())
|
|
|
|
// Test shared string item temporary files has been closed before set the cell value
|
|
|
|
assert.Error(t, f.SetCellValue("Sheet1", "A1", "A1"))
|
|
|
|
assert.Error(t, f.Close())
|
|
|
|
// Cleanup undelete temporary files
|
|
|
|
f.tempFiles.Range(func(k, v interface{}) bool {
|
|
|
|
return assert.NoError(t, os.Remove(v.(string)))
|
|
|
|
})
|
2021-12-27 23:34:14 +08:00
|
|
|
}
|