This closes #1425, breaking changes for sheet name (#1426)

- Checking and return error for invalid sheet name instead of trim invalid characters
- Add error return for the 4 functions: `DeleteSheet`, `GetSheetIndex`, `GetSheetVisible` and `SetSheetName`
- Export new error 4 constants: `ErrSheetNameBlank`, `ErrSheetNameInvalid`, `ErrSheetNameLength` and `ErrSheetNameSingleQuote`
- Rename exported error constant `ErrExistsWorksheet` to `ErrExistsSheet`
- Update unit tests for 90 functions: `AddChart`,  `AddChartSheet`, `AddComment`, `AddDataValidation`, `AddPicture`, `AddPictureFromBytes`, `AddPivotTable`, `AddShape`, `AddSparkline`, `AddTable`, `AutoFilter`, `CalcCellValue`, `Cols`, `DeleteChart`, `DeleteComment`, `DeleteDataValidation`, `DeletePicture`, `DeleteSheet`, `DuplicateRow`, `DuplicateRowTo`, `GetCellFormula`, `GetCellHyperLink`, `GetCellRichText`, `GetCellStyle`, `GetCellType`, `GetCellValue`, `GetColOutlineLevel`, `GetCols`, `GetColStyle`, `GetColVisible`, `GetColWidth`, `GetConditionalFormats`, `GetDataValidations`, `GetMergeCells`, `GetPageLayout`, `GetPageMargins`, `GetPicture`, `GetRowHeight`, `GetRowOutlineLevel`, `GetRows`, `GetRowVisible`, `GetSheetIndex`, `GetSheetProps`, `GetSheetVisible`, `GroupSheets`, `InsertCol`, `InsertPageBreak`, `InsertRows`, `MergeCell`, `NewSheet`, `NewStreamWriter`, `ProtectSheet`, `RemoveCol`, `RemovePageBreak`, `RemoveRow`, `Rows`, `SearchSheet`, `SetCellBool`, `SetCellDefault`, `SetCellFloat`, `SetCellFormula`, `SetCellHyperLink`, `SetCellInt`, `SetCellRichText`, `SetCellStr`, `SetCellStyle`, `SetCellValue`, `SetColOutlineLevel`, `SetColStyle`, `SetColVisible`, `SetColWidth`, `SetConditionalFormat`, `SetHeaderFooter`, `SetPageLayout`, `SetPageMargins`, `SetPanes`, `SetRowHeight`, `SetRowOutlineLevel`, `SetRowStyle`, `SetRowVisible`, `SetSheetBackground`, `SetSheetBackgroundFromBytes`, `SetSheetCol`, `SetSheetName`, `SetSheetProps`, `SetSheetRow`, `SetSheetVisible`, `UnmergeCell`, `UnprotectSheet` and
`UnsetConditionalFormat`
- Update documentation of the set style functions

Co-authored-by: guoweikuang <weikuang.guo@shopee.com>
This commit is contained in:
郭伟匡 2022-12-23 00:54:40 +08:00 committed by GitHub
parent ce4f7a25c9
commit 6a5ee811ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 761 additions and 455 deletions

11
calc.go
View File

