styles_test.go 9.4 KB
Newer Older
1 2 3
package excelize

import (
4
	"fmt"
5
	"math"
6
	"path/filepath"
7
	"strings"
8 9 10 11 12
	"testing"

	"github.com/stretchr/testify/assert"
)

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
func TestStyleFill(t *testing.T) {
	cases := []struct {
		label      string
		format     string
		expectFill bool
	}{{
		label:      "no_fill",
		format:     `{"alignment":{"wrap_text":true}}`,
		expectFill: false,
	}, {
		label:      "fill",
		format:     `{"fill":{"type":"pattern","pattern":1,"color":["#000000"]}}`,
		expectFill: true,
	}}

	for _, testCase := range cases {
		xl := NewFile()
		styleID, err := xl.NewStyle(testCase.format)
31
		assert.NoError(t, err)
32 33 34 35

		styles := xl.stylesReader()
		style := styles.CellXfs.Xf[styleID]
		if testCase.expectFill {
36
			assert.NotEqual(t, *style.FillID, 0, testCase.label)
37
		} else {
38
			assert.Equal(t, *style.FillID, 0, testCase.label)
39 40
		}
	}
41 42 43 44 45 46 47
	f := NewFile()
	styleID1, err := f.NewStyle(`{"fill":{"type":"pattern","pattern":1,"color":["#000000"]}}`)
	assert.NoError(t, err)
	styleID2, err := f.NewStyle(`{"fill":{"type":"pattern","pattern":1,"color":["#000000"]}}`)
	assert.NoError(t, err)
	assert.Equal(t, styleID1, styleID2)
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestStyleFill.xlsx")))
48 49
}

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
func TestSetConditionalFormat(t *testing.T) {
	cases := []struct {
		label  string
		format string
		rules  []*xlsxCfRule
	}{{
		label: "3_color_scale",
		format: `[{
			"type":"3_color_scale",
			"criteria":"=",
			"min_type":"num",
			"mid_type":"num",
			"max_type":"num",
			"min_value": "-10",
			"mid_value": "0",
			"max_value": "10",
			"min_color":"ff0000",
			"mid_color":"00ff00",
			"max_color":"0000ff"
		}]`,
		rules: []*xlsxCfRule{{
			Priority: 1,
			Type:     "colorScale",
			ColorScale: &xlsxColorScale{
				Cfvo: []*xlsxCfvo{{
					Type: "num",
76
					Val:  "-10",
77 78
				}, {
					Type: "num",
79
					Val:  "0",
80 81
				}, {
					Type: "num",
82
					Val:  "10",
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
				}},
				Color: []*xlsxColor{{
					RGB: "FFFF0000",
				}, {
					RGB: "FF00FF00",
				}, {
					RGB: "FF0000FF",
				}},
			},
		}},
	}, {
		label: "3_color_scale default min/mid/max",
		format: `[{
			"type":"3_color_scale",
			"criteria":"=",
			"min_type":"num",
			"mid_type":"num",
			"max_type":"num",
			"min_color":"ff0000",
			"mid_color":"00ff00",
			"max_color":"0000ff"
		}]`,
		rules: []*xlsxCfRule{{
			Priority: 1,
			Type:     "colorScale",
			ColorScale: &xlsxColorScale{
				Cfvo: []*xlsxCfvo{{
					Type: "num",
111
					Val:  "0",
112 113
				}, {
					Type: "num",
114
					Val:  "50",
115 116
				}, {
					Type: "num",
117
					Val:  "0",
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
				}},
				Color: []*xlsxColor{{
					RGB: "FFFF0000",
				}, {
					RGB: "FF00FF00",
				}, {
					RGB: "FF0000FF",
				}},
			},
		}},
	}, {
		label: "2_color_scale default min/max",
		format: `[{
			"type":"2_color_scale",
			"criteria":"=",
			"min_type":"num",
			"max_type":"num",
			"min_color":"ff0000",
			"max_color":"0000ff"
		}]`,
		rules: []*xlsxCfRule{{
			Priority: 1,
			Type:     "colorScale",
			ColorScale: &xlsxColorScale{
				Cfvo: []*xlsxCfvo{{
					Type: "num",
144
					Val:  "0",
145 146
				}, {
					Type: "num",
147
					Val:  "0",
148 149 150 151 152 153 154 155 156 157 158
				}},
				Color: []*xlsxColor{{
					RGB: "FFFF0000",
				}, {
					RGB: "FF0000FF",
				}},
			},
		}},
	}}

	for _, testCase := range cases {
159
		f := NewFile()
160 161 162
		const sheet = "Sheet1"
		const cellRange = "A1:A1"

163
		err := f.SetConditionalFormat(sheet, cellRange, testCase.format)
164 165 166 167
		if err != nil {
			t.Fatalf("%s", err)
		}

168
		ws, err := f.workSheetReader(sheet)
xurime's avatar
xurime 已提交
169
		assert.NoError(t, err)
170
		cf := ws.ConditionalFormatting
171 172 173 174 175 176
		assert.Len(t, cf, 1, testCase.label)
		assert.Len(t, cf[0].CfRule, 1, testCase.label)
		assert.Equal(t, cellRange, cf[0].SQRef, testCase.label)
		assert.EqualValues(t, testCase.rules, cf[0].CfRule, testCase.label)
	}
}
177

