2018-07-25 22:40:08 +08:00
|
|
|
package excelize
|
|
|
|
|
|
|
|
import (
|
2020-03-03 00:15:03 +08:00
|
|
|
"fmt"
|
2020-10-23 00:01:52 +08:00
|
|
|
"math"
|
2020-03-03 00:15:03 +08:00
|
|
|
"path/filepath"
|
2020-09-18 22:20:58 +08:00
|
|
|
"strings"
|
2018-07-25 22:40:08 +08:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
2019-01-09 23:12:53 +08:00
|
|
|
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)
|
2020-05-24 20:20:22 +08:00
|
|
|
assert.NoError(t, err)
|
2019-01-09 23:12:53 +08:00
|
|
|
|
|
|
|
styles := xl.stylesReader()
|
|
|
|
style := styles.CellXfs.Xf[styleID]
|
|
|
|
if testCase.expectFill {
|
2020-05-10 16:56:08 +08:00
|
|
|
assert.NotEqual(t, *style.FillID, 0, testCase.label)
|
2019-01-09 23:12:53 +08:00
|
|
|
} else {
|
2020-05-10 16:56:08 +08:00
|
|
|
assert.Equal(t, *style.FillID, 0, testCase.label)
|
2019-01-09 23:12:53 +08:00
|
|
|
}
|
|
|
|
}
|
2020-05-24 20:20:22 +08:00
|
|
|
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")))
|
2019-01-09 23:12:53 +08:00
|
|
|
}
|
|
|
|
|
2018-07-25 22:40:08 +08:00
|
|
|
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",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "-10",
|
2018-07-25 22:40:08 +08:00
|
|
|
}, {
|
|
|
|
Type: "num",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "0",
|
2018-07-25 22:40:08 +08:00
|
|
|
}, {
|
|
|
|
Type: "num",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "10",
|
2018-07-25 22:40:08 +08:00
|
|
|
}},
|
|
|
|
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",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "0",
|
2018-07-25 22:40:08 +08:00
|
|
|
}, {
|
|
|
|
Type: "num",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "50",
|
2018-07-25 22:40:08 +08:00
|
|
|
}, {
|
|
|
|
Type: "num",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "0",
|
2018-07-25 22:40:08 +08:00
|
|
|
}},
|
|
|
|
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",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "0",
|
2018-07-25 22:40:08 +08:00
|
|
|
}, {
|
|
|
|
Type: "num",
|
2018-07-25 04:12:26 +08:00
|
|
|
Val: "0",
|
2018-07-25 22:40:08 +08:00
|
|
|
}},
|
|
|
|
Color: []*xlsxColor{{
|
|
|
|
RGB: "FFFF0000",
|
|
|
|
}, {
|
|
|
|
RGB: "FF0000FF",
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
}}
|
|
|
|
|
|
|
|
for _, testCase := range cases {
|
2020-11-10 23:48:09 +08:00
|
|
|
f := NewFile()
|
2018-07-25 22:40:08 +08:00
|
|
|
const sheet = "Sheet1"
|
|
|
|
const cellRange = "A1:A1"
|
|
|
|
|
2020-11-10 23:48:09 +08:00
|
|
|
err := f.SetConditionalFormat(sheet, cellRange, testCase.format)
|
2018-07-25 22:40:08 +08:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("%s", err)
|
|
|
|
}
|
|
|
|
|
2020-11-10 23:48:09 +08:00
|
|
|
ws, err := f.workSheetReader(sheet)
|
2019-04-15 11:22:57 +08:00
|
|
|
assert.NoError(t, err)
|
2020-11-10 23:48:09 +08:00
|
|
|
cf := ws.ConditionalFormatting
|
2018-07-25 22:40:08 +08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2019-04-26 00:24:25 +08:00
|
|
|
|
2020-03-03 00:15:03 +08:00
|
|
|
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")
|
2020-11-10 23:48:09 +08:00
|
|
|
// Save spreadsheet by the given path.
|
2020-03-03 00:15:03 +08:00
|
|
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx")))
|
|
|
|
}
|
|
|
|
|
2019-04-26 00:24:25 +08:00
|
|
|
func TestNewStyle(t *testing.T) {
|
|
|
|
f := NewFile()
|
2019-08-21 23:03:34 +08:00
|
|
|
styleID, err := f.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Times New Roman","size":36,"color":"#777777"}}`)
|
2019-12-29 16:02:31 +08:00
|
|
|
assert.NoError(t, err)
|
2019-04-26 00:24:25 +08:00
|
|
|
styles := f.stylesReader()
|
|
|
|
fontID := styles.CellXfs.Xf[styleID].FontID
|
2020-05-10 16:56:08 +08:00
|
|
|
font := styles.Fonts.Font[*fontID]
|
2019-12-23 00:07:40 +08:00
|
|
|
assert.Contains(t, *font.Name.Val, "Times New Roman", "Stored font should contain font name")
|
2019-04-26 00:24:25 +08:00
|
|
|
assert.Equal(t, 2, styles.CellXfs.Count, "Should have 2 styles")
|
2020-03-10 00:04:23 +08:00
|
|
|
_, err = f.NewStyle(&Style{})
|
|
|
|
assert.NoError(t, err)
|
2020-04-06 00:23:27 +08:00
|
|
|
_, err = f.NewStyle(Style{})
|
2021-07-05 00:03:56 +08:00
|
|
|
assert.EqualError(t, err, ErrParameterInvalid.Error())
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2020-09-18 22:20:58 +08:00
|
|
|
_, 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")
|
2020-10-04 21:07:39 +08:00
|
|
|
|
|
|
|
// 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)
|
2019-04-26 00:24:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2020-03-10 00:04:23 +08:00
|
|
|
|
|
|
|
func TestStylesReader(t *testing.T) {
|
|
|
|
f := NewFile()
|
2021-03-30 23:02:22 +08:00
|
|
|
// Test read styles with unsupported charset.
|
2020-03-10 00:04:23 +08:00
|
|
|
f.Styles = nil
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Pkg.Store("xl/styles.xml", MacintoshCyrillicCharset)
|
2020-03-10 00:04:23 +08:00
|
|
|
assert.EqualValues(t, new(xlsxStyleSheet), f.stylesReader())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestThemeReader(t *testing.T) {
|
|
|
|
f := NewFile()
|
2021-03-30 23:02:22 +08:00
|
|
|
// Test read theme with unsupported charset.
|
2021-07-05 00:03:56 +08:00
|
|
|
f.Pkg.Store("xl/theme/theme1.xml", MacintoshCyrillicCharset)
|
2020-03-10 00:04:23 +08:00
|
|
|
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")
|
|
|
|
}
|
2020-05-24 20:20:22 +08:00
|
|
|
|
|
|
|
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"}}))
|
|
|
|
}
|
2020-10-04 21:07:39 +08:00
|
|
|
|
|
|
|
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"))
|
2021-05-15 23:42:52 +08:00
|
|
|
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"))
|
|
|
|
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"))
|
2020-10-04 21:07:39 +08:00
|
|
|
assert.Equal(t, "March", parseTime("43528", "mmmm"))
|
|
|
|
assert.Equal(t, "Monday", parseTime("43528", "dddd"))
|
2020-10-23 00:01:52 +08:00
|
|
|
}
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2020-10-23 00:01:52 +08:00
|
|
|
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])
|
|
|
|
}
|
2020-10-04 21:07:39 +08:00
|
|
|
}
|