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

import (
4
	"archive/zip"
5
	"bytes"
xurime's avatar
xurime 已提交
6 7
	"compress/gzip"
	"encoding/xml"
8
	"fmt"
xurime's avatar
xurime 已提交
9
	"image/color"
10 11 12
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
13
	"io"
14
	"math"
V
Veniamin Albaev 已提交
15
	"os"
16
	"path/filepath"
xurime's avatar
xurime 已提交
17
	"strconv"
xurime's avatar
xurime 已提交
18
	"strings"
xurime's avatar
xurime 已提交
19
	"sync"
xurime's avatar
xurime 已提交
20
	"testing"
21
	"time"
V
Veniamin Albaev 已提交
22 23

	"github.com/stretchr/testify/assert"
xurime's avatar
xurime 已提交
24 25
)

26
func TestOpenFile(t *testing.T) {
27
	// Test update the spreadsheet file
28
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
29
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
30

31
	// Test get all the rows in a not exists worksheet
32
	_, err = f.GetRows("Sheet4")
33
	assert.EqualError(t, err, "sheet Sheet4 does not exist")
34 35 36 37
	// Test get all the rows with invalid sheet name
	_, err = f.GetRows("Sheet:1")
	assert.EqualError(t, err, ErrSheetNameInvalid.Error())
	// Test get all the rows in a worksheet
38
	rows, err := f.GetRows("Sheet2")
39 40 41 42 43 44 45 46 47 48 49 50
	expected := [][]string{
		{"Monitor", "", "Brand", "", "inlineStr"},
		{"> 23 Inch", "19", "HP", "200"},
		{"20-23 Inch", "24", "DELL", "450"},
		{"17-20 Inch", "56", "Lenove", "200"},
		{"< 17 Inch", "21", "SONY", "510"},
		{"", "", "Acer", "315"},
		{"", "", "IBM", "127"},
		{"", "", "ASUS", "89"},
		{"", "", "Apple", "348"},
		{"", "", "SAMSUNG", "53"},
		{"", "", "Other", "37", "", "", "", "", ""},
51
	}
52 53 54
	assert.NoError(t, err)
	assert.Equal(t, expected, rows)

55
	assert.NoError(t, f.UpdateLinkedValue())
56

57 58
	assert.NoError(t, f.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(100.1588, 'f', -1, 32)))
	assert.NoError(t, f.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(-100.1588, 'f', -1, 64)))
59 60 61
	// Test set cell value with invalid sheet name
	assert.EqualError(t, f.SetCellDefault("Sheet:1", "A1", ""), ErrSheetNameInvalid.Error())
	// Test set cell value with illegal row number
