This closes #652, new SetColWidth API, support set column width in stream writing mode, and export error message
This commit is contained in:
parent
423bc26d1f
commit
be12cc27f1
|
@ -12,7 +12,6 @@
|
||||||
package excelize
|
package excelize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -219,7 +218,7 @@ func areaRangeToCoordinates(firstCell, lastCell string) ([]int, error) {
|
||||||
// correct C1:B3 to B1:C3.
|
// correct C1:B3 to B1:C3.
|
||||||
func sortCoordinates(coordinates []int) error {
|
func sortCoordinates(coordinates []int) error {
|
||||||
if len(coordinates) != 4 {
|
if len(coordinates) != 4 {
|
||||||
return errors.New("coordinates length must be 4")
|
return ErrCoordinates
|
||||||
}
|
}
|
||||||
if coordinates[2] < coordinates[0] {
|
if coordinates[2] < coordinates[0] {
|
||||||
coordinates[2], coordinates[0] = coordinates[0], coordinates[2]
|
coordinates[2], coordinates[0] = coordinates[0], coordinates[2]
|
||||||
|
@ -234,7 +233,7 @@ func sortCoordinates(coordinates []int) error {
|
||||||
// to area reference.
|
// to area reference.
|
||||||
func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
|
func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
|
||||||
if len(coordinates) != 4 {
|
if len(coordinates) != 4 {
|
||||||
return "", errors.New("coordinates length must be 4")
|
return "", ErrCoordinates
|
||||||
}
|
}
|
||||||
firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
|
firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -113,7 +113,7 @@ func TestAdjustCalcChain(t *testing.T) {
|
||||||
func TestCoordinatesToAreaRef(t *testing.T) {
|
func TestCoordinatesToAreaRef(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
_, err := f.coordinatesToAreaRef([]int{})
|
_, 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})
|
_, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
|
||||||
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
|
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
|
||||||
_, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
|
_, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
|
||||||
|
@ -124,5 +124,5 @@ func TestCoordinatesToAreaRef(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSortCoordinates(t *testing.T) {
|
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())
|
||||||
}
|
}
|
||||||
|
|
8
calc.go
8
calc.go
|
@ -647,7 +647,7 @@ func (f *File) evalInfixExp(sheet, cell string, tokens []efp.Token) (efp.Token,
|
||||||
optStack.Pop()
|
optStack.Pop()
|
||||||
}
|
}
|
||||||
if opdStack.Len() == 0 {
|
if opdStack.Len() == 0 {
|
||||||
return efp.Token{}, errors.New("formula not valid")
|
return efp.Token{}, ErrInvalidFormula
|
||||||
}
|
}
|
||||||
return opdStack.Peek().(efp.Token), err
|
return opdStack.Peek().(efp.Token), err
|
||||||
}
|
}
|
||||||
|
@ -849,7 +849,7 @@ func calcDiv(rOpd, lOpd string, opdStack *Stack) error {
|
||||||
func calculate(opdStack *Stack, opt efp.Token) error {
|
func calculate(opdStack *Stack, opt efp.Token) error {
|
||||||
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorPrefix {
|
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorPrefix {
|
||||||
if opdStack.Len() < 1 {
|
if opdStack.Len() < 1 {
|
||||||
return errors.New("formula not valid")
|
return ErrInvalidFormula
|
||||||
}
|
}
|
||||||
opd := opdStack.Pop().(efp.Token)
|
opd := opdStack.Pop().(efp.Token)
|
||||||
opdVal, err := strconv.ParseFloat(opd.TValue, 64)
|
opdVal, err := strconv.ParseFloat(opd.TValue, 64)
|
||||||
|
@ -874,7 +874,7 @@ func calculate(opdStack *Stack, opt efp.Token) error {
|
||||||
}
|
}
|
||||||
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
|
if opt.TValue == "-" && opt.TType == efp.TokenTypeOperatorInfix {
|
||||||
if opdStack.Len() < 2 {
|
if opdStack.Len() < 2 {
|
||||||
return errors.New("formula not valid")
|
return ErrInvalidFormula
|
||||||
}
|
}
|
||||||
rOpd := opdStack.Pop().(efp.Token)
|
rOpd := opdStack.Pop().(efp.Token)
|
||||||
lOpd := opdStack.Pop().(efp.Token)
|
lOpd := opdStack.Pop().(efp.Token)
|
||||||
|
@ -885,7 +885,7 @@ func calculate(opdStack *Stack, opt efp.Token) error {
|
||||||
fn, ok := tokenCalcFunc[opt.TValue]
|
fn, ok := tokenCalcFunc[opt.TValue]
|
||||||
if ok {
|
if ok {
|
||||||
if opdStack.Len() < 2 {
|
if opdStack.Len() < 2 {
|
||||||
return errors.New("formula not valid")
|
return ErrInvalidFormula
|
||||||
}
|
}
|
||||||
rOpd := opdStack.Pop().(efp.Token)
|
rOpd := opdStack.Pop().(efp.Token)
|
||||||
lOpd := opdStack.Pop().(efp.Token)
|
lOpd := opdStack.Pop().(efp.Token)
|
||||||
|
|
12
calc_test.go
12
calc_test.go
|
@ -1710,12 +1710,12 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=POISSON(0,0,\"\")": "strconv.ParseBool: parsing \"\": invalid syntax",
|
"=POISSON(0,0,\"\")": "strconv.ParseBool: parsing \"\": invalid syntax",
|
||||||
"=POISSON(0,-1,TRUE)": "#N/A",
|
"=POISSON(0,-1,TRUE)": "#N/A",
|
||||||
// SUM
|
// SUM
|
||||||
"=SUM((": "formula not valid",
|
"=SUM((": ErrInvalidFormula.Error(),
|
||||||
"=SUM(-)": "formula not valid",
|
"=SUM(-)": ErrInvalidFormula.Error(),
|
||||||
"=SUM(1+)": "formula not valid",
|
"=SUM(1+)": ErrInvalidFormula.Error(),
|
||||||
"=SUM(1-)": "formula not valid",
|
"=SUM(1-)": ErrInvalidFormula.Error(),
|
||||||
"=SUM(1*)": "formula not valid",
|
"=SUM(1*)": ErrInvalidFormula.Error(),
|
||||||
"=SUM(1/)": "formula not valid",
|
"=SUM(1/)": ErrInvalidFormula.Error(),
|
||||||
// SUMIF
|
// SUMIF
|
||||||
"=SUMIF()": "SUMIF requires at least 2 argument",
|
"=SUMIF()": "SUMIF requires at least 2 argument",
|
||||||
// SUMSQ
|
// SUMSQ
|
||||||
|
|
2
cell.go
2
cell.go
|
@ -475,7 +475,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ws.Hyperlinks.Hyperlink) > TotalSheetHyperlinks {
|
if len(ws.Hyperlinks.Hyperlink) > TotalSheetHyperlinks {
|
||||||
return errors.New("over maximum limit hyperlinks in a worksheet")
|
return ErrTotalSheetHyperlinks
|
||||||
}
|
}
|
||||||
|
|
||||||
switch linkType {
|
switch linkType {
|
||||||
|
|
2
chart.go
2
chart.go
|
@ -919,7 +919,7 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
|
||||||
func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
|
func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
|
||||||
// Check if the worksheet already exists
|
// Check if the worksheet already exists
|
||||||
if f.GetSheetIndex(sheet) != -1 {
|
if f.GetSheetIndex(sheet) != -1 {
|
||||||
return errors.New("the same name worksheet already exists")
|
return ErrExistsWorksheet
|
||||||
}
|
}
|
||||||
formatSet, comboCharts, err := f.getFormatChart(format, combo)
|
formatSet, comboCharts, err := f.getFormatChart(format, combo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -232,7 +232,7 @@ func TestAddChartSheet(t *testing.T) {
|
||||||
// Test cell value on chartsheet
|
// Test cell value on chartsheet
|
||||||
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is chart sheet")
|
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is chart sheet")
|
||||||
// Test add chartsheet on already existing name 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
|
// 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.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")
|
||||||
|
|
||||||
|
|
5
col.go
5
col.go
|
@ -14,7 +14,6 @@ package excelize
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -360,7 +359,7 @@ func (f *File) parseColRange(columns string) (start, end int, err error) {
|
||||||
//
|
//
|
||||||
func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
|
func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
|
||||||
if level > 7 || level < 1 {
|
if level > 7 || level < 1 {
|
||||||
return errors.New("invalid outline level")
|
return ErrOutlineLevel
|
||||||
}
|
}
|
||||||
colNum, err := ColumnNameToNumber(col)
|
colNum, err := ColumnNameToNumber(col)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -452,7 +451,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if width > MaxColumnWidth {
|
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 {
|
if min > max {
|
||||||
min, max = max, min
|
min, max = max, min
|
||||||
|
|
|
@ -246,12 +246,12 @@ func TestOutlineLevel(t *testing.T) {
|
||||||
assert.EqualError(t, err, "sheet Shee2 is not exist")
|
assert.EqualError(t, err, "sheet Shee2 is not exist")
|
||||||
|
|
||||||
assert.NoError(t, f.SetColWidth("Sheet2", "A", "D", 13))
|
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.SetColOutlineLevel("Sheet2", "B", 2))
|
||||||
assert.NoError(t, f.SetRowOutlineLevel("Sheet1", 2, 7))
|
assert.NoError(t, f.SetRowOutlineLevel("Sheet1", 2, 7))
|
||||||
assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "D", 8), "invalid outline level")
|
assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "D", 8), ErrOutlineLevel.Error())
|
||||||
assert.EqualError(t, f.SetRowOutlineLevel("Sheet1", 2, 8), "invalid outline level")
|
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 is not exist")
|
assert.EqualError(t, f.SetRowOutlineLevel("SheetN", 1, 4), "sheet SheetN is not exist")
|
||||||
// Test get row outline level on not exists worksheet.
|
// Test get row outline level on not exists worksheet.
|
||||||
|
|
3
date.go
3
date.go
|
@ -12,7 +12,6 @@
|
||||||
package excelize
|
package excelize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -35,7 +34,7 @@ func timeToExcelTime(t time.Time) (float64, error) {
|
||||||
// Because for example 1900-01-01 00:00:00 +0300 MSK converts to 1900-01-01 00:00:00 +0230 LMT
|
// 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.
|
// probably due to daylight saving.
|
||||||
if t.Location() != time.UTC {
|
if t.Location() != time.UTC {
|
||||||
return 0.0, errors.New("only UTC time expected")
|
return 0.0, ErrToExcelTime
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Before(excelMinTime1900) {
|
if t.Before(excelMinTime1900) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestTimeToExcelTime_Timezone(t *testing.T) {
|
||||||
for i, test := range trueExpectedDateList {
|
for i, test := range trueExpectedDateList {
|
||||||
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
||||||
_, err := timeToExcelTime(test.GoValue.In(location))
|
_, err := timeToExcelTime(test.GoValue.In(location))
|
||||||
assert.EqualError(t, err, "only UTC time expected")
|
assert.EqualError(t, err, ErrToExcelTime.Error())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
errors.go
46
errors.go
|
@ -11,7 +11,10 @@
|
||||||
|
|
||||||
package excelize
|
package excelize
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
func newInvalidColumnNameError(col string) error {
|
func newInvalidColumnNameError(col string) error {
|
||||||
return fmt.Errorf("invalid column name %q", col)
|
return fmt.Errorf("invalid column name %q", col)
|
||||||
|
@ -28,3 +31,44 @@ func newInvalidCellNameError(cell string) error {
|
||||||
func newInvalidExcelDateError(dateValue float64) error {
|
func newInvalidExcelDateError(dateValue float64) error {
|
||||||
return fmt.Errorf("invalid date value %f, negative values are not supported supported", dateValue)
|
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")
|
||||||
|
)
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -351,7 +350,7 @@ func (f *File) AddVBAProject(bin string) error {
|
||||||
return fmt.Errorf("stat %s: no such file or directory", bin)
|
return fmt.Errorf("stat %s: no such file or directory", bin)
|
||||||
}
|
}
|
||||||
if path.Ext(bin) != ".bin" {
|
if path.Ext(bin) != ".bin" {
|
||||||
return errors.New("unsupported VBA project extension")
|
return ErrAddVBAProject
|
||||||
}
|
}
|
||||||
f.setContentTypePartVBAProjectExtensions()
|
f.setContentTypePartVBAProjectExtensions()
|
||||||
wb := f.relsReader(f.getWorkbookRelsPath())
|
wb := f.relsReader(f.getWorkbookRelsPath())
|
||||||
|
|
|
@ -144,7 +144,7 @@ func TestOpenFile(t *testing.T) {
|
||||||
|
|
||||||
assert.NoError(t, f.SetCellValue("Sheet2", "G2", nil))
|
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()))
|
assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now().UTC()))
|
||||||
// 02:46:40
|
// 02:46:40
|
||||||
|
@ -166,7 +166,7 @@ func TestOpenFile(t *testing.T) {
|
||||||
assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
|
assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
|
||||||
}
|
}
|
||||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestOpenFile.xlsx")))
|
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) {
|
func TestSaveFile(t *testing.T) {
|
||||||
|
@ -344,7 +344,7 @@ func TestSetCellHyperLink(t *testing.T) {
|
||||||
_, err = f.workSheetReader("Sheet1")
|
_, err = f.workSheetReader("Sheet1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
f.Sheet["xl/worksheets/sheet1.xml"].Hyperlinks = &xlsxHyperlinks{Hyperlink: make([]xlsxHyperlink, 65530)}
|
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()
|
f = NewFile()
|
||||||
_, err = f.workSheetReader("Sheet1")
|
_, err = f.workSheetReader("Sheet1")
|
||||||
|
@ -449,7 +449,7 @@ func TestSetSheetBackgroundErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
|
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
|
// TestWriteArrayFormula tests the extended options of SetCellFormula by writing an array function
|
||||||
|
@ -1187,7 +1187,7 @@ func TestAddVBAProject(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
assert.NoError(t, f.SetSheetPrOptions("Sheet1", CodeName("Sheet1")))
|
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("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")))
|
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.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
|
||||||
|
|
3
file.go
3
file.go
|
@ -14,7 +14,6 @@ package excelize
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -66,7 +65,7 @@ func (f *File) Save() error {
|
||||||
// provided path.
|
// provided path.
|
||||||
func (f *File) SaveAs(name string, opt ...Options) error {
|
func (f *File) SaveAs(name string, opt ...Options) error {
|
||||||
if len(name) > MaxFileNameLength {
|
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)
|
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
4
lib.go
4
lib.go
|
@ -149,7 +149,7 @@ func ColumnNameToNumber(name string) (int, error) {
|
||||||
multi *= 26
|
multi *= 26
|
||||||
}
|
}
|
||||||
if col > TotalColumns {
|
if col > TotalColumns {
|
||||||
return -1, fmt.Errorf("column number exceeds maximum limit")
|
return -1, ErrColumnNumber
|
||||||
}
|
}
|
||||||
return col, nil
|
return col, nil
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ func ColumnNumberToName(num int) (string, error) {
|
||||||
return "", fmt.Errorf("incorrect column number %d", num)
|
return "", fmt.Errorf("incorrect column number %d", num)
|
||||||
}
|
}
|
||||||
if num > TotalColumns {
|
if num > TotalColumns {
|
||||||
return "", fmt.Errorf("column number exceeds maximum limit")
|
return "", ErrColumnNumber
|
||||||
}
|
}
|
||||||
var col string
|
var col string
|
||||||
for num > 0 {
|
for num > 0 {
|
||||||
|
|
|
@ -73,7 +73,7 @@ func TestColumnNameToNumber_Error(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err := ColumnNameToNumber("XFE")
|
_, err := ColumnNameToNumber("XFE")
|
||||||
assert.EqualError(t, err, "column number exceeds maximum limit")
|
assert.EqualError(t, err, ErrColumnNumber.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestColumnNumberToName_OK(t *testing.T) {
|
func TestColumnNumberToName_OK(t *testing.T) {
|
||||||
|
@ -98,7 +98,7 @@ func TestColumnNumberToName_Error(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = ColumnNumberToName(TotalColumns + 1)
|
_, 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) {
|
func TestSplitCellName_OK(t *testing.T) {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"io"
|
"io"
|
||||||
|
@ -93,7 +92,7 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error {
|
||||||
}
|
}
|
||||||
ext, ok := supportImageTypes[path.Ext(picture)]
|
ext, ok := supportImageTypes[path.Ext(picture)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unsupported image extension")
|
return ErrImgExt
|
||||||
}
|
}
|
||||||
file, _ := ioutil.ReadFile(picture)
|
file, _ := ioutil.ReadFile(picture)
|
||||||
_, name := filepath.Split(picture)
|
_, name := filepath.Split(picture)
|
||||||
|
@ -134,7 +133,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
|
||||||
var hyperlinkType string
|
var hyperlinkType string
|
||||||
ext, ok := supportImageTypes[extension]
|
ext, ok := supportImageTypes[extension]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unsupported image extension")
|
return ErrImgExt
|
||||||
}
|
}
|
||||||
formatSet, err := parseFormatPictureSet(format)
|
formatSet, err := parseFormatPictureSet(format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -82,10 +82,10 @@ func TestAddPictureErrors(t *testing.T) {
|
||||||
|
|
||||||
// Test add picture to worksheet with unsupported file type.
|
// Test add picture to worksheet with unsupported file type.
|
||||||
err = xlsx.AddPicture("Sheet1", "G21", filepath.Join("test", "Book1.xlsx"), "")
|
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))
|
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.
|
// Test add picture to worksheet with invalid file data.
|
||||||
err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1))
|
err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1))
|
||||||
|
|
5
rows.go
5
rows.go
|
@ -14,7 +14,6 @@ package excelize
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -245,7 +244,7 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
|
||||||
return newInvalidRowNumberError(row)
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
if height > MaxRowHeight {
|
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)
|
ws, err := f.workSheetReader(sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -436,7 +435,7 @@ func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error {
|
||||||
return newInvalidRowNumberError(row)
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
if level > 7 || level < 1 {
|
if level > 7 || level < 1 {
|
||||||
return errors.New("invalid outline level")
|
return ErrOutlineLevel
|
||||||
}
|
}
|
||||||
ws, err := f.workSheetReader(sheet)
|
ws, err := f.workSheetReader(sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -109,7 +109,7 @@ func TestRowHeight(t *testing.T) {
|
||||||
assert.Equal(t, 111.0, height)
|
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), "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.
|
// Test get row height that rows index over exists rows.
|
||||||
height, err = f.GetRowHeight(sheet1, 5)
|
height, err = f.GetRowHeight(sheet1, 5)
|
||||||
|
|
2
sheet.go
2
sheet.go
|
@ -482,7 +482,7 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
|
||||||
}
|
}
|
||||||
ext, ok := supportImageTypes[path.Ext(picture)]
|
ext, ok := supportImageTypes[path.Ext(picture)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unsupported image extension")
|
return ErrImgExt
|
||||||
}
|
}
|
||||||
file, _ := ioutil.ReadFile(picture)
|
file, _ := ioutil.ReadFile(picture)
|
||||||
name := f.addMedia(file, ext)
|
name := f.addMedia(file, ext)
|
||||||
|
|
40
stream.go
40
stream.go
|
@ -29,6 +29,8 @@ type StreamWriter struct {
|
||||||
File *File
|
File *File
|
||||||
Sheet string
|
Sheet string
|
||||||
SheetID int
|
SheetID int
|
||||||
|
sheetWritten bool
|
||||||
|
cols string
|
||||||
worksheet *xlsxWorksheet
|
worksheet *xlsxWorksheet
|
||||||
rawData bufferedWriter
|
rawData bufferedWriter
|
||||||
mergeCellsCount int
|
mergeCellsCount int
|
||||||
|
@ -104,8 +106,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
|
||||||
f.streams[sheetXML] = sw
|
f.streams[sheetXML] = sw
|
||||||
|
|
||||||
_, _ = sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
|
_, _ = sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
|
||||||
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
|
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 5)
|
||||||
_, _ = sw.rawData.WriteString(`<sheetData>`)
|
|
||||||
return sw, err
|
return sw, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +299,13 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
fmt.Fprintf(&sw.rawData, `<row r="%d">`, row)
|
||||||
for i, val := range values {
|
for i, val := range values {
|
||||||
axis, err := CoordinatesToCellName(col+i, row)
|
axis, err := CoordinatesToCellName(col+i, row)
|
||||||
|
@ -325,6 +332,33 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
|
||||||
return sw.rawData.Sync()
|
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
|
// 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
|
// the StreamWriter. Don't create a merged cell that overlaps with another
|
||||||
// existing merged cell.
|
// existing merged cell.
|
||||||
|
|
|
@ -57,7 +57,7 @@ func TestStreamWriter(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}, Cell{Formula: "SUM(A10,B10)"}}))
|
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.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++ {
|
for rowID := 10; rowID <= 51200; rowID++ {
|
||||||
row := make([]interface{}, 50)
|
row := make([]interface{}, 50)
|
||||||
|
@ -68,6 +68,9 @@ func TestStreamWriter(t *testing.T) {
|
||||||
assert.NoError(t, streamWriter.SetRow(cell, row))
|
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())
|
assert.NoError(t, streamWriter.Flush())
|
||||||
// Save spreadsheet by the given path.
|
// Save spreadsheet by the given path.
|
||||||
assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
|
assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
|
||||||
|
@ -112,6 +115,18 @@ func TestStreamWriter(t *testing.T) {
|
||||||
assert.Equal(t, "Data", cellValue)
|
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) {
|
func TestStreamTable(t *testing.T) {
|
||||||
file := NewFile()
|
file := NewFile()
|
||||||
streamWriter, err := file.NewStreamWriter("Sheet1")
|
streamWriter, err := file.NewStreamWriter("Sheet1")
|
||||||
|
|
Loading…
Reference in New Issue