瀏覽代碼

Improve code coverage unit tests

xuri 6 年之前
父節點
當前提交
ae2865d923
共有 16 個文件被更改,包括 438 次插入142 次删除
  1. 19 0
      calcchain_test.go
  2. 8 1
      cell_test.go
  3. 56 0
      comment_test.go
  4. 9 0
      datavalidation_test.go
  5. 13 0
      docProps_test.go
  6. 104 29
      excelize_test.go
  7. 26 13
      picture.go
  8. 24 18
      picture_test.go
  9. 58 20
      rows_test.go
  10. 19 9
      sheet.go
  11. 20 0
      sheet_test.go
  12. 55 48
      sparkline.go
  13. 9 0
      sparkline_test.go
  14. 16 2
      stream_test.go
  15. 1 1
      xmlWorkbook.go
  16. 1 1
      xmlWorksheet.go

+ 19 - 0
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")
+}

+ 8 - 1
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() {

+ 56 - 0
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)
+}

+ 9 - 0
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")
 }

+ 13 - 0
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")
 }

+ 104 - 29
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(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData/></worksheet>`)
+	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 {

+ 26 - 13
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
 }
 

+ 24 - 18
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")
 }

+ 58 - 20
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(`<worksheet><sheetData><row r="1"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)
+	_, 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(`<worksheet><sheetData><row r="A"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)))
+	_, err = rows.Columns()
+	assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
+
+	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="1"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)))
+	_, err = rows.Columns()
+	assert.NoError(t, err)
+
+	rows.curRow = 3
+	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="1"><c r="A" t="s"><v>1</v></c></row></sheetData></worksheet>`)))
+	_, 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) {

+ 19 - 9
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
 }
 

+ 20 - 0
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) {

+ 55 - 48
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("<extLst>" + ws.ExtLst.Ext + "</extLst>"))).
-			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, "<extLst>"), "</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("<extLst>" + ws.ExtLst.Ext + "</extLst>"))).
+		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), "<extLst>"), "</extLst>"),
+	}
+	return
+}

+ 9 - 0
sparkline_test.go

@@ -269,6 +269,15 @@ func TestAddSparkline(t *testing.T) {
 	}), "XML syntax error on line 6: element <sparklineGroup> closed by </sparklines>")
 }
 
+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{

+ 16 - 2
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) {

+ 1 - 1
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"`

+ 1 - 1
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"`