From 60b9d029a672634299fdab880423ba48a165507b Mon Sep 17 00:00:00 2001 From: xuri Date: Sat, 25 Mar 2023 13:30:13 +0800 Subject: [PATCH] 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 --- adjust_test.go | 29 ++++++++-------- cell.go | 4 +-- cell_test.go | 2 +- comment.go | 75 ++++++++++++++++++++--------------------- comment_test.go | 41 +++++++++++++--------- datavalidation_test.go | 10 +++--- errors.go | 2 +- excelize.go | 23 +++++++------ excelize_test.go | 35 ++++++++++--------- file.go | 4 --- lib_test.go | 2 +- merge_test.go | 2 +- shape.go | 2 +- sheet_test.go | 4 +-- stream.go | 15 +++++---- stream_test.go | 14 ++++---- table.go | 17 +++++----- table_test.go | 25 ++++++++------ test/vbaProject.bin | Bin 16896 -> 15360 bytes xmlTable.go | 5 +-- 20 files changed, 164 insertions(+), 147 deletions(-) mode change 100755 => 100644 test/vbaProject.bin diff --git a/adjust_test.go b/adjust_test.go index 7b992419..f55ef4b7 100644 --- a/adjust_test.go +++ b/adjust_test.go @@ -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)) } diff --git a/cell.go b/cell.go index 3fdbea96..5ebcefee 100644 --- a/cell.go +++ b/cell.go @@ -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 diff --git a/cell_test.go b/cell_test.go index 17ca800c..58a4bee6 100644 --- a/cell_test.go +++ b/cell_test.go @@ -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"))) diff --git a/comment.go b/comment.go index 40912d07..39f11762 100644 --- a/comment.go +++ b/comment.go @@ -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 diff --git a/comment_test.go b/comment_test.go index 7acce482..b6ea2aa0 100644 --- a/comment_test.go +++ b/comment_test.go @@ -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+`Excelize: Excelize: `)) - 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 diff --git a/datavalidation_test.go b/datavalidation_test.go index 4987f818..6b705918 100644 --- a/datavalidation_test.go +++ b/datavalidation_test.go @@ -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") diff --git a/errors.go b/errors.go index 1357d0f8..2e86470a 100644 --- a/errors.go +++ b/errors.go @@ -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 diff --git a/excelize.go b/excelize.go index a2b61a77..51ae99b9 100644 --- a/excelize.go +++ b/excelize.go @@ -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 } diff --git a/excelize_test.go b/excelize_test.go index e09c4b81..6ff1fc4e 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -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) { diff --git a/file.go b/file.go index 2896ee44..416c9343 100644 --- a/file.go +++ b/file.go @@ -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) diff --git a/lib_test.go b/lib_test.go index ab0ccc9a..013cf053 100644 --- a/lib_test.go +++ b/lib_test.go @@ -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) { diff --git a/merge_test.go b/merge_test.go index 9bef612c..6c9d2025 100644 --- a/merge_test.go +++ b/merge_test.go @@ -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()) diff --git a/shape.go b/shape.go index b0d449b2..cb8f49d5 100644 --- a/shape.go +++ b/shape.go @@ -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", diff --git a/sheet_test.go b/sheet_test.go index fae4e596..cfed8fdb 100644 --- a/sheet_test.go +++ b/sheet_test.go @@ -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() diff --git a/stream.go b/stream.go index 0577a7c9..55a2268d 100644 --- a/stream.go +++ b/stream.go @@ -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 } diff --git a/stream_test.go b/stream_test.go index da25bb9d..720f5985 100644 --- a/stream_test.go +++ b/stream_test.go @@ -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) { diff --git a/table.go b/table.go index 60cfb9ae..a914e15d 100644 --- a/table.go +++ b/table.go @@ -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++ diff --git a/table_test.go b/table_test.go index f55a5a0c..046a9338 100644 --- a/table_test.go +++ b/table_test.go @@ -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()) } } diff --git a/test/vbaProject.bin b/test/vbaProject.bin old mode 100755 new mode 100644 index fc15dca28e5ffd30e75f7464d4306110caaf3ff9..7e88db07c1f26ef2d4c082543627c13a90d546f6 GIT binary patch delta 5323 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 delta 5266 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 Dcn_v1 diff --git a/xmlTable.go b/xmlTable.go index 0779a8e0..789d4a28 100644 --- a/xmlTable.go +++ b/xmlTable.go @@ -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