styles_test.go 9.3 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 215 216 217 218 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

	// new numeric custom style
	fmt := "####;####"
	f.Styles.NumFmts = nil
	styleID, err = f.NewStyle(&Style{
		CustomNumFmt: &fmt,
	})
	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)
255 256 257 258 259 260 261 262 263 264
}

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()
265
	f.SetDefaultFont("Arial")
266 267
	styles := f.stylesReader()
	s := f.GetDefaultFont()
268
	assert.Equal(t, s, "Arial", "Default font should change to Arial")
269 270
	assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
}
271 272 273

func TestStylesReader(t *testing.T) {
	f := NewFile()
xurime's avatar
xurime 已提交
274
	// Test read styles with unsupported charset.
275
	f.Styles = nil
276
	f.Pkg.Store("xl/styles.xml", MacintoshCyrillicCharset)
277 278 279 280 281
	assert.EqualValues(t, new(xlsxStyleSheet), f.stylesReader())
}

func TestThemeReader(t *testing.T) {
	f := NewFile()
xurime's avatar
xurime 已提交
282
	// Test read theme with unsupported charset.
283
	f.Pkg.Store("xl/theme/theme1.xml", MacintoshCyrillicCharset)
284 285 286 287 288 289 290 291
	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")
}
292 293 294 295 296 297 298 299

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"}}))
}
300 301 302 303 304 305 306 307

func TestParseTime(t *testing.T) {
	assert.Equal(t, "2019", parseTime("43528", "YYYY"))
	assert.Equal(t, "43528", parseTime("43528", ""))

	assert.Equal(t, "2019-03-04 05:05:42", parseTime("43528.2123", "YYYY-MM-DD hh:mm:ss"))
	assert.Equal(t, "2019-03-04 05:05:42", parseTime("43528.2123", "YYYY-MM-DD hh:mm:ss;YYYY-MM-DD hh:mm:ss"))
	assert.Equal(t, "3/4/2019 5:5:42", parseTime("43528.2123", "M/D/YYYY h:m:s"))
308 309
	assert.Equal(t, "3/4/2019 0:5:42", parseTime("43528.003958333335", "m/d/yyyy h:m:s"))
	assert.Equal(t, "3/4/2019 0:05:42", parseTime("43528.003958333335", "M/D/YYYY h:mm:s"))
310
	assert.Equal(t, "3:30:00 PM", parseTime("0.64583333333333337", "h:mm:ss am/pm"))
311 312 313 314 315 316
	assert.Equal(t, "0:05", parseTime("43528.003958333335", "h:mm"))
	assert.Equal(t, "0:0", parseTime("6.9444444444444444E-5", "h:m"))
	assert.Equal(t, "0:00", parseTime("6.9444444444444444E-5", "h:mm"))
	assert.Equal(t, "0:0", parseTime("6.9444444444444444E-5", "h:m"))
	assert.Equal(t, "12:1", parseTime("0.50070601851851848", "h:m"))
	assert.Equal(t, "23:30", parseTime("0.97952546296296295", "h:m"))
317 318
	assert.Equal(t, "March", parseTime("43528", "mmmm"))
	assert.Equal(t, "Monday", parseTime("43528", "dddd"))
319
}
320

321 322 323 324 325 326 327 328 329 330 331
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])
	}
332
}