Ver Fonte

Improve code coverage unit tests

xuri há 6 anos atrás
pai
commit
09485b3f9f
54 ficheiros alterados com 383 adições e 320 exclusões
  1. 2 2
      LICENSE
  2. 25 45
      README.md
  3. 25 46
      README_zh.md
  4. 3 1
      adjust.go
  5. 4 0
      adjust_test.go
  6. 1 1
      calcchain.go
  7. 1 1
      cell.go
  8. 4 14
      cellmerged.go
  9. 2 2
      chart.go
  10. 1 1
      col.go
  11. 1 1
      comment.go
  12. 1 1
      comment_test.go
  13. 1 1
      datavalidation.go
  14. 1 1
      datavalidation_test.go
  15. 1 1
      date.go
  16. 1 1
      docProps.go
  17. 1 1
      docProps_test.go
  18. 1 1
      errors.go
  19. 1 1
      excelize.go
  20. 0 113
      excelize_test.go
  21. 1 1
      file.go
  22. 1 1
      lib.go
  23. 1 1
      picture.go
  24. 1 1
      pivotTable.go
  25. 1 1
      rows.go
  26. 1 1
      shape.go
  27. 28 0
      shape_test.go
  28. 1 1
      sheet.go
  29. 1 1
      sheetpr.go
  30. 1 1
      sheetview.go
  31. 1 1
      sparkline.go
  32. 75 52
      stream.go
  33. 48 1
      stream_test.go
  34. 1 1
      styles.go
  35. 1 3
      styles_test.go
  36. 1 1
      table.go
  37. 125 0
      table_test.go
  38. 1 1
      templates.go
  39. 1 1
      vmlDrawing.go
  40. 1 1
      xmlApp.go
  41. 1 1
      xmlCalcChain.go
  42. 1 1
      xmlChart.go
  43. 1 1
      xmlComments.go
  44. 1 1
      xmlContentTypes.go
  45. 1 1
      xmlCore.go
  46. 1 1
      xmlDecodeDrawing.go
  47. 1 1
      xmlDrawing.go
  48. 1 1
      xmlPivotTable.go
  49. 1 1
      xmlSharedStrings.go
  50. 1 1
      xmlStyles.go
  51. 1 1
      xmlTable.go
  52. 1 1
      xmlTheme.go
  53. 1 1
      xmlWorkbook.go
  54. 1 1
      xmlWorksheet.go

+ 2 - 2
LICENSE

@@ -1,7 +1,7 @@
 BSD 3-Clause License
 
-Copyright (c) 2016-2019, 360 Enterprise Security Group, Endpoint Security, Inc.
-Copyright (c) 2011-2017, Geoffrey J. Teale (complying with the tealeg/xlsx license)
+Copyright (c) 2016-2020, 360 Enterprise Security Group, Endpoint Security, Inc.
+Copyright (c) 2011-2017, Geoffrey J. Teale
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without

+ 25 - 45
README.md

@@ -31,11 +31,7 @@ Here is a minimal example usage that will create XLSX file.
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
     f := excelize.NewFile()
@@ -47,9 +43,8 @@ func main() {
     // Set active sheet of the workbook.
     f.SetActiveSheet(index)
     // Save xlsx file by the given path.
-    err := f.SaveAs("./Book1.xlsx")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.SaveAs("Book1.xlsx"); err != nil {
+        println(err.Error())
     }
 }
 ```
@@ -61,32 +56,28 @@ The following constitutes the bare to read a XLSX document.
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
-    f, err := excelize.OpenFile("./Book1.xlsx")
+    f, err := excelize.OpenFile("Book1.xlsx")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
     // Get value from cell by given worksheet name and axis.
     cell, err := f.GetCellValue("Sheet1", "B2")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
-    fmt.Println(cell)
+    println(cell)
     // Get all the rows in the Sheet1.
     rows, err := f.GetRows("Sheet1")
     for _, row := range rows {
         for _, colCell := range row {
-            fmt.Print(colCell, "\t")
+            print(colCell, "\t")
         }
-        fmt.Println()
+        println()
     }
 }
 ```
@@ -100,11 +91,7 @@ With Excelize chart generation and management is as easy as a few lines of code.
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
     categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"}
