excelize_test.go 47.7 KB
Newer Older
xurime's avatar
xurime 已提交
1 2 3
package excelize

import (
4
	"fmt"
5 6 7
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
8
	"io/ioutil"
9
	"reflect"
xurime's avatar
xurime 已提交
10
	"strconv"
xurime's avatar
xurime 已提交
11
	"strings"
xurime's avatar
xurime 已提交
12
	"testing"
13
	"time"
xurime's avatar
xurime 已提交
14 15
)

16
func TestOpenFile(t *testing.T) {
xurime's avatar
xurime 已提交
17
	// Test update a XLSX file.
xurime's avatar
xurime 已提交
18
	xlsx, err := OpenFile("./test/Book1.xlsx")
19
	if err != nil {
20
		t.Error(err)
21
	}
22
	// Test get all the rows in a not exists worksheet.
23
	rows := xlsx.GetRows("Sheet4")
24
	// Test get all the rows in a worksheet.
25
	rows = xlsx.GetRows("Sheet2")
26 27 28 29 30 31
	for _, row := range rows {
		for _, cell := range row {
			t.Log(cell, "\t")
		}
		t.Log("\r\n")
	}
32
	xlsx.UpdateLinkedValue()
33 34
	xlsx.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(float64(100.1588), 'f', -1, 32))
	xlsx.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
35 36
	// Test set cell value with illegal row number.
	xlsx.SetCellDefault("Sheet2", "A", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
37
	xlsx.SetCellInt("Sheet2", "A1", 100)
38 39
	// Test set cell integer value with illegal row number.
	xlsx.SetCellInt("Sheet2", "A", 100)
40
	xlsx.SetCellStr("Sheet2", "C11", "Knowns")
41
	// Test max characters in a cell.
42 43 44
	xlsx.SetCellStr("Sheet2", "D11", strings.Repeat("c", 32769))
	xlsx.NewSheet(":\\/?*[]Maximum 31 characters allowed in sheet title.")
	// Test set worksheet name with illegal name.
45 46
	xlsx.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title.")
	xlsx.SetCellInt("Sheet3", "A23", 10)
47 48
	xlsx.SetCellStr("Sheet3", "b230", "10")
	xlsx.SetCellStr("Sheet10", "b230", "10")
49 50
	// Test set cell string value with illegal row number.
	xlsx.SetCellStr("Sheet10", "A", "10")
51
	xlsx.SetActiveSheet(2)
52 53
	// Test get cell formula with given rows number.
	xlsx.GetCellFormula("Sheet1", "B19")
54
	// Test get cell formula with illegal worksheet name.
55 56 57 58
	xlsx.GetCellFormula("Sheet2", "B20")
	// Test get cell formula with illegal rows number.
	xlsx.GetCellFormula("Sheet1", "B20")
	xlsx.GetCellFormula("Sheet1", "B")
xurime's avatar
xurime 已提交
59
	// Test read cell value with given illegal rows number.
60
	xlsx.GetCellValue("Sheet2", "a-1")
61
	xlsx.GetCellValue("Sheet2", "A")
xurime's avatar
xurime 已提交
62
	// Test read cell value with given lowercase column number.
63 64 65 66
	xlsx.GetCellValue("Sheet2", "a5")
	xlsx.GetCellValue("Sheet2", "C11")
	xlsx.GetCellValue("Sheet2", "D11")
	xlsx.GetCellValue("Sheet2", "D12")
xurime's avatar
xurime 已提交
67
	// Test SetCellValue function.
68
	xlsx.SetCellValue("Sheet2", "F1", " Hello")
69 70
	xlsx.SetCellValue("Sheet2", "G1", []byte("World"))
	xlsx.SetCellValue("Sheet2", "F2", 42)
71 72 73 74 75 76 77 78 79 80 81 82 83 84
	xlsx.SetCellValue("Sheet2", "F3", int8(1<<8/2-1))
	xlsx.SetCellValue("Sheet2", "F4", int16(1<<16/2-1))
	xlsx.SetCellValue("Sheet2", "F5", int32(1<<32/2-1))
	xlsx.SetCellValue("Sheet2", "F6", int64(1<<32/2-1))
	xlsx.SetCellValue("Sheet2", "F7", float32(42.65418))
	xlsx.SetCellValue("Sheet2", "F8", float64(-42.65418))
	xlsx.SetCellValue("Sheet2", "F9", float32(42))
	xlsx.SetCellValue("Sheet2", "F10", float64(42))
	xlsx.SetCellValue("Sheet2", "F11", uint(1<<32-1))
	xlsx.SetCellValue("Sheet2", "F12", uint8(1<<8-1))
	xlsx.SetCellValue("Sheet2", "F13", uint16(1<<16-1))
	xlsx.SetCellValue("Sheet2", "F14", uint32(1<<32-1))
	xlsx.SetCellValue("Sheet2", "F15", uint64(1<<32-1))
	xlsx.SetCellValue("Sheet2", "F16", true)
85 86 87
	xlsx.SetCellValue("Sheet2", "F17", complex64(5+10i))
	t.Log(letterOnlyMapF('x'))
	t.Log(deepCopy(nil, nil))
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	// Test boolean write
	booltest := []struct {
		value    bool
		expected string
	}{
		{false, "0"},
		{true, "1"},
	}
	for _, test := range booltest {
		xlsx.SetCellValue("Sheet2", "F16", test.value)
		value := xlsx.GetCellValue("Sheet2", "F16")
		if value != test.expected {
			t.Errorf(`Expecting result of xlsx.SetCellValue("Sheet2", "F16", %v) to be %v (false), got: %s `, test.value, test.expected, value)
		}
	}
103
	xlsx.SetCellValue("Sheet2", "G2", nil)
104
	xlsx.SetCellValue("Sheet2", "G4", time.Now())
105 106
	// 02:46:40
	xlsx.SetCellValue("Sheet2", "G5", time.Duration(1e13))
xurime's avatar
xurime 已提交
107
	// Test completion column.
108
	xlsx.SetCellValue("Sheet2", "M2", nil)
xurime's avatar
xurime 已提交
109
	// Test read cell value with given axis large than exists row.
110
	xlsx.GetCellValue("Sheet2", "E231")
111
	// Test get active worksheet of XLSX and get worksheet name of XLSX by given worksheet index.
112
	xlsx.GetSheetName(xlsx.GetActiveSheetIndex())
113
	// Test get worksheet index of XLSX by given worksheet name.
114
	xlsx.GetSheetIndex("Sheet1")
115
	// Test get worksheet name of XLSX by given invalid worksheet index.
116
	xlsx.GetSheetName(4)
117
	// Test get worksheet map of XLSX.
118
	xlsx.GetSheetMap()
119
	for i := 1; i <= 300; i++ {
120
		xlsx.SetCellStr("Sheet3", "c"+strconv.Itoa(i), strconv.Itoa(i))
121 122 123 124 125 126
	}
	err = xlsx.Save()
	if err != nil {
		t.Log(err)
	}
	// Test write file to not exist directory.
127
	err = xlsx.SaveAs("")
128 129
	if err != nil {
		t.Log(err)
xurime's avatar
xurime 已提交
130
	}
131 132 133
}