@ -11460,19 +11460,20 @@ func (fn *formulaFuncs) SHEET(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, "SHEET accepts at most 1 argument")
}
if argsList.Len() == 0 {
return newNumberFormulaArg(float64(fn.f.GetSheetIndex(fn.sheet) + 1))
idx, _ := fn.f.GetSheetIndex(fn.sheet)
return newNumberFormulaArg(float64(idx + 1))
}
arg := argsList.Front().Value.(formulaArg)
if sheetIdx := fn.f.GetSheetIndex(arg.Value()); sheetIdx != -1 {
if sheetIdx, _ := fn.f.GetSheetIndex(arg.Value()); sheetIdx != -1 {
return newNumberFormulaArg(float64(sheetIdx + 1))
}
if arg.cellRanges != nil && arg.cellRanges.Len() > 0 {
if sheetIdx := fn.f.GetSheetIndex(arg.cellRanges.Front().Value.(cellRange).From.Sheet); sheetIdx != -1 {
if sheetIdx, _ := fn.f.GetSheetIndex(arg.cellRanges.Front().Value.(cellRange).From.Sheet); sheetIdx != -1 {
return newNumberFormulaArg(float64(sheetIdx + 1))
}
}
if arg.cellRefs != nil && arg.cellRefs.Len() > 0 {
if sheetIdx := fn.f.GetSheetIndex(arg.cellRefs.Front().Value.(cellRef).Sheet); sheetIdx != -1 {
if sheetIdx, _ := fn.f.GetSheetIndex(arg.cellRefs.Front().Value.(cellRef).Sheet); sheetIdx != -1 {
return newNumberFormulaArg(float64(sheetIdx + 1))
}
}
@ -13960,7 +13961,7 @@ func (fn *formulaFuncs) ADDRESS(argsList *list.List) formulaArg {
}
var sheetText string
if argsList.Len() == 5 {
sheetText = fmt.Sprintf("%s!", trimSheetName(argsList.Back().Value.(formulaArg).Value()))
sheetText = fmt.Sprintf("%s!", argsList.Back().Value.(formulaArg).Value())
}
formatter := addressFmtMaps[fmt.Sprintf("%d_%s", int(absNum.Number), a1.Value())]
addr, err := formatter(int(colNum.Number), int(rowNum.Number))

View File

@ -4389,16 +4389,19 @@ func TestCalcCellValue(t *testing.T) {
assert.NoError(t, err)
}
// Test get calculated cell value on not formula cell.
// Test get calculated cell value on not formula cell
f := prepareCalcData(cellData)
result, err := f.CalcCellValue("Sheet1", "A1")
assert.NoError(t, err)
assert.Equal(t, "", result)
// Test get calculated cell value on not exists worksheet.
// Test get calculated cell value on not exists worksheet
f = prepareCalcData(cellData)
_, err = f.CalcCellValue("SheetN", "A1")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get calculated cell value with not support formula.
// Test get calculated cell value with invalid sheet name
_, err = f.CalcCellValue("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get calculated cell value with not support formula
f = prepareCalcData(cellData)
assert.NoError(t, f.SetCellFormula("Sheet1", "A1", "=UNSUPPORT(A1)"))
_, err = f.CalcCellValue("Sheet1", "A1")

View File

@ -167,13 +167,15 @@ func TestSetCellFloat(t *testing.T) {
})
f := NewFile()
assert.EqualError(t, f.SetCellFloat(sheet, "A", 123.42, -1, 64), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test set cell float data type value with invalid sheet name
assert.EqualError(t, f.SetCellFloat("Sheet:1", "A1", 123.42, -1, 64), ErrSheetNameInvalid.Error())
}
func TestSetCellValue(t *testing.T) {
f := NewFile()
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())
// Test set cell value with column and row style inherit.
// Test set cell value with column and row style inherit
style1, err := f.NewStyle(&Style{NumFmt: 2})
assert.NoError(t, err)
style2, err := f.NewStyle(&Style{NumFmt: 9})
@ -189,11 +191,13 @@ func TestSetCellValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "0.50", B2)
// Test set cell value with unsupported charset shared strings table.
// Test set cell value with invalid sheet name
assert.EqualError(t, f.SetCellValue("Sheet:1", "A1", "A1"), ErrSheetNameInvalid.Error())
// Test set cell value with unsupported charset shared strings table
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")
// Test set cell value with unsupported charset workbook.
// 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")
@ -208,7 +212,7 @@ func TestSetCellValues(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, v, "12/31/10 00:00")
// Test date value lower than min date supported by Excel.
// 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)
@ -220,6 +224,8 @@ func TestSetCellValues(t *testing.T) {
func TestSetCellBool(t *testing.T) {
f := NewFile()
assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test set cell boolean data type value with invalid sheet name
assert.EqualError(t, f.SetCellBool("Sheet:1", "A1", true), ErrSheetNameInvalid.Error())
}
func TestSetCellTime(t *testing.T) {
@ -242,7 +248,7 @@ func TestSetCellTime(t *testing.T) {
}
func TestGetCellValue(t *testing.T) {
// Test get cell value without r attribute of the row.
// Test get cell value without r attribute of the row
f := NewFile()
sheetData := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>%s</sheetData></worksheet>`
@ -387,11 +393,14 @@ func TestGetCellValue(t *testing.T) {
}, rows[0])
assert.NoError(t, err)
// Test get cell value with unsupported charset shared strings table.
// 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")
// Test get cell value with invalid sheet name
_, err = f.GetCellValue("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestGetCellType(t *testing.T) {
@ -405,6 +414,9 @@ func TestGetCellType(t *testing.T) {
assert.Equal(t, CellTypeSharedString, cellType)
_, err = f.GetCellType("Sheet1", "A")
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test get cell type with invalid sheet name
_, err = f.GetCellType("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestGetValueFrom(t *testing.T) {
@ -418,12 +430,16 @@ func TestGetValueFrom(t *testing.T) {
}
func TestGetCellFormula(t *testing.T) {
// Test get cell formula on not exist worksheet.
// Test get cell formula on not exist worksheet
f := NewFile()
_, err := f.GetCellFormula("SheetN", "A1")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get cell formula on no formula cell.
// Test get cell formula with invalid sheet name
_, err = f.GetCellFormula("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get cell formula on no formula cell
assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
_, err = f.GetCellFormula("Sheet1", "A1")
assert.NoError(t, err)
@ -497,7 +513,10 @@ func TestSetCellFormula(t *testing.T) {
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.
// Test set cell formula with invalid sheet name
assert.EqualError(t, f.SetCellFormula("Sheet:1", "A1", "SUM(1,2)"), ErrSheetNameInvalid.Error())
// Test set cell formula with illegal rows number
assert.EqualError(t, f.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)"), newCellNameToCoordinatesError("C", newInvalidCellNameError("C")).Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
@ -507,15 +526,15 @@ func TestSetCellFormula(t *testing.T) {
if !assert.NoError(t, err) {
t.FailNow()
}
// Test remove cell formula.
// 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.
// Test remove all cell formula
assert.NoError(t, f.SetCellFormula("Sheet1", "B1", ""))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula3.xlsx")))
assert.NoError(t, f.Close())
// Test set shared formula for the cells.
// 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}))
@ -533,7 +552,7 @@ func TestSetCellFormula(t *testing.T) {
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")))
// Test set table formula for the cells.
// 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))
@ -583,46 +602,49 @@ func TestGetCellRichText(t *testing.T) {
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.
// Test get cell rich text when string item index overflow
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "2"
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.
// Test get cell rich text when string item index is negative
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "-1"
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.
// Test get cell rich text on invalid string item index
ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetData.Row[0].C[0].V = "x"
_, err = f.GetCellRichText("Sheet1", "A1")
assert.EqualError(t, err, "strconv.Atoi: parsing \"x\": invalid syntax")
// Test set cell rich text on not exists worksheet.
// Test set cell rich text on not exists worksheet
_, err = f.GetCellRichText("SheetN", "A1")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test set cell rich text with illegal cell reference.
// Test set cell rich text with illegal cell reference
_, err = f.GetCellRichText("Sheet1", "A")
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test set rich text color theme without tint.
// Test set rich text color theme without tint
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTheme: &theme}}}))
// Test set rich text color tint without theme.
// Test set rich text color tint without theme
assert.NoError(t, f.SetCellRichText("Sheet1", "A1", []RichTextRun{{Font: &Font{ColorTint: 0.5}}}))
// Test set cell rich text with unsupported charset shared strings table.
// 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.
// 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")
// Test get cell rich text with invalid sheet name
_, err = f.GetCellRichText("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestSetCellRichText(t *testing.T) {
@ -716,12 +738,14 @@ func TestSetCellRichText(t *testing.T) {
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.
// Test set cell rich text on not exists worksheet
assert.EqualError(t, f.SetCellRichText("SheetN", "A1", richTextRun), "sheet SheetN does not exist")
// Test set cell rich text with illegal cell reference.
// Test set cell rich text with invalid sheet name
assert.EqualError(t, f.SetCellRichText("Sheet:1", "A1", richTextRun), ErrSheetNameInvalid.Error())
// Test set cell rich text with illegal cell reference
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
richTextRun = []RichTextRun{{Text: strings.Repeat("s", TotalCellChars+1)}}
// Test set cell rich text with characters over the maximum limit.
// Test set cell rich text with characters over the maximum limit
assert.EqualError(t, f.SetCellRichText("Sheet1", "A1", richTextRun), ErrCellCharsLength.Error())
}
@ -747,7 +771,7 @@ func TestFormattedValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "03/04/2019", result)
// Test format value with no built-in number format ID.
// Test format value with no built-in number format ID
numFmtID := 5
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: &numFmtID,
@ -756,7 +780,7 @@ func TestFormattedValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "43528", result)
// Test format value with invalid number format ID.
// Test format value with invalid number format ID
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: nil,
})
@ -764,7 +788,7 @@ func TestFormattedValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "43528", result)
// Test format value with empty number format.
// Test format value with empty number format
f.Styles.NumFmts = nil
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: &numFmtID,
@ -773,7 +797,7 @@ func TestFormattedValue(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "43528", result)
// Test format decimal value with build-in number format ID.
// Test format decimal value with build-in number format ID
styleID, err := f.NewStyle(&Style{
NumFmt: 1,
})
@ -786,13 +810,13 @@ func TestFormattedValue(t *testing.T) {
assert.Equal(t, "0_0", fn("0_0", "", false))
}
// Test format value with unsupported charset workbook.
// 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")
// Test format value with unsupported charset style sheet.
// Test format value with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
_, err = f.formattedValue(1, "43528", false)
@ -800,7 +824,7 @@ func TestFormattedValue(t *testing.T) {
}
func TestFormattedValueNilXfs(t *testing.T) {
// Set the CellXfs to nil and verify that the formattedValue function does not crash.
// Set the CellXfs to nil and verify that the formattedValue function does not crash
f := NewFile()
f.Styles.CellXfs = nil
result, err := f.formattedValue(3, "43528", false)
@ -809,7 +833,7 @@ func TestFormattedValueNilXfs(t *testing.T) {
}
func TestFormattedValueNilNumFmts(t *testing.T) {
// Set the NumFmts value to nil and verify that the formattedValue function does not crash.
// Set the NumFmts value to nil and verify that the formattedValue function does not crash
f := NewFile()
f.Styles.NumFmts = nil
result, err := f.formattedValue(3, "43528", false)
@ -818,7 +842,7 @@ func TestFormattedValueNilNumFmts(t *testing.T) {
}
func TestFormattedValueNilWorkbook(t *testing.T) {
// Set the Workbook value to nil and verify that the formattedValue function does not crash.
// Set the Workbook value to nil and verify that the formattedValue function does not crash
f := NewFile()
f.WorkBook = nil
result, err := f.formattedValue(3, "43528", false)

View File

@ -941,8 +941,12 @@ func (f *File) AddChart(sheet, cell, opts string, combo ...string) error {
// a chart.
func (f *File) AddChartSheet(sheet, opts string, combo ...string) error {
// Check if the worksheet already exists
if f.GetSheetIndex(sheet) != -1 {
return ErrExistsWorksheet
idx, err := f.GetSheetIndex(sheet)
if err != nil {
return err
}
if idx != -1 {
return ErrExistsSheet
}
options, comboCharts, err := f.getChartOptions(opts, combo)
if err != nil {
@ -963,7 +967,7 @@ func (f *File) AddChartSheet(sheet, opts string, combo ...string) error {
}
sheetID++
path := "xl/chartsheets/sheet" + strconv.Itoa(sheetID) + ".xml"
f.sheetMap[trimSheetName(sheet)] = path
f.sheetMap[sheet] = path
f.Sheet.Store(path, nil)
drawingID := f.countDrawings() + 1
chartID := f.countCharts() + 1

View File

@ -217,6 +217,8 @@ func TestAddChart(t *testing.T) {
assert.NoError(t, f.AddChart("Combo Charts", axis, fmt.Sprintf(`{"type":"areaStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"%s"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true}}`, props[1]), fmt.Sprintf(`{"type":"%s","series":[{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true}}`, props[0])))
}
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChart.xlsx")))
// Test with invalid sheet name
assert.EqualError(t, f.AddChart("Sheet:1", "A1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}]}`), ErrSheetNameInvalid.Error())
// Test with illegal cell reference
assert.EqualError(t, f.AddChart("Sheet2", "A", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test with unsupported chart type
@ -257,14 +259,16 @@ func TestAddChartSheet(t *testing.T) {
// Test cell value on chartsheet
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is not a worksheet")
// Test add chartsheet on already existing name sheet
assert.EqualError(t, f.AddChartSheet("Sheet1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), ErrExistsWorksheet.Error())
assert.EqualError(t, f.AddChartSheet("Sheet1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), ErrExistsSheet.Error())
// Test add chartsheet with invalid sheet name
assert.EqualError(t, f.AddChartSheet("Sheet:1", "A1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), ErrSheetNameInvalid.Error())
// Test with unsupported chart type
assert.EqualError(t, f.AddChartSheet("Chart2", `{"type":"unknown","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), "unsupported chart type unknown")
assert.NoError(t, f.UpdateLinkedValue())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChartSheet.xlsx")))
// Test add chart sheet with unsupported charset content types.
// Test add chart sheet with unsupported charset content types
f = NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
@ -278,11 +282,13 @@ func TestDeleteChart(t *testing.T) {
assert.NoError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
assert.NoError(t, f.DeleteChart("Sheet1", "P1"))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteChart.xlsx")))
// Test delete chart on not exists worksheet.
// Test delete chart with invalid sheet name
assert.EqualError(t, f.DeleteChart("Sheet:1", "P1"), ErrSheetNameInvalid.Error())
// Test delete chart on not exists worksheet
assert.EqualError(t, f.DeleteChart("SheetN", "A1"), "sheet SheetN does not exist")
// Test delete chart with invalid coordinates.
// Test delete chart with invalid coordinates
assert.EqualError(t, f.DeleteChart("Sheet1", ""), newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
// Test delete chart on no chart worksheet.
// Test delete chart on no chart worksheet
assert.NoError(t, NewFile().DeleteChart("Sheet1", "A1"))
assert.NoError(t, f.Close())
}

5
col.go
View File

@ -208,6 +208,9 @@ func (cols *Cols) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
// fmt.Println()
// }
func (f *File) Cols(sheet string) (*Cols, error) {
if err := checkSheetName(sheet); err != nil {
return nil, err
}
name, ok := f.getSheetXMLPath(sheet)
if !ok {
return nil, ErrSheetNotExist{sheet}
@ -236,7 +239,7 @@ func (f *File) Cols(sheet string) (*Cols, error) {
case xml.EndElement:
if xmlElement.Name.Local == "sheetData" {
colIterator.cols.f = f
colIterator.cols.sheet = trimSheetName(sheet)
colIterator.cols.sheet = sheet
return &colIterator.cols, nil
}
}

View File

@ -57,7 +57,13 @@ func TestCols(t *testing.T) {
_, err = f.Rows("Sheet1")
assert.NoError(t, err)
// Test columns iterator with unsupported charset shared strings table.
// Test columns iterator with invalid sheet name
_, err = f.Cols("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get columns cells with invalid sheet name
_, err = f.GetCols("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test columns iterator with unsupported charset shared strings table
f.SharedStrings = nil
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
cols, err = f.Cols("Sheet1")
@ -212,14 +218,18 @@ func TestColumnVisibility(t *testing.T) {
assert.Equal(t, true, visible)
assert.NoError(t, err)
// Test get column visible on an inexistent worksheet.
// Test get column visible on an inexistent worksheet
_, err = f.GetColVisible("SheetN", "F")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get column visible with illegal cell reference.
// Test get column visible with invalid sheet name
_, err = f.GetColVisible("Sheet:1", "F")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get column visible with illegal cell reference
_, err = f.GetColVisible("Sheet1", "*")
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColVisible("Sheet1", "*", false), newInvalidColumnNameError("*").Error())
// Test set column visible with invalid sheet name
assert.EqualError(t, f.SetColVisible("Sheet:1", "A", false), ErrSheetNameInvalid.Error())
f.NewSheet("Sheet3")
assert.NoError(t, f.SetColVisible("Sheet3", "E", false))
@ -254,25 +264,35 @@ func TestOutlineLevel(t *testing.T) {
assert.Equal(t, uint8(0), level)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test column outline level with invalid sheet name
_, err = f.GetColOutlineLevel("Sheet:1", "A")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.NoError(t, f.SetColWidth("Sheet2", "A", "D", 13))
assert.EqualError(t, f.SetColWidth("Sheet2", "A", "D", MaxColumnWidth+1), ErrColumnWidth.Error())
// Test set column width with invalid sheet name
assert.EqualError(t, f.SetColWidth("Sheet:1", "A", "D", 13), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SetColOutlineLevel("Sheet2", "B", 2))
assert.NoError(t, f.SetRowOutlineLevel("Sheet1", 2, 7))
assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "D", 8), ErrOutlineLevel.Error())
assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 2, 8), ErrOutlineLevel.Error())
// Test set row outline level on not exists worksheet.
// Test set row outline level on not exists worksheet
assert.EqualError(t, f.SetRowOutlineLevel("SheetN", 1, 4), "sheet SheetN does not exist")
// Test get row outline level on not exists worksheet.
// Test set row outline level with invalid sheet name
assert.EqualError(t, f.SetRowOutlineLevel("Sheet:1", 1, 4), ErrSheetNameInvalid.Error())
// Test get row outline level on not exists worksheet
_, err = f.GetRowOutlineLevel("SheetN", 1)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test set and get column outline level with illegal cell reference.
// Test get row outline level with invalid sheet name
_, err = f.GetRowOutlineLevel("Sheet:1", 1)
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test set and get column outline level with illegal cell reference
assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "*", 1), newInvalidColumnNameError("*").Error())
_, err = f.GetColOutlineLevel("Sheet1", "*")
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
// Test set column outline level on not exists worksheet.
// Test set column outline level on not exists worksheet
assert.EqualError(t, f.SetColOutlineLevel("SheetN", "E", 2), "sheet SheetN does not exist")
assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 0, 1), newInvalidRowNumberError(0).Error())
@ -300,22 +320,24 @@ func TestSetColStyle(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet1", "B2", "Hello"))
styleID, err := f.NewStyle(`{"fill":{"type":"pattern","color":["#94d3a2"],"pattern":1}}`)
assert.NoError(t, err)
// Test set column style on not exists worksheet.
// Test set column style on not exists worksheet
assert.EqualError(t, f.SetColStyle("SheetN", "E", styleID), "sheet SheetN does not exist")
// Test set column style with illegal column name.
// Test set column style with illegal column name
assert.EqualError(t, f.SetColStyle("Sheet1", "*", styleID), newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColStyle("Sheet1", "A:*", styleID), newInvalidColumnNameError("*").Error())
// Test set column style with invalid style ID.
// Test set column style with invalid style ID
assert.EqualError(t, f.SetColStyle("Sheet1", "B", -1), newInvalidStyleID(-1).Error())
// Test set column style with not exists style ID.
// Test set column style with not exists style ID
assert.EqualError(t, f.SetColStyle("Sheet1", "B", 10), newInvalidStyleID(10).Error())
// Test set column style with invalid sheet name
assert.EqualError(t, f.SetColStyle("Sheet:1", "A", 0), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SetColStyle("Sheet1", "B", styleID))
style, err := f.GetColStyle("Sheet1", "B")
assert.NoError(t, err)
assert.Equal(t, styleID, style)
// Test set column style with already exists column with style.
// Test set column style with already exists column with style
assert.NoError(t, f.SetColStyle("Sheet1", "B", styleID))
assert.NoError(t, f.SetColStyle("Sheet1", "D:C", styleID))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
@ -325,7 +347,7 @@ func TestSetColStyle(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, styleID, cellStyleID)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetColStyle.xlsx")))
// Test set column style with unsupported charset style sheet.
// Test set column style with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
assert.EqualError(t, f.SetColStyle("Sheet1", "C:F", styleID), "XML syntax error on line 1: invalid UTF-8")
@ -342,19 +364,21 @@ func TestColWidth(t *testing.T) {
assert.Equal(t, defaultColWidth, width)
assert.NoError(t, err)
// Test set and get column width with illegal cell reference.
// Test set and get column width with illegal cell reference
width, err = f.GetColWidth("Sheet1", "*")
assert.Equal(t, defaultColWidth, width)
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColWidth("Sheet1", "*", "B", 1), newInvalidColumnNameError("*").Error())
assert.EqualError(t, f.SetColWidth("Sheet1", "A", "*", 1), newInvalidColumnNameError("*").Error())
// Test set column width on not exists worksheet.
// Test set column width on not exists worksheet
assert.EqualError(t, f.SetColWidth("SheetN", "B", "A", 12), "sheet SheetN does not exist")
// Test get column width on not exists worksheet.
// Test get column width on not exists worksheet
_, err = f.GetColWidth("SheetN", "A")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get column width invalid sheet name
_, err = f.GetColWidth("Sheet:1", "A")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestColWidth.xlsx")))
convertRowHeightToPixels(0)
@ -366,12 +390,15 @@ func TestGetColStyle(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, styleID, 0)
// Test set column style on not exists worksheet.
// Test get column style on not exists worksheet
_, err = f.GetColStyle("SheetN", "A")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test set column style with illegal column name.
// Test get column style with illegal column name
_, err = f.GetColStyle("Sheet1", "*")
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
// Test get column style with invalid sheet name
_, err = f.GetColStyle("Sheet:1", "A")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestInsertCols(t *testing.T) {
@ -386,9 +413,10 @@ func TestInsertCols(t *testing.T) {
assert.NoError(t, f.AutoFilter(sheet1, "A2", "B2", `{"column":"B","expression":"x != blanks"}`))
assert.NoError(t, f.InsertCols(sheet1, "A", 1))
// Test insert column with illegal cell reference.
// Test insert column with illegal cell reference
assert.EqualError(t, f.InsertCols(sheet1, "*", 1), newInvalidColumnNameError("*").Error())
// Test insert column with invalid sheet name
assert.EqualError(t, f.InsertCols("Sheet:1", "A", 1), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.InsertCols(sheet1, "A", 0), ErrColumnNumber.Error())
assert.EqualError(t, f.InsertCols(sheet1, "A", MaxColumns), ErrColumnNumber.Error())
assert.EqualError(t, f.InsertCols(sheet1, "A", MaxColumns-10), ErrColumnNumber.Error())
@ -411,11 +439,12 @@ func TestRemoveCol(t *testing.T) {
assert.NoError(t, f.RemoveCol(sheet1, "A"))
assert.NoError(t, f.RemoveCol(sheet1, "A"))
// Test remove column with illegal cell reference.
// Test remove column with illegal cell reference
assert.EqualError(t, f.RemoveCol("Sheet1", "*"), newInvalidColumnNameError("*").Error())
// Test remove column on not exists worksheet.
// Test remove column on not exists worksheet
assert.EqualError(t, f.RemoveCol("SheetN", "B"), "sheet SheetN does not exist")
// Test remove column with invalid sheet name
assert.EqualError(t, f.RemoveCol("Sheet:1", "A"), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemoveCol.xlsx")))
}

View File

@ -143,6 +143,9 @@ func (f *File) AddComment(sheet string, comment Comment) error {
//
// err := f.DeleteComment("Sheet1", "A30")
func (f *File) DeleteComment(sheet, cell string) error {
if err := checkSheetName(sheet); err != nil {
return err
}
sheetXMLPath, ok := f.getSheetXMLPath(sheet)
if !ok {
return newNoExistSheetError(sheet)

View File

@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestAddComments(t *testing.T) {
func TestAddComment(t *testing.T) {
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
@ -30,7 +30,7 @@ func TestAddComments(t *testing.T) {
assert.NoError(t, f.AddComment("Sheet1", Comment{Cell: "A30", Author: s, Text: s, Runs: []RichTextRun{{Text: s}, {Text: s}}}))
assert.NoError(t, f.AddComment("Sheet2", Comment{Cell: "B7", Author: "Excelize", Text: s[:TotalCellChars-1], Runs: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}}))
// Test add comment on not exists worksheet.
// Test add comment on not exists worksheet
assert.EqualError(t, f.AddComment("SheetN", Comment{Cell: "B7", Author: "Excelize", Runs: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}}), "sheet SheetN does not exist")
// Test add comment on with illegal cell reference
assert.EqualError(t, f.AddComment("Sheet1", Comment{Cell: "A", Author: "Excelize", Runs: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
@ -50,18 +50,21 @@ func TestAddComments(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, len(comments), 0)
// Test add comments with unsupported charset.
// Test add comments with invalid sheet name
assert.EqualError(t, f.AddComment("Sheet:1", Comment{Cell: "A1", Author: "Excelize", Text: "This is a comment."}), ErrSheetNameInvalid.Error())
// Test add comments with unsupported charset
f.Comments["xl/comments2.xml"] = nil
f.Pkg.Store("xl/comments2.xml", MacintoshCyrillicCharset)
_, err = f.GetComments()
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
// Test add comments with unsupported charset.
// Test add comments with unsupported charset
f.Comments["xl/comments2.xml"] = nil
f.Pkg.Store("xl/comments2.xml", MacintoshCyrillicCharset)
assert.EqualError(t, f.AddComment("Sheet2", Comment{Cell: "A30", Text: "Comment"}), "XML syntax error on line 1: invalid UTF-8")
// Test add comments with unsupported charset style sheet.
// Test add comments with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddComment("Sheet2", Comment{Cell: "A30", Text: "Comment"}), "XML syntax error on line 1: invalid UTF-8")
@ -90,6 +93,8 @@ func TestDeleteComment(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, len(comments), 0)
// Test delete comment with invalid sheet name
assert.EqualError(t, f.DeleteComment("Sheet:1", "A1"), ErrSheetNameInvalid.Error())
// Test delete all comments in a worksheet
assert.NoError(t, f.DeleteComment("Sheet2", "A41"))
assert.NoError(t, f.DeleteComment("Sheet2", "C41"))
@ -118,7 +123,7 @@ func TestDecodeVMLDrawingReader(t *testing.T) {
func TestCommentsReader(t *testing.T) {
f := NewFile()
// Test read comments with unsupported charset.
// Test read comments with unsupported charset
path := "xl/comments1.xml"
f.Pkg.Store(path, MacintoshCyrillicCharset)
_, err := f.commentsReader(path)

View File

@ -91,6 +91,9 @@ func TestDataValidation(t *testing.T) {
// Test get data validation on no exists worksheet
_, err = f.GetDataValidations("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get data validation with invalid sheet name
_, err = f.GetDataValidations("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(resultFile))
@ -130,7 +133,7 @@ func TestDataValidationError(t *testing.T) {
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
// Test width invalid data validation formula.
// Test width invalid data validation formula
prevFormula1 := dvRange.Formula1
for _, keys := range [][]string{
make([]string, 257),
@ -156,9 +159,13 @@ func TestDataValidationError(t *testing.T) {
DataValidationTypeWhole, DataValidationOperatorGreaterThan), ErrDataValidationRange.Error())
assert.NoError(t, f.SaveAs(resultFile))
// Test add data validation on no exists worksheet.
// Test add data validation on no exists worksheet
f = NewFile()
assert.EqualError(t, f.AddDataValidation("SheetN", nil), "sheet SheetN does not exist")
// Test add data validation with invalid sheet name
f = NewFile()
assert.EqualError(t, f.AddDataValidation("Sheet:1", nil), ErrSheetNameInvalid.Error())
}
func TestDeleteDataValidation(t *testing.T) {
@ -200,10 +207,11 @@ func TestDeleteDataValidation(t *testing.T) {
ws.(*xlsxWorksheet).DataValidations.DataValidation[0].Sqref = "A1:A"
assert.EqualError(t, f.DeleteDataValidation("Sheet1", "A1:B2"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test delete data validation on no exists worksheet.
// Test delete data validation on no exists worksheet
assert.EqualError(t, f.DeleteDataValidation("SheetN", "A1:B2"), "sheet SheetN does not exist")
// Test delete all data validations in the worksheet.
// Test delete all data validation with invalid sheet name
assert.EqualError(t, f.DeleteDataValidation("Sheet:1"), ErrSheetNameInvalid.Error())
// Test delete all data validations in the worksheet
assert.NoError(t, f.DeleteDataValidation("Sheet1"))
assert.Nil(t, ws.(*xlsxWorksheet).DataValidations)
}

View File

@ -113,9 +113,8 @@ var (
// ErrCoordinates defined the error message on invalid coordinates tuples
// length.
ErrCoordinates = errors.New("coordinates length must be 4")
// ErrExistsWorksheet defined the error message on given worksheet already
// exists.
ErrExistsWorksheet = errors.New("the same name worksheet already exists")
// ErrExistsSheet defined the error message on given sheet already exists.
ErrExistsSheet = errors.New("the same name sheet already exists")
// ErrTotalSheetHyperlinks defined the error message on hyperlinks count
// overflow.
ErrTotalSheetHyperlinks = errors.New("over maximum limit hyperlinks in a worksheet")
@ -219,4 +218,16 @@ var (
// ErrWorkbookPassword defined the error message on receiving the incorrect
// workbook password.
ErrWorkbookPassword = errors.New("the supplied open workbook password is not correct")
// ErrSheetNameInvalid defined the error message on receive the sheet name
// contains invalid characters.
ErrSheetNameInvalid = errors.New("the sheet can not contain any of the characters :\\/?*[or]")
// ErrSheetNameSingleQuote defined the error message on the first or last
// character of the sheet name was a single quote.
ErrSheetNameSingleQuote = errors.New("the first or last character of the sheet name can not be a single quote")
// ErrSheetNameBlank defined the error message on receive the blank sheet
// name.
ErrSheetNameBlank = errors.New("the sheet name can not be blank")
// ErrSheetNameLength defined the error message on receiving the sheet
// name length exceeds the limit.
ErrSheetNameLength = fmt.Errorf("the sheet name length exceeds the %d characters limit", MaxSheetNameLength)
)

View File

@ -233,6 +233,9 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
name string
ok bool
)
if err = checkSheetName(sheet); err != nil {
return
}
if name, ok = f.getSheetXMLPath(sheet); !ok {
err = newNoExistSheetError(sheet)
return

View File

@ -23,14 +23,17 @@ import (
)
func TestOpenFile(t *testing.T) {
// Test update the spreadsheet file.
// Test update the spreadsheet file
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// Test get all the rows in a not exists worksheet.
// Test get all the rows in a not exists worksheet
_, err = f.GetRows("Sheet4")
assert.EqualError(t, err, "sheet Sheet4 does not exist")
// Test get all the rows in a worksheet.
// Test get all the rows with invalid sheet name
_, err = f.GetRows("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get all the rows in a worksheet
rows, err := f.GetRows("Sheet2")
expected := [][]string{
{"Monitor", "", "Brand", "", "inlineStr"},
@ -52,40 +55,44 @@ func TestOpenFile(t *testing.T) {
assert.NoError(t, f.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(100.1588, 'f', -1, 32)))
assert.NoError(t, f.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(-100.1588, 'f', -1, 64)))
// Test set cell value with illegal row number.
// Test set cell value with invalid sheet name
assert.EqualError(t, f.SetCellDefault("Sheet:1", "A1", ""), ErrSheetNameInvalid.Error())
// Test set cell value with illegal row number
assert.EqualError(t, f.SetCellDefault("Sheet2", "A", strconv.FormatFloat(-100.1588, 'f', -1, 64)),
newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.NoError(t, f.SetCellInt("Sheet2", "A1", 100))
// Test set cell integer value with illegal row number.
// Test set cell integer value with illegal row number
assert.EqualError(t, f.SetCellInt("Sheet2", "A", 100), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test set cell integer value with invalid sheet name
assert.EqualError(t, f.SetCellInt("Sheet:1", "A1", 100), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SetCellStr("Sheet2", "C11", "Knowns"))
// Test max characters in a cell.
// Test max characters in a cell
assert.NoError(t, f.SetCellStr("Sheet2", "D11", strings.Repeat("c", TotalCellChars+2)))
f.NewSheet(":\\/?*[]Maximum 31 characters allowed in sheet title.")
// Test set worksheet name with illegal name.
// Test set worksheet name with illegal name
f.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title.")
assert.EqualError(t, f.SetCellInt("Sheet3", "A23", 10), "sheet Sheet3 does not exist")
assert.EqualError(t, f.SetCellStr("Sheet3", "b230", "10"), "sheet Sheet3 does not exist")
assert.EqualError(t, f.SetCellStr("Sheet10", "b230", "10"), "sheet Sheet10 does not exist")
// Test set cell string value with illegal row number.
// Test set cell string data type value with invalid sheet name
assert.EqualError(t, f.SetCellStr("Sheet:1", "A1", "1"), ErrSheetNameInvalid.Error())
// Test set cell string value with illegal row number
assert.EqualError(t, f.SetCellStr("Sheet1", "A", "10"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
f.SetActiveSheet(2)
// Test get cell formula with given rows number.
// Test get cell formula with given rows number
_, err = f.GetCellFormula("Sheet1", "B19")
assert.NoError(t, err)
// Test get cell formula with illegal worksheet name.
// Test get cell formula with illegal worksheet name
_, err = f.GetCellFormula("Sheet2", "B20")
assert.NoError(t, err)
_, err = f.GetCellFormula("Sheet1", "B20")
assert.NoError(t, err)
// Test get cell formula with illegal rows number.
// Test get cell formula with illegal rows number
_, err = f.GetCellFormula("Sheet1", "B")
assert.EqualError(t, err, newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
// Test get shared cell formula
@ -110,7 +117,7 @@ func TestOpenFile(t *testing.T) {
assert.NoError(t, err)
_, err = f.GetCellValue("Sheet2", "D12")
assert.NoError(t, err)
// Test SetCellValue function.
// Test SetCellValue function
assert.NoError(t, f.SetCellValue("Sheet2", "F1", " Hello"))
assert.NoError(t, f.SetCellValue("Sheet2", "G1", []byte("World")))
assert.NoError(t, f.SetCellValue("Sheet2", "F2", 42))
@ -130,7 +137,7 @@ func TestOpenFile(t *testing.T) {
assert.NoError(t, f.SetCellValue("Sheet2", "F16", true))
assert.NoError(t, f.SetCellValue("Sheet2", "F17", complex64(5+10i)))
// Test on not exists worksheet.
// Test on not exists worksheet
assert.EqualError(t, f.SetCellDefault("SheetN", "A1", ""), "sheet SheetN does not exist")
assert.EqualError(t, f.SetCellFloat("SheetN", "A1", 42.65418, 2, 32), "sheet SheetN does not exist")
assert.EqualError(t, f.SetCellBool("SheetN", "A1", true), "sheet SheetN does not exist")
@ -163,18 +170,18 @@ func TestOpenFile(t *testing.T) {
assert.EqualError(t, f.SetCellValue("SheetN", "A1", time.Now()), "sheet SheetN does not exist")
// 02:46:40
assert.NoError(t, f.SetCellValue("Sheet2", "G5", time.Duration(1e13)))
// Test completion column.
// Test completion column
assert.NoError(t, f.SetCellValue("Sheet2", "M2", nil))
// Test read cell value with given cell reference large than exists row.
// Test read cell value with given cell reference large than exists row
_, err = f.GetCellValue("Sheet2", "E231")
assert.NoError(t, err)
// Test get active worksheet of spreadsheet and get worksheet name of spreadsheet by given worksheet index.
// Test get active worksheet of spreadsheet and get worksheet name of spreadsheet by given worksheet index
f.GetSheetName(f.GetActiveSheetIndex())
// Test get worksheet index of spreadsheet by given worksheet name.
// Test get worksheet index of spreadsheet by given worksheet name
f.GetSheetIndex("Sheet1")
// Test get worksheet name of spreadsheet by given invalid worksheet index.
// Test get worksheet name of spreadsheet by given invalid worksheet index
f.GetSheetName(4)
// Test get worksheet map of workbook.
// Test get worksheet map of workbook
f.GetSheetMap()
for i := 1; i <= 300; i++ {
assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
@ -202,7 +209,7 @@ func TestSaveFile(t *testing.T) {
func TestSaveAsWrongPath(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// Test write file to not exist directory.
// Test write file to not exist directory
assert.Error(t, f.SaveAs(filepath.Join("x", "Book1.xlsx")))
assert.NoError(t, f.Close())
}
@ -218,7 +225,7 @@ func TestOpenReader(t *testing.T) {
_, err = OpenReader(bytes.NewReader(oleIdentifier), Options{Password: "password", UnzipXMLSizeLimit: UnzipSizeLimit + 1})
assert.EqualError(t, err, ErrWorkbookFileFormat.Error())
// Test open workbook with unsupported charset internal calculation chain.
// Test open workbook with unsupported charset internal calculation chain
preset := func(filePath string) *bytes.Buffer {
source, err := zip.OpenReader(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
@ -245,11 +252,11 @@ func TestOpenReader(t *testing.T) {
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
}
// Test open spreadsheet with unzip size limit.
// Test open spreadsheet with unzip size limit
_, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipSizeLimit: 100})
assert.EqualError(t, err, newUnzipSizeLimitError(100).Error())
// Test open password protected spreadsheet created by Microsoft Office Excel 2010.
// Test open password protected spreadsheet created by Microsoft Office Excel 2010
f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
assert.NoError(t, err)
val, err := f.GetCellValue("Sheet1", "A1")
@ -257,7 +264,7 @@ func TestOpenReader(t *testing.T) {
assert.Equal(t, "SECRET", val)
assert.NoError(t, f.Close())
// Test open password protected spreadsheet created by LibreOffice 7.0.0.3.
// Test open password protected spreadsheet created by LibreOffice 7.0.0.3
f, err = OpenFile(filepath.Join("test", "encryptAES.xlsx"), Options{Password: "password"})
assert.NoError(t, err)
val, err = f.GetCellValue("Sheet1", "A1")
@ -265,11 +272,11 @@ func TestOpenReader(t *testing.T) {
assert.Equal(t, "SECRET", val)
assert.NoError(t, f.Close())
// Test open spreadsheet with invalid options.
// Test open spreadsheet with invalid options
_, err = OpenReader(bytes.NewReader(oleIdentifier), Options{UnzipSizeLimit: 1, UnzipXMLSizeLimit: 2})
assert.EqualError(t, err, ErrOptionsUnzipSizeLimit.Error())
// Test unexpected EOF.
// Test unexpected EOF
var b bytes.Buffer
w := gzip.NewWriter(&b)
defer w.Close()
@ -299,7 +306,7 @@ func TestOpenReader(t *testing.T) {
}
func TestBrokenFile(t *testing.T) {
// Test write file with broken file struct.
// Test write file with broken file struct
f := File{}
t.Run("SaveWithoutName", func(t *testing.T) {
@ -307,12 +314,12 @@ func TestBrokenFile(t *testing.T) {
})
t.Run("SaveAsEmptyStruct", func(t *testing.T) {
// Test write file with broken file struct with given path.
// Test write file with broken file struct with given path
assert.NoError(t, f.SaveAs(filepath.Join("test", "BadWorkbook.SaveAsEmptyStruct.xlsx")))
})
t.Run("OpenBadWorkbook", func(t *testing.T) {
// Test set active sheet without BookViews and Sheets maps in xl/workbook.xml.
// Test set active sheet without BookViews and Sheets maps in xl/workbook.xml
f3, err := OpenFile(filepath.Join("test", "BadWorkbook.xlsx"))
f3.GetActiveSheetIndex()
f3.SetActiveSheet(1)
@ -321,7 +328,7 @@ func TestBrokenFile(t *testing.T) {
})
t.Run("OpenNotExistsFile", func(t *testing.T) {
// Test open a spreadsheet file with given illegal path.
// Test open a spreadsheet file with given illegal path
_, err := OpenFile(filepath.Join("test", "NotExistsFile.xlsx"))
if assert.Error(t, err) {
assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true")
@ -330,7 +337,7 @@ func TestBrokenFile(t *testing.T) {
}
func TestNewFile(t *testing.T) {
// Test create a spreadsheet file.
// Test create a spreadsheet file
f := NewFile()
f.NewSheet("Sheet1")
f.NewSheet("XLSXSheet2")
@ -339,20 +346,20 @@ func TestNewFile(t *testing.T) {
assert.NoError(t, f.SetCellStr("Sheet1", "B20", "42"))
f.SetActiveSheet(0)
// Test add picture to sheet with scaling and positioning.
// Test add picture to sheet with scaling and positioning
err := f.AddPicture("Sheet1", "H2", filepath.Join("test", "images", "excel.gif"),
`{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`)
if !assert.NoError(t, err) {
t.FailNow()
}
// Test add picture to worksheet without options.
// Test add picture to worksheet without options
err = f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), "")
if !assert.NoError(t, err) {
t.FailNow()
}
// Test add picture to worksheet with invalid options.
// Test add picture to worksheet with invalid options
err = f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), `{`)
if !assert.Error(t, err) {
t.FailNow()
@ -363,7 +370,7 @@ func TestNewFile(t *testing.T) {
}
func TestAddDrawingVML(t *testing.T) {
// Test addDrawingVML with illegal cell reference.
// Test addDrawingVML with illegal cell reference
f := NewFile()
assert.EqualError(t, f.addDrawingVML(0, "", "*", 0, 0), newCellNameToCoordinatesError("*", newInvalidCellNameError("*")).Error())
@ -374,23 +381,22 @@ func TestAddDrawingVML(t *testing.T) {
func TestSetCellHyperLink(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// Test set cell hyperlink in a work sheet already have hyperlinks.
// Test set cell hyperlink in a work sheet already have hyperlinks
assert.NoError(t, f.SetCellHyperLink("Sheet1", "B19", "https://github.com/xuri/excelize", "External"))
// Test add first hyperlink in a work sheet.
// Test add first hyperlink in a work sheet
assert.NoError(t, f.SetCellHyperLink("Sheet2", "C1", "https://github.com/xuri/excelize", "External"))
// Test add Location hyperlink in a work sheet.
assert.NoError(t, f.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location"))
// Test add Location hyperlink with display & tooltip in a work sheet.
// Test add Location hyperlink with display & tooltip in a work sheet
display, tooltip := "Display value", "Hover text"
assert.NoError(t, f.SetCellHyperLink("Sheet2", "D7", "Sheet1!D9", "Location", HyperlinkOpts{
Display: &display,
Tooltip: &tooltip,
}))
// Test set cell hyperlink with invalid sheet name
assert.EqualError(t, f.SetCellHyperLink("Sheet:1", "A1", "Sheet1!D60", "Location"), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", ""), `invalid link type ""`)
assert.EqualError(t, f.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location"), `invalid cell name ""`)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellHyperLink.xlsx")))
assert.NoError(t, f.Close())
@ -467,6 +473,10 @@ func TestGetCellHyperLink(t *testing.T) {
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.Equal(t, link, false)
assert.Equal(t, target, "")
// Test get cell hyperlink with invalid sheet name
_, _, err = f.GetCellHyperLink("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestSetSheetBackground(t *testing.T) {
@ -489,12 +499,14 @@ func TestSetSheetBackgroundErrors(t *testing.T) {
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
assert.EqualError(t, err, ErrImgExt.Error())
// Test set sheet background on not exist worksheet.
// Test set sheet background on not exist worksheet
err = f.SetSheetBackground("SheetN", filepath.Join("test", "images", "background.jpg"))
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test set sheet background with invalid sheet name
assert.EqualError(t, f.SetSheetBackground("Sheet:1", filepath.Join("test", "images", "background.jpg")), ErrSheetNameInvalid.Error())
assert.NoError(t, f.Close())
// Test set sheet background with unsupported charset content types.
// Test set sheet background with unsupported charset content types
f = NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
@ -510,7 +522,6 @@ func TestWriteArrayFormula(t *testing.T) {
if err != nil {
t.Fatal(err)
}
return c
}
@ -621,15 +632,20 @@ func TestSetCellStyleAlignment(t *testing.T) {
assert.NoError(t, f.SetCellStyle("Sheet1", "A22", "A22", style))
// Test set cell style with given illegal rows number.
// Test set cell style with given illegal rows number
assert.EqualError(t, f.SetCellStyle("Sheet1", "A", "A22", style), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.SetCellStyle("Sheet1", "A22", "A", style), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test get cell style with given illegal rows number.
// Test set cell style with invalid sheet name
assert.EqualError(t, f.SetCellStyle("Sheet:1", "A1", "A2", style), ErrSheetNameInvalid.Error())
// Test get cell style with given illegal rows number
index, err := f.GetCellStyle("Sheet1", "A")
assert.Equal(t, 0, index)
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test get cell style with invalid sheet name
_, err = f.GetCellStyle("Sheet:1", "A1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleAlignment.xlsx")))
}
@ -987,18 +1003,18 @@ func TestSheetVisibility(t *testing.T) {
assert.NoError(t, f.SetSheetVisible("Sheet2", false))
assert.NoError(t, f.SetSheetVisible("Sheet1", false))
assert.NoError(t, f.SetSheetVisible("Sheet1", true))
assert.Equal(t, true, f.GetSheetVisible("Sheet1"))
visible, err := f.GetSheetVisible("Sheet1")
assert.Equal(t, true, visible)
assert.NoError(t, err)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSheetVisibility.xlsx")))
}
func TestCopySheet(t *testing.T) {
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
idx := f.NewSheet("CopySheet")
idx, err := f.NewSheet("CopySheet")
assert.NoError(t, err)
assert.NoError(t, f.CopySheet(0, idx))
assert.NoError(t, f.SetCellValue("CopySheet", "F1", "Hello"))
@ -1011,15 +1027,9 @@ func TestCopySheet(t *testing.T) {
func TestCopySheetError(t *testing.T) {
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
}
assert.EqualError(t, f.copySheet(-1, -2), "sheet does not exist")
if !assert.EqualError(t, f.CopySheet(-1, -2), "invalid worksheet index") {
t.FailNow()
}
assert.NoError(t, err)
assert.EqualError(t, f.copySheet(-1, -2), ErrSheetNameBlank.Error())
assert.EqualError(t, f.CopySheet(-1, -2), ErrSheetIdx.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestCopySheetError.xlsx")))
}
@ -1072,9 +1082,9 @@ func TestConditionalFormat(t *testing.T) {
t.FailNow()
}
// Color scales: 2 color.
// Color scales: 2 color
assert.NoError(t, f.SetConditionalFormat(sheet1, "A1:A10", `[{"type":"2_color_scale","criteria":"=","min_type":"min","max_type":"max","min_color":"#F8696B","max_color":"#63BE7B"}]`))
// Color scales: 3 color.
// Color scales: 3 color
assert.NoError(t, f.SetConditionalFormat(sheet1, "B1:B10", `[{"type":"3_color_scale","criteria":"=","min_type":"min","mid_type":"percentile","max_type":"max","min_color":"#F8696B","mid_color":"#FFEB84","max_color":"#63BE7B"}]`))
// Highlight cells rules: between...
assert.NoError(t, f.SetConditionalFormat(sheet1, "C1:C10", fmt.Sprintf(`[{"type":"cell","criteria":"between","format":%d,"minimum":"6","maximum":"8"}]`, format1)))
@ -1092,29 +1102,31 @@ func TestConditionalFormat(t *testing.T) {
assert.NoError(t, f.SetConditionalFormat(sheet1, "I1:I10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": true}]`, format3)))
// Top/Bottom rules: Below Average...
assert.NoError(t, f.SetConditionalFormat(sheet1, "J1:J10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": false}]`, format1)))
// Data Bars: Gradient Fill.
// Data Bars: Gradient Fill
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10", `[{"type":"data_bar", "criteria":"=", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`))
// Use a formula to determine which cells to format.
// Use a formula to determine which cells to format
assert.NoError(t, f.SetConditionalFormat(sheet1, "L1:L10", fmt.Sprintf(`[{"type":"formula", "criteria":"L2<3", "format":%d}]`, format1)))
// Alignment/Border cells rules.
// Alignment/Border cells rules
assert.NoError(t, f.SetConditionalFormat(sheet1, "M1:M10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"0"}]`, format4)))
// Test set invalid format set in conditional format.
// Test set invalid format set in conditional format
assert.EqualError(t, f.SetConditionalFormat(sheet1, "L1:L10", ""), "unexpected end of JSON input")
// Set conditional format on not exists worksheet.
// Test set conditional format on not exists worksheet
assert.EqualError(t, f.SetConditionalFormat("SheetN", "L1:L10", "[]"), "sheet SheetN does not exist")
// Test set conditional format with invalid sheet name
assert.EqualError(t, f.SetConditionalFormat("Sheet:1", "L1:L10", "[]"), ErrSheetNameInvalid.Error())
err = f.SaveAs(filepath.Join("test", "TestConditionalFormat.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
// Set conditional format with illegal valid type.
// Set conditional format with illegal valid type
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10", `[{"type":"", "criteria":"=", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`))
// Set conditional format with illegal criteria type.
// Set conditional format with illegal criteria type
assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10", `[{"type":"data_bar", "criteria":"", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`))
// Set conditional format with file without dxfs element should not return error.
// Set conditional format with file without dxfs element should not return error
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
@ -1168,7 +1180,8 @@ func TestSetSheetCol(t *testing.T) {
assert.EqualError(t, f.SetSheetCol("Sheet1", "", &[]interface{}{"cell", nil, 2}),
newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
// Test set worksheet column values with invalid sheet name
assert.EqualError(t, f.SetSheetCol("Sheet:1", "A1", &[]interface{}{nil}), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.SetSheetCol("Sheet1", "B27", []interface{}{}), ErrParameterInvalid.Error())
assert.EqualError(t, f.SetSheetCol("Sheet1", "B27", &f), ErrParameterInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetCol.xlsx")))
@ -1185,7 +1198,8 @@ func TestSetSheetRow(t *testing.T) {
assert.EqualError(t, f.SetSheetRow("Sheet1", "", &[]interface{}{"cell", nil, 2}),
newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
// Test set worksheet row with invalid sheet name
assert.EqualError(t, f.SetSheetRow("Sheet:1", "A1", &[]interface{}{1}), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.SetSheetRow("Sheet1", "B27", []interface{}{}), ErrParameterInvalid.Error())
assert.EqualError(t, f.SetSheetRow("Sheet1", "B27", &f), ErrParameterInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetRow.xlsx")))
@ -1261,6 +1275,8 @@ func TestProtectSheet(t *testing.T) {
assert.Equal(t, int(sheetProtectionSpinCount), ws.SheetProtection.SpinCount)
// Test remove sheet protection with an incorrect password
assert.EqualError(t, f.UnprotectSheet(sheetName, "wrongPassword"), ErrUnprotectSheetPassword.Error())
// Test remove sheet protection with invalid sheet name
assert.EqualError(t, f.UnprotectSheet("Sheet:1", "wrongPassword"), ErrSheetNameInvalid.Error())
// Test remove sheet protection with password verification
assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
// Test protect worksheet with empty password
@ -1276,8 +1292,10 @@ func TestProtectSheet(t *testing.T) {
AlgorithmName: "RIPEMD-160",
Password: "password",
}), ErrUnsupportedHashAlgorithm.Error())
// Test protect not exists worksheet.
// Test protect not exists worksheet
assert.EqualError(t, f.ProtectSheet("SheetN", nil), "sheet SheetN does not exist")
// Test protect sheet with invalid sheet name
assert.EqualError(t, f.ProtectSheet("Sheet:1", nil), ErrSheetNameInvalid.Error())
}
func TestUnprotectSheet(t *testing.T) {
@ -1326,10 +1344,10 @@ func TestAddVBAProject(t *testing.T) {
assert.EqualError(t, f.AddVBAProject("macros.bin"), "stat macros.bin: no such file or directory")
assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "Book1.xlsx")), ErrAddVBAProject.Error())
assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
// Test add VBA project twice.
// Test add VBA project twice
assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
// Test add VBs with unsupported charset workbook relationships.
// Test add VBA with unsupported charset workbook relationships
f.Relationships.Delete(defaultXMLPathWorkbookRels)
f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")), "XML syntax error on line 1: invalid UTF-8")

View File

@ -29,7 +29,8 @@ func TestMergeCell(t *testing.T) {
value, err := f.GetCellValue("Sheet1", "H11")
assert.Equal(t, "100", value)
assert.NoError(t, err)
value, err = f.GetCellValue("Sheet2", "A6") // Merged cell ref is single coordinate.
// Merged cell ref is single coordinate
value, err = f.GetCellValue("Sheet2", "A6")
assert.Equal(t, "", value)
assert.NoError(t, err)
value, err = f.GetCellFormula("Sheet1", "G12")
@ -64,9 +65,10 @@ func TestMergeCell(t *testing.T) {
assert.NoError(t, f.MergeCell("Sheet3", "M8", "Q13"))
assert.NoError(t, f.MergeCell("Sheet3", "N10", "O11"))
// Test get merged cells on not exists worksheet.
// Test merge cells on not exists worksheet
assert.EqualError(t, f.MergeCell("SheetN", "N10", "O11"), "sheet SheetN does not exist")
// Test merged cells with invalid sheet name
assert.EqualError(t, f.MergeCell("Sheet:1", "N10", "O11"), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestMergeCell.xlsx")))
assert.NoError(t, f.Close())
@ -137,8 +139,10 @@ func TestGetMergeCells(t *testing.T) {
assert.Equal(t, wants[i].start, m.GetStartAxis())
assert.Equal(t, wants[i].end, m.GetEndAxis())
}
// Test get merged cells on not exists worksheet.
// Test get merged cells with invalid sheet name
_, err = f.GetMergeCells("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get merged cells on not exists worksheet
_, err = f.GetMergeCells("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
assert.NoError(t, f.Close())
@ -158,7 +162,7 @@ func TestUnmergeCell(t *testing.T) {
assert.EqualError(t, f.UnmergeCell("Sheet1", "A", "A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// unmerge the mergecell that contains A1
// Test unmerge the merged cells that contains A1
assert.NoError(t, f.UnmergeCell(sheet1, "A1", "A1"))
if len(sheet.MergeCells.Cells) != mergeCellNum-1 {
t.FailNow()
@ -169,9 +173,12 @@ func TestUnmergeCell(t *testing.T) {
f = NewFile()
assert.NoError(t, f.MergeCell("Sheet1", "A2", "B3"))
// Test unmerged range reference on not exists worksheet.
// Test unmerged range reference on not exists worksheet
assert.EqualError(t, f.UnmergeCell("SheetN", "A1", "A1"), "sheet SheetN does not exist")
// Test unmerge the merged cells with invalid sheet name
assert.EqualError(t, f.UnmergeCell("Sheet:1", "A1", "A1"), ErrSheetNameInvalid.Error())
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).MergeCells = nil

View File

@ -35,17 +35,17 @@ func TestAddPicture(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// Test add picture to worksheet with offset and location hyperlink.
// Test add picture to worksheet with offset and location hyperlink
assert.NoError(t, f.AddPicture("Sheet2", "I9", filepath.Join("test", "images", "excel.jpg"),
`{"x_offset": 140, "y_offset": 120, "hyperlink": "#Sheet2!D8", "hyperlink_type": "Location"}`))
// Test add picture to worksheet with offset, external hyperlink and positioning.
// Test add picture to worksheet with offset, external hyperlink and positioning
assert.NoError(t, f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"),
`{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/xuri/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`))
file, err := os.ReadFile(filepath.Join("test", "images", "excel.png"))
assert.NoError(t, err)
// Test add picture to worksheet with autofit.
// Test add picture to worksheet with autofit
assert.NoError(t, f.AddPicture("Sheet1", "A30", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`))
assert.NoError(t, f.AddPicture("Sheet1", "B30", filepath.Join("test", "images", "excel.jpg"), `{"x_offset": 10, "y_offset": 10, "autofit": true}`))
f.NewSheet("AddPicture")
@ -55,41 +55,44 @@ func TestAddPicture(t *testing.T) {
assert.NoError(t, f.AddPicture("AddPicture", "C6", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`))
assert.NoError(t, f.AddPicture("AddPicture", "A1", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`))
// Test add picture to worksheet from bytes.
// Test add picture to worksheet from bytes
assert.NoError(t, f.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".png", file))
// Test add picture to worksheet from bytes with illegal cell reference.
// Test add picture to worksheet from bytes with illegal cell reference
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "A", "", "Excel Logo", ".png", file), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.NoError(t, f.AddPicture("Sheet1", "Q8", filepath.Join("test", "images", "excel.gif"), ""))
assert.NoError(t, f.AddPicture("Sheet1", "Q15", filepath.Join("test", "images", "excel.jpg"), ""))
assert.NoError(t, f.AddPicture("Sheet1", "Q22", filepath.Join("test", "images", "excel.tif"), ""))
// Test write file to given path.
// Test write file to given path
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPicture1.xlsx")))
assert.NoError(t, f.Close())
// Test add picture with unsupported charset content types.
// Test add picture with unsupported charset content types
f = NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".png", file), "XML syntax error on line 1: invalid UTF-8")
// Test add picture with invalid sheet name
assert.EqualError(t, f.AddPicture("Sheet:1", "A1", filepath.Join("test", "images", "excel.jpg"), ""), ErrSheetNameInvalid.Error())
}
func TestAddPictureErrors(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// Test add picture to worksheet with invalid file path.
// Test add picture to worksheet with invalid file path
assert.Error(t, f.AddPicture("Sheet1", "G21", filepath.Join("test", "not_exists_dir", "not_exists.icon"), ""))
// Test add picture to worksheet with unsupported file type.
// Test add picture to worksheet with unsupported file type
assert.EqualError(t, f.AddPicture("Sheet1", "G21", filepath.Join("test", "Book1.xlsx"), ""), ErrImgExt.Error())
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", "jpg", make([]byte, 1)), ErrImgExt.Error())
// Test add picture to worksheet with invalid file data.
// Test add picture to worksheet with invalid file data
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1)), image.ErrFormat.Error())
// Test add picture with custom image decoder and encoder.
// Test add picture with custom image decoder and encoder
decode := func(r io.Reader) (image.Image, error) { return nil, nil }
decodeConfig := func(r io.Reader) (image.Config, error) { return image.Config{Height: 100, Width: 90}, nil }
image.RegisterFormat("emf", "", decode, decodeConfig)
@ -126,22 +129,26 @@ func TestGetPicture(t *testing.T) {
t.FailNow()
}
// Try to get picture from a worksheet with illegal cell reference.
// Try to get picture from a worksheet with illegal cell reference
_, _, err = f.GetPicture("Sheet1", "A")
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Try to get picture from a worksheet that doesn't contain any images.
// Try to get picture from a worksheet that doesn't contain any images
file, raw, err = f.GetPicture("Sheet3", "I9")
assert.EqualError(t, err, "sheet Sheet3 does not exist")
assert.Empty(t, file)
assert.Empty(t, raw)
// Try to get picture from a cell that doesn't contain an image.
// Try to get picture from a cell that doesn't contain an image
file, raw, err = f.GetPicture("Sheet2", "A2")
assert.NoError(t, err)
assert.Empty(t, file)
assert.Empty(t, raw)
// Test get picture with invalid sheet name
_, _, err = f.GetPicture("Sheet:1", "A2")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
f.getDrawingRelationships("xl/worksheets/_rels/sheet1.xml.rels", "rId8")
f.getDrawingRelationships("", "")
f.getSheetRelationshipsTargetByID("", "")
@ -160,14 +167,14 @@ func TestGetPicture(t *testing.T) {
t.FailNow()
}
// Try to get picture from a local storage file that doesn't contain an image.
// Try to get picture from a local storage file that doesn't contain an image
file, raw, err = f.GetPicture("Sheet1", "F22")
assert.NoError(t, err)
assert.Empty(t, file)
assert.Empty(t, raw)
assert.NoError(t, f.Close())
// Test get picture from none drawing worksheet.
// Test get picture from none drawing worksheet
f = NewFile()
file, raw, err = f.GetPicture("Sheet1", "F22")
assert.NoError(t, err)
@ -176,7 +183,7 @@ func TestGetPicture(t *testing.T) {
f, err = prepareTestBook1()
assert.NoError(t, err)
// Test get pictures with unsupported charset.
// Test get pictures with unsupported charset
path := "xl/drawings/drawing1.xml"
f.Pkg.Store(path, MacintoshCyrillicCharset)
_, _, err = f.getPicture(20, 5, path, "xl/drawings/_rels/drawing2.xml.rels")
@ -187,7 +194,7 @@ func TestGetPicture(t *testing.T) {
}
func TestAddDrawingPicture(t *testing.T) {
// Test addDrawingPicture with illegal cell reference.
// Test addDrawingPicture with illegal cell reference
f := NewFile()
assert.EqualError(t, f.addDrawingPicture("sheet1", "", "A", "", "", 0, 0, image.Config{}, nil), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
@ -211,6 +218,8 @@ func TestAddPictureFromBytes(t *testing.T) {
})
assert.Equal(t, 1, imageCount, "Duplicate image should only be stored once.")
assert.EqualError(t, f.AddPictureFromBytes("SheetN", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), "sheet SheetN does not exist")
// Test add picture from bytes with invalid sheet name
assert.EqualError(t, f.AddPictureFromBytes("Sheet:1", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), ErrSheetNameInvalid.Error())
}
func TestDeletePicture(t *testing.T) {
@ -220,21 +229,23 @@ func TestDeletePicture(t *testing.T) {
assert.NoError(t, f.AddPicture("Sheet1", "P1", filepath.Join("test", "images", "excel.jpg"), ""))
assert.NoError(t, f.DeletePicture("Sheet1", "P1"))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeletePicture.xlsx")))
// Test delete picture on not exists worksheet.
// Test delete picture on not exists worksheet
assert.EqualError(t, f.DeletePicture("SheetN", "A1"), "sheet SheetN does not exist")
// Test delete picture with invalid coordinates.
// Test delete picture with invalid sheet name
assert.EqualError(t, f.DeletePicture("Sheet:1", "A1"), ErrSheetNameInvalid.Error())
// Test delete picture with invalid coordinates
assert.EqualError(t, f.DeletePicture("Sheet1", ""), newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
assert.NoError(t, f.Close())
// Test delete picture on no chart worksheet.
// Test delete picture on no chart worksheet
assert.NoError(t, NewFile().DeletePicture("Sheet1", "A1"))
}
func TestDrawingResize(t *testing.T) {
f := NewFile()
// Test calculate drawing resize on not exists worksheet.
// Test calculate drawing resize on not exists worksheet
_, _, _, _, err := f.drawingResize("SheetN", "A1", 1, 1, nil)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test calculate drawing resize with invalid coordinates.
// Test calculate drawing resize with invalid coordinates
_, _, _, _, err = f.drawingResize("Sheet1", "", 1, 1, nil)
assert.EqualError(t, err, newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
@ -245,7 +256,7 @@ func TestDrawingResize(t *testing.T) {
func TestSetContentTypePartImageExtensions(t *testing.T) {
f := NewFile()
// Test set content type part image extensions with unsupported charset content types.
// Test set content type part image extensions with unsupported charset content types
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.setContentTypePartImageExtensions(), "XML syntax error on line 1: invalid UTF-8")
@ -253,7 +264,7 @@ func TestSetContentTypePartImageExtensions(t *testing.T) {
func TestSetContentTypePartVMLExtensions(t *testing.T) {
f := NewFile()
// Test set content type part VML extensions with unsupported charset content types.
// Test set content type part VML extensions with unsupported charset content types
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.setContentTypePartVMLExtensions(), "XML syntax error on line 1: invalid UTF-8")
@ -261,7 +272,7 @@ func TestSetContentTypePartVMLExtensions(t *testing.T) {
func TestAddContentTypePart(t *testing.T) {
f := NewFile()
// Test add content type part with unsupported charset content types.
// Test add content type part with unsupported charset content types
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.addContentTypePart(0, "unknown"), "XML syntax error on line 1: invalid UTF-8")

View File

@ -225,6 +225,12 @@ func TestAddPivotTable(t *testing.T) {
Data: []PivotTableField{{Data: "Sales", Subtotal: "-", Name: strings.Repeat("s", MaxFieldLength+1)}},
}))
// Test add pivot table with invalid sheet name
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
DataRange: "Sheet:1!$A$1:$E$31",
PivotTableRange: "Sheet:1!$G$2:$M$34",
Rows: []PivotTableField{{Data: "Year"}},
}), ErrSheetNameInvalid.Error())
// Test adjust range with invalid range
_, _, err := f.adjustRange("")
assert.EqualError(t, err, ErrParameterRequired.Error())

View File

@ -260,6 +260,9 @@ func (rows *Rows) rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.Sta
// fmt.Println(err)
// }
func (f *File) Rows(sheet string) (*Rows, error) {
if err := checkSheetName(sheet); err != nil {
return nil, err
}
name, ok := f.getSheetXMLPath(sheet)
if !ok {
return nil, ErrSheetNotExist{sheet}
@ -268,7 +271,7 @@ func (f *File) Rows(sheet string) (*Rows, error) {
worksheet := ws.(*xlsxWorksheet)
worksheet.Lock()
defer worksheet.Unlock()
// flush data
// Flush data
output, _ := xml.Marshal(worksheet)
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
}

View File

@ -13,17 +13,15 @@ import (
func TestRows(t *testing.T) {
const sheet2 = "Sheet2"
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
// Test get rows with invalid sheet name
_, err = f.Rows("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
rows, err := f.Rows(sheet2)
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
var collectedRows [][]string
for rows.Next() {
columns, err := rows.Columns()
@ -49,13 +47,13 @@ func TestRows(t *testing.T) {
_, err = f.Rows("Sheet1")
assert.NoError(t, err)
// Test reload the file to memory from system temporary directory.
// Test reload the file to memory from system temporary directory
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
assert.NoError(t, err)
value, err := f.GetCellValue("Sheet1", "A19")
assert.NoError(t, err)
assert.Equal(t, "Total:", value)
// Test load shared string table to memory.
// Test load shared string table to memory
err = f.SetCellValue("Sheet1", "A19", "A19")
assert.NoError(t, err)
value, err = f.GetCellValue("Sheet1", "A19")
@ -64,7 +62,7 @@ func TestRows(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetRow.xlsx")))
assert.NoError(t, f.Close())
// Test rows iterator with unsupported charset shared strings table.
// Test rows iterator with unsupported charset shared strings table
f.SharedStrings = nil
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
rows, err = f.Rows(sheet2)
@ -154,25 +152,32 @@ func TestRowHeight(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 111.0, height)
// Test set row height overflow max row height limit.
// Test set row height overflow max row height limit
assert.EqualError(t, f.SetRowHeight(sheet1, 4, MaxRowHeight+1), ErrMaxRowHeight.Error())
// Test get row height that rows index over exists rows.
// Test get row height that rows index over exists rows
height, err = f.GetRowHeight(sheet1, 5)
assert.NoError(t, err)
assert.Equal(t, defaultRowHeight, height)
// Test get row height that rows heights haven't changed.
// Test get row height that rows heights haven't changed
height, err = f.GetRowHeight(sheet1, 3)
assert.NoError(t, err)
assert.Equal(t, defaultRowHeight, height)
// Test set and get row height on not exists worksheet.
// Test set and get row height on not exists worksheet
assert.EqualError(t, f.SetRowHeight("SheetN", 1, 111.0), "sheet SheetN does not exist")
_, err = f.GetRowHeight("SheetN", 3)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get row height with custom default row height.
// Test set row height with invalid sheet name
assert.EqualError(t, f.SetRowHeight("Sheet:1", 1, 10.0), ErrSheetNameInvalid.Error())
// Test get row height with invalid sheet name
_, err = f.GetRowHeight("Sheet:1", 3)
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
// Test get row height with custom default row height
assert.NoError(t, f.SetSheetProps(sheet1, &SheetPropsOptions{
DefaultRowHeight: float64Ptr(30.0),
CustomHeight: boolPtr(true),
@ -181,7 +186,7 @@ func TestRowHeight(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 30.0, height)
// Test set row height with custom default row height with prepare XML.
// Test set row height with custom default row height with prepare XML
assert.NoError(t, f.SetCellValue(sheet1, "A10", "A10"))
f.NewSheet("Sheet2")
@ -233,17 +238,17 @@ func TestColumns(t *testing.T) {
func TestSharedStringsReader(t *testing.T) {
f := NewFile()
// Test read shared string with unsupported charset.
// Test read shared string with unsupported charset
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
_, err := f.sharedStringsReader()
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
// Test read shared strings with unsupported charset content types.
// Test read shared strings with unsupported charset content types
f = NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
_, err = f.sharedStringsReader()
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
// Test read shared strings with unsupported charset workbook relationships.
// Test read shared strings with unsupported charset workbook relationships
f = NewFile()
f.Relationships.Delete(defaultXMLPathWorkbookRels)
f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
@ -267,13 +272,17 @@ func TestRowVisibility(t *testing.T) {
assert.NoError(t, err)
assert.EqualError(t, f.SetRowVisible("Sheet3", 0, true), newInvalidRowNumberError(0).Error())
assert.EqualError(t, f.SetRowVisible("SheetN", 2, false), "sheet SheetN does not exist")
// Test set row visibility with invalid sheet name
assert.EqualError(t, f.SetRowVisible("Sheet:1", 1, false), ErrSheetNameInvalid.Error())
visible, err = f.GetRowVisible("Sheet3", 0)
assert.Equal(t, false, visible)
assert.EqualError(t, err, newInvalidRowNumberError(0).Error())
_, err = f.GetRowVisible("SheetN", 1)
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get row visibility with invalid sheet name
_, err = f.GetRowVisible("Sheet:1", 1)
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRowVisibility.xlsx")))
}
@ -335,7 +344,9 @@ func TestRemoveRow(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemoveRow.xlsx")))
// Test remove row on not exist worksheet
assert.EqualError(t, f.RemoveRow("SheetN", 1), `sheet SheetN does not exist`)
assert.EqualError(t, f.RemoveRow("SheetN", 1), "sheet SheetN does not exist")
// Test remove row with invalid sheet name
assert.EqualError(t, f.RemoveRow("Sheet:1", 1), ErrSheetNameInvalid.Error())
}
func TestInsertRows(t *testing.T) {
@ -365,6 +376,8 @@ func TestInsertRows(t *testing.T) {
if !assert.Len(t, r.SheetData.Row, rowCount+4) {
t.FailNow()
}
// Test insert rows with invalid sheet name
assert.EqualError(t, f.InsertRows("Sheet:1", 1, 1), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.InsertRows(sheet1, -1, 1), newInvalidRowNumberError(-1).Error())
assert.EqualError(t, f.InsertRows(sheet1, 0, 1), newInvalidRowNumberError(0).Error())
@ -892,6 +905,12 @@ func TestDuplicateRowInvalidRowNum(t *testing.T) {
}
}
func TestDuplicateRow(t *testing.T) {
f := NewFile()
// Test duplicate row with invalid sheet name
assert.EqualError(t, f.DuplicateRowTo("Sheet:1", 1, 2), ErrSheetNameInvalid.Error())
}
func TestDuplicateRowTo(t *testing.T) {
f, sheetName := NewFile(), "Sheet1"
// Test duplicate row with invalid target row number
@ -907,6 +926,8 @@ func TestDuplicateRowTo(t *testing.T) {
assert.EqualError(t, f.DuplicateRowTo(sheetName, 1, 2), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
// Test duplicate row on not exists worksheet
assert.EqualError(t, f.DuplicateRowTo("SheetN", 1, 2), "sheet SheetN does not exist")
// Test duplicate row with invalid sheet name
assert.EqualError(t, f.DuplicateRowTo("Sheet:1", 1, 2), ErrSheetNameInvalid.Error())
}
func TestDuplicateMergeCells(t *testing.T) {
@ -976,22 +997,24 @@ func TestSetRowStyle(t *testing.T) {
assert.NoError(t, f.SetCellStyle("Sheet1", "B2", "B2", style1))
assert.EqualError(t, f.SetRowStyle("Sheet1", 5, -1, style2), newInvalidRowNumberError(-1).Error())
assert.EqualError(t, f.SetRowStyle("Sheet1", 1, TotalRows+1, style2), ErrMaxRows.Error())
// Test set row style with invalid style ID.
// Test set row style with invalid style ID
assert.EqualError(t, f.SetRowStyle("Sheet1", 1, 1, -1), newInvalidStyleID(-1).Error())
// Test set row style with not exists style ID.
// Test set row style with not exists style ID
assert.EqualError(t, f.SetRowStyle("Sheet1", 1, 1, 10), newInvalidStyleID(10).Error())
assert.EqualError(t, f.SetRowStyle("SheetN", 1, 1, style2), "sheet SheetN does not exist")
// Test set row style with invalid sheet name
assert.EqualError(t, f.SetRowStyle("Sheet:1", 1, 1, 0), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SetRowStyle("Sheet1", 5, 1, style2))
cellStyleID, err := f.GetCellStyle("Sheet1", "B2")
assert.NoError(t, err)
assert.Equal(t, style2, cellStyleID)
// Test cell inheritance rows style.
// Test cell inheritance rows style
assert.NoError(t, f.SetCellValue("Sheet1", "C1", nil))
cellStyleID, err = f.GetCellStyle("Sheet1", "C1")
assert.NoError(t, err)
assert.Equal(t, style2, cellStyleID)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetRowStyle.xlsx")))
// Test set row style with unsupported charset style sheet.
// Test set row style with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
assert.EqualError(t, f.SetRowStyle("Sheet1", 1, 1, cellStyleID), "XML syntax error on line 1: invalid UTF-8")

View File

@ -59,7 +59,7 @@ func TestAddShape(t *testing.T) {
}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape1.xlsx")))
// Test add first shape for given sheet.
// Test add first shape for given sheet
f = NewFile()
assert.NoError(t, f.AddShape("Sheet1", "A1", `{
"type": "ellipseRibbon",
@ -87,11 +87,13 @@ func TestAddShape(t *testing.T) {
}
}`))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape2.xlsx")))
// Test add shape with unsupported charset style sheet.
// Test add shape with invalid sheet name
assert.EqualError(t, f.AddShape("Sheet:1", "A30", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`), ErrSheetNameInvalid.Error())
// Test add shape with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`), "XML syntax error on line 1: invalid UTF-8")
// Test add shape with unsupported charset content types.
// Test add shape with unsupported charset content types
f = NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)

170
sheet.go
View File

@ -35,14 +35,15 @@ import (
// name and returns the index of the sheets in the workbook after it appended.
// Note that when creating a new workbook, the default worksheet named
// `Sheet1` will be created.
func (f *File) NewSheet(sheet string) int {
if trimSheetName(sheet) == "" {
return -1
func (f *File) NewSheet(sheet string) (int, error) {
var err error
if err = checkSheetName(sheet); err != nil {
return -1, err
}
// Check if the worksheet already exists
index := f.GetSheetIndex(sheet)
index, err := f.GetSheetIndex(sheet)
if index != -1 {
return index
return index, err
}
f.DeleteSheet(sheet)
f.SheetCount++
@ -235,7 +236,7 @@ func (f *File) setSheet(index int, name string) {
},
}
sheetXMLPath := "xl/worksheets/sheet" + strconv.Itoa(index) + ".xml"
f.sheetMap[trimSheetName(name)] = sheetXMLPath
f.sheetMap[name] = sheetXMLPath
f.Sheet.Store(sheetXMLPath, &ws)
f.xmlAttr[sheetXMLPath] = []xml.Attr{NameSpaceSpreadSheet}
}
@ -352,11 +353,16 @@ func (f *File) getActiveSheetID() int {
// this function only changes the name of the sheet and will not update the
// sheet name in the formula or reference associated with the cell. So there
// may be problem formula error or reference missing.
func (f *File) SetSheetName(source, target string) {
source = trimSheetName(source)
target = trimSheetName(target)
func (f *File) SetSheetName(source, target string) error {
var err error
if err = checkSheetName(source); err != nil {
return err
}
if err = checkSheetName(target); err != nil {
return err
}
if strings.EqualFold(target, source) {
return
return err
}
wb, _ := f.workbookReader()
for k, v := range wb.Sheets.Sheet {
@ -366,6 +372,7 @@ func (f *File) SetSheetName(source, target string) {
delete(f.sheetMap, source)
}
}
return err
}
// GetSheetName provides a function to get the sheet name of the workbook by
@ -385,9 +392,8 @@ func (f *File) GetSheetName(index int) (name string) {
// given sheet name. If given worksheet name is invalid, will return an
// integer type value -1.
func (f *File) getSheetID(sheet string) int {
sheetName := trimSheetName(sheet)
for sheetID, name := range f.GetSheetMap() {
if strings.EqualFold(name, sheetName) {
if strings.EqualFold(name, sheet) {
return sheetID
}
}
@ -397,14 +403,16 @@ func (f *File) getSheetID(sheet string) int {
// GetSheetIndex provides a function to get a sheet index of the workbook by
// the given sheet name. If the given sheet name is invalid or sheet doesn't
// exist, it will return an integer type value -1.
func (f *File) GetSheetIndex(sheet string) int {
sheetName := trimSheetName(sheet)
func (f *File) GetSheetIndex(sheet string) (int, error) {
if err := checkSheetName(sheet); err != nil {
return -1, err
}
for index, name := range f.GetSheetList() {
if strings.EqualFold(name, sheetName) {
return index
if strings.EqualFold(name, sheet) {
return index, nil
}
}
return -1
return -1, nil
}
// GetSheetMap provides a function to get worksheets, chart sheets, dialog
@ -474,7 +482,6 @@ func (f *File) getSheetXMLPath(sheet string) (string, bool) {
name string
ok bool
)
sheet = trimSheetName(sheet)
for sheetName, filePath := range f.sheetMap {
if strings.EqualFold(sheetName, sheet) {
name, ok = filePath, true
@ -530,19 +537,22 @@ func (f *File) setSheetBackground(sheet, extension string, file []byte) error {
// references such as formulas, charts, and so on. If there is any referenced
// value of the deleted worksheet, it will cause a file error when you open
// it. This function will be invalid when only one worksheet is left.
func (f *File) DeleteSheet(sheet string) {
if f.SheetCount == 1 || f.GetSheetIndex(sheet) == -1 {
return
func (f *File) DeleteSheet(sheet string) error {
if err := checkSheetName(sheet); err != nil {
return err
}
sheetName := trimSheetName(sheet)
if idx, _ := f.GetSheetIndex(sheet); f.SheetCount == 1 || idx == -1 {
return nil
}
wb, _ := f.workbookReader()
wbRels, _ := f.relsReader(f.getWorkbookRelsPath())
activeSheetName := f.GetSheetName(f.GetActiveSheetIndex())
deleteLocalSheetID := f.GetSheetIndex(sheet)
deleteLocalSheetID, _ := f.GetSheetIndex(sheet)
deleteAndAdjustDefinedNames(wb, deleteLocalSheetID)
for idx, v := range wb.Sheets.Sheet {
if !strings.EqualFold(v.Name, sheetName) {
if !strings.EqualFold(v.Name, sheet) {
continue
}
@ -568,7 +578,9 @@ func (f *File) DeleteSheet(sheet string) {
delete(f.xmlAttr, sheetXML)
f.SheetCount--
}
f.SetActiveSheet(f.GetSheetIndex(activeSheetName))
index, err := f.GetSheetIndex(activeSheetName)
f.SetActiveSheet(index)
return err
}
// deleteAndAdjustDefinedNames delete and adjust defined name in the workbook
@ -683,7 +695,9 @@ func (f *File) copySheet(from, to int) error {
//
// err := f.SetSheetVisible("Sheet1", false)
func (f *File) SetSheetVisible(sheet string, visible bool) error {
sheet = trimSheetName(sheet)
if err := checkSheetName(sheet); err != nil {
return err
}
wb, err := f.workbookReader()
if err != nil {
return err
@ -857,17 +871,20 @@ func (f *File) SetPanes(sheet, panes string) error {
// name. For example, get visible state of Sheet1:
//
// f.GetSheetVisible("Sheet1")
func (f *File) GetSheetVisible(sheet string) bool {
name, visible := trimSheetName(sheet), false
func (f *File) GetSheetVisible(sheet string) (bool, error) {
var visible bool
if err := checkSheetName(sheet); err != nil {
return visible, err
}
wb, _ := f.workbookReader()
for k, v := range wb.Sheets.Sheet {
if strings.EqualFold(v.Name, name) {
if strings.EqualFold(v.Name, sheet) {
if wb.Sheets.Sheet[k].State == "" || wb.Sheets.Sheet[k].State == "visible" {
visible = true
}
}
}
return visible
return visible, nil
}
// SearchSheet provides a function to get cell reference by given worksheet name,
@ -889,6 +906,9 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
regSearch bool
result []string
)
if err := checkSheetName(sheet); err != nil {
return result, err
}
for _, r := range reg {
regSearch = r
}
@ -897,7 +917,7 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
return result, ErrSheetNotExist{sheet}
}
if ws, ok := f.Sheet.Load(name); ok && ws != nil {
// flush data
// Flush data
output, _ := xml.Marshal(ws.(*xlsxWorksheet))
f.saveFileList(name, f.replaceNameSpaceBytes(name, output))
}
@ -1051,7 +1071,7 @@ func attrValToBool(name string, attrs []xml.Attr) (val bool, err error) {
// |
// &F | Current workbook's file name
// |
// &G | Drawing object as background
// &G | Drawing object as background (Not support currently)
// |
// &H | Shadow text format
// |
@ -1167,47 +1187,47 @@ func (f *File) SetHeaderFooter(sheet string, settings *HeaderFooterOptions) erro
// Password: "password",
// EditScenarios: false,
// })
func (f *File) ProtectSheet(sheet string, settings *SheetProtectionOptions) error {
func (f *File) ProtectSheet(sheet string, opts *SheetProtectionOptions) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
if settings == nil {
settings = &SheetProtectionOptions{
if opts == nil {
opts = &SheetProtectionOptions{
EditObjects: true,
EditScenarios: true,
SelectLockedCells: true,
}
}
ws.SheetProtection = &xlsxSheetProtection{
AutoFilter: settings.AutoFilter,
DeleteColumns: settings.DeleteColumns,
DeleteRows: settings.DeleteRows,
FormatCells: settings.FormatCells,
FormatColumns: settings.FormatColumns,
FormatRows: settings.FormatRows,
InsertColumns: settings.InsertColumns,
InsertHyperlinks: settings.InsertHyperlinks,
InsertRows: settings.InsertRows,
Objects: settings.EditObjects,
PivotTables: settings.PivotTables,
Scenarios: settings.EditScenarios,
SelectLockedCells: settings.SelectLockedCells,
SelectUnlockedCells: settings.SelectUnlockedCells,
AutoFilter: opts.AutoFilter,
DeleteColumns: opts.DeleteColumns,
DeleteRows: opts.DeleteRows,
FormatCells: opts.FormatCells,
FormatColumns: opts.FormatColumns,
FormatRows: opts.FormatRows,
InsertColumns: opts.InsertColumns,
InsertHyperlinks: opts.InsertHyperlinks,
InsertRows: opts.InsertRows,
Objects: opts.EditObjects,
PivotTables: opts.PivotTables,
Scenarios: opts.EditScenarios,
SelectLockedCells: opts.SelectLockedCells,
SelectUnlockedCells: opts.SelectUnlockedCells,
Sheet: true,
Sort: settings.Sort,
Sort: opts.Sort,
}
if settings.Password != "" {
if settings.AlgorithmName == "" {
ws.SheetProtection.Password = genSheetPasswd(settings.Password)
if opts.Password != "" {
if opts.AlgorithmName == "" {
ws.SheetProtection.Password = genSheetPasswd(opts.Password)
return err
}
hashValue, saltValue, err := genISOPasswdHash(settings.Password, settings.AlgorithmName, "", int(sheetProtectionSpinCount))
hashValue, saltValue, err := genISOPasswdHash(opts.Password, opts.AlgorithmName, "", int(sheetProtectionSpinCount))
if err != nil {
return err
}
ws.SheetProtection.Password = ""
ws.SheetProtection.AlgorithmName = settings.AlgorithmName
ws.SheetProtection.AlgorithmName = opts.AlgorithmName
ws.SheetProtection.SaltValue = saltValue
ws.SheetProtection.HashValue = hashValue
ws.SheetProtection.SpinCount = int(sheetProtectionSpinCount)
@ -1246,25 +1266,25 @@ func (f *File) UnprotectSheet(sheet string, password ...string) error {
return err
}
// trimSheetName provides a function to trim invalid characters by given worksheet
// name.
func trimSheetName(name string) string {
if strings.ContainsAny(name, ":\\/?*[]") || utf8.RuneCountInString(name) > 31 {
r := make([]rune, 0, 31)
for _, v := range name {
switch v {
case 58, 92, 47, 63, 42, 91, 93: // replace :\/?*[]
continue
default:
r = append(r, v)
}
if len(r) == 31 {
break
}
}
name = string(r)
// checkSheetName check whether there are illegal characters in the sheet name.
// 1. Confirm that the sheet name is not empty
// 2. Make sure to enter a name with no more than 31 characters
// 3. Make sure the first or last character of the name cannot be a single quote
// 4. Verify that the following characters are not included in the name :\/?*[]
func checkSheetName(name string) error {
if name == "" {
return ErrSheetNameBlank
}
return name
if utf8.RuneCountInString(name) > MaxSheetNameLength {
return ErrSheetNameLength
}
if strings.HasPrefix(name, "'") || strings.HasSuffix(name, "'") {
return ErrSheetNameSingleQuote
}
if strings.ContainsAny(name, ":\\/?*[]") {
return ErrSheetNameInvalid
}
return nil
}
// SetPageLayout provides a function to sets worksheet page layout.
@ -1499,7 +1519,7 @@ func (f *File) SetDefinedName(definedName *DefinedName) error {
Data: definedName.RefersTo,
}
if definedName.Scope != "" {
if sheetIndex := f.GetSheetIndex(definedName.Scope); sheetIndex >= 0 {
if sheetIndex, _ := f.GetSheetIndex(definedName.Scope); sheetIndex >= 0 {
d.LocalSheetID = &sheetIndex
}
}
@ -1579,7 +1599,7 @@ func (f *File) GetDefinedName() []DefinedName {
// GroupSheets provides a function to group worksheets by given worksheets
// name. Group worksheets must contain an active worksheet.
func (f *File) GroupSheets(sheets []string) error {
// check an active worksheet in group worksheets
// Check an active worksheet in group worksheets
var inActiveSheet bool
activeSheet := f.GetActiveSheetIndex()
sheetMap := f.GetSheetList()

View File

@ -16,18 +16,27 @@ import (
func TestNewSheet(t *testing.T) {
f := NewFile()
f.NewSheet("Sheet2")
sheetID := f.NewSheet("sheet2")
sheetID, err := f.NewSheet("sheet2")
assert.NoError(t, err)
f.SetActiveSheet(sheetID)
// delete original sheet
f.DeleteSheet(f.GetSheetName(f.GetSheetIndex("Sheet1")))
// Test delete original sheet
idx, err := f.GetSheetIndex("Sheet1")
assert.NoError(t, err)
f.DeleteSheet(f.GetSheetName(idx))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestNewSheet.xlsx")))
// create new worksheet with already exists name
assert.Equal(t, f.GetSheetIndex("Sheet2"), f.NewSheet("Sheet2"))
// create new worksheet with empty sheet name
assert.Equal(t, -1, f.NewSheet(":\\/?*[]"))
// Test create new worksheet with already exists name
sheetID, err = f.NewSheet("Sheet2")
assert.NoError(t, err)
idx, err = f.GetSheetIndex("Sheet2")
assert.NoError(t, err)
assert.Equal(t, idx, sheetID)
// Test create new worksheet with empty sheet name
sheetID, err = f.NewSheet(":\\/?*[]")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
assert.Equal(t, -1, sheetID)
}
func TestSetPane(t *testing.T) {
func TestSetPanes(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
f.NewSheet("Panes 2")
@ -38,6 +47,8 @@ func TestSetPane(t *testing.T) {
assert.NoError(t, f.SetPanes("Panes 4", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`))
assert.EqualError(t, f.SetPanes("Panes 4", ""), "unexpected end of JSON input")
assert.EqualError(t, f.SetPanes("SheetN", ""), "sheet SheetN does not exist")
// Test set panes with invalid sheet name
assert.EqualError(t, f.SetPanes("Sheet:1", `{"freeze":false,"split":false}`), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
// Test add pane on empty sheet views worksheet
f = NewFile()
@ -52,11 +63,14 @@ func TestSearchSheet(t *testing.T) {
if !assert.NoError(t, err) {
t.FailNow()
}
// Test search in a not exists worksheet.
// Test search in a not exists worksheet
_, err = f.SearchSheet("Sheet4", "")
assert.EqualError(t, err, "sheet Sheet4 does not exist")
// Test search sheet with invalid sheet name
_, err = f.SearchSheet("Sheet:1", "")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
var expected []string
// Test search a not exists value.
// Test search a not exists value
result, err := f.SearchSheet("Sheet1", "X")
assert.NoError(t, err)
assert.EqualValues(t, expected, result)
@ -120,23 +134,30 @@ func TestSetPageLayout(t *testing.T) {
opts, err := f.GetPageLayout("Sheet1")
assert.NoError(t, err)
assert.Equal(t, expected, opts)
// Test set page layout on not exists worksheet.
// Test set page layout on not exists worksheet
assert.EqualError(t, f.SetPageLayout("SheetN", nil), "sheet SheetN does not exist")
// Test set page layout with invalid sheet name
assert.EqualError(t, f.SetPageLayout("Sheet:1", nil), ErrSheetNameInvalid.Error())
}
func TestGetPageLayout(t *testing.T) {
f := NewFile()
// Test get page layout on not exists worksheet.
// Test get page layout on not exists worksheet
_, err := f.GetPageLayout("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get page layout with invalid sheet name
_, err = f.GetPageLayout("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestSetHeaderFooter(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
// Test set header and footer on not exists worksheet.
// Test set header and footer on not exists worksheet
assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN does not exist")
// Test set header and footer with illegal setting.
// Test Sheet:1 with invalid sheet name
assert.EqualError(t, f.SetHeaderFooter("Sheet:1", nil), ErrSheetNameInvalid.Error())
// Test set header and footer with illegal setting
assert.EqualError(t, f.SetHeaderFooter("Sheet1", &HeaderFooterOptions{
OddHeader: strings.Repeat("c", MaxFieldLength+1),
}), newFieldLengthError("OddHeader").Error())
@ -190,13 +211,13 @@ func TestDefinedName(t *testing.T) {
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
assert.Exactly(t, 1, len(f.GetDefinedName()))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
// Test set defined name with unsupported charset workbook.
// Test set defined name with unsupported charset workbook
f.WorkBook = nil
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
assert.EqualError(t, f.SetDefinedName(&DefinedName{
Name: "Amount", RefersTo: "Sheet1!$A$2:$D$5",
}), "XML syntax error on line 1: invalid UTF-8")
// Test delete defined name with unsupported charset workbook.
// Test delete defined name with unsupported charset workbook
f.WorkBook = nil
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
assert.EqualError(t, f.DeleteDefinedName(&DefinedName{Name: "Amount"}),
@ -211,6 +232,8 @@ func TestGroupSheets(t *testing.T) {
}
assert.EqualError(t, f.GroupSheets([]string{"Sheet1", "SheetN"}), "sheet SheetN does not exist")
assert.EqualError(t, f.GroupSheets([]string{"Sheet2", "Sheet3"}), "group worksheet must contain an active worksheet")
// Test group sheets with invalid sheet name
assert.EqualError(t, f.GroupSheets([]string{"Sheet:1", "Sheet1"}), ErrSheetNameInvalid.Error())
assert.NoError(t, f.GroupSheets([]string{"Sheet1", "Sheet2"}))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestGroupSheets.xlsx")))
}
@ -232,6 +255,8 @@ func TestInsertPageBreak(t *testing.T) {
assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
assert.EqualError(t, f.InsertPageBreak("Sheet1", "A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.InsertPageBreak("SheetN", "C3"), "sheet SheetN does not exist")
// Test insert page break with invalid sheet name
assert.EqualError(t, f.InsertPageBreak("Sheet:1", "C3"), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestInsertPageBreak.xlsx")))
}
@ -258,6 +283,8 @@ func TestRemovePageBreak(t *testing.T) {
assert.EqualError(t, f.RemovePageBreak("Sheet1", "A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.RemovePageBreak("SheetN", "C3"), "sheet SheetN does not exist")
// Test remove page break with invalid sheet name
assert.EqualError(t, f.RemovePageBreak("Sheet:1", "A3"), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemovePageBreak.xlsx")))
}
@ -305,7 +332,8 @@ func TestSetActiveSheet(t *testing.T) {
f = NewFile()
f.WorkBook.BookViews = nil
idx := f.NewSheet("Sheet2")
idx, err := f.NewSheet("Sheet2")
assert.NoError(t, err)
ws, ok = f.Sheet.Load("xl/worksheets/sheet2.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{}}
@ -314,9 +342,11 @@ func TestSetActiveSheet(t *testing.T) {
func TestSetSheetName(t *testing.T) {
f := NewFile()
// Test set worksheet with the same name.
f.SetSheetName("Sheet1", "Sheet1")
// Test set worksheet with the same name
assert.NoError(t, f.SetSheetName("Sheet1", "Sheet1"))
assert.Equal(t, "Sheet1", f.GetSheetName(0))
// Test set sheet name with invalid sheet name
assert.EqualError(t, f.SetSheetName("Sheet:1", "Sheet1"), ErrSheetNameInvalid.Error())
}
func TestWorksheetWriter(t *testing.T) {
@ -348,7 +378,9 @@ func TestGetWorkbookRelsPath(t *testing.T) {
func TestDeleteSheet(t *testing.T) {
f := NewFile()
f.SetActiveSheet(f.NewSheet("Sheet2"))
idx, err := f.NewSheet("Sheet2")
assert.NoError(t, err)
f.SetActiveSheet(idx)
f.NewSheet("Sheet3")
f.DeleteSheet("Sheet1")
assert.Equal(t, "Sheet2", f.GetSheetName(f.GetActiveSheetIndex()))
@ -363,8 +395,10 @@ func TestDeleteSheet(t *testing.T) {
assert.NoError(t, f.AutoFilter("Sheet1", "A1", "A1", ""))
assert.NoError(t, f.AutoFilter("Sheet2", "A1", "A1", ""))
assert.NoError(t, f.AutoFilter("Sheet3", "A1", "A1", ""))
f.DeleteSheet("Sheet2")
f.DeleteSheet("Sheet1")
assert.NoError(t, f.DeleteSheet("Sheet2"))
assert.NoError(t, f.DeleteSheet("Sheet1"))
// Test delete sheet with invalid sheet name
assert.EqualError(t, f.DeleteSheet("Sheet:1"), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteSheet2.xlsx")))
}
@ -382,14 +416,32 @@ func TestGetSheetID(t *testing.T) {
func TestSetSheetVisible(t *testing.T) {
f := NewFile()
// Test set sheet visible with invalid sheet name
assert.EqualError(t, f.SetSheetVisible("Sheet:1", false), ErrSheetNameInvalid.Error())
f.WorkBook.Sheets.Sheet[0].Name = "SheetN"
assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "sheet SheetN does not exist")
// Test set sheet visible with unsupported charset workbook.
// Test set sheet visible with unsupported charset workbook
f.WorkBook = nil
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "XML syntax error on line 1: invalid UTF-8")
}
func TestGetSheetVisible(t *testing.T) {
f := NewFile()
// Test get sheet visible with invalid sheet name
visible, err := f.GetSheetVisible("Sheet:1")
assert.Equal(t, false, visible)
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestGetSheetIndex(t *testing.T) {
f := NewFile()
// Test get sheet index with invalid sheet name
idx, err := f.GetSheetIndex("Sheet:1")
assert.Equal(t, -1, idx)
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestSetContentTypes(t *testing.T) {
f := NewFile()
// Test set content type with unsupported charset content types.
@ -482,8 +534,34 @@ func TestSetSheetBackgroundFromBytes(t *testing.T) {
assert.NoError(t, img.Close())
assert.NoError(t, f.SetSheetBackgroundFromBytes(imageTypes, imageTypes, content))
}
// Test set worksheet background with invalid sheet name
img, err := os.Open(filepath.Join("test", "images", "excel.png"))
assert.NoError(t, err)
content, err := io.ReadAll(img)
assert.NoError(t, err)
assert.EqualError(t, f.SetSheetBackgroundFromBytes("Sheet:1", ".png", content), ErrSheetNameInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetBackgroundFromBytes.xlsx")))
assert.NoError(t, f.Close())
assert.EqualError(t, f.SetSheetBackgroundFromBytes("Sheet1", ".svg", nil), ErrParameterInvalid.Error())
}
func TestCheckSheetName(t *testing.T) {
// Test valid sheet name
assert.NoError(t, checkSheetName("Sheet1"))
assert.NoError(t, checkSheetName("She'et1"))
// Test invalid sheet name, empty name
assert.EqualError(t, checkSheetName(""), ErrSheetNameBlank.Error())
// Test invalid sheet name, include :\/?*[]
assert.EqualError(t, checkSheetName("Sheet:"), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName(`Sheet\`), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName("Sheet/"), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName("Sheet?"), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName("Sheet*"), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName("Sheet["), ErrSheetNameInvalid.Error())
assert.EqualError(t, checkSheetName("Sheet]"), ErrSheetNameInvalid.Error())
// Test invalid sheet name, single quotes at the front or at the end
assert.EqualError(t, checkSheetName("'Sheet"), ErrSheetNameSingleQuote.Error())
assert.EqualError(t, checkSheetName("Sheet'"), ErrSheetNameSingleQuote.Error())
}

View File

@ -27,15 +27,20 @@ func TestSetPageMargins(t *testing.T) {
opts, err := f.GetPageMargins("Sheet1")
assert.NoError(t, err)
assert.Equal(t, expected, opts)
// Test set page margins on not exists worksheet.
// Test set page margins on not exists worksheet
assert.EqualError(t, f.SetPageMargins("SheetN", nil), "sheet SheetN does not exist")
// Test set page margins with invalid sheet name
assert.EqualError(t, f.SetPageMargins("Sheet:1", nil), ErrSheetNameInvalid.Error())
}
func TestGetPageMargins(t *testing.T) {
f := NewFile()
// Test get page margins on not exists worksheet.
// Test get page margins on not exists worksheet
_, err := f.GetPageMargins("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get page margins with invalid sheet name
_, err = f.GetPageMargins("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestSetSheetProps(t *testing.T) {
@ -80,13 +85,18 @@ func TestSetSheetProps(t *testing.T) {
ws.(*xlsxWorksheet).SheetPr = nil
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{TabColorTint: float64Ptr(1)}))
// Test SetSheetProps on not exists worksheet.
// Test set worksheet properties on not exists worksheet
assert.EqualError(t, f.SetSheetProps("SheetN", nil), "sheet SheetN does not exist")
// Test set worksheet properties with invalid sheet name
assert.EqualError(t, f.SetSheetProps("Sheet:1", nil), ErrSheetNameInvalid.Error())
}
func TestGetSheetProps(t *testing.T) {
f := NewFile()
// Test GetSheetProps on not exists worksheet.
// Test get worksheet properties on not exists worksheet
_, err := f.GetSheetProps("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get worksheet properties with invalid sheet name
_, err = f.GetSheetProps("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}

View File

@ -214,7 +214,7 @@ func TestAddSparkline(t *testing.T) {
Negative: true,
}))
// Save spreadsheet by the given path.
// Save spreadsheet by the given path
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSparkline.xlsx")))
// Test error exceptions
@ -225,6 +225,14 @@ func TestAddSparkline(t *testing.T) {
assert.EqualError(t, f.AddSparkline("Sheet1", nil), ErrParameterRequired.Error())
// Test add sparkline with invalid sheet name
assert.EqualError(t, f.AddSparkline("Sheet:1", &SparklineOptions{
Location: []string{"F3"},
Range: []string{"Sheet2!A3:E3"},
Type: "win_loss",
Negative: true,
}), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.AddSparkline("Sheet1", &SparklineOptions{
Range: []string{"Sheet2!A3:E3"},
}), ErrSparklineLocation.Error())

View File

@ -102,6 +102,9 @@ type StreamWriter struct {
// excelize.Cell{Value: 1}},
// excelize.RowOpts{StyleID: styleID, Height: 20, Hidden: false});
func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
if err := checkSheetName(sheet); err != nil {
return nil, err
}
sheetID := f.getSheetID(sheet)
if sheetID == -1 {
return nil, newNoExistSheetError(sheet)
@ -219,8 +222,8 @@ func (sw *StreamWriter) AddTable(hCell, vCell, opts string) error {
sheetRelationshipsTableXML := "../tables/table" + strconv.Itoa(tableID) + ".xml"
tableXML := strings.ReplaceAll(sheetRelationshipsTableXML, "..", "xl")
// Add first table for given sheet.
sheetPath := sw.file.sheetMap[trimSheetName(sw.Sheet)]
// Add first table for given sheet
sheetPath := sw.file.sheetMap[sw.Sheet]
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
rID := sw.file.addRels(sheetRels, SourceRelationshipTable, sheetRelationshipsTableXML, "")
@ -661,7 +664,7 @@ func (sw *StreamWriter) Flush() error {
return err
}
sheetPath := sw.file.sheetMap[trimSheetName(sw.Sheet)]
sheetPath := sw.file.sheetMap[sw.Sheet]
sw.file.Sheet.Delete(sheetPath)
delete(sw.file.checked, sheetPath)
sw.file.Pkg.Delete(sheetPath)

View File

@ -257,6 +257,9 @@ func TestNewStreamWriter(t *testing.T) {
assert.NoError(t, err)
_, err = file.NewStreamWriter("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test new stream write with invalid sheet name
_, err = file.NewStreamWriter("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestStreamMarshalAttrs(t *testing.T) {

View File

@ -1101,11 +1101,25 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
return &fs, err
}
// NewStyle provides a function to create the style for cells by given
// structure pointer or JSON. This function is concurrency safe. Note that the
// color field uses RGB color code.
// NewStyle provides a function to create the style for cells by given structure
// pointer or JSON. This function is concurrency safe. Note that
// the 'Font.Color' field uses an RGB color represented in 'RRGGBB' hexadecimal
// notation.
//
// The following shows the border styles sorted by excelize index number:
// The following table shows the border types used in 'Border.Type' supported by
// excelize:
//
// Type | Description
// --------------+------------------
// left | Left border
// top | Top border
// right | Right border
// bottom | Bottom border
// diagonalDown | Diagonal down border
// diagonalUp | Diagonal up border
//
// The following table shows the border styles used in 'Border.Style' supported
// by excelize index number:
//
// Index | Name | Weight | Style
// -------+---------------+--------+-------------
@ -1124,7 +1138,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// 12 | Dash Dot Dot | 2 | - . . - . .
// 13 | SlantDash Dot | 2 | / - . / - .
//
// The following shows the borders in the order shown in the Excel dialog:
// The following table shows the border styles used in 'Border.Style' in the
// order shown in the Excel dialog:
//
// Index | Style | Index | Style
// -------+-------------+-------+-------------
@ -1136,7 +1151,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// 3 | - - - - - - | 5 | -----------
// 1 | ----------- | 6 | ===========
//
// The following shows the shading styles sorted by excelize index number:
// The following table shows the shading styles used in 'Fill.Shading' supported
// by excelize index number:
//
// Index | Style | Index | Style
// -------+-----------------+-------+-----------------
@ -1144,7 +1160,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// 1 | Vertical | 4 | From corner
// 2 | Diagonal Up | 5 | From center
//
// The following shows the patterns styles sorted by excelize index number:
// The following table shows the pattern styles used in 'Fill.Pattern' supported
// by excelize index number:
//
// Index | Style | Index | Style
// -------+-----------------+-------+-----------------
@ -1159,7 +1176,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// 8 | darkUp | 18 | gray0625
// 9 | darkGrid | |
//
// The following the type of horizontal alignment in cells:
// The following table shows the type of cells' horizontal alignment used
// in 'Alignment.Horizontal':
//
// Style
// ------------------
@ -1171,7 +1189,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// centerContinuous
// distributed
//
// The following the type of vertical alignment in cells:
// The following table shows the type of cells' vertical alignment used in
// 'Alignment.Vertical':
//
// Style
// ------------------
@ -1180,7 +1199,8 @@ func parseFormatStyleSet(style interface{}) (*Style, error) {
// justify
// distributed
//
// The following the type of font underline style:
// The following table shows the type of font underline style used in
// 'Font.Underline':
//
// Style
// ------------------

View File

@ -201,6 +201,9 @@ func TestGetConditionalFormats(t *testing.T) {
f := NewFile()
_, err := f.GetConditionalFormats("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test get conditional formats with invalid sheet name
_, err = f.GetConditionalFormats("Sheet:1")
assert.EqualError(t, err, ErrSheetNameInvalid.Error())
}
func TestUnsetConditionalFormat(t *testing.T) {
@ -211,9 +214,11 @@ func TestUnsetConditionalFormat(t *testing.T) {
assert.NoError(t, err)
assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format)))
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
// Test unset conditional format on not exists worksheet.
// Test unset conditional format on not exists worksheet
assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN does not exist")
// Save spreadsheet by the given path.
// Test unset conditional format with invalid sheet name
assert.EqualError(t, f.UnsetConditionalFormat("Sheet:1", "A1:A10"), ErrSheetNameInvalid.Error())
// Save spreadsheet by the given path
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx")))
}
@ -240,7 +245,7 @@ func TestNewStyle(t *testing.T) {
_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
assert.EqualError(t, err, ErrFontSize.Error())
// Test create numeric custom style.
// Test create numeric custom style
numFmt := "####;####"
f.Styles.NumFmts = nil
styleID, err = f.NewStyle(&Style{
@ -256,7 +261,7 @@ func TestNewStyle(t *testing.T) {
nf := f.Styles.CellXfs.Xf[styleID]
assert.Equal(t, 164, *nf.NumFmtID)
// Test create currency custom style.
// Test create currency custom style
f.Styles.NumFmts = nil
styleID, err = f.NewStyle(&Style{
Lang: "ko-kr",
@ -273,7 +278,7 @@ func TestNewStyle(t *testing.T) {
nf = f.Styles.CellXfs.Xf[styleID]
assert.Equal(t, 32, *nf.NumFmtID)
// Test set build-in scientific number format.
// Test set build-in scientific number format
styleID, err = f.NewStyle(&Style{NumFmt: 11})
assert.NoError(t, err)
assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "B1", styleID))
@ -283,7 +288,7 @@ func TestNewStyle(t *testing.T) {
assert.Equal(t, [][]string{{"1.23E+00", "1.23E+00"}}, rows)
f = NewFile()
// Test currency number format.
// Test currency number format
customNumFmt := "[$$-409]#,##0.00"
style1, err := f.NewStyle(&Style{CustomNumFmt: &customNumFmt})
assert.NoError(t, err)
@ -309,7 +314,7 @@ func TestNewStyle(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 0, style5)
// Test create style with unsupported charset style sheet.
// Test create style with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
_, err = f.NewStyle(&Style{NumFmt: 165})
@ -318,7 +323,7 @@ func TestNewStyle(t *testing.T) {
func TestNewConditionalStyle(t *testing.T) {
f := NewFile()
// Test create conditional style with unsupported charset style sheet.
// Test create conditional style with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
_, err := f.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
@ -330,7 +335,7 @@ func TestGetDefaultFont(t *testing.T) {
s, err := f.GetDefaultFont()
assert.NoError(t, err)
assert.Equal(t, s, "Calibri", "Default font should be Calibri")
// Test get default font with unsupported charset style sheet.
// Test get default font with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
_, err = f.GetDefaultFont()
@ -346,7 +351,7 @@ func TestSetDefaultFont(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, s, "Arial", "Default font should change to Arial")
assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
// Test set default font with unsupported charset style sheet.
// Test set default font with unsupported charset style sheet
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
assert.EqualError(t, f.SetDefaultFont("Arial"), "XML syntax error on line 1: invalid UTF-8")
@ -354,7 +359,7 @@ func TestSetDefaultFont(t *testing.T) {
func TestStylesReader(t *testing.T) {
f := NewFile()
// Test read styles with unsupported charset.
// Test read styles with unsupported charset
f.Styles = nil
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
styles, err := f.stylesReader()
@ -364,7 +369,7 @@ func TestStylesReader(t *testing.T) {
func TestThemeReader(t *testing.T) {
f := NewFile()
// Test read theme with unsupported charset.
// Test read theme with unsupported charset
f.Pkg.Store(defaultXMLPathTheme, MacintoshCyrillicCharset)
theme, err := f.themeReader()
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")

View File

@ -304,7 +304,10 @@ func (f *File) AutoFilter(sheet, hCell, vCell, opts string) error {
if err != nil {
return err
}
sheetID := f.GetSheetIndex(sheet)
sheetID, err := f.GetSheetIndex(sheet)
if err != nil {
return err
}
filterRange := fmt.Sprintf("'%s'!%s", sheet, ref)
d := xlsxDefinedName{
Name: filterDB,

View File

@ -10,36 +10,24 @@ import (
func TestAddTable(t *testing.T) {
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
assert.NoError(t, f.AddTable("Sheet1", "B26", "A21", `{}`))
assert.NoError(t, f.AddTable("Sheet2", "A2", "B5", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`))
assert.NoError(t, f.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`))
err = f.AddTable("Sheet1", "B26", "A21", `{}`)
if !assert.NoError(t, err) {
t.FailNow()
}
err = f.AddTable("Sheet2", "A2", "B5", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
if !assert.NoError(t, err) {
t.FailNow()
}
err = f.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`)
if !assert.NoError(t, err) {
t.FailNow()
}
// Test add table in not exist worksheet.
// Test add table in not exist worksheet
assert.EqualError(t, f.AddTable("SheetN", "B26", "A21", `{}`), "sheet SheetN does not exist")
// Test add table with illegal options.
// Test add table with illegal options
assert.EqualError(t, f.AddTable("Sheet1", "B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
// Test add table with illegal cell reference.
// Test add table with illegal cell reference
assert.EqualError(t, f.AddTable("Sheet1", "A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.AddTable("Sheet1", "A1", "B", `{}`), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddTable.xlsx")))
// Test addTable with illegal cell reference.
// Test add table with invalid sheet name
assert.EqualError(t, f.AddTable("Sheet:1", "B26", "A21", `{}`), ErrSheetNameInvalid.Error())
// Test addTable with illegal cell reference
f = NewFile()
assert.EqualError(t, f.addTable("sheet1", "", 0, 0, 0, 0, 0, nil), "invalid cell reference [0, 0]")
assert.EqualError(t, f.addTable("sheet1", "", 1, 1, 0, 0, 0, nil), "invalid cell reference [0, 0]")
@ -53,12 +41,8 @@ func TestSetTableHeader(t *testing.T) {
func TestAutoFilter(t *testing.T) {
outFile := filepath.Join("test", "TestAutoFilter%d.xlsx")
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
formats := []string{
``,
`{"column":"B","expression":"x != blanks"}`,
@ -69,7 +53,6 @@ func TestAutoFilter(t *testing.T) {
`{"column":"B","expression":"x == 1 or x == 2"}`,
`{"column":"B","expression":"x == 1 or x == 2*"}`,
}
for i, format := range formats {
t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) {
err = f.AutoFilter("Sheet1", "D4", "B1", format)
@ -78,10 +61,12 @@ func TestAutoFilter(t *testing.T) {
})
}
// Test add auto filter with illegal cell reference.
// Test add auto filter with invalid sheet name
assert.EqualError(t, f.AutoFilter("Sheet:1", "A1", "B1", ""), ErrSheetNameInvalid.Error())
// Test add auto filter with illegal cell reference
assert.EqualError(t, f.AutoFilter("Sheet1", "A", "B1", ""), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.AutoFilter("Sheet1", "A1", "B", ""), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
// Test add auto filter with unsupported charset workbook.
// Test add auto filter with unsupported charset workbook
f.WorkBook = nil
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
assert.EqualError(t, f.AutoFilter("Sheet1", "D4", "B1", formats[0]), "XML syntax error on line 1: invalid UTF-8")
@ -132,10 +117,10 @@ func TestAutoFilterError(t *testing.T) {
func TestParseFilterTokens(t *testing.T) {
f := NewFile()
// Test with unknown operator.
// Test with unknown operator
_, _, err := f.parseFilterTokens("", []string{"", "!"})
assert.EqualError(t, err, "unknown operator: !")
// Test invalid operator in context.
// Test invalid operator in context
_, _, err = f.parseFilterTokens("", []string{"", "<", "x != blanks"})
assert.EqualError(t, err, "the operator '<' in expression '' is not valid in relation to Blanks/NonBlanks'")
}

View File

@ -64,7 +64,7 @@ func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error) {
func (f *File) setWorkbook(name string, sheetID, rid int) {
wb, _ := f.workbookReader()
wb.Sheets.Sheet = append(wb.Sheets.Sheet, xlsxSheet{
Name: trimSheetName(name),
Name: name,
SheetID: sheetID,
ID: "rId" + strconv.Itoa(rid),
})

View File

@ -77,6 +77,6 @@ type Comment struct {
Author string `json:"author"`
AuthorID int `json:"author_id"`
Cell string `json:"cell"`
Text string `json:"string"`
Text string `json:"text"`
Runs []RichTextRun `json:"runs"`
}

View File

@ -19,58 +19,30 @@ import (
// Source relationship and namespace list, associated prefixes and schema in which it was
// introduced.
var (
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
NameSpaceDrawing2016SVG = xml.Attr{Name: xml.Name{Local: "asvg", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2016/SVG/main"}
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
NameSpaceDrawing2016SVG = xml.Attr{Name: xml.Name{Local: "asvg", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2016/SVG/main"}
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
)
// Source relationship and namespace.
const (
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships"
StrictSourceRelationshipOfficeDocument = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument"
StrictSourceRelationshipChart = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart"
StrictSourceRelationshipComments = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceDublinCoreMetadataInitiative = "http://purl.org/dc/dcmitype/"
ContentTypeAddinMacro = "application/vnd.ms-excel.addin.macroEnabled.main+xml"
ContentTypeDrawing = "application/vnd.openxmlformats-officedocument.drawing+xml"
ContentTypeDrawingML = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
ContentTypeSheetML = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
ContentTypeTemplate = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
ContentTypeAddinMacro = "application/vnd.ms-excel.addin.macroEnabled.main+xml"
ContentTypeMacro = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
ContentTypeTemplateMacro = "application/vnd.ms-excel.template.macroEnabled.main+xml"
ContentTypeSheetML = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
ContentTypeSpreadSheetMLChartsheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"
ContentTypeSpreadSheetMLComments = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
ContentTypeSpreadSheetMLPivotCacheDefinition = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
@ -78,44 +50,73 @@ const (
ContentTypeSpreadSheetMLSharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
ContentTypeSpreadSheetMLTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
ContentTypeSpreadSheetMLWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
ContentTypeTemplate = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
ContentTypeTemplateMacro = "application/vnd.ms-excel.template.macroEnabled.main+xml"
ContentTypeVBA = "application/vnd.ms-office.vbaProject"
ContentTypeVML = "application/vnd.openxmlformats-officedocument.vmlDrawing"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreMetadataInitiative = "http://purl.org/dc/dcmitype/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships"
StrictSourceRelationshipChart = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart"
StrictSourceRelationshipComments = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictSourceRelationshipOfficeDocument = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument"
// ExtURIConditionalFormattings is the extLst child element
// ([ISO/IEC29500-1:2016] section 18.2.10) of the worksheet element
// ([ISO/IEC29500-1:2016] section 18.3.1.99) is extended by the addition of
// new child ext elements ([ISO/IEC29500-1:2016] section 18.2.7)
ExtURIConditionalFormattings = "{78C0D931-6437-407D-A8EE-F0AAD7539E65}"
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
ExtURISparklineGroups = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
ExtURISlicerListX14 = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
ExtURISlicerCachesListX14 = "{BBE1A952-AA13-448e-AADC-164F8A28A991}"
ExtURISlicerListX15 = "{3A4CF648-6AED-40f4-86FF-DC5316D8AED3}"
ExtURIProtectedRanges = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
ExtURITimelineRefs = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
ExtURIMacExcelMX = "{64002731-A6B0-56B0-2670-7721B7C09600}"
ExtURIProtectedRanges = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
ExtURISlicerCachesListX14 = "{BBE1A952-AA13-448e-AADC-164F8A28A991}"
ExtURISlicerListX14 = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
ExtURISlicerListX15 = "{3A4CF648-6AED-40f4-86FF-DC5316D8AED3}"
ExtURISparklineGroups = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
ExtURISVG = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"
ExtURITimelineRefs = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
)
// Excel specifications and limits
const (
UnzipSizeLimit = 1000 << 24
StreamChunkSize = 1 << 24
MaxCellStyles = 64000
MaxColumns = 16384
MaxColumnWidth = 255
MaxFieldLength = 255
MaxFilePathLength = 207
MaxFontFamilyLength = 31
MaxFontSize = 409
MaxFilePathLength = 207
MaxFieldLength = 255
MaxColumnWidth = 255
MaxRowHeight = 409
MaxCellStyles = 64000
MinFontSize = 1
TotalRows = 1048576
MaxSheetNameLength = 31
MinColumns = 1
MaxColumns = 16384
TotalSheetHyperlinks = 65529
MinFontSize = 1
StreamChunkSize = 1 << 24
TotalCellChars = 32767
TotalRows = 1048576
TotalSheetHyperlinks = 65529
UnzipSizeLimit = 1000 << 24
// pivotTableVersion should be greater than 3. One or more of the
// PivotTables chosen are created in a version of Excel earlier than
// Excel 2007 or in compatibility mode. Slicer can only be used with