@@ -116,15 +103,13 @@ func main() {
     for k, v := range values {
         f.SetCellValue("Sheet1", k, v)
     }
-    err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`); err != nil {
+        println(err.Error())
         return
     }
     // Save xlsx file by the given path.
-    err = f.SaveAs("./Book1.xlsx")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.SaveAs("Book1.xlsx"); err != nil {
+        println(err.Error())
     }
 }
 ```
@@ -135,7 +120,6 @@ func main() {
 package main
 
 import (
-    "fmt"
     _ "image/gif"
     _ "image/jpeg"
     _ "image/png"
@@ -144,30 +128,26 @@ import (
 )
 
 func main() {
-    f, err := excelize.OpenFile("./Book1.xlsx")
+    f, err := excelize.OpenFile("Book1.xlsx")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
     // Insert a picture.
-    err = f.AddPicture("Sheet1", "A2", "./image1.png", "")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "A2", "image.png", ""); err != nil {
+        println(err.Error())
     }
     // Insert a picture to worksheet with scaling.
-    err = f.AddPicture("Sheet1", "D2", "./image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "D2", "image.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`); err != nil {
+        println(err.Error())
     }
     // Insert a picture offset in the cell with printing support.
-    err = f.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil {
+        println(err.Error())
     }
     // Save the xlsx file with the origin path.
-    err = f.Save()
-    if err != nil {
-        fmt.Println(err)
+    if err = f.Save(); err != nil {
+        println(err.Error())
     }
 }
 ```

+ 25 - 46
README_zh.md

@@ -30,11 +30,7 @@ go get github.com/360EntSecGroup-Skylar/excelize
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
     f := excelize.NewFile()
@@ -46,9 +42,8 @@ func main() {
     // 设置工作簿的默认工作表
     f.SetActiveSheet(index)
     // 根据指定路径保存文件
-    err := f.SaveAs("./Book1.xlsx")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.SaveAs("Book1.xlsx"); err != nil {
+        println(err.Error())
     }
 }
 ```
@@ -60,32 +55,28 @@ func main() {
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
-    f, err := excelize.OpenFile("./Book1.xlsx")
+    f, err := excelize.OpenFile("Book1.xlsx")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
     // 获取工作表中指定单元格的值
     cell, err := f.GetCellValue("Sheet1", "B2")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
-    fmt.Println(cell)
+    println(cell)
     // 获取 Sheet1 上所有单元格
     rows, err := f.GetRows("Sheet1")
     for _, row := range rows {
         for _, colCell := range row {
-            fmt.Print(colCell, "\t")
+            print(colCell, "\t")
         }
-        fmt.Println()
+        println()
     }
 }
 ```
@@ -99,11 +90,7 @@ func main() {
 ```go
 package main
 
-import (
-    "fmt"
-
-    "github.com/360EntSecGroup-Skylar/excelize"
-)
+import "github.com/360EntSecGroup-Skylar/excelize"
 
 func main() {
     categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"}
@@ -115,18 +102,15 @@ func main() {
     for k, v := range values {
         f.SetCellValue("Sheet1", k, v)
     }
-    err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`); err != nil {
+        println(err.Error())
         return
     }
     // 根据指定路径保存文件
-    err = f.SaveAs("./Book1.xlsx")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.SaveAs("Book1.xlsx"); err != nil {
+        println(err.Error())
     }
 }
-
 ```
 
 ### 向 Excel 文档中插入图片
@@ -135,7 +119,6 @@ func main() {
 package main
 
 import (
-    "fmt"
     _ "image/gif"
     _ "image/jpeg"
     _ "image/png"
@@ -144,30 +127,26 @@ import (
 )
 
 func main() {
-    f, err := excelize.OpenFile("./Book1.xlsx")
+    f, err := excelize.OpenFile("Book1.xlsx")
     if err != nil {
-        fmt.Println(err)
+        println(err.Error())
         return
     }
     // 插入图片
-    err = f.AddPicture("Sheet1", "A2", "./image1.png", "")
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "A2", "image.png", ""); err != nil {
+        println(err.Error())
     }
     // 在工作表中插入图片,并设置图片的缩放比例
-    err = f.AddPicture("Sheet1", "D2", "./image2.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "D2", "image.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`); err != nil {
+        println(err.Error())
     }
     // 在工作表中插入图片,并设置图片的打印属性
-    err = f.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`)
-    if err != nil {
-        fmt.Println(err)
+    if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil {
+        println(err.Error())
     }
     // 保存文件
-    err = f.Save()
-    if err != nil {
-        fmt.Println(err)
+    if err = f.Save(); err != nil {
+        println(err.Error())
     }
 }
 ```

+ 3 - 1
adjust.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //
@@ -213,6 +213,8 @@ func areaRangeToCoordinates(firstCell, lastCell string) ([]int, error) {
 	return coordinates, err
 }
 
+// sortCoordinates provides a function to correct the coordinate area, such
+// correct C1:B3 to B1:C3.
 func sortCoordinates(coordinates []int) error {
 	if len(coordinates) != 4 {
 		return errors.New("coordinates length must be 4")

+ 4 - 0
adjust_test.go

@@ -114,3 +114,7 @@ func TestCoordinatesToAreaRef(t *testing.T) {
 	assert.NoError(t, err)
 	assert.EqualValues(t, ref, "A1:A1")
 }
+
+func TestSortCoordinates(t *testing.T) {
+	assert.EqualError(t, sortCoordinates(make([]int, 3)), "coordinates length must be 4")
+}

+ 1 - 1
calcchain.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
cell.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 4 - 14
cellmerged.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //
@@ -43,13 +43,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
 		return err
 	}
 	// Correct the coordinate area, such correct C1:B3 to B1:C3.
-	if rect1[2] < rect1[0] {
-		rect1[0], rect1[2] = rect1[2], rect1[0]
-	}
-
-	if rect1[3] < rect1[1] {
-		rect1[1], rect1[3] = rect1[3], rect1[1]
-	}
+	_ = sortCoordinates(rect1)
 
 	hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
 	vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
@@ -123,12 +117,8 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
 		return err
 	}
 
-	if rect1[2] < rect1[0] {
-		rect1[0], rect1[2] = rect1[2], rect1[0]
-	}
-	if rect1[3] < rect1[1] {
-		rect1[1], rect1[3] = rect1[3], rect1[1]
-	}
+	// Correct the coordinate area, such correct C1:B3 to B1:C3.
+	_ = sortCoordinates(rect1)
 
 	// return nil since no MergeCells in the sheet
 	if xlsx.MergeCells == nil {

+ 2 - 2
chart.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //
@@ -657,6 +657,7 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
 //
 //    major_grid_lines
 //    minor_grid_lines
+//    tick_label_skip
 //    reverse_order
 //    maximum
 //    minimum
@@ -666,7 +667,6 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
 //    major_grid_lines
 //    minor_grid_lines
 //    major_unit
-//    tick_label_skip
 //    reverse_order
 //    maximum
 //    minimum

+ 1 - 1
col.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
comment.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
comment_test.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
datavalidation.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
datavalidation_test.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
date.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
docProps.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
docProps_test.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
errors.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
excelize.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 

+ 0 - 113
excelize_test.go

@@ -894,124 +894,11 @@ func TestCopySheetError(t *testing.T) {
 	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestCopySheetError.xlsx")))
 }
 
-func TestAddTable(t *testing.T) {
-	f, err := prepareTestBook1()
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	err = f.AddTable("Sheet1", "B26", "A21", `{}`)
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	err = f.AddTable("Sheet2", "A2", "B5", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	err = f.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`)
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	// Test add table with illegal formatset.
-	assert.EqualError(t, f.AddTable("Sheet1", "B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
-	// Test add table with illegal cell coordinates.
-	assert.EqualError(t, f.AddTable("Sheet1", "A", "B1", `{}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
-	assert.EqualError(t, f.AddTable("Sheet1", "A1", "B", `{}`), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
-
-	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddTable.xlsx")))
-
-	// Test addTable with illegal cell coordinates.
-	f = NewFile()
-	assert.EqualError(t, f.addTable("sheet1", "", 0, 0, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
-	assert.EqualError(t, f.addTable("sheet1", "", 1, 1, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
-}
-
-func TestAddShape(t *testing.T) {
-	f, err := prepareTestBook1()
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	assert.NoError(t, f.AddShape("Sheet1", "A30", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`))
-	assert.NoError(t, f.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`))
-	assert.NoError(t, f.AddShape("Sheet1", "C30", `{"type":"rect","paragraph":[]}`))
-	assert.EqualError(t, f.AddShape("Sheet3", "H1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777","underline":"single"}}], "height": 90}`), "sheet Sheet3 is not exist")
-	assert.EqualError(t, f.AddShape("Sheet3", "H1", ""), "unexpected end of JSON input")
-	assert.EqualError(t, f.AddShape("Sheet1", "A", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
-	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape1.xlsx")))
-
-	// Test add first shape for given sheet.
-	f = NewFile()
-	assert.NoError(t, f.AddShape("Sheet1", "A1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777","underline":"single"}}], "height": 90}`))
-	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape2.xlsx")))
-}
-
 func TestGetSheetComments(t *testing.T) {
 	f := NewFile()
 	assert.Equal(t, "", f.getSheetComments(0))
 }
 
-func TestAutoFilter(t *testing.T) {
-	outFile := filepath.Join("test", "TestAutoFilter%d.xlsx")
-
-	f, err := prepareTestBook1()
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	formats := []string{
-		``,
-		`{"column":"B","expression":"x != blanks"}`,
-		`{"column":"B","expression":"x == blanks"}`,
-		`{"column":"B","expression":"x != nonblanks"}`,
-		`{"column":"B","expression":"x == nonblanks"}`,
-		`{"column":"B","expression":"x <= 1 and x >= 2"}`,
-		`{"column":"B","expression":"x == 1 or x == 2"}`,
-		`{"column":"B","expression":"x == 1 or x == 2*"}`,
-	}
-
-	for i, format := range formats {
-		t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) {
-			err = f.AutoFilter("Sheet1", "D4", "B1", format)
-			assert.NoError(t, err)
-			assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, i+1)))
-		})
-	}
-
-	// testing AutoFilter with illegal cell coordinates.
-	assert.EqualError(t, f.AutoFilter("Sheet1", "A", "B1", ""), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
-	assert.EqualError(t, f.AutoFilter("Sheet1", "A1", "B", ""), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
-}
-
-func TestAutoFilterError(t *testing.T) {
-	outFile := filepath.Join("test", "TestAutoFilterError%d.xlsx")
-
-	f, err := prepareTestBook1()
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	formats := []string{
-		`{"column":"B","expression":"x <= 1 and x >= blanks"}`,
-		`{"column":"B","expression":"x -- y or x == *2*"}`,
-		`{"column":"B","expression":"x != y or x ? *2"}`,
-		`{"column":"B","expression":"x -- y o r x == *2"}`,
-		`{"column":"B","expression":"x -- y"}`,
-		`{"column":"A","expression":"x -- y"}`,
-	}
-	for i, format := range formats {
-		t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) {
-			err = f.AutoFilter("Sheet3", "D4", "B1", format)
-			if assert.Error(t, err) {
-				assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, i+1)))
-			}
-		})
-	}
-}
-
 func TestSetActiveSheet(t *testing.T) {
 	f := NewFile()
 	f.WorkBook.BookViews = nil

+ 1 - 1
file.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
lib.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
picture.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
pivotTable.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
rows.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
shape.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 28 - 0
shape_test.go

@@ -0,0 +1,28 @@
+package excelize
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAddShape(t *testing.T) {
+	f, err := prepareTestBook1()
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	assert.NoError(t, f.AddShape("Sheet1", "A30", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`))
+	assert.NoError(t, f.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`))
+	assert.NoError(t, f.AddShape("Sheet1", "C30", `{"type":"rect","paragraph":[]}`))
+	assert.EqualError(t, f.AddShape("Sheet3", "H1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777","underline":"single"}}], "height": 90}`), "sheet Sheet3 is not exist")
+	assert.EqualError(t, f.AddShape("Sheet3", "H1", ""), "unexpected end of JSON input")
+	assert.EqualError(t, f.AddShape("Sheet1", "A", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape1.xlsx")))
+
+	// Test add first shape for given sheet.
+	f = NewFile()
+	assert.NoError(t, f.AddShape("Sheet1", "A1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777","underline":"single"}}], "height": 90}`))
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape2.xlsx")))
+}