62
	assert.EqualError(t, f.SetCellDefault("Sheet2", "A", strconv.FormatFloat(-100.1588, 'f', -1, 64)),
63
		newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
64

65
	assert.NoError(t, f.SetCellInt("Sheet2", "A1", 100))
66

67
	// Test set cell integer value with illegal row number
68
	assert.EqualError(t, f.SetCellInt("Sheet2", "A", 100), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
69 70
	// Test set cell integer value with invalid sheet name
	assert.EqualError(t, f.SetCellInt("Sheet:1", "A1", 100), ErrSheetNameInvalid.Error())
71

72
	assert.NoError(t, f.SetCellStr("Sheet2", "C11", "Knowns"))
73
	// Test max characters in a cell
74
	assert.NoError(t, f.SetCellStr("Sheet2", "D11", strings.Repeat("c", TotalCellChars+2)))
75 76
	_, err = f.NewSheet(":\\/?*[]Maximum 31 characters allowed in sheet title.")
	assert.EqualError(t, err, ErrSheetNameLength.Error())
77
	// Test set worksheet name with illegal name
78
	assert.EqualError(t, f.SetSheetName("Maximum 31 characters allowed i", "[Rename]:\\/?* Maximum 31 characters allowed in sheet title."), ErrSheetNameLength.Error())
79 80 81
	assert.EqualError(t, f.SetCellInt("Sheet3", "A23", 10), "sheet Sheet3 does not exist")
	assert.EqualError(t, f.SetCellStr("Sheet3", "b230", "10"), "sheet Sheet3 does not exist")
	assert.EqualError(t, f.SetCellStr("Sheet10", "b230", "10"), "sheet Sheet10 does not exist")
82 83 84
	// Test set cell string data type value with invalid sheet name
	assert.EqualError(t, f.SetCellStr("Sheet:1", "A1", "1"), ErrSheetNameInvalid.Error())
	// Test set cell string value with illegal row number
85
	assert.EqualError(t, f.SetCellStr("Sheet1", "A", "10"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
86

87
	f.SetActiveSheet(2)
88
	// Test get cell formula with given rows number
89
	_, err = f.GetCellFormula("Sheet1", "B19")
90
	assert.NoError(t, err)
91
	// Test get cell formula with illegal worksheet name
92
	_, err = f.GetCellFormula("Sheet2", "B20")
93
	assert.NoError(t, err)
94
	_, err = f.GetCellFormula("Sheet1", "B20")
95
	assert.NoError(t, err)
96

97
	// Test get cell formula with illegal rows number
98
	_, err = f.GetCellFormula("Sheet1", "B")
99
	assert.EqualError(t, err, newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
100
	// Test get shared cell formula
101 102 103 104
	_, err = f.GetCellFormula("Sheet2", "H11")
	assert.NoError(t, err)
	_, err = f.GetCellFormula("Sheet2", "I11")
	assert.NoError(t, err)
105
	getSharedFormula(&xlsxWorksheet{}, 0, "")
106

107
	// Test read cell value with given illegal rows number
108
	_, err = f.GetCellValue("Sheet2", "a-1")
109
	assert.EqualError(t, err, newCellNameToCoordinatesError("A-1", newInvalidCellNameError("A-1")).Error())
110
	_, err = f.GetCellValue("Sheet2", "A")
111
	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
112

113
	// Test read cell value with given lowercase column number
114 115 116 117 118 119 120 121
	_, err = f.GetCellValue("Sheet2", "a5")
	assert.NoError(t, err)
	_, err = f.GetCellValue("Sheet2", "C11")
	assert.NoError(t, err)
	_, err = f.GetCellValue("Sheet2", "D11")
	assert.NoError(t, err)
	_, err = f.GetCellValue("Sheet2", "D12")
	assert.NoError(t, err)
122
	// Test SetCellValue function
123 124 125 126 127 128 129 130
	assert.NoError(t, f.SetCellValue("Sheet2", "F1", " Hello"))
	assert.NoError(t, f.SetCellValue("Sheet2", "G1", []byte("World")))
	assert.NoError(t, f.SetCellValue("Sheet2", "F2", 42))
	assert.NoError(t, f.SetCellValue("Sheet2", "F3", int8(1<<8/2-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F4", int16(1<<16/2-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F5", int32(1<<32/2-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F6", int64(1<<32/2-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F7", float32(42.65418)))
131
	assert.NoError(t, f.SetCellValue("Sheet2", "F8", -42.65418))
132 133 134 135 136 137 138 139 140
	assert.NoError(t, f.SetCellValue("Sheet2", "F9", float32(42)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F10", float64(42)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F11", uint(1<<32-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F12", uint8(1<<8-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F13", uint16(1<<16-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F14", uint32(1<<32-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F15", uint64(1<<32-1)))
	assert.NoError(t, f.SetCellValue("Sheet2", "F16", true))
	assert.NoError(t, f.SetCellValue("Sheet2", "F17", complex64(5+10i)))
xurime's avatar
xurime 已提交
141

142
	// Test on not exists worksheet
143 144 145 146 147
	assert.EqualError(t, f.SetCellDefault("SheetN", "A1", ""), "sheet SheetN does not exist")
	assert.EqualError(t, f.SetCellFloat("SheetN", "A1", 42.65418, 2, 32), "sheet SheetN does not exist")
	assert.EqualError(t, f.SetCellBool("SheetN", "A1", true), "sheet SheetN does not exist")
	assert.EqualError(t, f.SetCellFormula("SheetN", "A1", ""), "sheet SheetN does not exist")
	assert.EqualError(t, f.SetCellHyperLink("SheetN", "A1", "Sheet1!A40", "Location"), "sheet SheetN does not exist")
148

149
	// Test boolean write
150
	boolTest := []struct {
151
		value    bool
152
		raw      bool
153 154
		expected string
	}{
155 156 157 158
		{false, true, "0"},
		{true, true, "1"},
		{false, false, "FALSE"},
		{true, false, "TRUE"},
159
	}
160
	for _, test := range boolTest {
161
		assert.NoError(t, f.SetCellValue("Sheet2", "F16", test.value))
162
		val, err := f.GetCellValue("Sheet2", "F16", Options{RawCellValue: test.raw})
163 164
		assert.NoError(t, err)
		assert.Equal(t, test.expected, val)
165
	}
166

167
	assert.NoError(t, f.SetCellValue("Sheet2", "G2", nil))
168

169
	assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now()))
170

171
	assert.NoError(t, f.SetCellValue("Sheet2", "G4", time.Now().UTC()))
172
	assert.EqualError(t, f.SetCellValue("SheetN", "A1", time.Now()), "sheet SheetN does not exist")
173
	// 02:46:40
174
	assert.NoError(t, f.SetCellValue("Sheet2", "G5", time.Duration(1e13)))
175
	// Test completion column
176
	assert.NoError(t, f.SetCellValue("Sheet2", "M2", nil))
177
	// Test read cell value with given cell reference large than exists row
178 179
	_, err = f.GetCellValue("Sheet2", "E231")
	assert.NoError(t, err)
180 181
	// Test get active worksheet of spreadsheet and get worksheet name of
	// spreadsheet by given worksheet index
182
	f.GetSheetName(f.GetActiveSheetIndex())
183
	// Test get worksheet index of spreadsheet by given worksheet name
184 185
	_, err = f.GetSheetIndex("Sheet1")
	assert.NoError(t, err)
186
	// Test get worksheet name of spreadsheet by given invalid worksheet index
187
	f.GetSheetName(4)
188
	// Test get worksheet map of workbook
189
	f.GetSheetMap()
190
	for i := 1; i <= 300; i++ {
191
		assert.NoError(t, f.SetCellStr("Sheet2", "c"+strconv.Itoa(i), strconv.Itoa(i)))
192
	}
193
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestOpenFile.xlsx")))
194
	assert.EqualError(t, f.SaveAs(filepath.Join("test", strings.Repeat("c", 199), ".xlsx")), ErrMaxFilePathLength.Error())
195
	assert.NoError(t, f.Close())
V
Veniamin Albaev 已提交
196 197
}

xurime's avatar
xurime 已提交
198
func TestSaveFile(t *testing.T) {
199
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
200
	assert.NoError(t, err)
201
	assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestSaveFile.xlsb")), ErrWorkbookFileFormat.Error())
202 203 204
	for _, ext := range []string{".xlam", ".xlsm", ".xlsx", ".xltm", ".xltx"} {
		assert.NoError(t, f.SaveAs(filepath.Join("test", fmt.Sprintf("TestSaveFile%s", ext))))
	}
205
	assert.NoError(t, f.Close())
206

207
	f, err = OpenFile(filepath.Join("test", "TestSaveFile.xlsx"))
208
	assert.NoError(t, err)
209
	assert.NoError(t, f.Save())
210
	assert.NoError(t, f.Close())
xurime's avatar
xurime 已提交
211 212
}

V
Veniamin Albaev 已提交
213
func TestSaveAsWrongPath(t *testing.T) {
214
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
xurime's avatar
xurime 已提交
215
	assert.NoError(t, err)
216
	// Test write file to not exist directory
217
	assert.Error(t, f.SaveAs(filepath.Join("x", "Book1.xlsx")))
218
	assert.NoError(t, f.Close())
219 220
}

xurime's avatar
xurime 已提交
221 222 223 224 225
func TestCharsetTranscoder(t *testing.T) {
	f := NewFile()
	f.CharsetTranscoder(*new(charsetTranscoderFn))
}

226 227
func TestOpenReader(t *testing.T) {
	_, err := OpenReader(strings.NewReader(""))
228
	assert.EqualError(t, err, zip.ErrFormat.Error())
229
	_, err = OpenReader(bytes.NewReader(oleIdentifier), Options{Password: "password", UnzipXMLSizeLimit: UnzipSizeLimit + 1})
230
	assert.EqualError(t, err, ErrWorkbookFileFormat.Error())
231

232 233 234
	// Prepare unusual workbook, made the specified internal XML parts missing
	// or contain unsupported charset
	preset := func(filePath string, notExist bool) *bytes.Buffer {
235
		source, err := zip.OpenReader(filepath.Join("test", "Book1.xlsx"))
236
		assert.NoError(t, err)
237 238 239 240
		buf := new(bytes.Buffer)
		zw := zip.NewWriter(buf)
		for _, item := range source.File {
			// The following statements can be simplified as zw.Copy(item) in go1.17
241 242 243
			if notExist && item.Name == filePath {
				continue
			}
244 245 246 247 248 249 250
			writer, err := zw.Create(item.Name)
			assert.NoError(t, err)
			readerCloser, err := item.Open()
			assert.NoError(t, err)
			_, err = io.Copy(writer, readerCloser)
			assert.NoError(t, err)
		}
251 252 253 254 255 256
		if !notExist {
			fi, err := zw.Create(filePath)
			assert.NoError(t, err)
			_, err = fi.Write(MacintoshCyrillicCharset)
			assert.NoError(t, err)
		}
257 258 259
		assert.NoError(t, zw.Close())
		return buf
	}
260
	// Test open workbook with unsupported charset internal XML parts
261 262 263
	for _, defaultXMLPath := range []string{
		defaultXMLPathCalcChain,
		defaultXMLPathStyles,
264 265
		defaultXMLPathWorkbookRels,
	} {
266
		_, err = OpenReader(preset(defaultXMLPath, false))
267
		assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
268
	}
269 270 271 272 273 274 275 276 277
	// Test open workbook without internal XML parts
	for _, defaultXMLPath := range []string{
		defaultXMLPathCalcChain,
		defaultXMLPathStyles,
		defaultXMLPathWorkbookRels,
	} {
		_, err = OpenReader(preset(defaultXMLPath, true))
		assert.NoError(t, err)
	}
278

279
	// Test open spreadsheet with unzip size limit
xurime's avatar
xurime 已提交
280 281 282
	_, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipSizeLimit: 100})
	assert.EqualError(t, err, newUnzipSizeLimitError(100).Error())

283
	// Test open password protected spreadsheet created by Microsoft Office Excel 2010
284 285 286 287 288
	f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
	assert.NoError(t, err)
	val, err := f.GetCellValue("Sheet1", "A1")
	assert.NoError(t, err)
	assert.Equal(t, "SECRET", val)
289
	assert.NoError(t, f.Close())
xurime's avatar
xurime 已提交
290

291
	// Test open password protected spreadsheet created by LibreOffice 7.0.0.3
292 293 294 295 296
	f, err = OpenFile(filepath.Join("test", "encryptAES.xlsx"), Options{Password: "password"})
	assert.NoError(t, err)
	val, err = f.GetCellValue("Sheet1", "A1")
	assert.NoError(t, err)
	assert.Equal(t, "SECRET", val)
297 298
	assert.NoError(t, f.Close())

299
	// Test open spreadsheet with invalid options
300
	_, err = OpenReader(bytes.NewReader(oleIdentifier), Options{UnzipSizeLimit: 1, UnzipXMLSizeLimit: 2})
301
	assert.EqualError(t, err, ErrOptionsUnzipSizeLimit.Error())
302

303
	// Test unexpected EOF
xurime's avatar
xurime 已提交
304 305 306 307 308 309 310 311 312 313
	var b bytes.Buffer
	w := gzip.NewWriter(&b)
	defer w.Close()
	w.Flush()

	r, _ := gzip.NewReader(&b)
	defer r.Close()

	_, err = OpenReader(r)
	assert.EqualError(t, err, "unexpected EOF")
xurime's avatar
xurime 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

	_, err = OpenReader(bytes.NewReader([]byte{
		0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x09, 0x00, 0x63, 0x00, 0x47, 0xa3, 0xb6, 0x50, 0x00, 0x00,
		0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x70, 0x61,
		0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x01, 0x99, 0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00,
		0x00, 0x21, 0x06, 0x59, 0xc0, 0x12, 0xf3, 0x19, 0xc7, 0x51, 0xd1, 0xc9, 0x31, 0xcb, 0xcc, 0x8a,
		0xe1, 0x44, 0xe1, 0x56, 0x20, 0x24, 0x1f, 0xba, 0x09, 0xda, 0x53, 0xd5, 0xef, 0x50, 0x4b, 0x07,
		0x08, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01,
		0x02, 0x1f, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x63, 0x00, 0x47, 0xa3, 0xb6, 0x50, 0x00, 0x00, 0x00,
		0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x73, 0x73, 0x77,
		0x6f, 0x72, 0x64, 0x01, 0x99, 0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00, 0x50, 0x4b,
		0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x5d, 0x00,
		0x00, 0x00, 0x00, 0x00,
	}))
329
	assert.EqualError(t, err, zip.ErrAlgorithm.Error())
330 331
}

332
func TestBrokenFile(t *testing.T) {
333
	// Test write file with broken file struct
334
	f := File{}
xurime's avatar
xurime 已提交
335

V
Veniamin Albaev 已提交
336
	t.Run("SaveWithoutName", func(t *testing.T) {
337
		assert.EqualError(t, f.Save(), "no path defined for file, consider File.WriteTo or File.Write")
V
Veniamin Albaev 已提交
338
	})
339

V
Veniamin Albaev 已提交
340
	t.Run("SaveAsEmptyStruct", func(t *testing.T) {
341
		// Test write file with broken file struct with given path
342
		assert.NoError(t, f.SaveAs(filepath.Join("test", "BadWorkbook.SaveAsEmptyStruct.xlsx")))
V
Veniamin Albaev 已提交
343 344 345
	})

	t.Run("OpenBadWorkbook", func(t *testing.T) {
346
		// Test set active sheet without BookViews and Sheets maps in xl/workbook.xml
347
		f3, err := OpenFile(filepath.Join("test", "BadWorkbook.xlsx"))
V
Veniamin Albaev 已提交
348
		f3.GetActiveSheetIndex()
349
		f3.SetActiveSheet(1)
V
Veniamin Albaev 已提交
350
		assert.NoError(t, err)
351
		assert.NoError(t, f3.Close())
V
Veniamin Albaev 已提交
352 353 354
	})

	t.Run("OpenNotExistsFile", func(t *testing.T) {
355
		// Test open a spreadsheet file with given illegal path
356
		_, err := OpenFile(filepath.Join("test", "NotExistsFile.xlsx"))
V
Veniamin Albaev 已提交
357 358 359 360
		if assert.Error(t, err) {
			assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true")
		}
	})
361 362
}

363
func TestNewFile(t *testing.T) {
364
	// Test create a spreadsheet file
365
	f := NewFile()
366 367 368 369 370 371
	_, err := f.NewSheet("Sheet1")
	assert.NoError(t, err)
	_, err = f.NewSheet("XLSXSheet2")
	assert.NoError(t, err)
	_, err = f.NewSheet("XLSXSheet3")
	assert.NoError(t, err)
372 373
	assert.NoError(t, f.SetCellInt("XLSXSheet2", "A23", 56))
	assert.NoError(t, f.SetCellStr("Sheet1", "B20", "42"))
374
	f.SetActiveSheet(0)
V
Veniamin Albaev 已提交
375

376
	// Test add picture to sheet with scaling and positioning
377
	assert.NoError(t, f.AddPicture("Sheet1", "H2", filepath.Join("test", "images", "excel.gif"),
xurime's avatar
xurime 已提交
378
		&GraphicOptions{ScaleX: 0.5, ScaleY: 0.5, Positioning: "absolute"}))
V
Veniamin Albaev 已提交
379

380
	// Test add picture to worksheet without options
381
	assert.NoError(t, f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), nil))
V
Veniamin Albaev 已提交
382

383
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestNewFile.xlsx")))
384
	assert.NoError(t, f.Save())
xurime's avatar
xurime 已提交
385
}
386

387
func TestSetCellHyperLink(t *testing.T) {
388
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
389
	assert.NoError(t, err)
390
	// Test set cell hyperlink in a work sheet already have hyperlinks
391
	assert.NoError(t, f.SetCellHyperLink("Sheet1", "B19", "https://github.com/xuri/excelize", "External"))
392
	// Test add first hyperlink in a work sheet
393
	assert.NoError(t, f.SetCellHyperLink("Sheet2", "C1", "https://github.com/xuri/excelize", "External"))
394
	// Test add Location hyperlink in a work sheet
395
	assert.NoError(t, f.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location"))
396
	// Test add Location hyperlink with display & tooltip in a work sheet
397
	display, tooltip := "Display value", "Hover text"
398 399 400 401
	assert.NoError(t, f.SetCellHyperLink("Sheet2", "D7", "Sheet1!D9", "Location", HyperlinkOpts{
		Display: &display,
		Tooltip: &tooltip,
	}))
402
	// Test set cell hyperlink with invalid sheet name
403 404
	assert.Equal(t, ErrSheetNameInvalid, f.SetCellHyperLink("Sheet:1", "A1", "Sheet1!D60", "Location"))
	assert.Equal(t, newInvalidLinkTypeError(""), f.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", ""))
405 406
	assert.EqualError(t, f.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location"), `invalid cell name ""`)
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellHyperLink.xlsx")))
407
	assert.NoError(t, f.Close())
408

409
	f = NewFile()
410 411
	_, err = f.workSheetReader("Sheet1")
	assert.NoError(t, err)
412 413 414
	ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
	assert.True(t, ok)
	ws.(*xlsxWorksheet).Hyperlinks = &xlsxHyperlinks{Hyperlink: make([]xlsxHyperlink, 65530)}
415
	assert.EqualError(t, f.SetCellHyperLink("Sheet1", "A65531", "https://github.com/xuri/excelize", "External"), ErrTotalSheetHyperlinks.Error())
416 417

	f = NewFile()
418 419
	_, err = f.workSheetReader("Sheet1")
	assert.NoError(t, err)
420 421 422
	ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
	assert.True(t, ok)
	ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:A"}}}
423
	err = f.SetCellHyperLink("Sheet1", "A1", "https://github.com/xuri/excelize", "External")
424
	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
425 426 427 428 429 430 431 432 433

	// Test update cell hyperlink
	f = NewFile()
	assert.NoError(t, f.SetCellHyperLink("Sheet1", "A1", "https://github.com", "External"))
	assert.NoError(t, f.SetCellHyperLink("Sheet1", "A1", "https://github.com/xuri/excelize", "External"))
	link, target, err := f.GetCellHyperLink("Sheet1", "A1")
	assert.Equal(t, link, true)
	assert.Equal(t, "https://github.com/xuri/excelize", target)
	assert.NoError(t, err)
434 435
}

436
func TestGetCellHyperLink(t *testing.T) {
437
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
438
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
439

440
	_, _, err = f.GetCellHyperLink("Sheet1", "")
441
	assert.EqualError(t, err, `invalid cell name ""`)
442

443
	link, target, err := f.GetCellHyperLink("Sheet1", "A22")
444
	assert.NoError(t, err)
445 446 447
	assert.Equal(t, link, true)
	assert.Equal(t, target, "https://github.com/xuri/excelize")

448
	link, target, err = f.GetCellHyperLink("Sheet2", "D6")
449
	assert.NoError(t, err)
450 451 452
	assert.Equal(t, link, false)
	assert.Equal(t, target, "")

453
	link, target, err = f.GetCellHyperLink("Sheet3", "H3")
454
	assert.EqualError(t, err, "sheet Sheet3 does not exist")
455 456 457
	assert.Equal(t, link, false)
	assert.Equal(t, target, "")

458
	assert.NoError(t, f.Close())
459 460

	f = NewFile()
461 462
	_, err = f.workSheetReader("Sheet1")
	assert.NoError(t, err)
463 464 465
	ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
	assert.True(t, ok)
	ws.(*xlsxWorksheet).Hyperlinks = &xlsxHyperlinks{
466 467 468 469 470 471 472
		Hyperlink: []xlsxHyperlink{{Ref: "A1"}},
	}
	link, target, err = f.GetCellHyperLink("Sheet1", "A1")
	assert.NoError(t, err)
	assert.Equal(t, link, true)
	assert.Equal(t, target, "")

473 474
	ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
	assert.True(t, ok)
475
	ws.(*xlsxWorksheet).Hyperlinks = &xlsxHyperlinks{Hyperlink: []xlsxHyperlink{{Ref: "A:A"}}}
476
	link, target, err = f.GetCellHyperLink("Sheet1", "A1")
477
	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
478 479
	assert.Equal(t, link, false)
	assert.Equal(t, target, "")
480 481 482 483

	// Test get cell hyperlink with invalid sheet name
	_, _, err = f.GetCellHyperLink("Sheet:1", "A1")
	assert.EqualError(t, err, ErrSheetNameInvalid.Error())
484 485
}

486
func TestSetSheetBackground(t *testing.T) {
487
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
488 489 490
	assert.NoError(t, err)
	assert.NoError(t, f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")))
	assert.NoError(t, f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")))
491
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetBackground.xlsx")))
492
	assert.NoError(t, f.Close())
V
Veniamin Albaev 已提交
493 494 495
}

func TestSetSheetBackgroundErrors(t *testing.T) {
496
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
497
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
498

499
	err = f.SetSheetBackground("Sheet2", filepath.Join("test", "not_exists", "not_exists.png"))
V
Veniamin Albaev 已提交
500 501 502 503
	if assert.Error(t, err) {
		assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true")
	}

504
	err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
505
	assert.EqualError(t, err, ErrImgExt.Error())
506
	// Test set sheet background on not exist worksheet
507 508
	err = f.SetSheetBackground("SheetN", filepath.Join("test", "images", "background.jpg"))
	assert.EqualError(t, err, "sheet SheetN does not exist")
509 510
	// Test set sheet background with invalid sheet name
	assert.EqualError(t, f.SetSheetBackground("Sheet:1", filepath.Join("test", "images", "background.jpg")), ErrSheetNameInvalid.Error())
511
	assert.NoError(t, f.Close())
512

513
	// Test set sheet background with unsupported charset content types
514 515 516 517
	f = NewFile()
	f.ContentTypes = nil
	f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
	assert.EqualError(t, f.SetSheetBackground("Sheet1", filepath.Join("test", "images", "background.jpg")), "XML syntax error on line 1: invalid UTF-8")
518
}
xurime's avatar
xurime 已提交
519

520 521 522
// TestWriteArrayFormula tests the extended options of SetCellFormula by writing
// an array function to a workbook. In the resulting file, the lines 2 and 3 as
// well as 4 and 5 should have matching contents
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
func TestWriteArrayFormula(t *testing.T) {
	cell := func(col, row int) string {
		c, err := CoordinatesToCellName(col, row)
		if err != nil {
			t.Fatal(err)
		}
		return c
	}

	f := NewFile()

	sample := []string{"Sample 1", "Sample 2", "Sample 3"}
	values := []int{1855, 1709, 1462, 1115, 1524, 625, 773, 126, 1027, 1696, 1078, 1917, 1109, 1753, 1884, 659, 994, 1911, 1925, 899, 196, 244, 1488, 1056, 1986, 66, 784, 725, 767, 1722, 1541, 1026, 1455, 264, 1538, 877, 1581, 1098, 383, 762, 237, 493, 29, 1923, 474, 430, 585, 688, 308, 200, 1259, 622, 798, 1048, 996, 601, 582, 332, 377, 805, 250, 1860, 1360, 840, 911, 1346, 1651, 1651, 665, 584, 1057, 1145, 925, 1752, 202, 149, 1917, 1398, 1894, 818, 714, 624, 1085, 1566, 635, 78, 313, 1686, 1820, 494, 614, 1913, 271, 1016, 338, 1301, 489, 1733, 1483, 1141}
	assoc := []int{2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 2, 0, 2, 1, 2, 2, 2, 1, 0, 1, 0, 1, 1, 2, 0, 2, 1, 0, 2, 1, 0, 1, 0, 0, 2, 0, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 0, 1, 0, 2, 0, 0, 1, 2, 1, 0, 1, 0, 0, 2, 1, 1, 2, 0, 2, 1, 0, 2, 2, 2, 1, 0, 0, 1, 1, 1, 2, 0, 2, 0, 1, 1}
	if len(values) != len(assoc) {
		t.Fatal("values and assoc must be of same length")
	}

	// Average calculates the average of the n-th sample (0 <= n < len(sample)).
	average := func(n int) int {
		sum := 0
		count := 0
		for i := 0; i != len(values); i++ {
			if assoc[i] == n {
				sum += values[i]
				count++
			}
		}

		return int(math.Round(float64(sum) / float64(count)))
	}

	// Stdev calculates the standard deviation of the n-th sample (0 <= n < len(sample)).
	stdev := func(n int) int {
		avg := average(n)

		sum := 0
		count := 0
		for i := 0; i != len(values); i++ {
			if assoc[i] == n {
				sum += (values[i] - avg) * (values[i] - avg)
				count++
			}
		}

		return int(math.Round(math.Sqrt(float64(sum) / float64(count))))
	}

	// Line 2 contains the results of AVERAGEIF
572
	assert.NoError(t, f.SetCellStr("Sheet1", "A2", "Average"))
573 574

	// Line 3 contains the average that was calculated in Go
575
	assert.NoError(t, f.SetCellStr("Sheet1", "A3", "Average (calculated)"))
576 577

	// Line 4 contains the results of the array function that calculates the standard deviation
578
	assert.NoError(t, f.SetCellStr("Sheet1", "A4", "Std. deviation"))
579 580

	// Line 5 contains the standard deviations calculated in Go
581
	assert.NoError(t, f.SetCellStr("Sheet1", "A5", "Std. deviation (calculated)"))
582

583 584 585
	assert.NoError(t, f.SetCellStr("Sheet1", "B1", sample[0]))
	assert.NoError(t, f.SetCellStr("Sheet1", "C1", sample[1]))
	assert.NoError(t, f.SetCellStr("Sheet1", "D1", sample[2]))
586 587

	firstResLine := 8
588 589
	assert.NoError(t, f.SetCellStr("Sheet1", cell(1, firstResLine-1), "Result Values"))
	assert.NoError(t, f.SetCellStr("Sheet1", cell(2, firstResLine-1), "Sample"))
590 591 592 593 594

	for i := 0; i != len(values); i++ {
		valCell := cell(1, i+firstResLine)
		assocCell := cell(2, i+firstResLine)

595 596
		assert.NoError(t, f.SetCellInt("Sheet1", valCell, values[i]))
		assert.NoError(t, f.SetCellStr("Sheet1", assocCell, sample[assoc[i]]))
597 598 599 600 601 602 603 604 605 606 607 608
	}

	valRange := fmt.Sprintf("$A$%d:$A$%d", firstResLine, len(values)+firstResLine-1)
	assocRange := fmt.Sprintf("$B$%d:$B$%d", firstResLine, len(values)+firstResLine-1)

	for i := 0; i != len(sample); i++ {
		nameCell := cell(i+2, 1)
		avgCell := cell(i+2, 2)
		calcAvgCell := cell(i+2, 3)
		stdevCell := cell(i+2, 4)
		calcStdevCell := cell(i+2, 5)

609 610
		assert.NoError(t, f.SetCellInt("Sheet1", calcAvgCell, average(i)))
		assert.NoError(t, f.SetCellInt("Sheet1", calcStdevCell, stdev(i)))
611 612

		// Average can be done with AVERAGEIF
613
		assert.NoError(t, f.SetCellFormula("Sheet1", avgCell, fmt.Sprintf("ROUND(AVERAGEIF(%s,%s,%s),0)", assocRange, nameCell, valRange)))
614 615

		ref := stdevCell + ":" + stdevCell
616
		arr := STCellFormulaTypeArray
617
		// Use an array formula for standard deviation
618 619
		assert.NoError(t, f.SetCellFormula("Sheet1", stdevCell, fmt.Sprintf("ROUND(STDEVP(IF(%s=%s,%s)),0)", assocRange, nameCell, valRange),
			FormulaOpts{}, FormulaOpts{Type: &arr}, FormulaOpts{Ref: &ref}))
620 621 622 623 624
	}

	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestWriteArrayFormula.xlsx")))
}

625
func TestSetCellStyleAlignment(t *testing.T) {
626
	f, err := prepareTestBook1()
627
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
628

629
	var style int
630 631
	style, err = f.NewStyle(&Style{Alignment: &Alignment{Horizontal: "center", Indent: 1, JustifyLastLine: true, ReadingOrder: 0, RelativeIndent: 1, ShrinkToFit: true, TextRotation: 45, Vertical: "top", WrapText: true}})
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
632

633
	assert.NoError(t, f.SetCellStyle("Sheet1", "A22", "A22", style))
634

635
	// Test set cell style with given illegal rows number
636 637
	assert.EqualError(t, f.SetCellStyle("Sheet1", "A", "A22", style), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
	assert.EqualError(t, f.SetCellStyle("Sheet1", "A22", "A", style), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
638 639 640
	// Test set cell style with invalid sheet name
	assert.EqualError(t, f.SetCellStyle("Sheet:1", "A1", "A2", style), ErrSheetNameInvalid.Error())
	// Test get cell style with given illegal rows number
641
	index, err := f.GetCellStyle("Sheet1", "A")
642
	assert.Equal(t, 0, index)
643
	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
V
Veniamin Albaev 已提交
644

645 646 647 648
	// Test get cell style with invalid sheet name
	_, err = f.GetCellStyle("Sheet:1", "A1")
	assert.EqualError(t, err, ErrSheetNameInvalid.Error())

649
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleAlignment.xlsx")))
650 651 652
}

func TestSetCellStyleBorder(t *testing.T) {
653
	f, err := prepareTestBook1()
654
	assert.NoError(t, err)
655

V
Veniamin Albaev 已提交
656
	var style int
657

658
	// Test set border on overlapping range with vertical variants shading styles gradient fill
659 660 661 662 663 664 665 666 667 668
	style, err = f.NewStyle(&Style{
		Border: []Border{
			{Type: "left", Color: "0000FF", Style: 3},
			{Type: "top", Color: "00FF00", Style: 4},
			{Type: "bottom", Color: "FFFF00", Style: 5},
			{Type: "right", Color: "FF0000", Style: 6},
			{Type: "diagonalDown", Color: "A020F0", Style: 7},
			{Type: "diagonalUp", Color: "A020F0", Style: 8},
		},
	})
669
	assert.NoError(t, err)
670
	assert.NoError(t, f.SetCellStyle("Sheet1", "J21", "L25", style))
671

672
	style, err = f.NewStyle(&Style{Border: []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: Fill{Type: "gradient", Color: []string{"FFFFFF", "E0EBF5"}, Shading: 1}})
673
	assert.NoError(t, err)
674
	assert.NoError(t, f.SetCellStyle("Sheet1", "M28", "K24", style))
675

676
	style, err = f.NewStyle(&Style{Border: []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: Fill{Type: "gradient", Color: []string{"FFFFFF", "E0EBF5"}, Shading: 4}})
677
	assert.NoError(t, err)
678
	assert.NoError(t, f.SetCellStyle("Sheet1", "M28", "K24", style))
679

680
	// Test set border and solid style pattern fill for a single cell
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
	style, err = f.NewStyle(&Style{
		Border: []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: Fill{
			Type:    "pattern",
716
			Color:   []string{"E0EBF5"},
717 718 719
			Pattern: 1,
		},
	})
720
	assert.NoError(t, err)
721

722
	assert.NoError(t, f.SetCellStyle("Sheet1", "O22", "O22", style))
V
Veniamin Albaev 已提交
723

724
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleBorder.xlsx")))
V
Veniamin Albaev 已提交
725 726 727
}

func TestSetCellStyleBorderErrors(t *testing.T) {
728
	f, err := prepareTestBook1()
729
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
730

731 732 733
	// Set border with invalid style index number
	_, err = f.NewStyle(&Style{Border: []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}}})
	assert.NoError(t, err)
734 735
}

736
func TestSetCellStyleNumberFormat(t *testing.T) {
737
	f, err := prepareTestBook1()
738
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
739

740
	// Test only set fill and number format for a cell
741
	col := []string{"L", "M", "N", "O", "P"}
742
	idxTbl := []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}
743
	value := []string{"37947.7500001", "-37947.7500001", "0.007", "2.1", "String"}
744
	expected := [][]string{
745 746 747 748 749
		{"37947.75", "37948", "37947.75", "37,948", "37,947.75", "3794775%", "3794775.00%", "3.79E+04", "37947 3/4", "37947 3/4", "11-22-03", "22-Nov-03", "22-Nov", "Nov-03", "6:00 PM", "6:00:00 PM", "18:00", "18:00:00", "11/22/03 18:00", "37,948 ", "37,948 ", "37,947.75 ", "37,947.75 ", " 37,948 ", " $37,948 ", " 37,947.75 ", " $37,947.75 ", "00:00", "910746:00:00", "00:00.0", "37947.7500001", "37947.7500001"},
		{"-37947.75", "-37948", "-37947.75", "-37,948", "-37,947.75", "-3794775%", "-3794775.00%", "-3.79E+04", "-37947 3/4", "-37947 3/4", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "(37,948)", "(37,948)", "(37,947.75)", "(37,947.75)", " (37,948)", " $(37,948)", " (37,947.75)", " $(37,947.75)", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001", "-37947.7500001"},
		{"0.007", "0", "0.01", "0", "0.01", "1%", "0.70%", "7.00E-03", "0    ", "0    ", "12-30-99", "30-Dec-99", "30-Dec", "Dec-99", "12:10 AM", "12:10:05 AM", "00:10", "00:10:05", "12/30/99 00:10", "0 ", "0 ", "0.01 ", "0.01 ", " 0 ", " $0 ", " 0.01 ", " $0.01 ", "10:05", "0:10:05", "10:04.8", "0.007", "0.007"},
		{"2.1", "2", "2.10", "2", "2.10", "210%", "210.00%", "2.10E+00", "2 1/9", "2 1/10", "01-01-00", "1-Jan-00", "1-Jan", "Jan-00", "2:24 AM", "2:24:00 AM", "02:24", "02:24:00", "1/1/00 02:24", "2 ", "2 ", "2.10 ", "2.10 ", " 2 ", " $2 ", " 2.10 ", " $2.10 ", "24:00", "50:24:00", "24:00.0", "2.1", "2.1"},
		{"String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", "String", " String ", " String ", " String ", " String ", "String", "String", "String", "String", "String"},
750 751
	}

752 753 754
	for c, v := range value {
		for r, idx := range idxTbl {
			cell := col[c] + strconv.Itoa(r+1)
755 756 757
			var val float64
			val, err = strconv.ParseFloat(v, 64)
			if err != nil {
758
				assert.NoError(t, f.SetCellValue("Sheet2", cell, v))
759
			} else {
760
				assert.NoError(t, f.SetCellValue("Sheet2", cell, val))
761
			}
762
			style, err := f.NewStyle(&Style{Fill: Fill{Type: "gradient", Color: []string{"FFFFFF", "E0EBF5"}, Shading: 5}, NumFmt: idx})
V
Veniamin Albaev 已提交
763 764
			if !assert.NoError(t, err) {
				t.FailNow()
765
			}
766 767 768
			assert.NoError(t, f.SetCellStyle("Sheet2", cell, cell, style))
			cellValue, err := f.GetCellValue("Sheet2", cell)
			assert.Equal(t, expected[c][r], cellValue, fmt.Sprintf("Sheet2!%s value: %s, number format: %s c: %d r: %d", cell, value[c], builtInNumFmt[idx], c, r))
769
			assert.NoError(t, err)
770 771
		}
	}
772
	var style int
773 774
	style, err = f.NewStyle(&Style{NumFmt: -1})
	assert.NoError(t, err)
775
	assert.NoError(t, f.SetCellStyle("Sheet2", "L33", "L33", style))
V
Veniamin Albaev 已提交
776

777
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleNumberFormat.xlsx")))
778 779 780 781 782 783 784 785 786 787

	// Test get cell value with built-in number format code 22 with custom short date pattern
	f = NewFile(Options{ShortDatePattern: "yyyy-m-dd"})
	assert.NoError(t, f.SetCellValue("Sheet1", "A1", 45074.625694444447))
	style, err = f.NewStyle(&Style{NumFmt: 22})
	assert.NoError(t, err)
	assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "A1", style))
	cellValue, err := f.GetCellValue("Sheet1", "A1")
	assert.NoError(t, err)
	assert.Equal(t, "2023-5-28 15:01", cellValue)
788 789
}

790
func TestSetCellStyleCurrencyNumberFormat(t *testing.T) {
V
Veniamin Albaev 已提交
791
	t.Run("TestBook3", func(t *testing.T) {
792
		f, err := prepareTestBook3()
793
		assert.NoError(t, err)
794

795 796
		assert.NoError(t, f.SetCellValue("Sheet1", "A1", 56))
		assert.NoError(t, f.SetCellValue("Sheet1", "A2", -32.3))
V
Veniamin Albaev 已提交
797
		var style int
xurime's avatar
xurime 已提交
798
		style, err = f.NewStyle(&Style{NumFmt: 188, DecimalPlaces: intPtr(-1)})
799
		assert.NoError(t, err)
800

801
		assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "A1", style))
xurime's avatar
xurime 已提交
802
		style, err = f.NewStyle(&Style{NumFmt: 188, DecimalPlaces: intPtr(31), NegRed: true})
803
		assert.NoError(t, err)
804

805
		assert.NoError(t, f.SetCellStyle("Sheet1", "A2", "A2", style))
806

807
		assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook3.xlsx")))
V
Veniamin Albaev 已提交
808
	})
809

V
Veniamin Albaev 已提交
810
	t.Run("TestBook4", func(t *testing.T) {
811
		f, err := prepareTestBook4()
812
		assert.NoError(t, err)
813 814
		assert.NoError(t, f.SetCellValue("Sheet1", "A1", 42920.5))
		assert.NoError(t, f.SetCellValue("Sheet1", "A2", 42920.5))
V
Veniamin Albaev 已提交
815

816
		_, err = f.NewStyle(&Style{NumFmt: 26})
817
		assert.NoError(t, err)
V
Veniamin Albaev 已提交
818

819 820
		style, err := f.NewStyle(&Style{NumFmt: 27})
		assert.NoError(t, err)
V
Veniamin Albaev 已提交
821

822
		assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "A1", style))
823
		style, err = f.NewStyle(&Style{NumFmt: 31})
824
		assert.NoError(t, err)
V
Veniamin Albaev 已提交
825

826
		assert.NoError(t, f.SetCellStyle("Sheet1", "A2", "A2", style))
V
Veniamin Albaev 已提交
827

828
		style, err = f.NewStyle(&Style{NumFmt: 71})
829
		assert.NoError(t, err)
830
		assert.NoError(t, f.SetCellStyle("Sheet1", "A2", "A2", style))
V
Veniamin Albaev 已提交
831

832
		assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook4.xlsx")))
V
Veniamin Albaev 已提交
833
	})
834 835
}

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
func TestSetCellStyleLangNumberFormat(t *testing.T) {
	rawCellValues := [][]string{{"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}}
	for lang, expected := range map[CultureName][][]string{
		CultureNameUnknown: rawCellValues,
		CultureNameEnUS:    {{"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"0:00:00"}, {"0:00:00"}, {"0:00:00"}, {"0:00:00"}, {"45162"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"8/24/23"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}},
		CultureNameZhCN:    {{"2023年8月"}, {"8月24日"}, {"8月24日"}, {"8/24/23"}, {"2023年8月24日"}, {"0时00分"}, {"0时00分00秒"}, {"上午12时00分"}, {"上午12时00分00秒"}, {"2023年8月"}, {"2023年8月"}, {"8月24日"}, {"2023年8月"}, {"8月24日"}, {"8月24日"}, {"上午12时00分"}, {"上午12时00分00秒"}, {"2023年8月"}, {"8月24日"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}},
	} {
		f, err := prepareTestBook5(Options{CultureInfo: lang})
		assert.NoError(t, err)
		rows, err := f.GetRows("Sheet1")
		assert.NoError(t, err)
		assert.Equal(t, expected, rows)
		assert.NoError(t, f.Close())
	}
	// Test apply language number format code with date and time pattern
	for lang, expected := range map[CultureName][][]string{
		CultureNameEnUS: {{"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"00:00:00"}, {"00:00:00"}, {"00:00:00"}, {"00:00:00"}, {"45162"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"2023-8-24"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}},
		CultureNameZhCN: {{"2023年8月"}, {"8月24日"}, {"8月24日"}, {"2023-8-24"}, {"2023年8月24日"}, {"00:00:00"}, {"00:00:00"}, {"上午12时00分"}, {"上午12时00分00秒"}, {"2023年8月"}, {"2023年8月"}, {"8月24日"}, {"2023年8月"}, {"8月24日"}, {"8月24日"}, {"上午12时00分"}, {"上午12时00分00秒"}, {"2023年8月"}, {"8月24日"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}, {"45162"}},
	} {
		f, err := prepareTestBook5(Options{CultureInfo: lang, ShortDatePattern: "yyyy-M-d", LongTimePattern: "hh:mm:ss"})
		assert.NoError(t, err)
		rows, err := f.GetRows("Sheet1")
		assert.NoError(t, err)
		assert.Equal(t, expected, rows)
		assert.NoError(t, f.Close())
	}
	// Test open workbook with invalid date and time pattern options
	_, err := OpenFile(filepath.Join("test", "Book1.xlsx"), Options{LongDatePattern: "0.00"})
	assert.Equal(t, ErrUnsupportedNumberFormat, err)
	_, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{LongTimePattern: "0.00"})
	assert.Equal(t, ErrUnsupportedNumberFormat, err)
	_, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{ShortDatePattern: "0.00"})
	assert.Equal(t, ErrUnsupportedNumberFormat, err)
}

871
func TestSetCellStyleCustomNumberFormat(t *testing.T) {
872
	f := NewFile()
873 874
	assert.NoError(t, f.SetCellValue("Sheet1", "A1", 42920.5))
	assert.NoError(t, f.SetCellValue("Sheet1", "A2", 42920.5))
875 876
	customNumFmt := "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"
	style, err := f.NewStyle(&Style{CustomNumFmt: &customNumFmt})
877
	assert.NoError(t, err)
878
	assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "A1", style))
879
	style, err = f.NewStyle(&Style{CustomNumFmt: &customNumFmt, Font: &Font{Color: "9A0511"}})
880
	assert.NoError(t, err)
881
	assert.NoError(t, f.SetCellStyle("Sheet1", "A2", "A2", style))
V
Veniamin Albaev 已提交
882

883 884
	customNumFmt = "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yy;@"
	_, err = f.NewStyle(&Style{CustomNumFmt: &customNumFmt})
885
	assert.NoError(t, err)
886
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleCustomNumberFormat.xlsx")))
887 888
}

889
func TestSetCellStyleFill(t *testing.T) {
890
	f, err := prepareTestBook1()
891
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
892

893
	var style int
894
	// Test set fill for cell with invalid parameter
895
	style, err = f.NewStyle(&Style{Fill: Fill{Type: "gradient", Color: []string{"FFFFFF", "E0EBF5"}, Shading: 6}})
896
	assert.NoError(t, err)
897
	assert.NoError(t, f.SetCellStyle("Sheet1", "O23", "O23", style))
898

899
	style, err = f.NewStyle(&Style{Fill: Fill{Type: "gradient", Color: []string{"FFFFFF"}, Shading: 1}})
900
	assert.NoError(t, err)
901
	assert.NoError(t, f.SetCellStyle("Sheet1", "O23", "O23", style))
902

903
	style, err = f.NewStyle(&Style{Fill: Fill{Type: "pattern", Color: []string{}, Shading: 1}})
904
	assert.NoError(t, err)
905
	assert.NoError(t, f.SetCellStyle("Sheet1", "O23", "O23", style))
xurime's avatar
xurime 已提交
906

907 908
	style, err = f.NewStyle(&Style{Fill: Fill{Type: "pattern", Color: []string{"E0EBF5"}, Pattern: 19}})
	assert.NoError(t, err)
909
	assert.NoError(t, f.SetCellStyle("Sheet1", "O23", "O23", style))
910

911
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleFill.xlsx")))
912 913 914
}

func TestSetCellStyleFont(t *testing.T) {
915
	f, err := prepareTestBook1()
916
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
917

918
	var style int
919
	style, err = f.NewStyle(&Style{Font: &Font{Bold: true, Italic: true, Family: "Times New Roman", Size: 36, Color: "777777", Underline: "single"}})
920
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
921

922
	assert.NoError(t, f.SetCellStyle("Sheet2", "A1", "A1", style))
923

924 925
	style, err = f.NewStyle(&Style{Font: &Font{Italic: true, Underline: "double"}})
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
926

927
	assert.NoError(t, f.SetCellStyle("Sheet2", "A2", "A2", style))
928

929 930
	style, err = f.NewStyle(&Style{Font: &Font{Bold: true}})
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
931

932
	assert.NoError(t, f.SetCellStyle("Sheet2", "A3", "A3", style))
933

934 935
	style, err = f.NewStyle(&Style{Font: &Font{Bold: true, Family: "", Size: 0, Color: "", Underline: ""}})
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
936

937
	assert.NoError(t, f.SetCellStyle("Sheet2", "A4", "A4", style))
938

939
	style, err = f.NewStyle(&Style{Font: &Font{Color: "777777", Strike: true}})
940
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
941

942
	assert.NoError(t, f.SetCellStyle("Sheet2", "A5", "A5", style))
V
Veniamin Albaev 已提交
943

944
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellStyleFont.xlsx")))
945
}
946

947
func TestSetCellStyleProtection(t *testing.T) {
948
	f, err := prepareTestBook1()
949
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
950

951
	var style int
952 953
	style, err = f.NewStyle(&Style{Protection: &Protection{Hidden: true, Locked: true}})
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
954

955 956
	assert.NoError(t, f.SetCellStyle("Sheet2", "A6", "A6", style))
	err = f.SaveAs(filepath.Join("test", "TestSetCellStyleProtection.xlsx"))
957
	assert.NoError(t, err)
958 959
}

V
Veniamin Albaev 已提交
960 961
func TestSetDeleteSheet(t *testing.T) {
	t.Run("TestBook3", func(t *testing.T) {
962
		f, err := prepareTestBook3()
963
		assert.NoError(t, err)
V
Veniamin Albaev 已提交
964

965
		assert.NoError(t, f.DeleteSheet("XLSXSheet3"))
966
		assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetDeleteSheet.TestBook3.xlsx")))
V
Veniamin Albaev 已提交
967 968 969
	})

	t.Run("TestBook4", func(t *testing.T) {
970
		f, err := prepareTestBook4()
971 972
		assert.NoError(t, err)
		assert.NoError(t, f.DeleteSheet("Sheet1"))
973
		assert.NoError(t, f.AddComment("Sheet1", Comment{Cell: "A1", Author: "Excelize", Paragraph: []RichTextRun{{Text: "Excelize: ", Font: &Font{Bold: true}}, {Text: "This is a comment."}}}))
974
		assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetDeleteSheet.TestBook4.xlsx")))
V
Veniamin Albaev 已提交
975
	})
976
}
977

978
func TestSheetVisibility(t *testing.T) {
979
	f, err := prepareTestBook1()
980
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
981

982
	assert.NoError(t, f.SetSheetVisible("Sheet2", false))
983
	assert.NoError(t, f.SetSheetVisible("Sheet2", false, true))
984 985
	assert.NoError(t, f.SetSheetVisible("Sheet1", false))
	assert.NoError(t, f.SetSheetVisible("Sheet1", true))
986 987 988
	visible, err := f.GetSheetVisible("Sheet1")
	assert.Equal(t, true, visible)
	assert.NoError(t, err)
989
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSheetVisibility.xlsx")))
990 991
}

992
func TestCopySheet(t *testing.T) {
993
	f, err := prepareTestBook1()
994
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
995

996 997
	idx, err := f.NewSheet("CopySheet")
	assert.NoError(t, err)
998
	assert.NoError(t, f.CopySheet(0, idx))
V
Veniamin Albaev 已提交
999

1000
	assert.NoError(t, f.SetCellValue("CopySheet", "F1", "Hello"))
1001
	val, err := f.GetCellValue("Sheet1", "F1")
1002 1003
	assert.NoError(t, err)
	assert.NotEqual(t, "Hello", val)
V
Veniamin Albaev 已提交
1004

1005
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestCopySheet.xlsx")))
V
Veniamin Albaev 已提交
1006 1007 1008
}

func TestCopySheetError(t *testing.T) {
1009
	f, err := prepareTestBook1()
1010 1011 1012
	assert.NoError(t, err)
	assert.EqualError(t, f.copySheet(-1, -2), ErrSheetNameBlank.Error())
	assert.EqualError(t, f.CopySheet(-1, -2), ErrSheetIdx.Error())
1013
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestCopySheetError.xlsx")))
1014
}
1015

1016 1017
func TestGetSheetComments(t *testing.T) {
	f := NewFile()
1018
	assert.Equal(t, "", f.getSheetComments("sheet0"))
1019 1020
}

xurime's avatar
xurime 已提交
1021 1022 1023
func TestGetActiveSheetIndex(t *testing.T) {
	f := NewFile()
	f.WorkBook.BookViews = nil
1024
	assert.Equal(t, 0, f.GetActiveSheetIndex())
xurime's avatar
xurime 已提交
1025 1026 1027 1028
}

func TestRelsWriter(t *testing.T) {
	f := NewFile()
1029
	f.Relationships.Store("xl/worksheets/sheet/rels/sheet1.xml.rel", &xlsxRelationships{})
xurime's avatar
xurime 已提交
1030 1031 1032
	f.relsWriter()
}

1033
func TestConditionalFormat(t *testing.T) {
1034
	f := NewFile()
1035
	sheet1 := f.GetSheetName(0)
1036

1037
	assert.NoError(t, fillCells(f, sheet1, 10, 15))
1038

1039
	var format1, format2, format3, format4 int
1040
	var err error
1041
	// Rose format for bad conditional
1042
	format1, err = f.NewConditionalStyle(&Style{Font: &Font{Color: "9A0511"}, Fill: Fill{Type: "pattern", Color: []string{"FEC7CE"}, Pattern: 1}})
1043
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
1044

1045
	// Light yellow format for neutral conditional
1046
	format2, err = f.NewConditionalStyle(&Style{Fill: Fill{Type: "pattern", Color: []string{"FEEAA0"}, Pattern: 1}})
1047
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
1048

1049
	// Light green format for good conditional
1050
	format3, err = f.NewConditionalStyle(&Style{Font: &Font{Color: "09600B"}, Fill: Fill{Type: "pattern", Color: []string{"C7EECF"}, Pattern: 1}})
1051
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
1052

1053
	// conditional style with align and left border
1054
	format4, err = f.NewConditionalStyle(&Style{Alignment: &Alignment{WrapText: true}, Border: []Border{{Type: "left", Color: "000000", Style: 1}}})
1055
	assert.NoError(t, err)
1056

1057
	// Color scales: 2 color
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
	assert.NoError(t, f.SetConditionalFormat(sheet1, "A1:A10",
		[]ConditionalFormatOptions{
			{
				Type:     "2_color_scale",
				Criteria: "=",
				MinType:  "min",
				MaxType:  "max",
				MinColor: "#F8696B",
				MaxColor: "#63BE7B",
			},
		},
	))
1070
	// Color scales: 3 color
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
	assert.NoError(t, f.SetConditionalFormat(sheet1, "B1:B10",
		[]ConditionalFormatOptions{
			{
				Type:     "3_color_scale",
				Criteria: "=",
				MinType:  "min",
				MidType:  "percentile",
				MaxType:  "max",
				MinColor: "#F8696B",
				MidColor: "#FFEB84",
				MaxColor: "#63BE7B",
			},
		},
	))
1085
	// Highlight cells rules: between...
1086 1087 1088 1089 1090
	assert.NoError(t, f.SetConditionalFormat(sheet1, "C1:C10",
		[]ConditionalFormatOptions{
			{
				Type:     "cell",
				Criteria: "between",
1091
				Format:   &format1,
1092 1093
				MinValue: "6",
				MaxValue: "8",
1094 1095 1096
			},
		},
	))
1097
	// Highlight cells rules: Greater Than...
1098 1099 1100 1101 1102
	assert.NoError(t, f.SetConditionalFormat(sheet1, "D1:D10",
		[]ConditionalFormatOptions{
			{
				Type:     "cell",
				Criteria: ">",
1103
				Format:   &format3,
1104 1105 1106 1107
				Value:    "6",
			},
		},
	))
1108
	// Highlight cells rules: Equal To...
1109 1110 1111 1112 1113
	assert.NoError(t, f.SetConditionalFormat(sheet1, "E1:E10",
		[]ConditionalFormatOptions{
			{
				Type:     "top",
				Criteria: "=",
1114
				Format:   &format3,
1115 1116 1117
			},
		},
	))
1118
	// Highlight cells rules: Not Equal To...
1119 1120 1121 1122 1123
	assert.NoError(t, f.SetConditionalFormat(sheet1, "F1:F10",
		[]ConditionalFormatOptions{
			{
				Type:     "unique",
				Criteria: "=",
1124
				Format:   &format2,
1125 1126 1127
			},
		},
	))
1128
	// Highlight cells rules: Duplicate Values...
1129 1130 1131 1132 1133
	assert.NoError(t, f.SetConditionalFormat(sheet1, "G1:G10",
		[]ConditionalFormatOptions{
			{
				Type:     "duplicate",
				Criteria: "=",
1134
				Format:   &format2,
1135 1136 1137
			},
		},
	))
1138
	// Top/Bottom rules: Top 10%.
1139 1140 1141 1142 1143
	assert.NoError(t, f.SetConditionalFormat(sheet1, "H1:H10",
		[]ConditionalFormatOptions{
			{
				Type:     "top",
				Criteria: "=",
1144
				Format:   &format1,
1145 1146 1147 1148 1149
				Value:    "6",
				Percent:  true,
			},
		},
	))
1150
	// Top/Bottom rules: Above Average...
1151 1152 1153 1154 1155
	assert.NoError(t, f.SetConditionalFormat(sheet1, "I1:I10",
		[]ConditionalFormatOptions{
			{
				Type:         "average",
				Criteria:     "=",
1156
				Format:       &format3,
1157 1158 1159 1160
				AboveAverage: true,
			},
		},
	))
1161
	// Top/Bottom rules: Below Average...
1162 1163 1164 1165 1166
	assert.NoError(t, f.SetConditionalFormat(sheet1, "J1:J10",
		[]ConditionalFormatOptions{
			{
				Type:         "average",
				Criteria:     "=",
1167
				Format:       &format1,
1168 1169 1170 1171
				AboveAverage: false,
			},
		},
	))
1172
	// Data Bars: Gradient Fill
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
	assert.NoError(t, f.SetConditionalFormat(sheet1, "K1:K10",
		[]ConditionalFormatOptions{
			{
				Type:     "data_bar",
				Criteria: "=",
				MinType:  "min",
				MaxType:  "max",
				BarColor: "#638EC6",
			},
		},
	))
1184
	// Use a formula to determine which cells to format
1185 1186 1187 1188 1189
	assert.NoError(t, f.SetConditionalFormat(sheet1, "L1:L10",
		[]ConditionalFormatOptions{
			{
				Type:     "formula",
				Criteria: "L2<3",
1190
				Format:   &format1,
1191 1192 1193
			},
		},
	))
1194
	// Alignment/Border cells rules
1195 1196 1197 1198 1199
	assert.NoError(t, f.SetConditionalFormat(sheet1, "M1:M10",
		[]ConditionalFormatOptions{
			{
				Type:     "cell",
				Criteria: ">",
1200
				Format:   &format4,
1201 1202 1203 1204
				Value:    "0",
			},
		},
	))
1205 1206
	// Test set conditional format with invalid cell reference
	assert.Equal(t, newCellNameToCoordinatesError("-", newInvalidCellNameError("-")), f.SetConditionalFormat("Sheet1", "A1:-", nil))
1207
	// Test set conditional format on not exists worksheet
1208
	assert.EqualError(t, f.SetConditionalFormat("SheetN", "L1:L10", nil), "sheet SheetN does not exist")
1209
	// Test set conditional format with invalid sheet name
1210
	assert.Equal(t, ErrSheetNameInvalid, f.SetConditionalFormat("Sheet:1", "L1:L10", nil))
V
Veniamin Albaev 已提交
1211

1212
	err = f.SaveAs(filepath.Join("test", "TestConditionalFormat.xlsx"))
1213
	assert.NoError(t, err)
1214

1215
	// Set conditional format with illegal valid type
1216
	assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat(sheet1, "K1:K10",
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
		[]ConditionalFormatOptions{
			{
				Type:     "",
				Criteria: "=",
				MinType:  "min",
				MaxType:  "max",
				BarColor: "#638EC6",
			},
		},
	))
1227
	// Set conditional format with illegal criteria type
1228
	assert.Equal(t, ErrParameterInvalid, f.SetConditionalFormat(sheet1, "K1:K10",
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
		[]ConditionalFormatOptions{
			{
				Type:     "data_bar",
				Criteria: "",
				MinType:  "min",
				MaxType:  "max",
				BarColor: "#638EC6",
			},
		},
	))
	// Test create conditional format with invalid custom number format
	var exp string
	_, err = f.NewConditionalStyle(&Style{CustomNumFmt: &exp})
1242
	assert.Equal(t, ErrCustomNumFmt, err)
V
Veniamin Albaev 已提交
1243

1244
	// Set conditional format with file without dxfs element should not return error
1245
	f, err = OpenFile(filepath.Join("test", "Book1.xlsx"))
1246
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
1247

1248
	_, err = f.NewConditionalStyle(&Style{Font: &Font{Color: "9A0511"}, Fill: Fill{Type: "", Color: []string{"FEC7CE"}, Pattern: 1}})
1249
	assert.NoError(t, err)
1250
	assert.NoError(t, f.Close())
1251
}
xurime's avatar
xurime 已提交
1252

1253
func TestSharedStrings(t *testing.T) {
1254
	f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
1255
	assert.NoError(t, err)
H
Harris 已提交
1256
	rows, err := f.GetRows("Sheet1")
1257
	assert.NoError(t, err)
H
Harris 已提交
1258
	assert.Equal(t, "A", rows[0][0])
H
Harris 已提交
1259
	rows, err = f.GetRows("Sheet2")
1260
	assert.NoError(t, err)
H
Harris 已提交
1261
	assert.Equal(t, "Test Weight (Kgs)", rows[0][0])
1262
	assert.NoError(t, f.Close())
1263
}
1264

1265 1266
func TestSetSheetCol(t *testing.T) {
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
1267
	assert.NoError(t, err)
1268 1269 1270 1271 1272

	assert.NoError(t, f.SetSheetCol("Sheet1", "B27", &[]interface{}{"cell", nil, int32(42), float64(42), time.Now().UTC()}))

	assert.EqualError(t, f.SetSheetCol("Sheet1", "", &[]interface{}{"cell", nil, 2}),
		newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
1273 1274
	// Test set worksheet column values with invalid sheet name
	assert.EqualError(t, f.SetSheetCol("Sheet:1", "A1", &[]interface{}{nil}), ErrSheetNameInvalid.Error())
1275 1276 1277 1278 1279 1280
	assert.EqualError(t, f.SetSheetCol("Sheet1", "B27", []interface{}{}), ErrParameterInvalid.Error())
	assert.EqualError(t, f.SetSheetCol("Sheet1", "B27", &f), ErrParameterInvalid.Error())
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetCol.xlsx")))
	assert.NoError(t, f.Close())
}

1281
func TestSetSheetRow(t *testing.T) {
1282
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
1283
	assert.NoError(t, err)
V
Veniamin Albaev 已提交
1284

1285
	assert.NoError(t, f.SetSheetRow("Sheet1", "B27", &[]interface{}{"cell", nil, int32(42), float64(42), time.Now().UTC()}))
1286

1287
	assert.EqualError(t, f.SetSheetRow("Sheet1", "", &[]interface{}{"cell", nil, 2}),
1288
		newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
1289 1290
	// Test set worksheet row with invalid sheet name
	assert.EqualError(t, f.SetSheetRow("Sheet:1", "A1", &[]interface{}{1}), ErrSheetNameInvalid.Error())
1291 1292
	assert.EqualError(t, f.SetSheetRow("Sheet1", "B27", []interface{}{}), ErrParameterInvalid.Error())
	assert.EqualError(t, f.SetSheetRow("Sheet1", "B27", &f), ErrParameterInvalid.Error())
1293
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetRow.xlsx")))
1294
	assert.NoError(t, f.Close())
1295
}
1296

xurime's avatar
xurime 已提交
1297 1298
func TestHSL(t *testing.T) {
	var hsl HSL
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
	r, g, b, a := hsl.RGBA()
	assert.Equal(t, uint32(0), r)
	assert.Equal(t, uint32(0), g)
	assert.Equal(t, uint32(0), b)
	assert.Equal(t, uint32(0xffff), a)
	assert.Equal(t, HSL{0, 0, 0}, hslModel(hsl))
	assert.Equal(t, HSL{0, 0, 0}, hslModel(color.Gray16{Y: uint16(1)}))
	R, G, B := HSLToRGB(0, 1, 0.4)
	assert.Equal(t, uint8(204), R)
	assert.Equal(t, uint8(0), G)
	assert.Equal(t, uint8(0), B)
	R, G, B = HSLToRGB(0, 1, 0.6)
	assert.Equal(t, uint8(255), R)
	assert.Equal(t, uint8(51), G)
	assert.Equal(t, uint8(51), B)
	assert.Equal(t, 0.0, hueToRGB(0, 0, -1))
	assert.Equal(t, 0.0, hueToRGB(0, 0, 2))
	assert.Equal(t, 0.0, hueToRGB(0, 0, 1.0/7))
	assert.Equal(t, 0.0, hueToRGB(0, 0, 0.4))
	assert.Equal(t, 0.0, hueToRGB(0, 0, 2.0/4))
1319 1320 1321 1322 1323
	h, s, l := RGBToHSL(255, 255, 0)
	assert.Equal(t, 0.16666666666666666, h)
	assert.Equal(t, 1.0, s)
	assert.Equal(t, 0.5, l)
	h, s, l = RGBToHSL(0, 255, 255)
1324 1325 1326
	assert.Equal(t, 0.5, h)
	assert.Equal(t, 1.0, s)
	assert.Equal(t, 0.5, l)
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
	h, s, l = RGBToHSL(250, 100, 50)
	assert.Equal(t, 0.041666666666666664, h)
	assert.Equal(t, 0.9523809523809524, s)
	assert.Equal(t, 0.5882352941176471, l)
	h, s, l = RGBToHSL(50, 100, 250)
	assert.Equal(t, 0.625, h)
	assert.Equal(t, 0.9523809523809524, s)
	assert.Equal(t, 0.5882352941176471, l)
	h, s, l = RGBToHSL(250, 50, 100)
	assert.Equal(t, 0.9583333333333334, h)
	assert.Equal(t, 0.9523809523809524, s)
	assert.Equal(t, 0.5882352941176471, l)
xurime's avatar
xurime 已提交
1339 1340
}

1341
func TestProtectSheet(t *testing.T) {
1342
	f := NewFile()
1343
	sheetName := f.GetSheetName(0)
xurime's avatar
xurime 已提交
1344
	assert.EqualError(t, f.ProtectSheet(sheetName, nil), ErrParameterInvalid.Error())
1345
	// Test protect worksheet with XOR hash algorithm
1346
	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
1347 1348
		Password:      "password",
		EditScenarios: false,
1349
	}))
1350 1351 1352
	ws, err := f.workSheetReader(sheetName)
	assert.NoError(t, err)
	assert.Equal(t, "83AF", ws.SheetProtection.Password)
1353
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestProtectSheet.xlsx")))
1354
	// Test protect worksheet with SHA-512 hash algorithm
1355
	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
1356 1357 1358 1359 1360
		AlgorithmName: "SHA-512",
		Password:      "password",
	}))
	ws, err = f.workSheetReader(sheetName)
	assert.NoError(t, err)
