Breaking changes: changed the function signature for 4 exported functions

- Change
    `func (f *File) AddVBAProject(bin string) error`
    to
    `func (f *File) AddVBAProject(file []byte) error`
- Change
    `func (f *File) GetComments() (map[string][]Comment, error)`
    to
    `func (f *File) GetComments(sheet string) ([]Comment, error)`
- Change
    `func (f *File) AddTable(sheet, rangeRef string, opts *TableOptions) error`
    to
    `func (f *File) AddTable(sheet string, table *Table) error`
- Change
    `func (sw *StreamWriter) AddTable(rangeRef string, opts *TableOptions) error`
    to
    `func (sw *StreamWriter) AddTable(table *Table) error`
- Rename exported data type `TableOptions` to `Table`
- Simplify the assert statements in the unit tests
- Update documents for the functions
- Update unit tests
This commit is contained in:
xuri 2023-03-25 13:30:13 +08:00
parent 5878fbd282
commit 60b9d029a6
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
20 changed files with 164 additions and 147 deletions

View File

@ -11,7 +11,7 @@ import (
func TestAdjustMergeCells(t *testing.T) {
f := NewFile()
// Test adjustAutoFilter with illegal cell reference
assert.EqualError(t, f.adjustMergeCells(&xlsxWorksheet{
assert.Equal(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
{
@ -19,8 +19,8 @@ func TestAdjustMergeCells(t *testing.T) {
},
},
},
}, rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.adjustMergeCells(&xlsxWorksheet{
}, rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
assert.Equal(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
{
@ -28,7 +28,7 @@ func TestAdjustMergeCells(t *testing.T) {
},
},
},
}, rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
}, rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")))
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
@ -272,7 +272,7 @@ func TestAdjustMergeCells(t *testing.T) {
}
for _, c := range cases {
assert.NoError(t, f.adjustMergeCells(c.ws, c.dir, c.num, -1))
assert.Equal(t, 0, len(c.ws.MergeCells.Cells), c.label)
assert.Len(t, c.ws.MergeCells.Cells, 0, c.label)
}
f = NewFile()
@ -293,22 +293,23 @@ func TestAdjustAutoFilter(t *testing.T) {
},
}, rows, 1, -1))
// Test adjustAutoFilter with illegal cell reference
assert.EqualError(t, f.adjustAutoFilter(&xlsxWorksheet{
assert.Equal(t, f.adjustAutoFilter(&xlsxWorksheet{
AutoFilter: &xlsxAutoFilter{
Ref: "A:B1",
},
}, rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.adjustAutoFilter(&xlsxWorksheet{
}, rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
assert.Equal(t, f.adjustAutoFilter(&xlsxWorksheet{
AutoFilter: &xlsxAutoFilter{
Ref: "A1:B",
},
}, rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
}, rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")))
}
func TestAdjustTable(t *testing.T) {
f, sheetName := NewFile(), "Sheet1"
for idx, reference := range []string{"B2:C3", "E3:F5", "H5:H8", "J5:K9"} {
assert.NoError(t, f.AddTable(sheetName, reference, &TableOptions{
assert.NoError(t, f.AddTable(sheetName, &Table{
Range: reference,
Name: fmt.Sprintf("table%d", idx),
StyleName: "TableStyleMedium2",
ShowFirstColumn: true,
@ -323,7 +324,7 @@ func TestAdjustTable(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAdjustTable.xlsx")))
f = NewFile()
assert.NoError(t, f.AddTable(sheetName, "A1:D5", nil))
assert.NoError(t, f.AddTable(sheetName, &Table{Range: "A1:D5"}))
// Test adjust table with non-table part
f.Pkg.Delete("xl/tables/table1.xml")
assert.NoError(t, f.RemoveRow(sheetName, 1))
@ -346,8 +347,8 @@ func TestAdjustHelper(t *testing.T) {
AutoFilter: &xlsxAutoFilter{Ref: "A1:B"},
})
// Test adjustHelper with illegal cell reference
assert.EqualError(t, f.adjustHelper("Sheet1", rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.adjustHelper("Sheet2", rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
assert.Equal(t, f.adjustHelper("Sheet1", rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
assert.Equal(t, f.adjustHelper("Sheet2", rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")))
// Test adjustHelper on not exists worksheet
assert.EqualError(t, f.adjustHelper("SheetN", rows, 0, 0), "sheet SheetN does not exist")
}
@ -363,7 +364,7 @@ func TestAdjustCalcChain(t *testing.T) {
assert.NoError(t, f.InsertRows("Sheet1", 1, 1))
f.CalcChain.C[1].R = "invalid coordinates"
assert.EqualError(t, f.InsertCols("Sheet1", "A", 1), newCellNameToCoordinatesError("invalid coordinates", newInvalidCellNameError("invalid coordinates")).Error())
assert.Equal(t, f.InsertCols("Sheet1", "A", 1), newCellNameToCoordinatesError("invalid coordinates", newInvalidCellNameError("invalid coordinates")))
f.CalcChain = nil
assert.NoError(t, f.InsertCols("Sheet1", "A", 1))
}

View File

@ -694,8 +694,8 @@ type FormulaOpts struct {
// return
// }
// }
// if err := f.AddTable("Sheet1", "A1:C2", &excelize.TableOptions{
// Name: "Table1", StyleName: "TableStyleMedium2",
// if err := f.AddTable("Sheet1", &excelize.Table{
// Range: "A1:C2", Name: "Table1", StyleName: "TableStyleMedium2",
// }); err != nil {
// fmt.Println(err)
// return

View File

@ -571,7 +571,7 @@ func TestSetCellFormula(t *testing.T) {
for idx, row := range [][]interface{}{{"A", "B", "C"}, {1, 2}} {
assert.NoError(t, f.SetSheetRow("Sheet1", fmt.Sprintf("A%d", idx+1), &row))
}
assert.NoError(t, f.AddTable("Sheet1", "A1:C2", &TableOptions{Name: "Table1", StyleName: "TableStyleMedium2"}))
assert.NoError(t, f.AddTable("Sheet1", &Table{Range: "A1:C2", Name: "Table1", StyleName: "TableStyleMedium2"}))
formulaType = STCellFormulaTypeDataTable
assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=SUM(Table1[[A]:[B]])", FormulaOpts{Type: &formulaType}))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula6.xlsx")))

View File

@ -21,46 +21,43 @@ import (
"strings"
)
// GetComments retrieves all comments and returns a map of worksheet name to
// the worksheet comments.
func (f *File) GetComments() (map[string][]Comment, error) {
comments := map[string][]Comment{}
for n, path := range f.sheetMap {
target := f.getSheetComments(filepath.Base(path))
if target == "" {
continue
}
if !strings.HasPrefix(target, "/") {
target = "xl" + strings.TrimPrefix(target, "..")
}
cmts, err := f.commentsReader(strings.TrimPrefix(target, "/"))
if err != nil {
return comments, err
}
if cmts != nil {
var sheetComments []Comment
for _, comment := range cmts.CommentList.Comment {
sheetComment := Comment{}
if comment.AuthorID < len(cmts.Authors.Author) {
sheetComment.Author = cmts.Authors.Author[comment.AuthorID]
}
sheetComment.Cell = comment.Ref
sheetComment.AuthorID = comment.AuthorID
if comment.Text.T != nil {
sheetComment.Text += *comment.Text.T
}
for _, text := range comment.Text.R {
if text.T != nil {
run := RichTextRun{Text: text.T.Val}
if text.RPr != nil {
run.Font = newFont(text.RPr)
}
sheetComment.Runs = append(sheetComment.Runs, run)
}
}
sheetComments = append(sheetComments, sheetComment)
// GetComments retrieves all comments in a worksheet by given worksheet name.
func (f *File) GetComments(sheet string) ([]Comment, error) {
var comments []Comment
sheetXMLPath, ok := f.getSheetXMLPath(sheet)
if !ok {
return comments, newNoExistSheetError(sheet)
}
commentsXML := f.getSheetComments(filepath.Base(sheetXMLPath))
if !strings.HasPrefix(commentsXML, "/") {
commentsXML = "xl" + strings.TrimPrefix(commentsXML, "..")
}
commentsXML = strings.TrimPrefix(commentsXML, "/")
cmts, err := f.commentsReader(commentsXML)
if err != nil {
return comments, err
}
if cmts != nil {
for _, cmt := range cmts.CommentList.Comment {
comment := Comment{}
if cmt.AuthorID < len(cmts.Authors.Author) {
comment.Author = cmts.Authors.Author[cmt.AuthorID]
}
comments[n] = sheetComments
comment.Cell = cmt.Ref
comment.AuthorID = cmt.AuthorID
if cmt.Text.T != nil {
comment.Text += *cmt.Text.T
}
for _, text := range cmt.Text.R {
if text.T != nil {
run := RichTextRun{Text: text.T.Val}
if text.RPr != nil {
run.Font = newFont(text.RPr)
}
comment.Runs = append(comment.Runs, run)
}
}
comments = append(comments, comment)
}
}
return comments, nil

View File

@ -34,21 +34,25 @@ func TestAddComment(t *testing.T) {
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())
comments, err := f.GetComments()
comments, err := f.GetComments("Sheet1")
assert.NoError(t, err)
if assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddComments.xlsx"))) {
assert.Len(t, comments, 2)
}
assert.Len(t, comments, 2)
comments, err = f.GetComments("Sheet2")
assert.NoError(t, err)
assert.Len(t, comments, 1)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddComments.xlsx")))
f.Comments["xl/comments2.xml"] = nil
f.Pkg.Store("xl/comments2.xml", []byte(xml.Header+`<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><authors><author>Excelize: </author></authors><commentList><comment ref="B7" authorId="0"><text><t>Excelize: </t></text></comment></commentList></comments>`))
comments, err = f.GetComments()
comments, err = f.GetComments("Sheet1")
assert.NoError(t, err)
assert.EqualValues(t, 2, len(comments["Sheet1"]))
assert.EqualValues(t, 1, len(comments["Sheet2"]))
comments, err = NewFile().GetComments()
assert.Len(t, comments, 2)
comments, err = f.GetComments("Sheet2")
assert.NoError(t, err)
assert.EqualValues(t, len(comments), 0)
assert.Len(t, comments, 1)
comments, err = NewFile().GetComments("Sheet1")
assert.NoError(t, err)
assert.Len(t, comments, 0)
// 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())
@ -56,7 +60,7 @@ func TestAddComment(t *testing.T) {
// Test add comments with unsupported charset
f.Comments["xl/comments2.xml"] = nil
f.Pkg.Store("xl/comments2.xml", MacintoshCyrillicCharset)
_, err = f.GetComments()
_, err = f.GetComments("Sheet2")
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
// Test add comments with unsupported charset
@ -68,6 +72,11 @@ func TestAddComment(t *testing.T) {
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")
// Test get comments on not exists worksheet
comments, err = f.GetComments("SheetN")
assert.Len(t, comments, 0)
assert.EqualError(t, err, "sheet SheetN does not exist")
}
func TestDeleteComment(t *testing.T) {
@ -85,13 +94,13 @@ func TestDeleteComment(t *testing.T) {
assert.NoError(t, f.DeleteComment("Sheet2", "A40"))
comments, err := f.GetComments()
comments, err := f.GetComments("Sheet2")
assert.NoError(t, err)
assert.EqualValues(t, 5, len(comments["Sheet2"]))
assert.Len(t, comments, 5)
comments, err = NewFile().GetComments()
comments, err = NewFile().GetComments("Sheet1")
assert.NoError(t, err)
assert.EqualValues(t, len(comments), 0)
assert.Len(t, comments, 0)
// Test delete comment with invalid sheet name
assert.EqualError(t, f.DeleteComment("Sheet:1", "A1"), ErrSheetNameInvalid.Error())
@ -99,9 +108,9 @@ func TestDeleteComment(t *testing.T) {
assert.NoError(t, f.DeleteComment("Sheet2", "A41"))
assert.NoError(t, f.DeleteComment("Sheet2", "C41"))
assert.NoError(t, f.DeleteComment("Sheet2", "C42"))
comments, err = f.GetComments()
comments, err = f.GetComments("Sheet2")
assert.NoError(t, err)
assert.EqualValues(t, 0, len(comments["Sheet2"]))
assert.EqualValues(t, 0, len(comments))
// Test delete comment on not exists worksheet
assert.EqualError(t, f.DeleteComment("SheetN", "A1"), "sheet SheetN does not exist")
// Test delete comment with worksheet part

View File

@ -35,7 +35,7 @@ func TestDataValidation(t *testing.T) {
dataValidations, err := f.GetDataValidations("Sheet1")
assert.NoError(t, err)
assert.Equal(t, len(dataValidations), 1)
assert.Len(t, dataValidations, 1)
assert.NoError(t, f.SaveAs(resultFile))
@ -47,7 +47,7 @@ func TestDataValidation(t *testing.T) {
dataValidations, err = f.GetDataValidations("Sheet1")
assert.NoError(t, err)
assert.Equal(t, len(dataValidations), 2)
assert.Len(t, dataValidations, 2)
assert.NoError(t, f.SaveAs(resultFile))
@ -62,10 +62,10 @@ func TestDataValidation(t *testing.T) {
assert.NoError(t, f.AddDataValidation("Sheet2", dv))
dataValidations, err = f.GetDataValidations("Sheet1")
assert.NoError(t, err)
assert.Equal(t, len(dataValidations), 2)
assert.Len(t, dataValidations, 2)
dataValidations, err = f.GetDataValidations("Sheet2")
assert.NoError(t, err)
assert.Equal(t, len(dataValidations), 1)
assert.Len(t, dataValidations, 1)
dv = NewDataValidation(true)
dv.Sqref = "A5:B6"
@ -87,7 +87,7 @@ func TestDataValidation(t *testing.T) {
dataValidations, err = f.GetDataValidations("Sheet1")
assert.NoError(t, err)
assert.Equal(t, len(dataValidations), 3)
assert.Len(t,dataValidations, 3)
// Test get data validation on no exists worksheet
_, err = f.GetDataValidations("SheetN")

View File

@ -129,7 +129,7 @@ var (
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")
ErrAddVBAProject = errors.New("unsupported VBA project")
// ErrMaxRows defined the error message on receive a row number exceeds maximum limit.
ErrMaxRows = errors.New("row number exceeds maximum limit")
// ErrMaxRowHeight defined the error message on receive an invalid row

View File

@ -16,10 +16,8 @@ import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"os"
"path"
"path/filepath"
"strconv"
"strings"
@ -460,27 +458,33 @@ func (f *File) UpdateLinkedValue() error {
}
// AddVBAProject provides the method to add vbaProject.bin file which contains
// functions and/or macros. The file extension should be .xlsm. For example:
// functions and/or macros. The file extension should be XLSM or XLTM. For
// example:
//
// codeName := "Sheet1"
// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
// CodeName: &codeName,
// }); err != nil {
// fmt.Println(err)
// return
// }
// if err := f.AddVBAProject("vbaProject.bin"); err != nil {
// file, err := os.ReadFile("vbaProject.bin")
// if err != nil {
// fmt.Println(err)
// return
// }
// if err := f.AddVBAProject(file); err != nil {
// fmt.Println(err)
// return
// }
// if err := f.SaveAs("macros.xlsm"); err != nil {
// fmt.Println(err)
// return
// }
func (f *File) AddVBAProject(bin string) error {
func (f *File) AddVBAProject(file []byte) error {
var err error
// Check vbaProject.bin exists first.
if _, err = os.Stat(bin); os.IsNotExist(err) {
return fmt.Errorf("stat %s: no such file or directory", bin)
}
if path.Ext(bin) != ".bin" {
if !bytes.Contains(file, oleIdentifier) {
return ErrAddVBAProject
}
rels, err := f.relsReader(f.getWorkbookRelsPath())
@ -509,7 +513,6 @@ func (f *File) AddVBAProject(bin string) error {
Type: SourceRelationshipVBAProject,
})
}
file, _ := os.ReadFile(filepath.Clean(bin))
f.Pkg.Store("xl/vbaProject.bin", file)
return err
}

View File

@ -1319,8 +1319,8 @@ func TestProtectSheet(t *testing.T) {
}))
ws, err = f.workSheetReader(sheetName)
assert.NoError(t, err)
assert.Equal(t, 24, len(ws.SheetProtection.SaltValue))
assert.Equal(t, 88, len(ws.SheetProtection.HashValue))
assert.Len(t, ws.SheetProtection.SaltValue, 24)
assert.Len(t, ws.SheetProtection.HashValue, 88)
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())
@ -1387,8 +1387,8 @@ func TestProtectWorkbook(t *testing.T) {
wb, err := f.workbookReader()
assert.NoError(t, err)
assert.Equal(t, "SHA-512", wb.WorkbookProtection.WorkbookAlgorithmName)
assert.Equal(t, 24, len(wb.WorkbookProtection.WorkbookSaltValue))
assert.Equal(t, 88, len(wb.WorkbookProtection.WorkbookHashValue))
assert.Len(t, wb.WorkbookProtection.WorkbookSaltValue, 24)
assert.Len(t, wb.WorkbookProtection.WorkbookHashValue, 88)
assert.Equal(t, int(workbookProtectionSpinCount), wb.WorkbookProtection.WorkbookSpinCount)
// Test protect workbook with password exceeds the limit length
@ -1447,18 +1447,21 @@ func TestSetDefaultTimeStyle(t *testing.T) {
}
func TestAddVBAProject(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("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")), 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")))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
// 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")
f := NewFile()
file, err := os.ReadFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("Sheet1")}))
assert.EqualError(t, f.AddVBAProject(file), ErrAddVBAProject.Error())
file, err = os.ReadFile(filepath.Join("test", "vbaProject.bin"))
assert.NoError(t, err)
assert.NoError(t, f.AddVBAProject(file))
// Test add VBA project twice
assert.NoError(t, f.AddVBAProject(file))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
// Test add VBA with unsupported charset workbook relationships
f.Relationships.Delete(defaultXMLPathWorkbookRels)
f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddVBAProject(file), "XML syntax error on line 1: invalid UTF-8")
}
func TestContentTypesReader(t *testing.T) {

View File

@ -39,12 +39,8 @@ func NewFile() *File {
f.Pkg.Store(defaultXMLPathContentTypes, []byte(xml.Header+templateContentTypes))
f.SheetCount = 1
f.CalcChain, _ = f.calcChainReader()
f.Comments = make(map[string]*xlsxComments)
f.ContentTypes, _ = f.contentTypesReader()
f.Drawings = sync.Map{}
f.Styles, _ = f.stylesReader()
f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
f.VMLDrawing = make(map[string]*vmlDrawing)
f.WorkBook, _ = f.workbookReader()
f.Relationships = sync.Map{}
rels, _ := f.relsReader(defaultXMLPathWorkbookRels)

View File

@ -274,7 +274,7 @@ func TestBytesReplace(t *testing.T) {
}
func TestGetRootElement(t *testing.T) {
assert.Equal(t, 0, len(getRootElement(xml.NewDecoder(strings.NewReader("")))))
assert.Len(t, getRootElement(xml.NewDecoder(strings.NewReader(""))), 0)
}
func TestSetIgnorableNameSpace(t *testing.T) {

View File

@ -93,7 +93,7 @@ func TestMergeCellOverlap(t *testing.T) {
}
mc, err := f.GetMergeCells("Sheet1")
assert.NoError(t, err)
assert.Equal(t, 1, len(mc))
assert.Len(t, mc, 1)
assert.Equal(t, "A1", mc[0].GetStartAxis())
assert.Equal(t, "D3", mc[0].GetEndAxis())
assert.Equal(t, "", mc[0].GetCellValue())

View File

@ -56,7 +56,7 @@ func parseShapeOptions(opts *Shape) (*Shape, error) {
// &excelize.Shape{
// Type: "rect",
// Line: excelize.ShapeLine{Color: "4286F4", Width: &lineWidth},
// Fill: excelize.Fill{Color: []string{"8EB9FF"}},
// Fill: excelize.Fill{Color: []string{"8EB9FF"}, Pattern: 1},
// Paragraph: []excelize.RichTextRun{
// {
// Text: "Rectangle Shape",

View File

@ -273,7 +273,7 @@ func TestDefinedName(t *testing.T) {
Name: "Amount",
}))
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
assert.Exactly(t, 1, len(f.GetDefinedName()))
assert.Len(t, f.GetDefinedName(), 1)
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
// Test set defined name with unsupported charset workbook
f.WorkBook = nil
@ -376,7 +376,7 @@ func TestGetSheetMap(t *testing.T) {
for idx, name := range sheetMap {
assert.Equal(t, expectedMap[idx], name)
}
assert.Equal(t, len(sheetMap), 2)
assert.Len(t, sheetMap, 2)
assert.NoError(t, f.Close())
f = NewFile()

View File

@ -139,12 +139,13 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
// AddTable creates an Excel table for the StreamWriter using the given
// cell range and format set. For example, create a table of A1:D5:
//
// err := sw.AddTable("A1:D5", nil)
// err := sw.AddTable(&excelize.Table{Range: "A1:D5"})
//
// Create a table of F2:H6 with format set:
//
// disable := false
// err := sw.AddTable("F2:H6", &excelize.TableOptions{
// err := sw.AddTable(&excelize.Table{
// Range: "F2:H6",
// Name: "table",
// StyleName: "TableStyleMedium2",
// ShowFirstColumn: true,
@ -160,12 +161,12 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
// called after the rows are written but before Flush.
//
// See File.AddTable for details on the table format.
func (sw *StreamWriter) AddTable(rangeRef string, opts *TableOptions) error {
options, err := parseTableOptions(opts)
func (sw *StreamWriter) AddTable(table *Table) error {
options, err := parseTableOptions(table)
if err != nil {
return err
}
coordinates, err := rangeRefToCoordinates(rangeRef)
coordinates, err := rangeRefToCoordinates(options.Range)
if err != nil {
return err
}
@ -202,7 +203,7 @@ func (sw *StreamWriter) AddTable(rangeRef string, opts *TableOptions) error {
name = "Table" + strconv.Itoa(tableID)
}
table := xlsxTable{
tbl := xlsxTable{
XMLNS: NameSpaceSpreadSheet.Value,
ID: tableID,
Name: name,
@ -237,7 +238,7 @@ func (sw *StreamWriter) AddTable(rangeRef string, opts *TableOptions) error {
if err = sw.file.addContentTypePart(tableID, "table"); err != nil {
return err
}
b, _ := xml.Marshal(table)
b, _ := xml.Marshal(tbl)
sw.file.saveFileList(tableXML, b)
return err
}

View File

@ -196,7 +196,7 @@ func TestStreamTable(t *testing.T) {
streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err)
// Test add table without table header
assert.EqualError(t, streamWriter.AddTable("A1:C2", nil), "XML syntax error on line 2: unexpected EOF")
assert.EqualError(t, streamWriter.AddTable(&Table{Range: "A1:C2"}), "XML syntax error on line 2: unexpected EOF")
// Write some rows. We want enough rows to force a temp file (>16MB)
assert.NoError(t, streamWriter.SetRow("A1", []interface{}{"A", "B", "C"}))
row := []interface{}{1, 2, 3}
@ -205,7 +205,7 @@ func TestStreamTable(t *testing.T) {
}
// Write a table
assert.NoError(t, streamWriter.AddTable("A1:C2", nil))
assert.NoError(t, streamWriter.AddTable(&Table{Range: "A1:C2"}))
assert.NoError(t, streamWriter.Flush())
// Verify the table has names
@ -217,17 +217,17 @@ func TestStreamTable(t *testing.T) {
assert.Equal(t, "B", table.TableColumns.TableColumn[1].Name)
assert.Equal(t, "C", table.TableColumns.TableColumn[2].Name)
assert.NoError(t, streamWriter.AddTable("A1:C1", nil))
assert.NoError(t, streamWriter.AddTable(&Table{Range: "A1:C1"}))
// Test add table with illegal cell reference
assert.EqualError(t, streamWriter.AddTable("A:B1", nil), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, streamWriter.AddTable("A1:B", nil), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
assert.EqualError(t, streamWriter.AddTable(&Table{Range: "A:B1"}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, streamWriter.AddTable(&Table{Range: "A1:B"}), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
// Test add table with invalid table name
assert.EqualError(t, streamWriter.AddTable("A:B1", &TableOptions{Name: "1Table"}), newInvalidTableNameError("1Table").Error())
assert.EqualError(t, streamWriter.AddTable(&Table{Range: "A:B1", Name: "1Table"}), newInvalidTableNameError("1Table").Error())
// Test add table with unsupported charset content types
file.ContentTypes = nil
file.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, streamWriter.AddTable("A1:C2", nil), "XML syntax error on line 1: invalid UTF-8")
assert.EqualError(t, streamWriter.AddTable(&Table{Range: "A1:C2"}), "XML syntax error on line 1: invalid UTF-8")
}
func TestStreamMergeCells(t *testing.T) {

View File

@ -23,10 +23,10 @@ import (
// parseTableOptions provides a function to parse the format settings of the
// table with default value.
func parseTableOptions(opts *TableOptions) (*TableOptions, error) {
func parseTableOptions(opts *Table) (*Table, error) {
var err error
if opts == nil {
return &TableOptions{ShowRowStripes: boolPtr(true)}, err
return &Table{ShowRowStripes: boolPtr(true)}, err
}
if opts.ShowRowStripes == nil {
opts.ShowRowStripes = boolPtr(true)
@ -41,12 +41,13 @@ func parseTableOptions(opts *TableOptions) (*TableOptions, error) {
// name, range reference and format set. For example, create a table of A1:D5
// on Sheet1:
//
// err := f.AddTable("Sheet1", "A1:D5", nil)
// err := f.AddTable("Sheet1", &excelize.Table{Range: "A1:D5"})
//
// Create a table of F2:H6 on Sheet2 with format set:
//
// disable := false
// err := f.AddTable("Sheet2", "F2:H6", &excelize.TableOptions{
// err := f.AddTable("Sheet2", &excelize.Table{
// Range: "F2:H6",
// Name: "table",
// StyleName: "TableStyleMedium2",
// ShowFirstColumn: true,
@ -69,13 +70,13 @@ func parseTableOptions(opts *TableOptions) (*TableOptions, error) {
// TableStyleLight1 - TableStyleLight21
// TableStyleMedium1 - TableStyleMedium28
// TableStyleDark1 - TableStyleDark11
func (f *File) AddTable(sheet, rangeRef string, opts *TableOptions) error {
options, err := parseTableOptions(opts)
func (f *File) AddTable(sheet string, table *Table) error {
options, err := parseTableOptions(table)
if err != nil {
return err
}
// Coordinate conversion, convert C1:B3 to 2,0,1,2.
coordinates, err := rangeRefToCoordinates(rangeRef)
coordinates, err := rangeRefToCoordinates(options.Range)
if err != nil {
return err
}
@ -187,7 +188,7 @@ func checkTableName(name string) error {
// addTable provides a function to add table by given worksheet name,
// range reference and format set.
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, opts *TableOptions) error {
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, opts *Table) error {
// Correct the minimum number of rows, the table at least two lines.
if y1 == y2 {
y2++

View File

@ -12,8 +12,9 @@ import (
func TestAddTable(t *testing.T) {
f, err := prepareTestBook1()
assert.NoError(t, err)
assert.NoError(t, f.AddTable("Sheet1", "B26:A21", nil))
assert.NoError(t, f.AddTable("Sheet2", "A2:B5", &TableOptions{
assert.NoError(t, f.AddTable("Sheet1", &Table{Range: "B26:A21"}))
assert.NoError(t, f.AddTable("Sheet2", &Table{
Range: "A2:B5",
Name: "table",
StyleName: "TableStyleMedium2",
ShowColumnStripes: true,
@ -21,21 +22,24 @@ func TestAddTable(t *testing.T) {
ShowLastColumn: true,
ShowRowStripes: boolPtr(true),
}))
assert.NoError(t, f.AddTable("Sheet2", "D1:D11", &TableOptions{
assert.NoError(t, f.AddTable("Sheet2", &Table{
Range: "D1:D11",
ShowHeaderRow: boolPtr(false),
}))
assert.NoError(t, f.AddTable("Sheet2", "F1:F1", &TableOptions{StyleName: "TableStyleMedium8"}))
assert.NoError(t, f.AddTable("Sheet2", &Table{Range: "F1:F1", StyleName: "TableStyleMedium8"}))
// Test add table with invalid table options
assert.Equal(t, f.AddTable("Sheet1", nil), ErrParameterInvalid)
// Test add table in not exist worksheet
assert.EqualError(t, f.AddTable("SheetN", "B26:A21", nil), "sheet SheetN does not exist")
assert.EqualError(t, f.AddTable("SheetN", &Table{Range: "B26:A21"}), "sheet SheetN does not exist")
// Test add table with illegal cell reference
assert.EqualError(t, f.AddTable("Sheet1", "A:B1", nil), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
assert.EqualError(t, f.AddTable("Sheet1", "A1:B", nil), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
assert.Equal(t, f.AddTable("Sheet1", &Table{Range: "A:B1"}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
assert.Equal(t, f.AddTable("Sheet1", &Table{Range: "A1:B"}), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddTable.xlsx")))
// Test add table with invalid sheet name
assert.EqualError(t, f.AddTable("Sheet:1", "B26:A21", nil), ErrSheetNameInvalid.Error())
assert.EqualError(t, f.AddTable("Sheet:1", &Table{Range: "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]")
@ -54,8 +58,9 @@ func TestAddTable(t *testing.T) {
{name: "\u0f5f\u0fb3\u0f0b\u0f21", err: newInvalidTableNameError("\u0f5f\u0fb3\u0f0b\u0f21")},
{name: strings.Repeat("c", MaxFieldLength+1), err: ErrTableNameLength},
} {
assert.EqualError(t, f.AddTable("Sheet1", "A1:B2", &TableOptions{
Name: cases.name,
assert.EqualError(t, f.AddTable("Sheet1", &Table{
Range: "A1:B2",
Name: cases.name,
}), cases.err.Error())
}
}

BIN
test/vbaProject.bin Executable file → Normal file

Binary file not shown.

View File

@ -196,8 +196,9 @@ type xlsxTableStyleInfo struct {
ShowColumnStripes bool `xml:"showColumnStripes,attr"`
}
// TableOptions directly maps the format settings of the table.
type TableOptions struct {
// Table directly maps the format settings of the table.
type Table struct {
Range string
Name string
StyleName string
ShowColumnStripes bool