178 179 180 181 182 183 184 185 186 187
func TestUnsetConditionalFormat(t *testing.T) {
	f := NewFile()
	assert.NoError(t, f.SetCellValue("Sheet1", "A1", 7))
	assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
	format, err := f.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
	assert.NoError(t, err)
	assert.NoError(t, f.SetConditionalFormat("Sheet1", "A1:A10", fmt.Sprintf(`[{"type":"cell","criteria":">","format":%d,"value":"6"}]`, format)))
	assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
	// Test unset conditional format on not exists worksheet.
	assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN is not exist")
188
	// Save spreadsheet by the given path.
189 190 191
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx")))
}

192 193
func TestNewStyle(t *testing.T) {
	f := NewFile()
xurime's avatar
xurime 已提交
194
	styleID, err := f.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777"}}`)
xurime's avatar
xurime 已提交
195
	assert.NoError(t, err)
196 197
	styles := f.stylesReader()
	fontID := styles.CellXfs.Xf[styleID].FontID
198
	font := styles.Fonts.Font[*fontID]
199
	assert.Contains(t, *font.Name.Val, "Times New Roman", "Stored font should contain font name")
200
	assert.Equal(t, 2, styles.CellXfs.Count, "Should have 2 styles")
201 202
	_, err = f.NewStyle(&Style{})
	assert.NoError(t, err)
xurime's avatar
xurime 已提交
203
	_, err = f.NewStyle(Style{})
204
	assert.EqualError(t, err, ErrParameterInvalid.Error())
205

xurime's avatar
xurime 已提交
206 207 208
	var exp string
	_, err = f.NewStyle(&Style{CustomNumFmt: &exp})
	assert.EqualError(t, err, ErrCustomNumFmt.Error())
209
	_, err = f.NewStyle(&Style{Font: &Font{Family: strings.Repeat("s", MaxFontFamilyLength+1)}})
xurime's avatar
xurime 已提交
210
	assert.EqualError(t, err, ErrFontLength.Error())
211
	_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
xurime's avatar
xurime 已提交
212
	assert.EqualError(t, err, ErrFontSize.Error())
213 214

	// new numeric custom style
215
	numFmt := "####;####"
216 217
	f.Styles.NumFmts = nil
	styleID, err = f.NewStyle(&Style{
218
		CustomNumFmt: &numFmt,
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	})
	assert.NoError(t, err)
	assert.Equal(t, 2, styleID)

	assert.NotNil(t, f.Styles)
	assert.NotNil(t, f.Styles.CellXfs)
	assert.NotNil(t, f.Styles.CellXfs.Xf)

	nf := f.Styles.CellXfs.Xf[styleID]
	assert.Equal(t, 164, *nf.NumFmtID)

	// new currency custom style
	f.Styles.NumFmts = nil
	styleID, err = f.NewStyle(&Style{
		Lang:   "ko-kr",
		NumFmt: 32, // must not be in currencyNumFmt

	})
	assert.NoError(t, err)
	assert.Equal(t, 3, styleID)

	assert.NotNil(t, f.Styles)
	assert.NotNil(t, f.Styles.CellXfs)
	assert.NotNil(t, f.Styles.CellXfs.Xf)

	nf = f.Styles.CellXfs.Xf[styleID]
	assert.Equal(t, 32, *nf.NumFmtID)
xurime's avatar
xurime 已提交
246 247 248 249 250 251 252 253 254

	// Test set build-in scientific number format
	styleID, err = f.NewStyle(&Style{NumFmt: 11})
	assert.NoError(t, err)
	assert.NoError(t, f.SetCellStyle("Sheet1", "A1", "B1", styleID))
	assert.NoError(t, f.SetSheetRow("Sheet1", "A1", &[]float64{1.23, 1.234}))
	rows, err := f.GetRows("Sheet1")
	assert.NoError(t, err)
	assert.Equal(t, [][]string{{"1.23E+00", "1.23E+00"}}, rows)
xurime's avatar
xurime 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

	f = NewFile()
	// Test currency number format
	customNumFmt := "[$$-409]#,##0.00"
	style1, err := f.NewStyle(&Style{CustomNumFmt: &customNumFmt})
	assert.NoError(t, err)
	style2, err := f.NewStyle(&Style{NumFmt: 165})
	assert.NoError(t, err)
	assert.Equal(t, style1, style2)

	style3, err := f.NewStyle(&Style{NumFmt: 166})
	assert.NoError(t, err)
	assert.Equal(t, 2, style3)

	f = NewFile()
	f.Styles.NumFmts = nil
	f.Styles.CellXfs.Xf = nil
	style4, err := f.NewStyle(&Style{NumFmt: 160, Lang: "unknown"})
	assert.NoError(t, err)
	assert.Equal(t, 1, style4)

	f = NewFile()
	f.Styles.NumFmts = nil
	f.Styles.CellXfs.Xf = nil
	style5, err := f.NewStyle(&Style{NumFmt: 160, Lang: "zh-cn"})
	assert.NoError(t, err)
	assert.Equal(t, 1, style5)
282 283 284 285 286 287 288 289 290 291
}