1361 1362
	assert.Len(t, ws.SheetProtection.SaltValue, 24)
	assert.Len(t, ws.SheetProtection.HashValue, 88)
1363 1364 1365
	assert.Equal(t, int(sheetProtectionSpinCount), ws.SheetProtection.SpinCount)
	// Test remove sheet protection with an incorrect password
	assert.EqualError(t, f.UnprotectSheet(sheetName, "wrongPassword"), ErrUnprotectSheetPassword.Error())
1366 1367
	// Test remove sheet protection with invalid sheet name
	assert.EqualError(t, f.UnprotectSheet("Sheet:1", "wrongPassword"), ErrSheetNameInvalid.Error())
1368 1369 1370
	// Test remove sheet protection with password verification
	assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
	// Test protect worksheet with empty password
1371
	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{}))
1372 1373
	assert.Equal(t, "", ws.SheetProtection.Password)
	// Test protect worksheet with password exceeds the limit length
1374
	assert.EqualError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
1375 1376 1377 1378
		AlgorithmName: "MD4",
		Password:      strings.Repeat("s", MaxFieldLength+1),
	}), ErrPasswordLengthInvalid.Error())
	// Test protect worksheet with unsupported hash algorithm
1379
	assert.EqualError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
1380 1381 1382
		AlgorithmName: "RIPEMD-160",
		Password:      "password",
	}), ErrUnsupportedHashAlgorithm.Error())