func TestAddPicture(t *testing.T) {
xurime's avatar
xurime 已提交
134
	xlsx, err := OpenFile("./test/Book1.xlsx")
xurime's avatar
xurime 已提交
135
	if err != nil {
136
		t.Error(err)
xurime's avatar
xurime 已提交
137
	}
138 139
	// Test add picture to worksheet with offset and location hyperlink.
	err = xlsx.AddPicture("Sheet2", "I9", "./test/images/excel.jpg", `{"x_offset": 140, "y_offset": 120, "hyperlink": "#Sheet2!D8", "hyperlink_type": "Location"}`)
140
	if err != nil {
141
		t.Error(err)
142
	}
143 144
	// Test add picture to worksheet with offset, external hyperlink and positioning.
	err = xlsx.AddPicture("Sheet1", "F21", "./test/images/excel.png", `{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`)
145
	if err != nil {
146
		t.Error(err)
147
	}
148
	// Test add picture to worksheet with invalid file path.
149
	err = xlsx.AddPicture("Sheet1", "G21", "./test/images/excel.icon", "")
150 151 152
	if err != nil {
		t.Log(err)
	}
153
	// Test add picture to worksheet with unsupport file type.
xurime's avatar
xurime 已提交
154
	err = xlsx.AddPicture("Sheet1", "G21", "./test/Book1.xlsx", "")
155 156 157
	if err != nil {
		t.Log(err)
	}
xurime's avatar
xurime 已提交
158
	// Test write file to given path.
xurime's avatar
xurime 已提交
159
	err = xlsx.SaveAs("./test/Book2.xlsx")
160
	if err != nil {
161
		t.Error(err)
162
	}
163
}
xurime's avatar
xurime 已提交
164

165
func TestBrokenFile(t *testing.T) {
xurime's avatar
xurime 已提交
166
	// Test write file with broken file struct.
167 168
	xlsx := File{}
	err := xlsx.Save()
xurime's avatar
xurime 已提交
169 170 171 172
	if err != nil {
		t.Log(err)
	}
	// Test write file with broken file struct with given path.
xurime's avatar
xurime 已提交
173
	err = xlsx.SaveAs("./test/Book3.xlsx")
xurime's avatar
xurime 已提交
174 175 176 177
	if err != nil {
		t.Log(err)
	}

178 179
	// Test set active sheet without BookViews and Sheets maps in xl/workbook.xml.
	f3, err := OpenFile("./test/badWorkbook.xlsx")
xurime's avatar
xurime 已提交
180
	f3.GetActiveSheetIndex()
181
	f3.SetActiveSheet(2)
182 183 184
	if err != nil {
		t.Log(err)
	}
185 186

	// Test open a XLSX file with given illegal path.
xurime's avatar
xurime 已提交
187
	_, err = OpenFile("./test/Book.xlsx")
188 189 190
	if err != nil {
		t.Log(err)
	}
191 192
}

193
func TestNewFile(t *testing.T) {
194
	// Test create a XLSX file.
195
	xlsx := NewFile()
196
	xlsx.NewSheet("Sheet1")
197 198 199 200
	xlsx.NewSheet("XLSXSheet2")
	xlsx.NewSheet("XLSXSheet3")
	xlsx.SetCellInt("XLSXSheet2", "A23", 56)
	xlsx.SetCellStr("Sheet1", "B20", "42")
201
	xlsx.SetActiveSheet(0)
202 203
	// Test add picture to sheet with scaling and positioning.
	err := xlsx.AddPicture("Sheet1", "H2", "./test/images/excel.gif", `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`)
xurime's avatar
xurime 已提交
204
	if err != nil {
205
		t.Error(err)
xurime's avatar
xurime 已提交
206
	}
207
	err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", "")
xurime's avatar
xurime 已提交
208
	if err != nil {
209
		t.Error(err)
xurime's avatar
xurime 已提交
210
	}
xurime's avatar
xurime 已提交
211
	err = xlsx.SaveAs("./test/Book3.xlsx")
212
	if err != nil {
213
		t.Error(err)
214
	}
xurime's avatar
xurime 已提交
215
}
216

217
func TestColWidth(t *testing.T) {
218
	xlsx := NewFile()
219 220 221 222
	xlsx.SetColWidth("Sheet1", "B", "A", 12)
	xlsx.SetColWidth("Sheet1", "A", "B", 12)
	xlsx.GetColWidth("Sheet1", "A")
	xlsx.GetColWidth("Sheet1", "C")
xurime's avatar
xurime 已提交
223
	err := xlsx.SaveAs("./test/Book4.xlsx")
224
	if err != nil {
225
		t.Error(err)
226
	}
227 228 229 230 231
	convertRowHeightToPixels(0)
}

func TestRowHeight(t *testing.T) {
	xlsx := NewFile()
232 233
	xlsx.SetRowHeight("Sheet1", 1, 50)
	xlsx.SetRowHeight("Sheet1", 4, 90)
234
	t.Log(xlsx.GetRowHeight("Sheet1", 1))
235
	t.Log(xlsx.GetRowHeight("Sheet1", 0))
xurime's avatar
xurime 已提交
236
	err := xlsx.SaveAs("./test/Book5.xlsx")
237
	if err != nil {
238
		t.Error(err)
239 240
	}
	convertColWidthToPixels(0)
241 242 243
}

