diff --git a/calcchain_test.go b/calcchain_test.go
new file mode 100644
index 0000000..842dde1
--- /dev/null
+++ b/calcchain_test.go
@@ -0,0 +1,19 @@
+package excelize
+
+import "testing"
+
+func TestCalcChainReader(t *testing.T) {
+ f := NewFile()
+ f.CalcChain = nil
+ f.XLSX["xl/calcChain.xml"] = MacintoshCyrillicCharset
+ f.calcChainReader()
+}
+
+func TestDeleteCalcChain(t *testing.T) {
+ f := NewFile()
+ f.CalcChain = &xlsxCalcChain{C: []xlsxCalcChainC{}}
+ f.ContentTypes.Overrides = append(f.ContentTypes.Overrides, xlsxOverride{
+ PartName: "/xl/calcChain.xml",
+ })
+ f.deleteCalcChain(1, "A1")
+}
diff --git a/cell_test.go b/cell_test.go
index b030622..7d3339f 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -95,8 +95,15 @@ func TestSetCellBool(t *testing.T) {
}
func TestGetCellFormula(t *testing.T) {
+ // Test get cell formula on not exist worksheet.
f := NewFile()
- f.GetCellFormula("Sheet", "A1")
+ _, err := f.GetCellFormula("SheetN", "A1")
+ assert.EqualError(t, err, "sheet SheetN is not exist")
+
+ // Test get cell formula on no formula cell.
+ f.SetCellValue("Sheet1", "A1", true)
+ _, err = f.GetCellFormula("Sheet1", "A1")
+ assert.NoError(t, err)
}
func ExampleFile_SetCellFloat() {
diff --git a/comment_test.go b/comment_test.go
new file mode 100644
index 0000000..dd07951
--- /dev/null
+++ b/comment_test.go
@@ -0,0 +1,56 @@
+// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+//
+// Package excelize providing a set of functions that allow you to write to
+// and read from XLSX files. Support reads and writes XLSX file generated by
+// Microsoft Excelâ„¢ 2007 and later. Support save file without losing original
+// charts of XLSX. This library needs Go version 1.10 or later.
+
+package excelize
+
+import (
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAddComments(t *testing.T) {
+ f, err := prepareTestBook1()
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+
+ s := strings.Repeat("c", 32768)
+ assert.NoError(t, f.AddComment("Sheet1", "A30", `{"author":"`+s+`","text":"`+s+`"}`))
+ assert.NoError(t, f.AddComment("Sheet2", "B7", `{"author":"Excelize: ","text":"This is a comment."}`))
+
+ // Test add comment on not exists worksheet.
+ assert.EqualError(t, f.AddComment("SheetN", "B7", `{"author":"Excelize: ","text":"This is a comment."}`), "sheet SheetN is not exist")
+
+ if assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddComments.xlsx"))) {
+ assert.Len(t, f.GetComments(), 2)
+ }
+}
+
+func TestDecodeVMLDrawingReader(t *testing.T) {
+ f := NewFile()
+ path := "xl/drawings/vmlDrawing1.xml"
+ f.XLSX[path] = MacintoshCyrillicCharset
+ f.decodeVMLDrawingReader(path)
+}
+
+func TestCommentsReader(t *testing.T) {
+ f := NewFile()
+ path := "xl/comments1.xml"
+ f.XLSX[path] = MacintoshCyrillicCharset
+ f.commentsReader(path)
+}
+
+func TestCountComments(t *testing.T) {
+ f := NewFile()
+ f.Comments["xl/comments1.xml"] = nil
+ assert.Equal(t, f.countComments(), 1)
+}
diff --git a/datavalidation_test.go b/datavalidation_test.go
index 211830d..763bad1 100644
--- a/datavalidation_test.go
+++ b/datavalidation_test.go
@@ -11,6 +11,7 @@ package excelize
import (
"path/filepath"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -85,4 +86,12 @@ func TestDataValidationError(t *testing.T) {
if !assert.NoError(t, f.SaveAs(resultFile)) {
t.FailNow()
}
+
+ // Test width invalid data validation formula.
+ dvRange.Formula1 = strings.Repeat("s", dataValidationFormulaStrLen+22)
+ assert.EqualError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan), "data validation must be 0-255 characters")
+
+ // Test add data validation on no exists worksheet.
+ f = NewFile()
+ assert.EqualError(t, f.AddDataValidation("SheetN", nil), "sheet SheetN is not exist")
}
diff --git a/docProps_test.go b/docProps_test.go
index df3122b..30c3149 100644
--- a/docProps_test.go
+++ b/docProps_test.go
@@ -16,6 +16,8 @@ import (
"github.com/stretchr/testify/assert"
)
+var MacintoshCyrillicCharset = []byte{0x8F, 0xF0, 0xE8, 0xE2, 0xE5, 0xF2, 0x20, 0xEC, 0xE8, 0xF0}
+
func TestSetDocProps(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
@@ -40,6 +42,11 @@ func TestSetDocProps(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetDocProps.xlsx")))
f.XLSX["docProps/core.xml"] = nil
assert.NoError(t, f.SetDocProps(&DocProperties{}))
+
+ // Test unsupport charset
+ f = NewFile()
+ f.XLSX["docProps/core.xml"] = MacintoshCyrillicCharset
+ assert.EqualError(t, f.SetDocProps(&DocProperties{}), "xml decode error: XML syntax error on line 1: invalid UTF-8")
}
func TestGetDocProps(t *testing.T) {
@@ -53,4 +60,10 @@ func TestGetDocProps(t *testing.T) {
f.XLSX["docProps/core.xml"] = nil
_, err = f.GetDocProps()
assert.NoError(t, err)
+
+ // Test unsupport charset
+ f = NewFile()
+ f.XLSX["docProps/core.xml"] = MacintoshCyrillicCharset
+ _, err = f.GetDocProps()
+ assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
}
diff --git a/excelize_test.go b/excelize_test.go
index 95d63fd..6929a4f 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -2,6 +2,8 @@ package excelize
import (
"bytes"
+ "compress/gzip"
+ "encoding/xml"
"fmt"
"image/color"
_ "image/gif"
@@ -184,6 +186,11 @@ func TestSaveAsWrongPath(t *testing.T) {
}
}
+func TestCharsetTranscoder(t *testing.T) {
+ f := NewFile()
+ f.CharsetTranscoder(*new(charsetTranscoderFn))
+}
+
func TestOpenReader(t *testing.T) {
_, err := OpenReader(strings.NewReader(""))
assert.EqualError(t, err, "zip: not a valid zip file")
@@ -195,6 +202,18 @@ func TestOpenReader(t *testing.T) {
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
}))
assert.EqualError(t, err, "not support encrypted file currently")
+
+ // Test unexpected EOF.
+ var b bytes.Buffer
+ w := gzip.NewWriter(&b)
+ defer w.Close()
+ w.Flush()
+
+ r, _ := gzip.NewReader(&b)
+ defer r.Close()
+
+ _, err = OpenReader(r)
+ assert.EqualError(t, err, "unexpected EOF")
}
func TestBrokenFile(t *testing.T) {
@@ -924,24 +943,6 @@ func TestAddShape(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape2.xlsx")))
}
-func TestAddComments(t *testing.T) {
- f, err := prepareTestBook1()
- if !assert.NoError(t, err) {
- t.FailNow()
- }
-
- s := strings.Repeat("c", 32768)
- assert.NoError(t, f.AddComment("Sheet1", "A30", `{"author":"`+s+`","text":"`+s+`"}`))
- assert.NoError(t, f.AddComment("Sheet2", "B7", `{"author":"Excelize: ","text":"This is a comment."}`))
-
- // Test add comment on not exists worksheet.
- assert.EqualError(t, f.AddComment("SheetN", "B7", `{"author":"Excelize: ","text":"This is a comment."}`), "sheet SheetN is not exist")
-
- if assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddComments.xlsx"))) {
- assert.Len(t, f.GetComments(), 2)
- }
-}
-
func TestGetSheetComments(t *testing.T) {
f := NewFile()
assert.Equal(t, "", f.getSheetComments(0))
@@ -1005,18 +1006,37 @@ func TestAutoFilterError(t *testing.T) {
}
}
-func TestSetPane(t *testing.T) {
+func TestSetActiveSheet(t *testing.T) {
+ f := NewFile()
+ f.WorkBook.BookViews = nil
+ f.SetActiveSheet(1)
+ f.WorkBook.BookViews = &xlsxBookViews{WorkBookView: []xlsxWorkBookView{}}
+ f.Sheet["xl/worksheets/sheet1.xml"].SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{}}
+ f.SetActiveSheet(1)
+}
+
+func TestSetSheetVisible(t *testing.T) {
+ f := NewFile()
+ f.WorkBook.Sheets.Sheet[0].Name = "SheetN"
+ assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "sheet SheetN is not exist")
+}
+
+func TestGetActiveSheetIndex(t *testing.T) {
+ f := NewFile()
+ f.WorkBook.BookViews = nil
+ assert.Equal(t, 1, f.GetActiveSheetIndex())
+}
+
+func TestRelsWriter(t *testing.T) {
+ f := NewFile()
+ f.Relationships["xl/worksheets/sheet/rels/sheet1.xml.rel"] = &xlsxRelationships{}
+ f.relsWriter()
+}
+
+func TestGetSheetView(t *testing.T) {
f := NewFile()
- f.SetPanes("Sheet1", `{"freeze":false,"split":false}`)
- f.NewSheet("Panes 2")
- f.SetPanes("Panes 2", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`)
- f.NewSheet("Panes 3")
- f.SetPanes("Panes 3", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`)
- f.NewSheet("Panes 4")
- f.SetPanes("Panes 4", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`)
- f.SetPanes("Panes 4", "")
-
- assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
+ _, err := f.getSheetView("SheetN", 0)
+ assert.EqualError(t, err, "sheet SheetN is not exist")
}
func TestConditionalFormat(t *testing.T) {
@@ -1207,6 +1227,61 @@ func TestAddVBAProject(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
}
+func TestContentTypesReader(t *testing.T) {
+ // Test unsupport charset.
+ f := NewFile()
+ f.ContentTypes = nil
+ f.XLSX["[Content_Types].xml"] = MacintoshCyrillicCharset
+ f.contentTypesReader()
+}
+
+func TestWorkbookReader(t *testing.T) {
+ // Test unsupport charset.
+ f := NewFile()
+ f.WorkBook = nil
+ f.XLSX["xl/workbook.xml"] = MacintoshCyrillicCharset
+ f.workbookReader()
+}
+
+func TestWorkSheetReader(t *testing.T) {
+ // Test unsupport charset.
+ f := NewFile()
+ delete(f.Sheet, "xl/worksheets/sheet1.xml")
+ f.XLSX["xl/worksheets/sheet1.xml"] = MacintoshCyrillicCharset
+ _, err := f.workSheetReader("Sheet1")
+ assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
+
+ // Test on no checked worksheet.
+ f = NewFile()
+ delete(f.Sheet, "xl/worksheets/sheet1.xml")
+ f.XLSX["xl/worksheets/sheet1.xml"] = []byte(``)
+ f.checked = nil
+ _, err = f.workSheetReader("Sheet1")
+ assert.NoError(t, err)
+}
+
+func TestRelsReader(t *testing.T) {
+ // Test unsupport charset.
+ f := NewFile()
+ rels := "xl/_rels/workbook.xml.rels"
+ f.Relationships[rels] = nil
+ f.XLSX[rels] = MacintoshCyrillicCharset
+ f.relsReader(rels)
+}
+
+func TestDeleteSheetFromWorkbookRels(t *testing.T) {
+ f := NewFile()
+ rels := "xl/_rels/workbook.xml.rels"
+ f.Relationships[rels] = nil
+ assert.Equal(t, f.deleteSheetFromWorkbookRels("rID"), "")
+}
+
+func TestAttrValToInt(t *testing.T) {
+ _, err := attrValToInt("r", []xml.Attr{
+ {Name: xml.Name{Local: "r"}, Value: "s"}})
+ assert.EqualError(t, err, `strconv.Atoi: parsing "s": invalid syntax`)
+}
+
func prepareTestBook1() (*File, error) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if err != nil {
diff --git a/picture.go b/picture.go
index 2420350..01df849 100644
--- a/picture.go
+++ b/picture.go
@@ -477,24 +477,14 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
var (
wsDr *xlsxWsDr
ok bool
- anchor *xdrCellAnchor
deWsDr *decodeWsDr
drawRel *xlsxRelationship
deTwoCellAnchor *decodeTwoCellAnchor
)
wsDr, _ = f.drawingParser(drawingXML)
- for _, anchor = range wsDr.TwoCellAnchor {
- if anchor.From != nil && anchor.Pic != nil {
- if anchor.From.Col == col && anchor.From.Row == row {
- drawRel = f.getDrawingRelationships(drawingRelationships,
- anchor.Pic.BlipFill.Blip.Embed)
- if _, ok = supportImageTypes[filepath.Ext(drawRel.Target)]; ok {
- ret, buf = filepath.Base(drawRel.Target), []byte(f.XLSX[strings.Replace(drawRel.Target, "..", "xl", -1)])
- return
- }
- }
- }
+ if ret, buf = f.getPictureFromWsDr(row, col, drawingRelationships, wsDr); len(buf) > 0 {
+ return
}
deWsDr = new(decodeWsDr)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(drawingXML)))).
@@ -514,13 +504,36 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
drawRel = f.getDrawingRelationships(drawingRelationships, deTwoCellAnchor.Pic.BlipFill.Blip.Embed)
if _, ok = supportImageTypes[filepath.Ext(drawRel.Target)]; ok {
- ret, buf = filepath.Base(drawRel.Target), []byte(f.XLSX[strings.Replace(drawRel.Target, "..", "xl", -1)])
+ ret, buf = filepath.Base(drawRel.Target), f.XLSX[strings.Replace(drawRel.Target, "..", "xl", -1)]
return
}
}
}
}
+ return
+}
+// getPictureFromWsDr provides a function to get picture base name and raw
+// content in worksheet drawing by given coordinates and drawing
+// relationships.
+func (f *File) getPictureFromWsDr(row, col int, drawingRelationships string, wsDr *xlsxWsDr) (ret string, buf []byte) {
+ var (
+ ok bool
+ anchor *xdrCellAnchor
+ drawRel *xlsxRelationship
+ )
+ for _, anchor = range wsDr.TwoCellAnchor {
+ if anchor.From != nil && anchor.Pic != nil {
+ if anchor.From.Col == col && anchor.From.Row == row {
+ drawRel = f.getDrawingRelationships(drawingRelationships,
+ anchor.Pic.BlipFill.Blip.Embed)
+ if _, ok = supportImageTypes[filepath.Ext(drawRel.Target)]; ok {
+ ret, buf = filepath.Base(drawRel.Target), f.XLSX[strings.Replace(drawRel.Target, "..", "xl", -1)]
+ return
+ }
+ }
+ }
+ }
return
}
diff --git a/picture_test.go b/picture_test.go
index 9a2edda..6af3904 100644
--- a/picture_test.go
+++ b/picture_test.go
@@ -92,12 +92,12 @@ func TestAddPictureErrors(t *testing.T) {
}
func TestGetPicture(t *testing.T) {
- xlsx, err := prepareTestBook1()
+ f, err := prepareTestBook1()
if !assert.NoError(t, err) {
t.FailNow()
}
- file, raw, err := xlsx.GetPicture("Sheet1", "F21")
+ file, raw, err := f.GetPicture("Sheet1", "F21")
assert.NoError(t, err)
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
@@ -106,37 +106,37 @@ func TestGetPicture(t *testing.T) {
}
// Try to get picture from a worksheet with illegal cell coordinates.
- _, _, err = xlsx.GetPicture("Sheet1", "A")
+ _, _, err = f.GetPicture("Sheet1", "A")
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
// Try to get picture from a worksheet that doesn't contain any images.
- file, raw, err = xlsx.GetPicture("Sheet3", "I9")
+ file, raw, err = f.GetPicture("Sheet3", "I9")
assert.EqualError(t, err, "sheet Sheet3 is not exist")
assert.Empty(t, file)
assert.Empty(t, raw)
// Try to get picture from a cell that doesn't contain an image.
- file, raw, err = xlsx.GetPicture("Sheet2", "A2")
+ file, raw, err = f.GetPicture("Sheet2", "A2")
assert.NoError(t, err)
assert.Empty(t, file)
assert.Empty(t, raw)
- xlsx.getDrawingRelationships("xl/worksheets/_rels/sheet1.xml.rels", "rId8")
- xlsx.getDrawingRelationships("", "")
- xlsx.getSheetRelationshipsTargetByID("", "")
- xlsx.deleteSheetRelationships("", "")
+ f.getDrawingRelationships("xl/worksheets/_rels/sheet1.xml.rels", "rId8")
+ f.getDrawingRelationships("", "")
+ f.getSheetRelationshipsTargetByID("", "")
+ f.deleteSheetRelationships("", "")
// Try to get picture from a local storage file.
- if !assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestGetPicture.xlsx"))) {
+ if !assert.NoError(t, f.SaveAs(filepath.Join("test", "TestGetPicture.xlsx"))) {
t.FailNow()
}
- xlsx, err = OpenFile(filepath.Join("test", "TestGetPicture.xlsx"))
+ f, err = OpenFile(filepath.Join("test", "TestGetPicture.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
- file, raw, err = xlsx.GetPicture("Sheet1", "F21")
+ file, raw, err = f.GetPicture("Sheet1", "F21")
assert.NoError(t, err)
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
@@ -145,7 +145,14 @@ func TestGetPicture(t *testing.T) {
}
// Try to get picture from a local storage file that doesn't contain an image.
- file, raw, err = xlsx.GetPicture("Sheet1", "F22")
+ file, raw, err = f.GetPicture("Sheet1", "F22")
+ assert.NoError(t, err)
+ assert.Empty(t, file)
+ assert.Empty(t, raw)
+
+ // Test get picture from none drawing worksheet.
+ f = NewFile()
+ file, raw, err = f.GetPicture("Sheet1", "F22")
assert.NoError(t, err)
assert.Empty(t, file)
assert.Empty(t, raw)
@@ -160,11 +167,9 @@ func TestAddDrawingPicture(t *testing.T) {
func TestAddPictureFromBytes(t *testing.T) {
f := NewFile()
imgFile, err := ioutil.ReadFile("logo.png")
- if err != nil {
- t.Error("Unable to load logo for test")
- }
- f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", 1), "", "logo", ".png", imgFile)
- f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", 50), "", "logo", ".png", imgFile)
+ assert.NoError(t, err, "Unable to load logo for test")
+ assert.NoError(t, f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", 1), "", "logo", ".png", imgFile))
+ assert.NoError(t, f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", 50), "", "logo", ".png", imgFile))
imageCount := 0
for fileName := range f.XLSX {
if strings.Contains(fileName, "media/image") {
@@ -172,4 +177,5 @@ func TestAddPictureFromBytes(t *testing.T) {
}
}
assert.Equal(t, 1, imageCount, "Duplicate image should only be stored once.")
+ assert.EqualError(t, f.AddPictureFromBytes("SheetN", fmt.Sprint("A", 1), "", "logo", ".png", imgFile), "sheet SheetN is not exist")
}
diff --git a/rows_test.go b/rows_test.go
index 6b50c75..6494242 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -1,6 +1,7 @@
package excelize
import (
+ "bytes"
"fmt"
"path/filepath"
"testing"
@@ -12,12 +13,12 @@ import (
func TestRows(t *testing.T) {
const sheet2 = "Sheet2"
- xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
+ f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
- rows, err := xlsx.Rows(sheet2)
+ rows, err := f.Rows(sheet2)
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -32,7 +33,7 @@ func TestRows(t *testing.T) {
t.FailNow()
}
- returnedRows, err := xlsx.GetRows(sheet2)
+ returnedRows, err := f.GetRows(sheet2)
assert.NoError(t, err)
for i := range returnedRows {
returnedRows[i] = trimSliceSpace(returnedRows[i])
@@ -40,6 +41,11 @@ func TestRows(t *testing.T) {
if !assert.Equal(t, collectedRows, returnedRows) {
t.FailNow()
}
+
+ f = NewFile()
+ f.XLSX["xl/worksheets/sheet1.xml"] = []byte(`1
B
`)
+ _, err = f.Rows("Sheet1")
+ assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
}
func TestRowsIterator(t *testing.T) {
@@ -126,6 +132,35 @@ func TestRowHeight(t *testing.T) {
convertColWidthToPixels(0)
}
+func TestColumns(t *testing.T) {
+ f := NewFile()
+ rows, err := f.Rows("Sheet1")
+ assert.NoError(t, err)
+ rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`1
B
`)))
+ _, err = rows.Columns()
+ assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
+
+ rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`1
B
`)))
+ _, err = rows.Columns()
+ assert.NoError(t, err)
+
+ rows.curRow = 3
+ rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`1
`)))
+ _, err = rows.Columns()
+ assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+
+ // Test token is nil
+ rows.decoder = f.xmlNewDecoder(bytes.NewReader(nil))
+ _, err = rows.Columns()
+ assert.NoError(t, err)
+}
+
+func TestSharedStringsReader(t *testing.T) {
+ f := NewFile()
+ f.XLSX["xl/sharedStrings.xml"] = MacintoshCyrillicCharset
+ f.sharedStringsReader()
+}
+
func TestRowVisibility(t *testing.T) {
f, err := prepareTestBook1()
if !assert.NoError(t, err) {
@@ -149,61 +184,64 @@ func TestRowVisibility(t *testing.T) {
}
func TestRemoveRow(t *testing.T) {
- xlsx := NewFile()
- sheet1 := xlsx.GetSheetName(1)
- r, err := xlsx.workSheetReader(sheet1)
+ f := NewFile()
+ sheet1 := f.GetSheetName(1)
+ r, err := f.workSheetReader(sheet1)
assert.NoError(t, err)
const (
colCount = 10
rowCount = 10
)
- fillCells(xlsx, sheet1, colCount, rowCount)
+ fillCells(f, sheet1, colCount, rowCount)
- xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
+ f.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
- assert.EqualError(t, xlsx.RemoveRow(sheet1, -1), "invalid row number -1")
+ assert.EqualError(t, f.RemoveRow(sheet1, -1), "invalid row number -1")
- assert.EqualError(t, xlsx.RemoveRow(sheet1, 0), "invalid row number 0")
+ assert.EqualError(t, f.RemoveRow(sheet1, 0), "invalid row number 0")
- assert.NoError(t, xlsx.RemoveRow(sheet1, 4))
+ assert.NoError(t, f.RemoveRow(sheet1, 4))
if !assert.Len(t, r.SheetData.Row, rowCount-1) {
t.FailNow()
}
- xlsx.MergeCell(sheet1, "B3", "B5")
+ f.MergeCell(sheet1, "B3", "B5")
- assert.NoError(t, xlsx.RemoveRow(sheet1, 2))
+ assert.NoError(t, f.RemoveRow(sheet1, 2))
if !assert.Len(t, r.SheetData.Row, rowCount-2) {
t.FailNow()
}
- assert.NoError(t, xlsx.RemoveRow(sheet1, 4))
+ assert.NoError(t, f.RemoveRow(sheet1, 4))
if !assert.Len(t, r.SheetData.Row, rowCount-3) {
t.FailNow()
}
- err = xlsx.AutoFilter(sheet1, "A2", "A2", `{"column":"A","expression":"x != blanks"}`)
+ err = f.AutoFilter(sheet1, "A2", "A2", `{"column":"A","expression":"x != blanks"}`)
if !assert.NoError(t, err) {
t.FailNow()
}
- assert.NoError(t, xlsx.RemoveRow(sheet1, 1))
+ assert.NoError(t, f.RemoveRow(sheet1, 1))
if !assert.Len(t, r.SheetData.Row, rowCount-4) {
t.FailNow()
}
- assert.NoError(t, xlsx.RemoveRow(sheet1, 2))
+ assert.NoError(t, f.RemoveRow(sheet1, 2))
if !assert.Len(t, r.SheetData.Row, rowCount-5) {
t.FailNow()
}
- assert.NoError(t, xlsx.RemoveRow(sheet1, 1))
+ assert.NoError(t, f.RemoveRow(sheet1, 1))
if !assert.Len(t, r.SheetData.Row, rowCount-6) {
t.FailNow()
}
- assert.NoError(t, xlsx.RemoveRow(sheet1, 10))
- assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRemoveRow.xlsx")))
+ assert.NoError(t, f.RemoveRow(sheet1, 10))
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemoveRow.xlsx")))
+
+ // Test remove row on not exist worksheet
+ assert.EqualError(t, f.RemoveRow("SheetN", 1), `sheet SheetN is not exist`)
}
func TestInsertRow(t *testing.T) {
diff --git a/sheet.go b/sheet.go
index 6ef7c6e..7412fce 100644
--- a/sheet.go
+++ b/sheet.go
@@ -505,7 +505,7 @@ func (f *File) copySheet(from, to int) error {
// SetSheetVisible provides a function to set worksheet visible by given worksheet
// name. A workbook must contain at least one visible worksheet. If the given
// worksheet has been activated, this setting will be invalidated. Sheet state
-// values as defined by http://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetstatevalues.aspx
+// values as defined by https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.sheetstatevalues
//
// visible
// hidden
@@ -738,7 +738,8 @@ func (f *File) searchSheet(name, value string, regSearch bool) (result []string,
d = f.sharedStringsReader()
decoder := f.xmlNewDecoder(bytes.NewReader(f.readXML(name)))
for {
- token, err := decoder.Token()
+ var token xml.Token
+ token, err = decoder.Token()
if err != nil || token == nil {
if err == io.EOF {
err = nil
@@ -749,13 +750,9 @@ func (f *File) searchSheet(name, value string, regSearch bool) (result []string,
case xml.StartElement:
inElement = startElement.Name.Local
if inElement == "row" {
- for _, attr := range startElement.Attr {
- if attr.Name.Local == "r" {
- row, err = strconv.Atoi(attr.Value)
- if err != nil {
- return result, err
- }
- }
+ row, err = attrValToInt("r", startElement.Attr)
+ if err != nil {
+ return
}
}
if inElement == "c" {
@@ -785,7 +782,20 @@ func (f *File) searchSheet(name, value string, regSearch bool) (result []string,
default:
}
}
+ return
+}
+// attrValToInt provides a function to convert the local names to an integer
+// by given XML attributes and specified names.
+func attrValToInt(name string, attrs []xml.Attr) (val int, err error) {
+ for _, attr := range attrs {
+ if attr.Name.Local == name {
+ val, err = strconv.Atoi(attr.Value)
+ if err != nil {
+ return
+ }
+ }
+ }
return
}
diff --git a/sheet_test.go b/sheet_test.go
index b9e4abf..aada60a 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -75,6 +75,20 @@ func TestNewSheet(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestNewSheet.xlsx")))
}
+func TestSetPane(t *testing.T) {
+ f := excelize.NewFile()
+ assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
+ f.NewSheet("Panes 2")
+ assert.NoError(t, f.SetPanes("Panes 2", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`))
+ f.NewSheet("Panes 3")
+ assert.NoError(t, f.SetPanes("Panes 3", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`))
+ f.NewSheet("Panes 4")
+ assert.NoError(t, f.SetPanes("Panes 4", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`))
+ assert.NoError(t, f.SetPanes("Panes 4", ""))
+ assert.EqualError(t, f.SetPanes("SheetN", ""), "sheet SheetN is not exist")
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
+}
+
func TestPageLayoutOption(t *testing.T) {
const sheet = "Sheet1"
@@ -156,6 +170,12 @@ func TestSearchSheet(t *testing.T) {
result, err = f.SearchSheet("Sheet1", "[0-9]", true)
assert.NoError(t, err)
assert.EqualValues(t, expected, result)
+
+ // Test search worksheet data after set cell value
+ f = excelize.NewFile()
+ assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
+ _, err = f.SearchSheet("Sheet1", "")
+ assert.NoError(t, err)
}
func TestSetPageLayout(t *testing.T) {
diff --git a/sparkline.go b/sparkline.go
index 9ad5087..47c8d5a 100644
--- a/sparkline.go
+++ b/sparkline.go
@@ -390,21 +390,14 @@ func (f *File) addSparklineGroupByStyle(ID int) *xlsxX14SparklineGroup {
//
func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
var (
- ws *xlsxWorksheet
- sparkType string
- sparkTypes map[string]string
- specifiedSparkTypes string
- ok bool
- group *xlsxX14SparklineGroup
- groups *xlsxX14SparklineGroups
- decodeExtLst *decodeWorksheetExt
- idx int
- ext *xlsxWorksheetExt
- decodeSparklineGroups *decodeX14SparklineGroups
- sparklineGroupBytes []byte
- sparklineGroupsBytes []byte
- extLst string
- extLstBytes, extBytes []byte
+ ws *xlsxWorksheet
+ sparkType string
+ sparkTypes map[string]string
+ specifiedSparkTypes string
+ ok bool
+ group *xlsxX14SparklineGroup
+ groups *xlsxX14SparklineGroups
+ sparklineGroupsBytes, extBytes []byte
)
// parameter validation
@@ -442,38 +435,9 @@ func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
}
f.addSparkline(opt, group)
if ws.ExtLst.Ext != "" { // append mode ext
- decodeExtLst = new(decodeWorksheetExt)
- if err = f.xmlNewDecoder(bytes.NewReader([]byte("" + ws.ExtLst.Ext + ""))).
- Decode(decodeExtLst); err != nil && err != io.EOF {
+ if err = f.appendSparkline(ws, group, groups); err != nil {
return
}
- for idx, ext = range decodeExtLst.Ext {
- if ext.URI == ExtURISparklineGroups {
- decodeSparklineGroups = new(decodeX14SparklineGroups)
- if err = f.xmlNewDecoder(bytes.NewReader([]byte(ext.Content))).
- Decode(decodeSparklineGroups); err != nil && err != io.EOF {
- return
- }
- if sparklineGroupBytes, err = xml.Marshal(group); err != nil {
- return
- }
- groups = &xlsxX14SparklineGroups{
- XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
- Content: decodeSparklineGroups.Content + string(sparklineGroupBytes),
- }
- if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
- return
- }
- decodeExtLst.Ext[idx].Content = string(sparklineGroupsBytes)
- }
- }
- if extLstBytes, err = xml.Marshal(decodeExtLst); err != nil {
- return
- }
- extLst = string(extLstBytes)
- ws.ExtLst = &xlsxExtLst{
- Ext: strings.TrimSuffix(strings.TrimPrefix(extLst, ""), ""),
- }
} else {
groups = &xlsxX14SparklineGroups{
XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
@@ -482,11 +446,10 @@ func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
return
}
- ext = &xlsxWorksheetExt{
+ if extBytes, err = xml.Marshal(&xlsxWorksheetExt{
URI: ExtURISparklineGroups,
Content: string(sparklineGroupsBytes),
- }
- if extBytes, err = xml.Marshal(ext); err != nil {
+ }); err != nil {
return
}
ws.ExtLst.Ext = string(extBytes)
@@ -534,3 +497,47 @@ func (f *File) addSparkline(opt *SparklineOption, group *xlsxX14SparklineGroup)
})
}
}
+
+// appendSparkline provides a function to append sparkline to sparkline
+// groups.
+func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup, groups *xlsxX14SparklineGroups) (err error) {
+ var (
+ idx int
+ decodeExtLst *decodeWorksheetExt
+ decodeSparklineGroups *decodeX14SparklineGroups
+ ext *xlsxWorksheetExt
+ sparklineGroupsBytes, sparklineGroupBytes, extLstBytes []byte
+ )
+ decodeExtLst = new(decodeWorksheetExt)
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte("" + ws.ExtLst.Ext + ""))).
+ Decode(decodeExtLst); err != nil && err != io.EOF {
+ return
+ }
+ for idx, ext = range decodeExtLst.Ext {
+ if ext.URI == ExtURISparklineGroups {
+ decodeSparklineGroups = new(decodeX14SparklineGroups)
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte(ext.Content))).
+ Decode(decodeSparklineGroups); err != nil && err != io.EOF {
+ return
+ }
+ if sparklineGroupBytes, err = xml.Marshal(group); err != nil {
+ return
+ }
+ groups = &xlsxX14SparklineGroups{
+ XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
+ Content: decodeSparklineGroups.Content + string(sparklineGroupBytes),
+ }
+ if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
+ return
+ }
+ decodeExtLst.Ext[idx].Content = string(sparklineGroupsBytes)
+ }
+ }
+ if extLstBytes, err = xml.Marshal(decodeExtLst); err != nil {
+ return
+ }
+ ws.ExtLst = &xlsxExtLst{
+ Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), ""), ""),
+ }
+ return
+}
diff --git a/sparkline_test.go b/sparkline_test.go
index d52929b..a5cb216 100644
--- a/sparkline_test.go
+++ b/sparkline_test.go
@@ -269,6 +269,15 @@ func TestAddSparkline(t *testing.T) {
}), "XML syntax error on line 6: element closed by ")
}
+func TestAppendSparkline(t *testing.T) {
+ // Test unsupport charset.
+ f := NewFile()
+ ws, err := f.workSheetReader("Sheet1")
+ assert.NoError(t, err)
+ ws.ExtLst = &xlsxExtLst{Ext: string(MacintoshCyrillicCharset)}
+ assert.EqualError(t, f.appendSparkline(ws, &xlsxX14SparklineGroup{}, &xlsxX14SparklineGroups{}), "XML syntax error on line 1: invalid UTF-8")
+}
+
func prepareSparklineDataset() *File {
f := NewFile()
sheet2 := [][]int{
diff --git a/stream_test.go b/stream_test.go
index 97c55a7..8371a4e 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -37,8 +37,7 @@ func TestStreamWriter(t *testing.T) {
assert.NoError(t, streamWriter.SetRow(cell, &row))
}
- err = streamWriter.Flush()
- assert.NoError(t, err)
+ assert.NoError(t, streamWriter.Flush())
// Save xlsx file by the given path.
assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
@@ -54,6 +53,21 @@ func TestFlush(t *testing.T) {
assert.NoError(t, err)
streamWriter.Sheet = "SheetN"
assert.EqualError(t, streamWriter.Flush(), "sheet SheetN is not exist")
+
+ // Test close temporary file error
+ file = NewFile()
+ streamWriter, err = file.NewStreamWriter("Sheet1")
+ assert.NoError(t, err)
+ for rowID := 10; rowID <= 51200; rowID++ {
+ row := make([]interface{}, 50)
+ for colID := 0; colID < 50; colID++ {
+ row[colID] = rand.Intn(640000)
+ }
+ cell, _ := CoordinatesToCellName(1, rowID)
+ assert.NoError(t, streamWriter.SetRow(cell, &row))
+ }
+ assert.NoError(t, streamWriter.tmpFile.Close())
+ assert.Error(t, streamWriter.Flush())
}
func TestSetRow(t *testing.T) {
diff --git a/xmlWorkbook.go b/xmlWorkbook.go
index e9ded6c..65606b0 100644
--- a/xmlWorkbook.go
+++ b/xmlWorkbook.go
@@ -203,7 +203,7 @@ type xlsxDefinedNames struct {
// http://schemas.openxmlformats.org/spreadsheetml/2006/main This element
// defines a defined name within this workbook. A defined name is descriptive
// text that is used to represents a cell, range of cells, formula, or constant
-// value. For a descriptions of the attributes see https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.definedname.aspx
+// value. For a descriptions of the attributes see https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.definedname
type xlsxDefinedName struct {
Comment string `xml:"comment,attr,omitempty"`
CustomMenu string `xml:"customMenu,attr,omitempty"`
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index 71ff4cc..8f39adf 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -182,7 +182,7 @@ type xlsxSheetViews struct {
// last sheetView definition is loaded, and the others are discarded. When
// multiple windows are viewing the same sheet, multiple sheetView elements
// (with corresponding workbookView entries) are saved.
-// See https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetview.aspx
+// See https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.sheetview
type xlsxSheetView struct {
WindowProtection bool `xml:"windowProtection,attr,omitempty"`
ShowFormulas bool `xml:"showFormulas,attr,omitempty"`