1383
	// Test protect not exists worksheet
1384
	assert.EqualError(t, f.ProtectSheet("SheetN", nil), "sheet SheetN does not exist")
1385 1386
	// Test protect sheet with invalid sheet name
	assert.EqualError(t, f.ProtectSheet("Sheet:1", nil), ErrSheetNameInvalid.Error())
1387 1388
}

1389
func TestUnprotectSheet(t *testing.T) {
1390
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
1391 1392
	assert.NoError(t, err)
	// Test remove protection on not exists worksheet
1393
	assert.EqualError(t, f.UnprotectSheet("SheetN"), "sheet SheetN does not exist")
V
Veniamin Albaev 已提交
1394

1395
	assert.NoError(t, f.UnprotectSheet("Sheet1"))
1396
	assert.EqualError(t, f.UnprotectSheet("Sheet1", "password"), ErrUnprotectSheet.Error())
1397
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnprotectSheet.xlsx")))
1398
	assert.NoError(t, f.Close())
1399 1400 1401

	f = NewFile()
	sheetName := f.GetSheetName(0)
1402
	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{Password: "password"}))
1403 1404 1405 1406 1407
	// Test remove sheet protection with an incorrect password
	assert.EqualError(t, f.UnprotectSheet(sheetName, "wrongPassword"), ErrUnprotectSheetPassword.Error())
	// Test remove sheet protection with password verification
	assert.NoError(t, f.UnprotectSheet(sheetName, "password"))
	// Test with invalid salt value