+ 1 - 1
sheet.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
sheetpr.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
sheetview.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
sparkline.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 75 - 52
stream.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //
@@ -36,20 +36,27 @@ type StreamWriter struct {
 // rows, you must call the 'Flush' method to end the streaming writing
 // process and ensure that the order of line numbers is ascending. For
 // example, set data for worksheet of size 102400 rows x 50 columns with
-// numbers:
+// numbers and style:
 //
 //    file := excelize.NewFile()
 //    streamWriter, err := file.NewStreamWriter("Sheet1")
 //    if err != nil {
 //        panic(err)
 //    }
-//    for rowID := 1; rowID <= 102400; rowID++ {
+//    styleID, err := file.NewStyle(`{"font":{"color":"#777777"}}`)
+//    if err != nil {
+//        panic(err)
+//    }
+//    if err := streamWriter.SetRow("A1", []interface{}{excelize.Cell{StyleID: styleID, Value: "Data"}}); err != nil {
+//        panic(err)
+//    }
+//    for rowID := 2; rowID <= 102400; rowID++ {
 //        row := make([]interface{}, 50)
 //        for colID := 0; colID < 50; colID++ {
 //            row[colID] = rand.Intn(640000)
 //        }
 //        cell, _ := excelize.CoordinatesToCellName(1, rowID)
-//        if err := streamWriter.SetRow(cell, row, nil); err != nil {
+//        if err := streamWriter.SetRow(cell, row); err != nil {
 //            panic(err)
 //        }
 //    }
@@ -107,7 +114,7 @@ func (sw *StreamWriter) AddTable(hcell, vcell, format string) error {
 	if err != nil {
 		return err
 	}
-	sortCoordinates(coordinates)
+	_ = sortCoordinates(coordinates)
 
 	// Correct the minimum number of rows, the table at least two lines.
 	if coordinates[1] == coordinates[3] {
@@ -188,7 +195,7 @@ func (sw *StreamWriter) getRowValues(hrow, hcol, vcol int) (res []string, err er
 		return nil, err
 	}
 
-	dec := xml.NewDecoder(r)
+	dec := sw.File.xmlNewDecoder(r)
 	for {
 		token, err := dec.Token()
 		if err == io.EOF {
@@ -248,7 +255,7 @@ func getRowElement(token xml.Token, hrow int) (startElement xml.StartElement, ok
 // a value.
 type Cell struct {
 	StyleID int
-	Value interface{}
+	Value   interface{}
 }
 
 // SetRow writes an array to stream rows by giving a worksheet name, starting
@@ -277,47 +284,8 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
 			c.S = v.StyleID
 			val = v.Value
 		}
-		switch val := val.(type) {
-		case int:
-			c.T, c.V = setCellInt(val)
-		case int8:
-			c.T, c.V = setCellInt(int(val))
-		case int16:
-			c.T, c.V = setCellInt(int(val))
-		case int32:
-			c.T, c.V = setCellInt(int(val))
-		case int64:
-			c.T, c.V = setCellInt(int(val))
-		case uint:
-			c.T, c.V = setCellInt(int(val))
-		case uint8:
-			c.T, c.V = setCellInt(int(val))
-		case uint16:
-			c.T, c.V = setCellInt(int(val))
-		case uint32:
-			c.T, c.V = setCellInt(int(val))
-		case uint64:
-			c.T, c.V = setCellInt(int(val))
-		case float32:
-			c.T, c.V = setCellFloat(float64(val), -1, 32)
-		case float64:
-			c.T, c.V = setCellFloat(val, -1, 64)
-		case string:
-			c.T, c.V, c.XMLSpace = setCellStr(val)
-		case []byte:
-			c.T, c.V, c.XMLSpace = setCellStr(string(val))
-		case time.Duration:
-			c.T, c.V = setCellDuration(val)
-		case time.Time:
-			c.T, c.V, _, err = setCellTime(val)
-		case bool:
-			c.T, c.V = setCellBool(val)
-		case nil:
-			c.T, c.V, c.XMLSpace = setCellStr("")
-		default:
-			c.T, c.V, c.XMLSpace = setCellStr(fmt.Sprint(val))
-		}
-		if err != nil {
+		if err = setCellValFunc(&c, val); err != nil {
+			sw.rawData.WriteString(`</row>`)
 			return err
 		}
 		writeCell(&sw.rawData, c)
@@ -326,6 +294,61 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
 	return sw.rawData.Sync()
 }
 
+// setCellValFunc provides a function to set value of a cell.
+func setCellValFunc(c *xlsxC, val interface{}) (err error) {
+	switch val := val.(type) {
+	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+		err = setCellIntFunc(c, val)
+	case float32:
+		c.T, c.V = setCellFloat(float64(val), -1, 32)
+	case float64:
+		c.T, c.V = setCellFloat(val, -1, 64)
+	case string:
+		c.T, c.V, c.XMLSpace = setCellStr(val)
+	case []byte:
+		c.T, c.V, c.XMLSpace = setCellStr(string(val))
+	case time.Duration:
+		c.T, c.V = setCellDuration(val)
+	case time.Time:
+		c.T, c.V, _, err = setCellTime(val)
+	case bool:
+		c.T, c.V = setCellBool(val)
+	case nil:
+		c.T, c.V, c.XMLSpace = setCellStr("")
+	default:
+		c.T, c.V, c.XMLSpace = setCellStr(fmt.Sprint(val))
+	}
+	return err
+}
+
+// setCellIntFunc is a wrapper of SetCellInt.
+func setCellIntFunc(c *xlsxC, val interface{}) (err error) {
+	switch val := val.(type) {
+	case int:
+		c.T, c.V = setCellInt(val)
+	case int8:
+		c.T, c.V = setCellInt(int(val))
+	case int16:
+		c.T, c.V = setCellInt(int(val))
+	case int32:
+		c.T, c.V = setCellInt(int(val))
+	case int64:
+		c.T, c.V = setCellInt(int(val))
+	case uint:
+		c.T, c.V = setCellInt(int(val))
+	case uint8:
+		c.T, c.V = setCellInt(int(val))
+	case uint16:
+		c.T, c.V = setCellInt(int(val))
+	case uint32:
+		c.T, c.V = setCellInt(int(val))
+	case uint64:
+		c.T, c.V = setCellInt(int(val))
+	default:
+	}
+	return
+}
+
 func writeCell(buf *bufferedWriter, c xlsxC) {
 	buf.WriteString(`<c`)
 	if c.XMLSpace.Value != "" {
@@ -391,8 +414,8 @@ func bulkAppendOtherFields(w io.Writer, ws *xlsxWorksheet, skip ...string) {
 
 // bufferedWriter uses a temp file to store an extended buffer. Writes are
 // always made to an in-memory buffer, which will always succeed. The buffer
-// is written to the temp file with Sync, which may return an error. Therefore,
-// Sync should be periodically called and the error checked.
+// is written to the temp file with Sync, which may return an error.
+// Therefore, Sync should be periodically called and the error checked.
 type bufferedWriter struct {
 	tmp *os.File
 	buf bytes.Buffer
@@ -454,8 +477,8 @@ func (bw *bufferedWriter) Bytes() ([]byte, error) {
 	return buf.Bytes(), err
 }
 
-// Sync will write the in-memory buffer to a temp file, if the in-memory buffer
-// has grown large enough. Any error will be returned.
+// Sync will write the in-memory buffer to a temp file, if the in-memory
+// buffer has grown large enough. Any error will be returned.
 func (bw *bufferedWriter) Sync() (err error) {
 	// Try to use local storage
 	const chunk = 1 << 24

+ 48 - 1
stream_test.go

@@ -3,10 +3,13 @@ package excelize
 import (
 	"encoding/xml"
 	"fmt"
+	"io/ioutil"
 	"math/rand"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -49,6 +52,13 @@ func TestStreamWriter(t *testing.T) {
 	row[0] = []byte("Word")
 	assert.NoError(t, streamWriter.SetRow("A3", row))
 
+	// Test set cell with style.
+	styleID, err := file.NewStyle(`{"font":{"color":"#777777"}}`)
+	assert.NoError(t, err)
+	assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}}))
+	assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}}))
+	assert.EqualError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}), "only UTC time expected")
+
 	for rowID := 10; rowID <= 51200; rowID++ {
 		row := make([]interface{}, 50)
 		for colID := 0; colID < 50; colID++ {
@@ -62,7 +72,7 @@ func TestStreamWriter(t *testing.T) {
 	// Save xlsx file by the given path.
 	assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
 
-	// Test close temporary file error
+	// Test close temporary file error.
 	file = NewFile()
 	streamWriter, err = file.NewStreamWriter("Sheet1")
 	assert.NoError(t, err)
@@ -76,6 +86,12 @@ func TestStreamWriter(t *testing.T) {
 	}
 	assert.NoError(t, streamWriter.rawData.Close())
 	assert.Error(t, streamWriter.Flush())
+
+	streamWriter.rawData.tmp, err = ioutil.TempFile(os.TempDir(), "excelize-")
+	assert.NoError(t, err)
+	_, err = streamWriter.rawData.Reader()
+	assert.NoError(t, err)
+	assert.NoError(t, os.Remove(streamWriter.rawData.tmp.Name()))
 }
 
 func TestStreamTable(t *testing.T) {
@@ -100,6 +116,14 @@ func TestStreamTable(t *testing.T) {
 	assert.Equal(t, "A", table.TableColumns.TableColumn[0].Name)
 	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", ``))
+
+	// Test add table with illegal formatset.
+	assert.EqualError(t, streamWriter.AddTable("B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
+	// Test add table with illegal cell coordinates.
+	assert.EqualError(t, streamWriter.AddTable("A", "B1", `{}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+	assert.EqualError(t, streamWriter.AddTable("A1", "B", `{}`), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
 }
 
 func TestNewStreamWriter(t *testing.T) {
@@ -118,3 +142,26 @@ func TestSetRow(t *testing.T) {
 	assert.NoError(t, err)
 	assert.EqualError(t, streamWriter.SetRow("A", []interface{}{}), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
 }
+
+func TestSetCellValFunc(t *testing.T) {
+	c := &xlsxC{}
+	assert.NoError(t, setCellValFunc(c, 128))
+	assert.NoError(t, setCellValFunc(c, int8(-128)))
+	assert.NoError(t, setCellValFunc(c, int16(-32768)))
+	assert.NoError(t, setCellValFunc(c, int32(-2147483648)))
+	assert.NoError(t, setCellValFunc(c, int64(-9223372036854775808)))
+	assert.NoError(t, setCellValFunc(c, uint(128)))
+	assert.NoError(t, setCellValFunc(c, uint8(255)))
+	assert.NoError(t, setCellValFunc(c, uint16(65535)))
+	assert.NoError(t, setCellValFunc(c, uint32(4294967295)))
+	assert.NoError(t, setCellValFunc(c, uint64(18446744073709551615)))
+	assert.NoError(t, setCellValFunc(c, float32(100.1588)))
+	assert.NoError(t, setCellValFunc(c, float64(100.1588)))
+	assert.NoError(t, setCellValFunc(c, " Hello"))
+	assert.NoError(t, setCellValFunc(c, []byte(" Hello")))
+	assert.NoError(t, setCellValFunc(c, time.Now().UTC()))
+	assert.NoError(t, setCellValFunc(c, time.Duration(1e13)))
+	assert.NoError(t, setCellValFunc(c, true))
+	assert.NoError(t, setCellValFunc(c, nil))
+	assert.NoError(t, setCellValFunc(c, complex64(5+10i)))
+}

+ 1 - 1
styles.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 3
styles_test.go

@@ -169,9 +169,7 @@ func TestSetConditionalFormat(t *testing.T) {
 func TestNewStyle(t *testing.T) {
 	f := NewFile()
 	styleID, err := f.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777"}}`)
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NoError(t, err)
 	styles := f.stylesReader()
 	fontID := styles.CellXfs.Xf[styleID].FontID
 	font := styles.Fonts.Font[fontID]

+ 1 - 1
table.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 125 - 0
table_test.go

@@ -0,0 +1,125 @@
+package excelize
+
+import (
+	"fmt"
+	"path/filepath"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAddTable(t *testing.T) {
+	f, err := prepareTestBook1()
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	err = f.AddTable("Sheet1", "B26", "A21", `{}`)
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	err = f.AddTable("Sheet2", "A2", "B5", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	err = f.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`)
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	// Test add table with illegal formatset.
+	assert.EqualError(t, f.AddTable("Sheet1", "B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
+	// Test add table with illegal cell coordinates.
+	assert.EqualError(t, f.AddTable("Sheet1", "A", "B1", `{}`), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+	assert.EqualError(t, f.AddTable("Sheet1", "A1", "B", `{}`), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
+
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddTable.xlsx")))
+
+	// Test addTable with illegal cell coordinates.
+	f = NewFile()
+	assert.EqualError(t, f.addTable("sheet1", "", 0, 0, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
+	assert.EqualError(t, f.addTable("sheet1", "", 1, 1, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
+}
+
+func TestAutoFilter(t *testing.T) {
+	outFile := filepath.Join("test", "TestAutoFilter%d.xlsx")
+
+	f, err := prepareTestBook1()
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	formats := []string{
+		``,
+		`{"column":"B","expression":"x != blanks"}`,
+		`{"column":"B","expression":"x == blanks"}`,
+		`{"column":"B","expression":"x != nonblanks"}`,
+		`{"column":"B","expression":"x == nonblanks"}`,
+		`{"column":"B","expression":"x <= 1 and x >= 2"}`,
+		`{"column":"B","expression":"x == 1 or x == 2"}`,
+		`{"column":"B","expression":"x == 1 or x == 2*"}`,
+	}
+
+	for i, format := range formats {
+		t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) {
+			err = f.AutoFilter("Sheet1", "D4", "B1", format)
+			assert.NoError(t, err)
+			assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, i+1)))
+		})
+	}
+
+	// testing AutoFilter with illegal cell coordinates.
+	assert.EqualError(t, f.AutoFilter("Sheet1", "A", "B1", ""), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+	assert.EqualError(t, f.AutoFilter("Sheet1", "A1", "B", ""), `cannot convert cell "B" to coordinates: invalid cell name "B"`)
+}
+
+func TestAutoFilterError(t *testing.T) {
+	outFile := filepath.Join("test", "TestAutoFilterError%d.xlsx")
+
+	f, err := prepareTestBook1()
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+
+	formats := []string{
+		`{"column":"B","expression":"x <= 1 and x >= blanks"}`,
+		`{"column":"B","expression":"x -- y or x == *2*"}`,
+		`{"column":"B","expression":"x != y or x ? *2"}`,
+		`{"column":"B","expression":"x -- y o r x == *2"}`,
+		`{"column":"B","expression":"x -- y"}`,
+		`{"column":"A","expression":"x -- y"}`,
+	}
+	for i, format := range formats {
+		t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) {
+			err = f.AutoFilter("Sheet3", "D4", "B1", format)
+			if assert.Error(t, err) {
+				assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, i+1)))
+			}
+		})
+	}
+
+	assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &formatAutoFilter{
+		Column:     "-",
+		Expression: "-",
+	}), `invalid column name "-"`)
+	assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 100, &formatAutoFilter{
+		Column:     "A",
+		Expression: "-",
+	}), `incorrect index of column 'A'`)
+	assert.EqualError(t, f.autoFilter("Sheet1", "A1", 1, 1, &formatAutoFilter{
+		Column:     "A",
+		Expression: "-",
+	}), `incorrect number of tokens in criteria '-'`)
+}
+
+func TestParseFilterTokens(t *testing.T) {
+	f := NewFile()
+	// Test with unknown operator.
+	_, _, err := f.parseFilterTokens("", []string{"", "!"})
+	assert.EqualError(t, err, "unknown operator: !")
+	// Test invalid operator in context.
+	_, _, err = f.parseFilterTokens("", []string{"", "<", "x != blanks"})
+	assert.EqualError(t, err, "the operator '<' in expression '' is not valid in relation to Blanks/NonBlanks'")
+}

+ 1 - 1
templates.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
vmlDrawing.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlApp.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlCalcChain.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlChart.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlComments.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlContentTypes.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlCore.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlDecodeDrawing.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlDrawing.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlPivotTable.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlSharedStrings.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlStyles.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlTable.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlTheme.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlWorkbook.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //

+ 1 - 1
xmlWorksheet.go

@@ -1,4 +1,4 @@
-// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2020 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.
 //