func TestSetCellHyperLink(t *testing.T) {
xurime's avatar
xurime 已提交
244
	xlsx, err := OpenFile("./test/Book1.xlsx")
245 246 247 248
	if err != nil {
		t.Log(err)
	}
	// Test set cell hyperlink in a work sheet already have hyperlinks.
249
	xlsx.SetCellHyperLink("Sheet1", "B19", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
250
	// Test add first hyperlink in a work sheet.
251
	xlsx.SetCellHyperLink("Sheet2", "C1", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
252
	// Test add Location hyperlink in a work sheet.
253 254 255
	xlsx.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location")
	xlsx.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", "")
	xlsx.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location")
256 257
	err = xlsx.Save()
	if err != nil {
258
		t.Error(err)
259 260 261
	}
}

262
func TestGetCellHyperLink(t *testing.T) {
xurime's avatar
xurime 已提交
263
	xlsx, err := OpenFile("./test/Book1.xlsx")
264
	if err != nil {
265
		t.Error(err)
266 267 268 269 270 271 272 273 274 275 276
	}
	link, target := xlsx.GetCellHyperLink("Sheet1", "")
	t.Log(link, target)
	link, target = xlsx.GetCellHyperLink("Sheet1", "B19")
	t.Log(link, target)
	link, target = xlsx.GetCellHyperLink("Sheet2", "D6")
	t.Log(link, target)
	link, target = xlsx.GetCellHyperLink("Sheet3", "H3")
	t.Log(link, target)
}

277
func TestSetCellFormula(t *testing.T) {
xurime's avatar
xurime 已提交
278
	xlsx, err := OpenFile("./test/Book1.xlsx")
279
	if err != nil {
280
		t.Error(err)
281
	}
282 283
	xlsx.SetCellFormula("Sheet1", "B19", "SUM(Sheet2!D2,Sheet2!D11)")
	xlsx.SetCellFormula("Sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)")
284 285
	// Test set cell formula with illegal rows number.
	xlsx.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)")
286
	err = xlsx.Save()
287
	if err != nil {
288
		t.Error(err)
289 290
	}
}
291 292

func TestSetSheetBackground(t *testing.T) {
xurime's avatar
xurime 已提交
293
	xlsx, err := OpenFile("./test/Book1.xlsx")
294
	if err != nil {
295
		t.Error(err)
296
	}
297
	err = xlsx.SetSheetBackground("Sheet2", "./test/images/background.png")
298 299 300
	if err != nil {
		t.Log(err)
	}
xurime's avatar
xurime 已提交
301
	err = xlsx.SetSheetBackground("Sheet2", "./test/Book1.xlsx")
302 303 304
	if err != nil {
		t.Log(err)
	}
305
	err = xlsx.SetSheetBackground("Sheet2", "./test/images/background.jpg")
306
	if err != nil {
307
		t.Error(err)
308
	}
309
	err = xlsx.SetSheetBackground("Sheet2", "./test/images/background.jpg")
310
	if err != nil {
311
		t.Error(err)
312 313 314
	}
	err = xlsx.Save()
	if err != nil {
315
		t.Error(err)
316 317
	}
}
xurime's avatar
xurime 已提交
318

319
func TestMergeCell(t *testing.T) {
xurime's avatar
xurime 已提交
320
	xlsx, err := OpenFile("./test/Book1.xlsx")
xurime's avatar
xurime 已提交
321
	if err != nil {
322
		t.Error(err)
xurime's avatar
xurime 已提交
323
	}
324 325 326 327 328 329 330 331 332 333 334
	xlsx.MergeCell("Sheet1", "D9", "D9")
	xlsx.MergeCell("Sheet1", "D9", "E9")
	xlsx.MergeCell("Sheet1", "H14", "G13")
	xlsx.MergeCell("Sheet1", "C9", "D8")
	xlsx.MergeCell("Sheet1", "F11", "G13")
	xlsx.MergeCell("Sheet1", "H7", "B15")
	xlsx.MergeCell("Sheet1", "D11", "F13")
	xlsx.MergeCell("Sheet1", "G10", "K12")
	xlsx.SetCellValue("Sheet1", "G11", "set value in merged cell")
	xlsx.SetCellInt("Sheet1", "H11", 100)
	xlsx.SetCellValue("Sheet1", "I11", float64(0.5))
335
	xlsx.SetCellHyperLink("Sheet1", "J11", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
336 337
	xlsx.SetCellFormula("Sheet1", "G12", "SUM(Sheet1!B19,Sheet1!C19)")
	xlsx.GetCellValue("Sheet1", "H11")
338
	xlsx.GetCellValue("Sheet2", "A6") // Merged cell ref is single coordinate.
339
	xlsx.GetCellFormula("Sheet1", "G12")
xurime's avatar
xurime 已提交
340 341
	err = xlsx.Save()
	if err != nil {
342
		t.Error(err)
xurime's avatar
xurime 已提交
343 344
	}
}
N
Nikolas Silva 已提交
345

346
func TestSetCellStyleAlignment(t *testing.T) {
xurime's avatar
xurime 已提交
347
	xlsx, err := OpenFile("./test/Book2.xlsx")
348
	if err != nil {
349
		t.Error(err)
350
	}
351 352 353
	var style int
	style, err = xlsx.NewStyle(`{"alignment":{"horizontal":"center","ident":1,"justify_last_line":true,"reading_order":0,"relative_indent":1,"shrink_to_fit":true,"text_rotation":45,"vertical":"top","wrap_text":true}}`)
	if err != nil {
354
		t.Error(err)
355 356
	}
	xlsx.SetCellStyle("Sheet1", "A22", "A22", style)
357 358 359 360 361
	// Test set cell style with given illegal rows number.
	xlsx.SetCellStyle("Sheet1", "A", "A22", style)
	xlsx.SetCellStyle("Sheet1", "A22", "A", style)
	// Test get cell style with given illegal rows number.
	xlsx.GetCellStyle("Sheet1", "A")
362 363
	err = xlsx.Save()
	if err != nil {
364
		t.Error(err)
365 366 367 368
	}
}

func TestSetCellStyleBorder(t *testing.T) {
xurime's avatar
xurime 已提交
369
	xlsx, err := OpenFile("./test/Book2.xlsx")
370
	if err != nil {
371
		t.Error(err)
372
	}
373
	var style int
374
	// Test set border with invalid style parameter.
375
	style, err = xlsx.NewStyle("")
376 377 378
	if err != nil {
		t.Log(err)
	}
379 380
	xlsx.SetCellStyle("Sheet1", "J21", "L25", style)

381
	// Test set border with invalid style index number.
382
	style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":-1},{"type":"top","color":"00FF00","style":14},{"type":"bottom","color":"FFFF00","style":5},{"type":"right","color":"FF0000","style":6},{"type":"diagonalDown","color":"A020F0","style":9},{"type":"diagonalUp","color":"A020F0","style":8}]}`)
383 384 385
	if err != nil {
		t.Log(err)
	}
386 387
	xlsx.SetCellStyle("Sheet1", "J21", "L25", style)

388
	// Test set border on overlapping area with vertical variants shading styles gradient fill.
389
	style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":12},{"type":"bottom","color":"FFFF00","style":5},{"type":"right","color":"FF0000","style":6},{"type":"diagonalDown","color":"A020F0","style":9},{"type":"diagonalUp","color":"A020F0","style":8}]}`)
390 391 392
	if err != nil {
		t.Log(err)
	}
393 394 395
	xlsx.SetCellStyle("Sheet1", "J21", "L25", style)

	style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":1}}`)
396 397 398
	if err != nil {
		t.Log(err)
	}
399 400 401 402 403 404 405 406
	xlsx.SetCellStyle("Sheet1", "M28", "K24", style)

	style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":4}}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "M28", "K24", style)

407
	// Test set border and solid style pattern fill for a single cell.
408
	style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":8},{"type":"top","color":"00FF00","style":9},{"type":"bottom","color":"FFFF00","style":10},{"type":"right","color":"FF0000","style":11},{"type":"diagonalDown","color":"A020F0","style":12},{"type":"diagonalUp","color":"A020F0","style":13}],"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":1}}`)
409 410 411
	if err != nil {
		t.Log(err)
	}
412 413

	xlsx.SetCellStyle("Sheet1", "O22", "O22", style)
414 415
	err = xlsx.Save()
	if err != nil {
416
		t.Error(err)
417 418 419
	}
}

420
func TestSetCellStyleNumberFormat(t *testing.T) {
xurime's avatar
xurime 已提交
421
	xlsx, err := OpenFile("./test/Book2.xlsx")
422
	if err != nil {
423
		t.Error(err)
424
	}
xurime's avatar
xurime 已提交
425
	// Test only set fill and number format for a cell.
426 427 428 429 430 431 432 433 434 435 436 437 438
	col := []string{"L", "M", "N", "O", "P"}
	data := []int{0, 1, 2, 3, 4, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49}
	value := []string{"37947.7500001", "-37947.7500001", "0.007", "2.1", "String"}
	for i, v := range value {
		for k, d := range data {
			c := col[i] + strconv.Itoa(k+1)
			var val float64
			val, err = strconv.ParseFloat(v, 64)
			if err != nil {
				xlsx.SetCellValue("Sheet2", c, v)
			} else {
				xlsx.SetCellValue("Sheet2", c, val)
			}
439
			style, err := xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":5},"number_format": ` + strconv.Itoa(d) + `}`)
440 441 442
			if err != nil {
				t.Log(err)
			}
443
			xlsx.SetCellStyle("Sheet2", c, c, style)
444 445 446
			t.Log(xlsx.GetCellValue("Sheet2", c))
		}
	}
447 448 449 450 451 452
	var style int
	style, err = xlsx.NewStyle(`{"number_format":-1}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet2", "L33", "L33", style)
453
	err = xlsx.Save()
454
	if err != nil {
455
		t.Error(err)
456
	}
457 458
}

459
func TestSetCellStyleCurrencyNumberFormat(t *testing.T) {
xurime's avatar
xurime 已提交
460
	xlsx, err := OpenFile("./test/Book3.xlsx")
461
	if err != nil {
462
		t.Error(err)
463 464
	}
	xlsx.SetCellValue("Sheet1", "A1", 56)
465
	xlsx.SetCellValue("Sheet1", "A2", -32.3)
466 467 468 469 470 471
	var style int
	style, err = xlsx.NewStyle(`{"number_format": 188, "decimal_places": -1}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
472
	style, err = xlsx.NewStyle(`{"number_format": 188, "decimal_places": 31, "negred": true}`)
473 474 475 476 477 478 479 480 481 482
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A2", "A2", style)

	err = xlsx.Save()
	if err != nil {
		t.Log(err)
	}

xurime's avatar
xurime 已提交
483
	xlsx, err = OpenFile("./test/Book4.xlsx")
484 485 486
	if err != nil {
		t.Log(err)
	}
487 488
	xlsx.SetCellValue("Sheet1", "A1", 42920.5)
	xlsx.SetCellValue("Sheet1", "A2", 42920.5)
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

	style, err = xlsx.NewStyle(`{"number_format": 26, "lang": "zh-tw"}`)
	if err != nil {
		t.Log(err)
	}
	style, err = xlsx.NewStyle(`{"number_format": 27}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
	style, err = xlsx.NewStyle(`{"number_format": 31, "lang": "ko-kr"}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A2", "A2", style)

	style, err = xlsx.NewStyle(`{"number_format": 71, "lang": "th-th"}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A2", "A2", style)

	err = xlsx.Save()
	if err != nil {
513
		t.Error(err)
514 515 516
	}
}

517 518 519 520 521 522 523 524 525 526 527 528 529 530
func TestSetCellStyleCustomNumberFormat(t *testing.T) {
	xlsx := NewFile()
	xlsx.SetCellValue("Sheet1", "A1", 42920.5)
	xlsx.SetCellValue("Sheet1", "A2", 42920.5)
	style, err := xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
	style, err = xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet1", "A2", "A2", style)
xurime's avatar
xurime 已提交
531
	err = xlsx.SaveAs("./test/Book_custom_number_format.xlsx")
532
	if err != nil {
533
		t.Error(err)
534 535 536
	}
}

537
func TestSetCellStyleFill(t *testing.T) {
xurime's avatar
xurime 已提交
538
	xlsx, err := OpenFile("./test/Book2.xlsx")
539
	if err != nil {
540
		t.Error(err)
541
	}
542
	var style int
543
	// Test set fill for cell with invalid parameter.
544
	style, err = xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":6}}`)
545 546 547
	if err != nil {
		t.Log(err)
	}
548 549 550
	xlsx.SetCellStyle("Sheet1", "O23", "O23", style)

	style, err = xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF"],"shading":1}}`)
551 552 553
	if err != nil {
		t.Log(err)
	}
554 555 556
	xlsx.SetCellStyle("Sheet1", "O23", "O23", style)

	style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":[],"pattern":1}}`)
557 558 559
	if err != nil {
		t.Log(err)
	}
560
	xlsx.SetCellStyle("Sheet1", "O23", "O23", style)
xurime's avatar
xurime 已提交
561

562
	style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":19}}`)
563 564 565
	if err != nil {
		t.Log(err)
	}
566 567
	xlsx.SetCellStyle("Sheet1", "O23", "O23", style)

568 569
	err = xlsx.Save()
	if err != nil {
570
		t.Error(err)
571 572 573 574
	}
}

func TestSetCellStyleFont(t *testing.T) {
xurime's avatar
xurime 已提交
575
	xlsx, err := OpenFile("./test/Book2.xlsx")
576
	if err != nil {
577
		t.Error(err)
578
	}
579 580
	var style int
	style, err = xlsx.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777","underline":"single"}}`)
581 582 583
	if err != nil {
		t.Log(err)
	}
584 585 586
	xlsx.SetCellStyle("Sheet2", "A1", "A1", style)

	style, err = xlsx.NewStyle(`{"font":{"italic":true,"underline":"double"}}`)
587 588 589
	if err != nil {
		t.Log(err)
	}
590 591 592
	xlsx.SetCellStyle("Sheet2", "A2", "A2", style)

	style, err = xlsx.NewStyle(`{"font":{"bold":true}}`)
593 594 595
	if err != nil {
		t.Log(err)
	}
596 597 598
	xlsx.SetCellStyle("Sheet2", "A3", "A3", style)

	style, err = xlsx.NewStyle(`{"font":{"bold":true,"family":"","size":0,"color":"","underline":""}}`)
599 600 601
	if err != nil {
		t.Log(err)
	}
602 603 604
	xlsx.SetCellStyle("Sheet2", "A4", "A4", style)

	style, err = xlsx.NewStyle(`{"font":{"color":"#777777"}}`)
605 606 607
	if err != nil {
		t.Log(err)
	}
608
	xlsx.SetCellStyle("Sheet2", "A5", "A5", style)
609 610
	err = xlsx.Save()
	if err != nil {
611
		t.Error(err)
612 613
	}
}
614

615 616 617
func TestSetCellStyleProtection(t *testing.T) {
	xlsx, err := OpenFile("./test/Book2.xlsx")
	if err != nil {
618
		t.Error(err)
619 620 621 622 623 624 625 626 627
	}
	var style int
	style, err = xlsx.NewStyle(`{"protection":{"hidden":true, "locked":true}}`)
	if err != nil {
		t.Log(err)
	}
	xlsx.SetCellStyle("Sheet2", "A6", "A6", style)
	err = xlsx.Save()
	if err != nil {
628
		t.Error(err)
629 630 631
	}
}

632
func TestSetDeleteSheet(t *testing.T) {
xurime's avatar
xurime 已提交
633
	xlsx, err := OpenFile("./test/Book3.xlsx")
634
	if err != nil {
635
		t.Error(err)
636 637 638 639
	}
	xlsx.DeleteSheet("XLSXSheet3")
	err = xlsx.Save()
	if err != nil {
640
		t.Error(err)
641
	}
xurime's avatar
xurime 已提交
642
	xlsx, err = OpenFile("./test/Book4.xlsx")
643
	if err != nil {
644
		t.Error(err)
645 646
	}
	xlsx.DeleteSheet("Sheet1")
xurime's avatar
xurime 已提交
647
	xlsx.AddComment("Sheet1", "A1", `{"author":"Excelize: ","text":"This is a comment."}`)
xurime's avatar
xurime 已提交
648
	err = xlsx.SaveAs("./test/Book_delete_sheet.xlsx")
649
	if err != nil {
650
		t.Error(err)
651 652
	}
}
653 654

func TestGetPicture(t *testing.T) {
xurime's avatar
xurime 已提交
655
	xlsx, err := OpenFile("./test/Book2.xlsx")
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
	if err != nil {
		t.Log(err)
	}
	file, raw := xlsx.GetPicture("Sheet1", "F21")
	if file == "" {
		err = ioutil.WriteFile(file, raw, 0644)
		if err != nil {
			t.Log(err)
		}
	}
	// Try to get picture from a worksheet that doesn't contain any images.
	file, raw = xlsx.GetPicture("Sheet3", "I9")
	if file != "" {
		err = ioutil.WriteFile(file, raw, 0644)
		if err != nil {
			t.Log(err)
		}
	}
	// Try to get picture from a cell that doesn't contain an image.
	file, raw = xlsx.GetPicture("Sheet2", "A2")
	t.Log(file, len(raw))
xurime's avatar
xurime 已提交
677 678 679
	xlsx.getDrawingRelationships("xl/worksheets/_rels/sheet1.xml.rels", "rId8")
	xlsx.getDrawingRelationships("", "")
	xlsx.getSheetRelationshipsTargetByID("", "")
680
	xlsx.deleteSheetRelationships("", "")
681
}
682

683
func TestSheetVisibility(t *testing.T) {
xurime's avatar
xurime 已提交
684
	xlsx, err := OpenFile("./test/Book2.xlsx")
685
	if err != nil {
686
		t.Error(err)
687
	}
688 689 690 691
	xlsx.SetSheetVisible("Sheet2", false)
	xlsx.SetSheetVisible("Sheet1", false)
	xlsx.SetSheetVisible("Sheet1", true)
	xlsx.GetSheetVisible("Sheet1")
692 693
	err = xlsx.Save()
	if err != nil {
694
		t.Error(err)
695 696 697
	}
}

698
func TestRowVisibility(t *testing.T) {
xurime's avatar
xurime 已提交
699
	xlsx, err := OpenFile("./test/Book2.xlsx")
700
	if err != nil {
701
		t.Error(err)
702
	}
703 704 705
	xlsx.SetRowVisible("Sheet3", 2, false)
	xlsx.SetRowVisible("Sheet3", 2, true)
	xlsx.GetRowVisible("Sheet3", 2)
706 707
	err = xlsx.Save()
	if err != nil {
708
		t.Error(err)
709 710 711
	}
}

712
func TestColumnVisibility(t *testing.T) {
xurime's avatar
xurime 已提交
713
	xlsx, err := OpenFile("./test/Book2.xlsx")
714
	if err != nil {
715
		t.Error(err)
716 717 718 719 720 721 722
	}
	xlsx.SetColVisible("Sheet1", "F", false)
	xlsx.SetColVisible("Sheet1", "F", true)
	xlsx.GetColVisible("Sheet1", "F")
	xlsx.SetColVisible("Sheet3", "E", false)
	err = xlsx.Save()
	if err != nil {
723
		t.Error(err)
724
	}
xurime's avatar
xurime 已提交
725
	xlsx, err = OpenFile("./test/Book3.xlsx")
726
	if err != nil {
727
		t.Error(err)
728 729 730 731
	}
	xlsx.GetColVisible("Sheet1", "B")
}

732
func TestCopySheet(t *testing.T) {
xurime's avatar
xurime 已提交
733
	xlsx, err := OpenFile("./test/Book2.xlsx")
734
	if err != nil {
735
		t.Error(err)
736 737 738 739 740
	}
	err = xlsx.CopySheet(0, -1)
	if err != nil {
		t.Log(err)
	}
741 742
	idx := xlsx.NewSheet("CopySheet")
	err = xlsx.CopySheet(1, idx)
743 744 745
	if err != nil {
		t.Log(err)
	}
746 747 748 749
	xlsx.SetCellValue("Sheet4", "F1", "Hello")
	if xlsx.GetCellValue("Sheet1", "F1") == "Hello" {
		t.Error("Invalid value \"Hello\" in Sheet1")
	}
750 751
	err = xlsx.Save()
	if err != nil {
752
		t.Error(err)
753 754
	}
}
755

xurime's avatar
xurime 已提交
756
func TestAddTable(t *testing.T) {
xurime's avatar
xurime 已提交
757
	xlsx, err := OpenFile("./test/Book2.xlsx")
xurime's avatar
xurime 已提交
758
	if err != nil {
759
		t.Error(err)
xurime's avatar
xurime 已提交
760 761
	}
	xlsx.AddTable("Sheet1", "B26", "A21", ``)
762
	xlsx.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}`)
xurime's avatar
xurime 已提交
763 764 765
	xlsx.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`)
	err = xlsx.Save()
	if err != nil {
766
		t.Error(err)
xurime's avatar
xurime 已提交
767 768 769
	}
}

770
func TestAddShape(t *testing.T) {
xurime's avatar
xurime 已提交
771
	xlsx, err := OpenFile("./test/Book2.xlsx")
772
	if err != nil {
773
		t.Error(err)
774
	}
775 776 777 778
	xlsx.AddShape("Sheet1", "A30", `{"type":"rect","paragraph":[{"text":"Rectangle","font":{"color":"CD5C5C"}},{"text":"Shape","font":{"bold":true,"color":"2980B9"}}]}`)
	xlsx.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`)
	xlsx.AddShape("Sheet1", "C30", `{"type":"rect","paragraph":[]}`)
	xlsx.AddShape("Sheet3", "H1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777","underline":"single"}}], "height": 90}`)
779 780
	err = xlsx.Save()
	if err != nil {
781
		t.Error(err)
782 783 784
	}
}

785
func TestAddComments(t *testing.T) {
xurime's avatar
xurime 已提交
786
	xlsx, err := OpenFile("./test/Book2.xlsx")
787
	if err != nil {
788
		t.Error(err)
789
	}
xurime's avatar
xurime 已提交
790
	s := strings.Repeat("c", 32768)
791 792
	xlsx.AddComment("Sheet1", "A30", `{"author":"`+s+`","text":"`+s+`"}`)
	xlsx.AddComment("Sheet2", "B7", `{"author":"Excelize: ","text":"This is a comment."}`)
793 794
	err = xlsx.Save()
	if err != nil {
795
		t.Error(err)
796 797 798
	}
}

799
func TestAutoFilter(t *testing.T) {
xurime's avatar
xurime 已提交
800
	xlsx, err := OpenFile("./test/Book2.xlsx")
801
	if err != nil {
802
		t.Error(err)
803
	}
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
	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*"}`,
		`{"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 _, format := range formats {
		err = xlsx.AutoFilter("Sheet3", "D4", "B1", format)
		t.Log(err)
	}
823 824
	err = xlsx.Save()
	if err != nil {
825
		t.Error(err)
826 827 828
	}
}

829
func TestAddChart(t *testing.T) {
xurime's avatar
xurime 已提交
830
	xlsx, err := OpenFile("./test/Book1.xlsx")
831
	if err != nil {
832
		t.Error(err)
833
	}
xurime's avatar
xurime 已提交
834 835 836 837 838 839 840 841
	categories := map[string]string{"A30": "Small", "A31": "Normal", "A32": "Large", "B29": "Apple", "C29": "Orange", "D29": "Pear"}
	values := map[string]int{"B30": 2, "C30": 3, "D30": 3, "B31": 5, "C31": 2, "D31": 4, "B32": 6, "C32": 7, "D32": 8}
	for k, v := range categories {
		xlsx.SetCellValue("Sheet1", k, v)
	}
	for k, v := range values {
		xlsx.SetCellValue("Sheet1", k, v)
	}
842 843 844 845 846 847 848
	xlsx.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "X1", `{"type":"colStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "P16", `{"type":"colPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 100% Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "X16", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit 3D Clustered Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "P30", `{"type":"col3DStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "X30", `{"type":"col3DPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet1", "P45", `{"type":"col3D","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
849 850
	xlsx.AddChart("Sheet2", "P1", `{"type":"radar","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"top_right","show_legend_key":false},"title":{"name":"Fruit Radar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"span"}`)
	xlsx.AddChart("Sheet2", "X1", `{"type":"scatter","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Scatter Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
851 852 853 854 855 856
	xlsx.AddChart("Sheet2", "P16", `{"type":"doughnut","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"right","show_legend_key":false},"title":{"name":"Fruit Doughnut Chart"},"plotarea":{"show_bubble_size":false,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":false,"show_val":false},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet2", "X16", `{"type":"line","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"top","show_legend_key":false},"title":{"name":"Fruit Line Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet2", "P32", `{"type":"pie3D","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit 3D Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":false,"show_val":false},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet2", "X32", `{"type":"pie","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":false,"show_val":false},"show_blanks_as":"gap"}`)
	xlsx.AddChart("Sheet2", "P48", `{"type":"bar","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Clustered Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
	xlsx.AddChart("Sheet2", "X48", `{"type":"barStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
857
	xlsx.AddChart("Sheet2", "P64", `{"type":"barPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked 100% Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
858
	xlsx.AddChart("Sheet2", "X64", `{"type":"bar3DClustered","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Clustered Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
859 860
	xlsx.AddChart("Sheet2", "P80", `{"type":"bar3DStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","y_axis":{"maximum":7.5,"minimum":0.5}}`)
	xlsx.AddChart("Sheet2", "X80", `{"type":"bar3DPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"reverse_order":true,"maximum":0,"minimum":0},"y_axis":{"reverse_order":true,"maximum":0,"minimum":0}}`)
861
	// Save xlsx file by the given path.
xurime's avatar
xurime 已提交
862
	err = xlsx.SaveAs("./test/Book_addchart.xlsx")
863
	if err != nil {
864
		t.Error(err)
865 866 867 868 869 870 871 872 873 874 875
	}
}

func TestInsertCol(t *testing.T) {
	xlsx := NewFile()
	for j := 1; j <= 10; j++ {
		for i := 0; i <= 10; i++ {
			axis := ToAlphaString(i) + strconv.Itoa(j)
			xlsx.SetCellStr("Sheet1", axis, axis)
		}
	}
876
	xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
877
	xlsx.MergeCell("Sheet1", "A1", "C3")
878 879 880
	err := xlsx.AutoFilter("Sheet1", "A2", "B2", `{"column":"B","expression":"x != blanks"}`)
	t.Log(err)
	xlsx.InsertCol("Sheet1", "A")
xurime's avatar
xurime 已提交
881
	err = xlsx.SaveAs("./test/Book_insertcol.xlsx")
882
	if err != nil {
883
		t.Error(err)
884 885 886 887 888 889 890 891 892 893 894
	}
}

func TestRemoveCol(t *testing.T) {
	xlsx := NewFile()
	for j := 1; j <= 10; j++ {
		for i := 0; i <= 10; i++ {
			axis := ToAlphaString(i) + strconv.Itoa(j)
			xlsx.SetCellStr("Sheet1", axis, axis)
		}
	}
895
	xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
896
	xlsx.SetCellHyperLink("Sheet1", "C5", "https://github.com", "External")
897 898
	xlsx.MergeCell("Sheet1", "A1", "B1")
	xlsx.MergeCell("Sheet1", "A2", "B2")
899 900
	xlsx.RemoveCol("Sheet1", "A")
	xlsx.RemoveCol("Sheet1", "A")
xurime's avatar
xurime 已提交
901
	err := xlsx.SaveAs("./test/Book_removecol.xlsx")
902
	if err != nil {
903
		t.Error(err)
904 905 906 907 908 909 910 911 912 913 914
	}
}

func TestInsertRow(t *testing.T) {
	xlsx := NewFile()
	for j := 1; j <= 10; j++ {
		for i := 0; i <= 10; i++ {
			axis := ToAlphaString(i) + strconv.Itoa(j)
			xlsx.SetCellStr("Sheet1", axis, axis)
		}
	}
915
	xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
916 917
	xlsx.InsertRow("Sheet1", -1)
	xlsx.InsertRow("Sheet1", 4)
xurime's avatar
xurime 已提交
918
	err := xlsx.SaveAs("./test/Book_insertrow.xlsx")
919
	if err != nil {
920
		t.Error(err)
921 922 923
	}
}

xurime's avatar
xurime 已提交
924 925 926
func TestSetPane(t *testing.T) {
	xlsx := NewFile()
	xlsx.SetPanes("Sheet1", `{"freeze":false,"split":false}`)
927 928 929 930 931 932
	xlsx.NewSheet("Panes 2")
	xlsx.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"}]}`)
	xlsx.NewSheet("Panes 3")
	xlsx.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"}]}`)
	xlsx.NewSheet("Panes 4")
	xlsx.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"}]}`)
xurime's avatar
xurime 已提交
933
	err := xlsx.SaveAs("./test/Book_set_panes.xlsx")
xurime's avatar
xurime 已提交
934
	if err != nil {
935
		t.Error(err)
xurime's avatar
xurime 已提交
936 937 938
	}
}

939 940 941 942 943 944 945 946
func TestRemoveRow(t *testing.T) {
	xlsx := NewFile()
	for j := 1; j <= 10; j++ {
		for i := 0; i <= 10; i++ {
			axis := ToAlphaString(i) + strconv.Itoa(j)
			xlsx.SetCellStr("Sheet1", axis, axis)
		}
	}
947
	xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
948 949
	xlsx.RemoveRow("Sheet1", -1)
	xlsx.RemoveRow("Sheet1", 4)
950
	xlsx.MergeCell("Sheet1", "B3", "B5")
951 952 953 954 955 956 957
	xlsx.RemoveRow("Sheet1", 2)
	xlsx.RemoveRow("Sheet1", 4)
	err := xlsx.AutoFilter("Sheet1", "A2", "A2", `{"column":"A","expression":"x != blanks"}`)
	t.Log(err)
	xlsx.RemoveRow("Sheet1", 0)
	xlsx.RemoveRow("Sheet1", 1)
	xlsx.RemoveRow("Sheet1", 0)
xurime's avatar
xurime 已提交
958
	err = xlsx.SaveAs("./test/Book_removerow.xlsx")
959
	if err != nil {
960
		t.Error(err)
961 962
	}
}
963 964 965 966

func TestConditionalFormat(t *testing.T) {
	xlsx := NewFile()
	for j := 1; j <= 10; j++ {
967
		for i := 0; i <= 15; i++ {
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
			xlsx.SetCellInt("Sheet1", ToAlphaString(i)+strconv.Itoa(j), j)
		}
	}
	var format1, format2, format3 int
	var err error
	// Rose format for bad conditional.
	format1, err = xlsx.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
	t.Log(err)
	// Light yellow format for neutral conditional.
	format2, err = xlsx.NewConditionalStyle(`{"fill":{"type":"pattern","color":["#FEEAA0"],"pattern":1}}`)
	t.Log(err)
	// Light green format for good conditional.
	format3, err = xlsx.NewConditionalStyle(`{"font":{"color":"#09600B"},"fill":{"type":"pattern","color":["#C7EECF"],"pattern":1}}`)
	t.Log(err)
	// Color scales: 2 color.
	xlsx.SetConditionalFormat("Sheet1", "A1:A10", `[{"type":"2_color_scale","criteria":"=","min_type":"min","max_type":"max","min_color":"#F8696B","max_color":"#63BE7B"}]`)
	// Color scales: 3 color.
	xlsx.SetConditionalFormat("Sheet1", "B1:B10", `[{"type":"3_color_scale","criteria":"=","min_type":"min","mid_type":"percentile","max_type":"max","min_color":"#F8696B","mid_color":"#FFEB84","max_color":"#63BE7B"}]`)
	// Hightlight cells rules: between...
	xlsx.SetConditionalFormat("Sheet1", "C1:C10", fmt.Sprintf(`[{"type":"cell","criteria":"between","format":%d,"minimum":"6","maximum":"8"}]`, format1))
	// Hightlight cells rules: Greater Than...
	xlsx.SetConditionalFormat("Sheet1", "D1:D10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format3))
	// Hightlight cells rules: Equal To...
	xlsx.SetConditionalFormat("Sheet1", "E1:E10", fmt.Sprintf(`[{"type":"top","criteria":"=","format":%d}]`, format3))
	// Hightlight cells rules: Not Equal To...
	xlsx.SetConditionalFormat("Sheet1", "F1:F10", fmt.Sprintf(`[{"type":"unique","criteria":"=","format":%d}]`, format2))
	// Hightlight cells rules: Duplicate Values...
	xlsx.SetConditionalFormat("Sheet1", "G1:G10", fmt.Sprintf(`[{"type":"duplicate","criteria":"=","format":%d}]`, format2))
	// Top/Bottom rules: Top 10%.
	xlsx.SetConditionalFormat("Sheet1", "H1:H10", fmt.Sprintf(`[{"type":"top","criteria":"=","format":%d,"value":"6","percent":true}]`, format1))
	// Top/Bottom rules: Above Average...
	xlsx.SetConditionalFormat("Sheet1", "I1:I10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": true}]`, format3))
	// Top/Bottom rules: Below Average...
	xlsx.SetConditionalFormat("Sheet1", "J1:J10", fmt.Sprintf(`[{"type":"average","criteria":"=","format":%d, "above_average": false}]`, format1))
	// Data Bars: Gradient Fill.
	xlsx.SetConditionalFormat("Sheet1", "K1:K10", `[{"type":"data_bar", "criteria":"=", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`)
1004 1005
	// Use a formula to determine which cells to format.
	xlsx.SetConditionalFormat("Sheet1", "L1:L10", fmt.Sprintf(`[{"type":"formula", "criteria":"L2<3", "format":%d}]`, format1))
xurime's avatar
xurime 已提交
1006
	err = xlsx.SaveAs("./test/Book_conditional_format.xlsx")
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
	if err != nil {
		t.Log(err)
	}

	// Set conditional format with illegal JSON string.
	_, err = xlsx.NewConditionalStyle("")
	t.Log(err)
	// Set conditional format with illegal valid type.
	xlsx.SetConditionalFormat("Sheet1", "K1:K10", `[{"type":"", "criteria":"=", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`)
	// Set conditional format with illegal criteria type.
	xlsx.SetConditionalFormat("Sheet1", "K1:K10", `[{"type":"data_bar", "criteria":"", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`)
	// Set conditional format with file without dxfs element.
xurime's avatar
xurime 已提交
1019
	xlsx, err = OpenFile("./test/Book1.xlsx")
1020 1021 1022 1023
	t.Log(err)
	_, err = xlsx.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
	t.Log(err)
}
xurime's avatar
xurime 已提交
1024 1025 1026 1027 1028 1029 1030 1031 1032

func TestTitleToNumber(t *testing.T) {
	if TitleToNumber("AK") != 36 {
		t.Error("Conver title to number failed")
	}
	if TitleToNumber("ak") != 36 {
		t.Error("Conver title to number failed")
	}
}
1033 1034 1035 1036

func TestSharedStrings(t *testing.T) {
	xlsx, err := OpenFile("./test/SharedStrings.xlsx")
	if err != nil {
1037
		t.Error(err)
1038 1039 1040 1041
		return
	}
	xlsx.GetRows("Sheet1")
}
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

func TestSetSheetRow(t *testing.T) {
	xlsx, err := OpenFile("./test/Book1.xlsx")
	if err != nil {
		t.Error(err)
		return
	}
	xlsx.SetSheetRow("Sheet1", "B27", &[]interface{}{"cell", nil, int32(42), float64(42), time.Now()})
	xlsx.SetSheetRow("Sheet1", "", &[]interface{}{"cell", nil, 2})
	xlsx.SetSheetRow("Sheet1", "B27", []interface{}{})
	xlsx.SetSheetRow("Sheet1", "B27", &xlsx)
	err = xlsx.Save()
	if err != nil {
		t.Error(err)
		return
	}
}
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098

func TestRows(t *testing.T) {
	xlsx, err := OpenFile("./test/Book1.xlsx")
	if err != nil {
		t.Error(err)
		return
	}
	rows, err := xlsx.Rows("Sheet2")
	if err != nil {
		t.Error(err)
		return
	}
	rowStrs := make([][]string, 0)
	var i = 0
	for rows.Next() {
		i++
		columns := rows.Columns()
		rowStrs = append(rowStrs, columns)
	}
	if rows.Error() != nil {
		t.Error(rows.Error())
		return
	}
	dstRows := xlsx.GetRows("Sheet2")
	if len(dstRows) != len(rowStrs) {
		t.Error("values not equal")
		return
	}
	for i := 0; i < len(rowStrs); i++ {
		if !reflect.DeepEqual(trimSliceSpace(dstRows[i]), trimSliceSpace(rowStrs[i])) {
			t.Error("values not equal")
			return
		}
	}
	rows, err = xlsx.Rows("SheetN")
	if err != nil {
		t.Log(err)
	}
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
func TestOutlineLevel(t *testing.T) {
	xlsx := NewFile()
	xlsx.NewSheet("Sheet2")
	xlsx.SetColOutlineLevel("Sheet1", "D", 4)
	xlsx.GetColOutlineLevel("Sheet1", "D")
	xlsx.GetColOutlineLevel("Shee2", "A")
	xlsx.SetColWidth("Sheet2", "A", "D", 13)
	xlsx.SetColOutlineLevel("Sheet2", "B", 2)
	xlsx.SetRowOutlineLevel("Sheet1", 2, 1)
	xlsx.GetRowOutlineLevel("Sheet1", 2)
	err := xlsx.SaveAs("./test/Book_outline_level.xlsx")
	if err != nil {
		t.Error(err)
		return
	}
	xlsx, err = OpenFile("./test/Book1.xlsx")
	if err != nil {
		t.Error(err)
		return
	}
	xlsx.SetColOutlineLevel("Sheet2", "B", 2)
}

1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
func trimSliceSpace(s []string) []string {
	for {
		if len(s) > 0 && s[len(s)-1] == "" {
			s = s[:len(s)-1]
		} else {
			break
		}
	}
	return s
}