1408
	assert.NoError(t, f.ProtectSheet(sheetName, &SheetProtectionOptions{
1409 1410 1411 1412 1413 1414 1415
		AlgorithmName: "SHA-512",
		Password:      "password",
	}))
	ws, err := f.workSheetReader(sheetName)
	assert.NoError(t, err)
	ws.SheetProtection.SaltValue = "YWJjZA====="
	assert.EqualError(t, f.UnprotectSheet(sheetName, "wrongPassword"), "illegal base64 data at input byte 8")
G
Gin 已提交
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
}

func TestProtectWorkbook(t *testing.T) {
	f := NewFile()
	assert.NoError(t, f.ProtectWorkbook(nil))
	// Test protect workbook with default hash algorithm
	assert.NoError(t, f.ProtectWorkbook(&WorkbookProtectionOptions{
		Password:      "password",
		LockStructure: true,
	}))
	wb, err := f.workbookReader()
	assert.NoError(t, err)
	assert.Equal(t, "SHA-512", wb.WorkbookProtection.WorkbookAlgorithmName)
1429 1430
	assert.Len(t, wb.WorkbookProtection.WorkbookSaltValue, 24)
	assert.Len(t, wb.WorkbookProtection.WorkbookHashValue, 88)
G
Gin 已提交
1431
	assert.Equal(t, int(workbookProtectionSpinCount), wb.WorkbookProtection.WorkbookSpinCount)
1432

G
Gin 已提交
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
	// Test protect workbook with password exceeds the limit length
	assert.EqualError(t, f.ProtectWorkbook(&WorkbookProtectionOptions{
		AlgorithmName: "MD4",
		Password:      strings.Repeat("s", MaxFieldLength+1),
	}), ErrPasswordLengthInvalid.Error())
	// Test protect workbook with unsupported hash algorithm
	assert.EqualError(t, f.ProtectWorkbook(&WorkbookProtectionOptions{
		AlgorithmName: "RIPEMD-160",
		Password:      "password",
	}), ErrUnsupportedHashAlgorithm.Error())
1443 1444 1445 1446
	// Test protect workbook with unsupported charset workbook
	f.WorkBook = nil
	f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
	assert.EqualError(t, f.ProtectWorkbook(nil), "XML syntax error on line 1: invalid UTF-8")
G
Gin 已提交
1447 1448 1449 1450
}