func TestGetDefaultFont(t *testing.T) {
	f := NewFile()
	s := f.GetDefaultFont()
	assert.Equal(t, s, "Calibri", "Default font should be Calibri")
}

func TestSetDefaultFont(t *testing.T) {
	f := NewFile()
292
	f.SetDefaultFont("Arial")
293 294
	styles := f.stylesReader()
	s := f.GetDefaultFont()
295
	assert.Equal(t, s, "Arial", "Default font should change to Arial")
296 297
	assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
}
298 299 300

func TestStylesReader(t *testing.T) {
	f := NewFile()
xurime's avatar
xurime 已提交
301
	// Test read styles with unsupported charset.
302
	f.Styles = nil
303
	f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
304 305 306 307 308
	assert.EqualValues(t, new(xlsxStyleSheet), f.stylesReader())
}

func TestThemeReader(t *testing.T) {
	f := NewFile()
xurime's avatar
xurime 已提交
309
	// Test read theme with unsupported charset.
310
	f.Pkg.Store("xl/theme/theme1.xml", MacintoshCyrillicCharset)
311 312 313 314 315 316 317 318
	assert.EqualValues(t, new(xlsxTheme), f.themeReader())
}

func TestSetCellStyle(t *testing.T) {
	f := NewFile()
	// Test set cell style on not exists worksheet.
	assert.EqualError(t, f.SetCellStyle("SheetN", "A1", "A2", 1), "sheet SheetN is not exist")
}
319 320 321 322 323 324 325 326

func TestGetStyleID(t *testing.T) {
	assert.Equal(t, -1, NewFile().getStyleID(&xlsxStyleSheet{}, nil))
}

func TestGetFillID(t *testing.T) {
	assert.Equal(t, -1, getFillID(NewFile().stylesReader(), &Style{Fill: Fill{Type: "unknown"}}))
}
327

328 329 330 331 332 333 334 335 336 337 338
func TestThemeColor(t *testing.T) {
	for _, clr := range [][]string{
		{"FF000000", ThemeColor("000000", -0.1)},
		{"FF000000", ThemeColor("000000", 0)},
		{"FF33FF33", ThemeColor("00FF00", 0.2)},
		{"FFFFFFFF", ThemeColor("000000", 1)},
		{"FFFFFFFF", ThemeColor(strings.Repeat(string(rune(math.MaxUint8+1)), 6), 1)},
		{"FFFFFFFF", ThemeColor(strings.Repeat(string(rune(-1)), 6), 1)},
	} {
		assert.Equal(t, clr[0], clr[1])
	}
339
}
340 341 342 343 344 345 346 347 348 349 350 351 352 353

func TestGetNumFmtID(t *testing.T) {
	f := NewFile()

	fs1, err := parseFormatStyleSet(`{"protection":{"hidden":false,"locked":false},"number_format":10}`)
	assert.NoError(t, err)
	id1 := getNumFmtID(&xlsxStyleSheet{}, fs1)

	fs2, err := parseFormatStyleSet(`{"protection":{"hidden":false,"locked":false},"number_format":0}`)
	assert.NoError(t, err)
	id2 := getNumFmtID(&xlsxStyleSheet{}, fs2)

	assert.NotEqual(t, id1, id2)
	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestStyleNumFmt.xlsx")))
xurime's avatar
xurime 已提交
354
}