styles_test.go 8.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 204
	_, err = f.NewStyle(Style{})
	assert.EqualError(t, err, "invalid parameter type")
205

206 207 208 209
	_, err = f.NewStyle(&Style{Font: &Font{Family: strings.Repeat("s", MaxFontFamilyLength+1)}})
	assert.EqualError(t, err, "the length of the font family name must be smaller than or equal to 31")
	_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
	assert.EqualError(t, err, "font size must be between 1 and 409 points")
210 211 212 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

	// 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)
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
}

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()
	f.SetDefaultFont("Ariel")
	styles := f.stylesReader()
	s := f.GetDefaultFont()
	assert.Equal(t, s, "Ariel", "Default font should change to Ariel")
	assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
}
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

func TestStylesReader(t *testing.T) {
	f := NewFile()
	// Test read styles with unsupport charset.
	f.Styles = nil
	f.XLSX["xl/styles.xml"] = MacintoshCyrillicCharset
	assert.EqualValues(t, new(xlsxStyleSheet), f.stylesReader())
}

func TestThemeReader(t *testing.T) {
	f := NewFile()
	// Test read theme with unsupport charset.
	f.XLSX["xl/theme/theme1.xml"] = MacintoshCyrillicCharset
	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")
}
280 281 282 283 284 285 286 287

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"}}))
}
288 289 290 291 292 293 294 295 296 297

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"))
	assert.Equal(t, "March", parseTime("43528", "mmmm"))
	assert.Equal(t, "Monday", parseTime("43528", "dddd"))
298
}
299

300 301 302 303 304 305 306 307 308 309 310
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])
	}
311
}