func TestUnprotectWorkbook(t *testing.T) {
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
1451
	assert.NoError(t, err)
G
Gin 已提交
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472

	assert.NoError(t, f.UnprotectWorkbook())
	assert.EqualError(t, f.UnprotectWorkbook("password"), ErrUnprotectWorkbook.Error())
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnprotectWorkbook.xlsx")))
	assert.NoError(t, f.Close())

	f = NewFile()
	assert.NoError(t, f.ProtectWorkbook(&WorkbookProtectionOptions{Password: "password"}))
	// Test remove workbook protection with an incorrect password
	assert.EqualError(t, f.UnprotectWorkbook("wrongPassword"), ErrUnprotectWorkbookPassword.Error())
	// Test remove workbook protection with password verification
	assert.NoError(t, f.UnprotectWorkbook("password"))
	// Test with invalid salt value
	assert.NoError(t, f.ProtectWorkbook(&WorkbookProtectionOptions{
		AlgorithmName: "SHA-512",
		Password:      "password",
	}))
	wb, err := f.workbookReader()
	assert.NoError(t, err)
	wb.WorkbookProtection.WorkbookSaltValue = "YWJjZA====="
	assert.EqualError(t, f.UnprotectWorkbook("wrongPassword"), "illegal base64 data at input byte 8")
1473 1474 1475 1476
	// Test remove workbook protection with unsupported charset workbook
	f.WorkBook = nil
	f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
	assert.EqualError(t, f.UnprotectWorkbook(), "XML syntax error on line 1: invalid UTF-8")
1477
}
xurime's avatar
xurime 已提交
1478 1479 1480 1481

