package excelize
import (
- "errors"
"strings"
)
// correct C1:B3 to B1:C3.
func sortCoordinates(coordinates []int) error {
if len(coordinates) != 4 {
- return errors.New("coordinates length must be 4")
+ return ErrCoordinates
}
if coordinates[2] < coordinates[0] {
coordinates[2], coordinates[0] = coordinates[0], coordinates[2]
// to area reference.
func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
if len(coordinates) != 4 {
- return "", errors.New("coordinates length must be 4")
+ return "", ErrCoordinates
}
firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
if err != nil {
func TestCoordinatesToAreaRef(t *testing.T) {
f := NewFile()
_, err := f.coordinatesToAreaRef([]int{})
- assert.EqualError(t, err, "coordinates length must be 4")
+ assert.EqualError(t, err, ErrCoordinates.Error())
_, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
_, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
}
func TestSortCoordinates(t *testing.T) {
- assert.EqualError(t, sortCoordinates(make([]int, 3)), "coordinates length must be 4")
+ assert.EqualError(t, sortCoordinates(make([]int, 3)), ErrCoordinates.Error())
}
optStack.Pop()
}
if opdStack.Len() == 0 {
- return efp.Token{}, errors.New("formula not valid")
+ return efp.Token{}, ErrInvalidFormula
}
return opdStack.Peek().(efp.Token), err
}
func calculate(opdStack *Stack, opt efp.Token) error {
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorPrefix {
if opdStack.Len() < 1 {
- return errors.New("formula not valid")
+ return ErrInvalidFormula
}
opd := opdStack.Pop().(efp.Token)
opdVal, err := strconv.ParseFloat(opd.TValue, 64)
}
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
if opdStack.Len() < 2 {
- return errors.New("formula not valid")
+ return ErrInvalidFormula
}
rOpd := opdStack.Pop().(efp.Token)
lOpd := opdStack.Pop().(efp.Token)
fn, ok := tokenCalcFunc[opt.TValue]
if ok {
if opdStack.Len() < 2 {
- return errors.New("formula not valid")
+ return ErrInvalidFormula
}
rOpd := opdStack.Pop().(efp.Token)
lOpd := opdStack.Pop().(efp.Token)
"=POISSON(0,0,\"\")": "strconv.ParseBool: parsing \"\": invalid syntax",
"=POISSON(0,-1,TRUE)": "#N/A",
// SUM
- "=SUM((": "formula not valid",
- "=SUM(-)": "formula not valid",
- "=SUM(1+)": "formula not valid",
- "=SUM(1-)": "formula not valid",
- "=SUM(1*)": "formula not valid",
- "=SUM(1/)": "formula not valid",
+ "=SUM((": ErrInvalidFormula.Error(),
+ "=SUM(-)": ErrInvalidFormula.Error(),
+ "=SUM(1+)": ErrInvalidFormula.Error(),
+ "=SUM(1-)": ErrInvalidFormula.Error(),
+ "=SUM(1*)": ErrInvalidFormula.Error(),
+ "=SUM(1/)": ErrInvalidFormula.Error(),
// SUMIF
"=SUMIF()": "SUMIF requires at least 2 argument",
// SUMSQ
}
if len(ws.Hyperlinks.Hyperlink) > TotalSheetHyperlinks {
- return errors.New("over maximum limit hyperlinks in a worksheet")
+ return ErrTotalSheetHyperlinks
}
switch linkType {
func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
// Check if the worksheet already exists
if f.GetSheetIndex(sheet) != -1 {
- return errors.New("the same name worksheet already exists")
+ return ErrExistsWorksheet
}
formatSet, comboCharts, err := f.getFormatChart(format, combo)
if err != nil {
// Test cell value on chartsheet
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is chart sheet")
// 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"}}`), "the same name worksheet already exists")
+ 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())
// 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")
import (
"bytes"
"encoding/xml"
- "errors"
"math"
"strconv"
"strings"
//
func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
if level > 7 || level < 1 {
- return errors.New("invalid outline level")
+ return ErrOutlineLevel
}
colNum, err := ColumnNameToNumber(col)
if err != nil {
return err
}
if width > MaxColumnWidth {
- return errors.New("the width of the column must be smaller than or equal to 255 characters")
+ return ErrColumnWidth
}
if min > max {
min, max = max, min
assert.EqualError(t, err, "sheet Shee2 is not exist")
assert.NoError(t, f.SetColWidth("Sheet2", "A", "D", 13))
- assert.EqualError(t, f.SetColWidth("Sheet2", "A", "D", MaxColumnWidth+1), "the width of the column must be smaller than or equal to 255 characters")
+ assert.EqualError(t, f.SetColWidth("Sheet2", "A", "D", MaxColumnWidth+1), ErrColumnWidth.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), "invalid outline level")
- assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 2, 8), "invalid outline level")
+ 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.
assert.EqualError(t, f.SetRowOutlineLevel("SheetN", 1, 4), "sheet SheetN is not exist")
// Test get row outline level on not exists worksheet.
package excelize
import (
- "errors"
"math"
"time"
)
// Because for example 1900-01-01 00:00:00 +0300 MSK converts to 1900-01-01 00:00:00 +0230 LMT
// probably due to daylight saving.
if t.Location() != time.UTC {
- return 0.0, errors.New("only UTC time expected")
+ return 0.0, ErrToExcelTime
}
if t.Before(excelMinTime1900) {
for i, test := range trueExpectedDateList {
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
_, err := timeToExcelTime(test.GoValue.In(location))
- assert.EqualError(t, err, "only UTC time expected")
+ assert.EqualError(t, err, ErrToExcelTime.Error())
})
}
}
package excelize
-import "fmt"
+import (
+ "errors"
+ "fmt"
+)
func newInvalidColumnNameError(col string) error {
return fmt.Errorf("invalid column name %q", col)
func newInvalidExcelDateError(dateValue float64) error {
return fmt.Errorf("invalid date value %f, negative values are not supported supported", dateValue)
}
+
+var (
+ // ErrStreamSetColWidth defined the error message on set column width in
+ // stream writing mode.
+ ErrStreamSetColWidth = errors.New("must call the SetColWidth function before the SetRow function")
+ // ErrColumnNumber defined the error message on receive an invalid column
+ // number.
+ ErrColumnNumber = errors.New("column number exceeds maximum limit")
+ // ErrColumnWidth defined the error message on receive an invalid column
+ // width.
+ ErrColumnWidth = errors.New("the width of the column must be smaller than or equal to 255 characters")
+ // ErrOutlineLevel defined the error message on receive an invalid outline
+ // level number.
+ ErrOutlineLevel = errors.New("invalid outline level")
+ // 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")
+ // ErrTotalSheetHyperlinks defined the error message on hyperlinks count
+ // overflow.
+ ErrTotalSheetHyperlinks = errors.New("over maximum limit hyperlinks in a worksheet")
+ // ErrInvalidFormula defined the error message on receive an invalid
+ // formula.
+ ErrInvalidFormula = errors.New("formula not valid")
+ // ErrAddVBAProject defined the error message on add the VBA project in
+ // the workbook.
+ ErrAddVBAProject = errors.New("unsupported VBA project extension")
+ // ErrToExcelTime defined the error message on receive a not UTC time.
+ ErrToExcelTime = errors.New("only UTC time expected")
+ // ErrMaxRowHeight defined the error message on receive an invalid row
+ // height.
+ ErrMaxRowHeight = errors.New("the height of the row must be smaller than or equal to 409 points")
+ // ErrImgExt defined the error message on receive an unsupported image
+ // extension.
+ ErrImgExt = errors.New("unsupported image extension")
+ // ErrMaxFileNameLength defined the error message on receive the file name
+ // length overflow.
+ ErrMaxFileNameLength = errors.New("file name length exceeds maximum limit")
+)
"archive/zip"
"bytes"
"encoding/xml"
- "errors"
"fmt"
"io"
"io/ioutil"
return fmt.Errorf("stat %s: no such file or directory", bin)
}
if path.Ext(bin) != ".bin" {
- return errors.New("unsupported VBA project extension")
+ return ErrAddVBAProject
}
f.setContentTypePartVBAProjectExtensions()
wb := f.relsReader(f.getWorkbookRelsPath())
assert.NoError(t, f.SetCellValue("Sheet2", "G2", nil))
- assert.EqualError(t, f.SetCellValue("Sheet2", "G4", time.Now()), "only UTC time expected")
+ assert.EqualError(t, f.SetCellValue("Sheet2", "G4", time.Now()), ErrToExcelTime.Error())
assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now().UTC()))
// 02:46:40
assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
}
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestOpenFile.xlsx")))
- assert.EqualError(t, f.SaveAs(filepath.Join("test", strings.Repeat("c", 199), ".xlsx")), "file name length exceeds maximum limit")
+ assert.EqualError(t, f.SaveAs(filepath.Join("test", strings.Repeat("c", 199), ".xlsx")), ErrMaxFileNameLength.Error())
}
func TestSaveFile(t *testing.T) {
_, err = f.workSheetReader("Sheet1")
assert.NoError(t, err)
f.Sheet["xl/worksheets/sheet1.xml"].Hyperlinks = &xlsxHyperlinks{Hyperlink: make([]xlsxHyperlink, 65530)}
- assert.EqualError(t, f.SetCellHyperLink("Sheet1", "A65531", "https://github.com/360EntSecGroup-Skylar/excelize", "External"), "over maximum limit hyperlinks in a worksheet")
+ assert.EqualError(t, f.SetCellHyperLink("Sheet1", "A65531", "https://github.com/360EntSecGroup-Skylar/excelize", "External"), ErrTotalSheetHyperlinks.Error())
f = NewFile()
_, err = f.workSheetReader("Sheet1")
}
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
- assert.EqualError(t, err, "unsupported image extension")
+ assert.EqualError(t, err, ErrImgExt.Error())
}
// TestWriteArrayFormula tests the extended options of SetCellFormula by writing an array function
f := NewFile()
assert.NoError(t, f.SetSheetPrOptions("Sheet1", CodeName("Sheet1")))
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")), "unsupported VBA project extension")
+ 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.
assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
import (
"archive/zip"
"bytes"
- "errors"
"fmt"
"io"
"os"
// provided path.
func (f *File) SaveAs(name string, opt ...Options) error {
if len(name) > MaxFileNameLength {
- return errors.New("file name length exceeds maximum limit")
+ return ErrMaxFileNameLength
}
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
if err != nil {
multi *= 26
}
if col > TotalColumns {
- return -1, fmt.Errorf("column number exceeds maximum limit")
+ return -1, ErrColumnNumber
}
return col, nil
}
return "", fmt.Errorf("incorrect column number %d", num)
}
if num > TotalColumns {
- return "", fmt.Errorf("column number exceeds maximum limit")
+ return "", ErrColumnNumber
}
var col string
for num > 0 {
}
}
_, err := ColumnNameToNumber("XFE")
- assert.EqualError(t, err, "column number exceeds maximum limit")
+ assert.EqualError(t, err, ErrColumnNumber.Error())
}
func TestColumnNumberToName_OK(t *testing.T) {
}
_, err = ColumnNumberToName(TotalColumns + 1)
- assert.EqualError(t, err, "column number exceeds maximum limit")
+ assert.EqualError(t, err, ErrColumnNumber.Error())
}
func TestSplitCellName_OK(t *testing.T) {
"bytes"
"encoding/json"
"encoding/xml"
- "errors"
"fmt"
"image"
"io"
}
ext, ok := supportImageTypes[path.Ext(picture)]
if !ok {
- return errors.New("unsupported image extension")
+ return ErrImgExt
}
file, _ := ioutil.ReadFile(picture)
_, name := filepath.Split(picture)
var hyperlinkType string
ext, ok := supportImageTypes[extension]
if !ok {
- return errors.New("unsupported image extension")
+ return ErrImgExt
}
formatSet, err := parseFormatPictureSet(format)
if err != nil {
// Test add picture to worksheet with unsupported file type.
err = xlsx.AddPicture("Sheet1", "G21", filepath.Join("test", "Book1.xlsx"), "")
- assert.EqualError(t, err, "unsupported image extension")
+ assert.EqualError(t, err, ErrImgExt.Error())
err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", "jpg", make([]byte, 1))
- assert.EqualError(t, err, "unsupported image extension")
+ assert.EqualError(t, err, ErrImgExt.Error())
// Test add picture to worksheet with invalid file data.
err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1))
import (
"bytes"
"encoding/xml"
- "errors"
"fmt"
"io"
"log"
return newInvalidRowNumberError(row)
}
if height > MaxRowHeight {
- return errors.New("the height of the row must be smaller than or equal to 409 points")
+ return ErrMaxRowHeight
}
ws, err := f.workSheetReader(sheet)
if err != nil {
return newInvalidRowNumberError(row)
}
if level > 7 || level < 1 {
- return errors.New("invalid outline level")
+ return ErrOutlineLevel
}
ws, err := f.workSheetReader(sheet)
if err != nil {
assert.Equal(t, 111.0, height)
// Test set row height overflow max row height limit.
- assert.EqualError(t, f.SetRowHeight(sheet1, 4, MaxRowHeight+1), "the height of the row must be smaller than or equal to 409 points")
+ assert.EqualError(t, f.SetRowHeight(sheet1, 4, MaxRowHeight+1), ErrMaxRowHeight.Error())
// Test get row height that rows index over exists rows.
height, err = f.GetRowHeight(sheet1, 5)
}
ext, ok := supportImageTypes[path.Ext(picture)]
if !ok {
- return errors.New("unsupported image extension")
+ return ErrImgExt
}
file, _ := ioutil.ReadFile(picture)
name := f.addMedia(file, ext)
File *File
Sheet string
SheetID int
+ sheetWritten bool
+ cols string
worksheet *xlsxWorksheet
rawData bufferedWriter
mergeCellsCount int
f.streams[sheetXML] = sw
_, _ = sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
- bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
- _, _ = sw.rawData.WriteString(`<sheetData>`)
+ bulkAppendFields(&sw.rawData, sw.worksheet, 2, 5)
return sw, err
}
if err != nil {
return err
}
-
+ if !sw.sheetWritten {
+ if len(sw.cols) > 0 {
+ sw.rawData.WriteString("<cols>" + sw.cols + "</cols>")
+ }
+ _, _ = sw.rawData.WriteString(`<sheetData>`)
+ sw.sheetWritten = true
+ }
fmt.Fprintf(&sw.rawData, `<row r="%d">`, row)
for i, val := range values {
axis, err := CoordinatesToCellName(col+i, row)
return sw.rawData.Sync()
}
+// SetColWidth provides a function to set the width of a single column or
+// multiple columns for the the StreamWriter. Note that you must call
+// the 'SetColWidth' function before the 'SetRow' function. For example set
+// the width column B:C as 20:
+//
+// err := streamWriter.SetColWidth(2, 3, 20)
+//
+func (sw *StreamWriter) SetColWidth(min, max int, width float64) error {
+ if sw.sheetWritten {
+ return ErrStreamSetColWidth
+ }
+ if min > TotalColumns || max > TotalColumns {
+ return ErrColumnNumber
+ }
+ if min < 1 || max < 1 {
+ return ErrColumnNumber
+ }
+ if width > MaxColumnWidth {
+ return ErrColumnWidth
+ }
+ if min > max {
+ min, max = max, min
+ }
+ sw.cols += fmt.Sprintf(`<col min="%d" max="%d" width="%f" customWidth="1"/>`, min, max, width)
+ return nil
+}
+
// MergeCell provides a function to merge cells by a given coordinate area for
// the StreamWriter. Don't create a merged cell that overlaps with another
// existing merged cell.
assert.NoError(t, err)
assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}, Cell{Formula: "SUM(A10,B10)"}}))
assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}}))
- assert.EqualError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}), "only UTC time expected")
+ assert.EqualError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}), ErrToExcelTime.Error())
for rowID := 10; rowID <= 51200; rowID++ {
row := make([]interface{}, 50)
assert.NoError(t, streamWriter.SetRow(cell, row))
}
+ // Test set cell column overflow.
+ assert.EqualError(t, streamWriter.SetRow("XFD1", []interface{}{"A", "B", "C"}), ErrColumnNumber.Error())
+
assert.NoError(t, streamWriter.Flush())
// Save spreadsheet by the given path.
assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
assert.Equal(t, "Data", cellValue)
}
+func TestStreamSetColWidth(t *testing.T) {
+ file := NewFile()
+ streamWriter, err := file.NewStreamWriter("Sheet1")
+ assert.NoError(t, err)
+ assert.NoError(t, streamWriter.SetColWidth(3, 2, 20))
+ assert.EqualError(t, streamWriter.SetColWidth(0, 3, 20), ErrColumnNumber.Error())
+ assert.EqualError(t, streamWriter.SetColWidth(TotalColumns+1, 3, 20), ErrColumnNumber.Error())
+ assert.EqualError(t, streamWriter.SetColWidth(1, 3, MaxColumnWidth+1), ErrColumnWidth.Error())
+ assert.NoError(t, streamWriter.SetRow("A1", []interface{}{"A", "B", "C"}))
+ assert.EqualError(t, streamWriter.SetColWidth(2, 3, 20), ErrStreamSetColWidth.Error())
+}
+
func TestStreamTable(t *testing.T) {
file := NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")