func TestSetDefaultTimeStyle(t *testing.T) {
	f := NewFile()
	// Test set default time style on not exists worksheet.
1482
	assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN does not exist")
1483 1484

	// Test set default time style on invalid cell
1485
	assert.EqualError(t, f.setDefaultTimeStyle("Sheet1", "", 42), newCellNameToCoordinatesError("", newInvalidCellNameError("")).Error())
xurime's avatar
xurime 已提交
1486
}
1487

1488
func TestAddVBAProject(t *testing.T) {
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
	f := NewFile()
	file, err := os.ReadFile(filepath.Join("test", "Book1.xlsx"))
	assert.NoError(t, err)
	assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("Sheet1")}))
	assert.EqualError(t, f.AddVBAProject(file), ErrAddVBAProject.Error())
	file, err = os.ReadFile(filepath.Join("test", "vbaProject.bin"))
	assert.NoError(t, err)
	assert.NoError(t, f.AddVBAProject(file))
	// Test add VBA project twice
	assert.NoError(t, f.AddVBAProject(file))
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
	// Test add VBA with unsupported charset workbook relationships
	f.Relationships.Delete(defaultXMLPathWorkbookRels)
	f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
	assert.EqualError(t, f.AddVBAProject(file), "XML syntax error on line 1: invalid UTF-8")
1504 1505
}

xurime's avatar
xurime 已提交
1506
func TestContentTypesReader(t *testing.T) {
1507
	// Test unsupported charset
xurime's avatar
xurime 已提交
1508 1509
	f := NewFile()
	f.ContentTypes = nil
1510
	f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
1511 1512
	_, err := f.contentTypesReader()
	assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
xurime's avatar
xurime 已提交
1513 1514 1515
}

func TestWorkbookReader(t *testing.T) {
1516
	// Test unsupported charset
xurime's avatar
xurime 已提交
1517 1518
	f := NewFile()
	f.WorkBook = nil
1519
	f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
1520 1521
	_, err := f.workbookReader()
	assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
xurime's avatar
xurime 已提交
1522 1523 1524
}

func TestWorkSheetReader(t *testing.T) {
1525
	// Test unsupported charset
xurime's avatar
xurime 已提交
1526
	f := NewFile()
1527 1528
	f.Sheet.Delete("xl/worksheets/sheet1.xml")
	f.Pkg.Store("xl/worksheets/sheet1.xml", MacintoshCyrillicCharset)
xurime's avatar
xurime 已提交
1529
	_, err := f.workSheetReader("Sheet1")
1530 1531
	assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
	assert.EqualError(t, f.UpdateLinkedValue(), "XML syntax error on line 1: invalid UTF-8")
xurime's avatar
xurime 已提交
1532

1533
	// Test on no checked worksheet
xurime's avatar
xurime 已提交
1534
	f = NewFile()
1535 1536
	f.Sheet.Delete("xl/worksheets/sheet1.xml")
	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData/></worksheet>`))
xurime's avatar
xurime 已提交
1537
	f.checked = sync.Map{}
xurime's avatar
xurime 已提交
1538 1539 1540 1541 1542
	_, err = f.workSheetReader("Sheet1")
	assert.NoError(t, err)
}

func TestRelsReader(t *testing.T) {
1543
	// Test unsupported charset
xurime's avatar
xurime 已提交
1544
	f := NewFile()
1545
	rels := defaultXMLPathWorkbookRels
1546
	f.Relationships.Store(rels, nil)
1547
	f.Pkg.Store(rels, MacintoshCyrillicCharset)
1548 1549
	_, err := f.relsReader(rels)
	assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
xurime's avatar
xurime 已提交
1550 1551 1552 1553
}

func TestDeleteSheetFromWorkbookRels(t *testing.T) {
	f := NewFile()
1554
	rels := defaultXMLPathWorkbookRels
1555
	f.Relationships.Store(rels, nil)
xurime's avatar
xurime 已提交
1556 1557 1558
	assert.Equal(t, f.deleteSheetFromWorkbookRels("rID"), "")
}

1559 1560
func TestUpdateLinkedValue(t *testing.T) {
	f := NewFile()
1561
	// Test update lined value with unsupported charset workbook
1562 1563 1564 1565 1566
	f.WorkBook = nil
	f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
	assert.EqualError(t, f.UpdateLinkedValue(), "XML syntax error on line 1: invalid UTF-8")
}

xurime's avatar
xurime 已提交
1567 1568
func TestAttrValToInt(t *testing.T) {
	_, err := attrValToInt("r", []xml.Attr{
1569 1570
		{Name: xml.Name{Local: "r"}, Value: "s"},
	})
xurime's avatar
xurime 已提交
1571 1572 1573
	assert.EqualError(t, err, `strconv.Atoi: parsing "s": invalid syntax`)
}

V
Veniamin Albaev 已提交
1574
func prepareTestBook1() (*File, error) {
1575
	f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
V
Veniamin Albaev 已提交
1576 1577 1578 1579
	if err != nil {
		return nil, err
	}

1580
	if err = f.AddPicture("Sheet2", "I9", filepath.Join("test", "images", "excel.jpg"),
xurime's avatar
xurime 已提交
1581
		&GraphicOptions{OffsetX: 140, OffsetY: 120, Hyperlink: "#Sheet2!D8", HyperlinkType: "Location"}); err != nil {
V
Veniamin Albaev 已提交
1582 1583 1584
		return nil, err
	}

1585 1586
	// Test add picture to worksheet with offset, external hyperlink and positioning
	if err := f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.png"),
xurime's avatar
xurime 已提交
1587
		&GraphicOptions{
1588 1589 1590 1591 1592 1593 1594
			OffsetX:       10,
			OffsetY:       10,
			Hyperlink:     "https://github.com/xuri/excelize",
			HyperlinkType: "External",
			Positioning:   "oneCell",
		},
	); err != nil {
V
Veniamin Albaev 已提交
1595 1596 1597
		return nil, err
	}

1598
	file, err := os.ReadFile(filepath.Join("test", "images", "excel.jpg"))
V
Veniamin Albaev 已提交
1599 1600 1601 1602
	if err != nil {
		return nil, err
	}

1603
	err = f.AddPictureFromBytes("Sheet1", "Q1", &Picture{Extension: ".jpg", File: file, Format: &GraphicOptions{AltText: "Excel Logo"}})
V
Veniamin Albaev 已提交
1604 1605 1606 1607
	if err != nil {
		return nil, err
	}

1608
	return f, nil
V
Veniamin Albaev 已提交
1609 1610 1611
}

func prepareTestBook3() (*File, error) {
1612
	f := NewFile()
1613 1614 1615 1616 1617 1618
	if _, err := f.NewSheet("XLSXSheet2"); err != nil {
		return nil, err
	}
	if _, err := f.NewSheet("XLSXSheet3"); err != nil {
		return nil, err
	}
1619 1620 1621 1622 1623 1624
	if err := f.SetCellInt("XLSXSheet2", "A23", 56); err != nil {
		return nil, err
	}
	if err := f.SetCellStr("Sheet1", "B20", "42"); err != nil {
		return nil, err
	}
1625
	f.SetActiveSheet(0)
1626
	if err := f.AddPicture("Sheet1", "H2", filepath.Join("test", "images", "excel.gif"),
xurime's avatar
xurime 已提交
1627
		&GraphicOptions{ScaleX: 0.5, ScaleY: 0.5, Positioning: "absolute"}); err != nil {
V
Veniamin Albaev 已提交
1628 1629
		return nil, err
	}
1630
	if err := f.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), nil); err != nil {
V
Veniamin Albaev 已提交
1631 1632
		return nil, err
	}
1633
	return f, nil
V
Veniamin Albaev 已提交
1634 1635 1636
}

func prepareTestBook4() (*File, error) {
1637
	f := NewFile()
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
	if err := f.SetColWidth("Sheet1", "B", "A", 12); err != nil {
		return f, err
	}
	if err := f.SetColWidth("Sheet1", "A", "B", 12); err != nil {
		return f, err
	}
	if _, err := f.GetColWidth("Sheet1", "A"); err != nil {
		return f, err
	}
	if _, err := f.GetColWidth("Sheet1", "C"); err != nil {
		return f, err
	}
V
Veniamin Albaev 已提交
1650

1651
	return f, nil
V
Veniamin Albaev 已提交
1652
}
1653

1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
func prepareTestBook5(opts Options) (*File, error) {
	f := NewFile(opts)
	var rowNum int
	for _, idxRange := range [][]int{{27, 36}, {50, 81}} {
		for numFmtIdx := idxRange[0]; numFmtIdx <= idxRange[1]; numFmtIdx++ {
			rowNum++
			styleID, err := f.NewStyle(&Style{NumFmt: numFmtIdx})
			if err != nil {
				return f, err
			}
			cell, err := CoordinatesToCellName(1, rowNum)
			if err != nil {
				return f, err
			}
			if err := f.SetCellValue("Sheet1", cell, 45162); err != nil {
				return f, err
			}
			if err := f.SetCellStyle("Sheet1", cell, cell, styleID); err != nil {
				return f, err
			}
		}
	}
	return f, nil
}

1679
func fillCells(f *File, sheet string, colCount, rowCount int) error {
1680 1681
	for col := 1; col <= colCount; col++ {
		for row := 1; row <= rowCount; row++ {
1682
			cell, _ := CoordinatesToCellName(col, row)
1683
			if err := f.SetCellStr(sheet, cell, cell); err != nil {
1684
				return err
1685
			}
1686 1687
		}
	}
1688
	return nil
1689
}
1690 1691 1692

func BenchmarkOpenFile(b *testing.B) {
	for i := 0; i < b.N; i++ {
1693 1694 1695 1696 1697
		f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
		if err != nil {
			b.Error(err)
		}
		if err := f.Close(); err != nil {
1698 1699
			b.Error(err)
		}
1700 1701
	}
}