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
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
styles, err := xl.stylesReader()
|
|
|
|
assert.NoError(t, err)
|
2019-01-09 23:12:53 +08:00
|
|
|
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
|
|
|
|
2022-08-27 00:45:46 +08:00
|
|
|
func TestGetConditionalFormats(t *testing.T) {
|
|
|
|
for _, format := range []string{
|
|
|
|
`[{"type":"cell","format":1,"criteria":"greater than","value":"6"}]`,
|
|
|
|
`[{"type":"cell","format":1,"criteria":"between","minimum":"6","maximum":"8"}]`,
|
|
|
|
`[{"type":"top","format":1,"criteria":"=","value":"6"}]`,
|
|
|
|
`[{"type":"bottom","format":1,"criteria":"=","value":"6"}]`,
|
|
|
|
`[{"type":"average","above_average":true,"format":1,"criteria":"="}]`,
|
|
|
|
`[{"type":"duplicate","format":1,"criteria":"="}]`,
|
|
|
|
`[{"type":"unique","format":1,"criteria":"="}]`,
|
|
|
|
`[{"type":"3_color_scale","criteria":"=","min_type":"num","mid_type":"num","max_type":"num","min_value":"-10","mid_value":"50","max_value":"10","min_color":"#FF0000","mid_color":"#00FF00","max_color":"#0000FF"}]`,
|
|
|
|
`[{"type":"2_color_scale","criteria":"=","min_type":"num","max_type":"num","min_color":"#FF0000","max_color":"#0000FF"}]`,
|
|
|
|
`[{"type":"data_bar","criteria":"=","min_type":"min","max_type":"max","bar_color":"#638EC6"}]`,
|
|
|
|
`[{"type":"formula","format":1,"criteria":"="}]`,
|
|
|
|
} {
|
|
|
|
f := NewFile()
|
|
|
|
err := f.SetConditionalFormat("Sheet1", "A1:A2", format)
|
|
|
|
assert.NoError(t, err)
|
This closes #1358, made a refactor with breaking changes, see details:
This made a refactor with breaking changes:
Motivation and Context
When I decided to add set horizontal centered support for this library to resolve #1358, the reason I made this huge breaking change was:
- There are too many exported types for set sheet view, properties, and format properties, although a function using the functional options pattern can be optimized by returning an anonymous function, these types or property set or get function has no binding categorization, so I change these functions like `SetAppProps` to accept a pointer of options structure.
- Users can not easily find out which properties should be in the `SetSheetPrOptions` or `SetSheetFormatPr` categories
- Nested properties cannot proceed modify easily
Introduce 5 new export data types:
`HeaderFooterOptions`, `PageLayoutMarginsOptions`, `PageLayoutOptions`, `SheetPropsOptions`, and `ViewOptions`
Rename 4 exported data types:
- Rename `PivotTableOption` to `PivotTableOptions`
- Rename `FormatHeaderFooter` to `HeaderFooterOptions`
- Rename `FormatSheetProtection` to `SheetProtectionOptions`
- Rename `SparklineOption` to `SparklineOptions`
Remove 54 exported types:
`AutoPageBreaks`, `BaseColWidth`, `BlackAndWhite`, `CodeName`, `CustomHeight`, `Date1904`, `DefaultColWidth`, `DefaultGridColor`, `DefaultRowHeight`, `EnableFormatConditionsCalculation`, `FilterPrivacy`, `FirstPageNumber`, `FitToHeight`, `FitToPage`, `FitToWidth`, `OutlineSummaryBelow`, `PageLayoutOption`, `PageLayoutOptionPtr`, `PageLayoutOrientation`, `PageLayoutPaperSize`, `PageLayoutScale`, `PageMarginBottom`, `PageMarginFooter`, `PageMarginHeader`, `PageMarginLeft`, `PageMarginRight`, `PageMarginsOptions`, `PageMarginsOptionsPtr`, `PageMarginTop`, `Published`, `RightToLeft`, `SheetFormatPrOptions`, `SheetFormatPrOptionsPtr`, `SheetPrOption`, `SheetPrOptionPtr`, `SheetViewOption`, `SheetViewOptionPtr`, `ShowFormulas`, `ShowGridLines`, `ShowRowColHeaders`, `ShowRuler`, `ShowZeros`, `TabColorIndexed`, `TabColorRGB`, `TabColorTheme`, `TabColorTint`, `ThickBottom`, `ThickTop`, `TopLeftCell`, `View`, `WorkbookPrOption`, `WorkbookPrOptionPtr`, `ZeroHeight` and `ZoomScale`
Remove 2 exported constants:
`OrientationPortrait` and `OrientationLandscape`
Change 8 functions:
- Change the `func (f *File) SetPageLayout(sheet string, opts ...PageLayoutOption) error` to `func (f *File) SetPageLayout(sheet string, opts *PageLayoutOptions) error`
- Change the `func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error` to `func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error)`
- Change the `func (f *File) SetPageMargins(sheet string, opts ...PageMarginsOptions) error` to `func (f *File) SetPageMargins(sheet string, opts *PageLayoutMarginsOptions) error`
- Change the `func (f *File) GetPageMargins(sheet string, opts ...PageMarginsOptionsPtr) error` to `func (f *File) GetPageMargins(sheet string) (PageLayoutMarginsOptions, error)`
- Change the `func (f *File) SetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOption) error` to `func (f *File) SetSheetView(sheet string, viewIndex int, opts *ViewOptions) error`
- Change the `func (f *File) GetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOptionPtr) error` to `func (f *File) GetSheetView(sheet string, viewIndex int) (ViewOptions, error)`
- Change the `func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error` to `func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error`
- Change the `func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error` to `func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error)`
Introduce new function to instead of existing functions:
- New function `func (f *File) SetSheetProps(sheet string, opts *SheetPropsOptions) error` instead of `func (f *File) SetSheetPrOptions(sheet string, opts ...SheetPrOption) error` and `func (f *File) SetSheetFormatPr(sheet string, opts ...SheetFormatPrOption
2022-09-29 22:00:21 +08:00
|
|
|
opts, err := f.GetConditionalFormats("Sheet1")
|
2022-08-27 00:45:46 +08:00
|
|
|
assert.NoError(t, err)
|
This closes #1358, made a refactor with breaking changes, see details:
This made a refactor with breaking changes:
Motivation and Context
When I decided to add set horizontal centered support for this library to resolve #1358, the reason I made this huge breaking change was:
- There are too many exported types for set sheet view, properties, and format properties, although a function using the functional options pattern can be optimized by returning an anonymous function, these types or property set or get function has no binding categorization, so I change these functions like `SetAppProps` to accept a pointer of options structure.
- Users can not easily find out which properties should be in the `SetSheetPrOptions` or `SetSheetFormatPr` categories
- Nested properties cannot proceed modify easily
Introduce 5 new export data types:
`HeaderFooterOptions`, `PageLayoutMarginsOptions`, `PageLayoutOptions`, `SheetPropsOptions`, and `ViewOptions`
Rename 4 exported data types:
- Rename `PivotTableOption` to `PivotTableOptions`
- Rename `FormatHeaderFooter` to `HeaderFooterOptions`
- Rename `FormatSheetProtection` to `SheetProtectionOptions`
- Rename `SparklineOption` to `SparklineOptions`
Remove 54 exported types:
`AutoPageBreaks`, `BaseColWidth`, `BlackAndWhite`, `CodeName`, `CustomHeight`, `Date1904`, `DefaultColWidth`, `DefaultGridColor`, `DefaultRowHeight`, `EnableFormatConditionsCalculation`, `FilterPrivacy`, `FirstPageNumber`, `FitToHeight`, `FitToPage`, `FitToWidth`, `OutlineSummaryBelow`, `PageLayoutOption`, `PageLayoutOptionPtr`, `PageLayoutOrientation`, `PageLayoutPaperSize`, `PageLayoutScale`, `PageMarginBottom`, `PageMarginFooter`, `PageMarginHeader`, `PageMarginLeft`, `PageMarginRight`, `PageMarginsOptions`, `PageMarginsOptionsPtr`, `PageMarginTop`, `Published`, `RightToLeft`, `SheetFormatPrOptions`, `SheetFormatPrOptionsPtr`, `SheetPrOption`, `SheetPrOptionPtr`, `SheetViewOption`, `SheetViewOptionPtr`, `ShowFormulas`, `ShowGridLines`, `ShowRowColHeaders`, `ShowRuler`, `ShowZeros`, `TabColorIndexed`, `TabColorRGB`, `TabColorTheme`, `TabColorTint`, `ThickBottom`, `ThickTop`, `TopLeftCell`, `View`, `WorkbookPrOption`, `WorkbookPrOptionPtr`, `ZeroHeight` and `ZoomScale`
Remove 2 exported constants:
`OrientationPortrait` and `OrientationLandscape`
Change 8 functions:
- Change the `func (f *File) SetPageLayout(sheet string, opts ...PageLayoutOption) error` to `func (f *File) SetPageLayout(sheet string, opts *PageLayoutOptions) error`
- Change the `func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error` to `func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error)`
- Change the `func (f *File) SetPageMargins(sheet string, opts ...PageMarginsOptions) error` to `func (f *File) SetPageMargins(sheet string, opts *PageLayoutMarginsOptions) error`
- Change the `func (f *File) GetPageMargins(sheet string, opts ...PageMarginsOptionsPtr) error` to `func (f *File) GetPageMargins(sheet string) (PageLayoutMarginsOptions, error)`
- Change the `func (f *File) SetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOption) error` to `func (f *File) SetSheetView(sheet string, viewIndex int, opts *ViewOptions) error`
- Change the `func (f *File) GetSheetViewOptions(sheet string, viewIndex int, opts ...SheetViewOptionPtr) error` to `func (f *File) GetSheetView(sheet string, viewIndex int) (ViewOptions, error)`
- Change the `func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error` to `func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error`
- Change the `func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error` to `func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error)`
Introduce new function to instead of existing functions:
- New function `func (f *File) SetSheetProps(sheet string, opts *SheetPropsOptions) error` instead of `func (f *File) SetSheetPrOptions(sheet string, opts ...SheetPrOption) error` and `func (f *File) SetSheetFormatPr(sheet string, opts ...SheetFormatPrOption
2022-09-29 22:00:21 +08:00
|
|
|
assert.Equal(t, format, opts["A1:A2"])
|
2022-08-27 00:45:46 +08:00
|
|
|
}
|
|
|
|
// Test get conditional formats on no exists worksheet
|
|
|
|
f := NewFile()
|
|
|
|
_, err := f.GetConditionalFormats("SheetN")
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, err, "sheet SheetN does not exist")
|
2022-08-27 00:45:46 +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.
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN does 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)
|
2022-11-12 00:02:11 +08:00
|
|
|
styles, err := f.stylesReader()
|
|
|
|
assert.NoError(t, err)
|
2019-04-26 00:24:25 +08:00
|
|
|
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
|
|
|
|
2021-09-28 22:02:31 +08:00
|
|
|
var exp string
|
|
|
|
_, err = f.NewStyle(&Style{CustomNumFmt: &exp})
|
|
|
|
assert.EqualError(t, err, ErrCustomNumFmt.Error())
|
2020-09-18 22:20:58 +08:00
|
|
|
_, err = f.NewStyle(&Style{Font: &Font{Family: strings.Repeat("s", MaxFontFamilyLength+1)}})
|
2021-09-28 22:02:31 +08:00
|
|
|
assert.EqualError(t, err, ErrFontLength.Error())
|
2020-09-18 22:20:58 +08:00
|
|
|
_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
|
2021-09-28 22:02:31 +08:00
|
|
|
assert.EqualError(t, err, ErrFontSize.Error())
|
2020-10-04 21:07:39 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test create numeric custom style.
|
2022-03-24 00:19:30 +08:00
|
|
|
numFmt := "####;####"
|
2020-10-04 21:07:39 +08:00
|
|
|
f.Styles.NumFmts = nil
|
|
|
|
styleID, err = f.NewStyle(&Style{
|
2022-03-24 00:19:30 +08:00
|
|
|
CustomNumFmt: &numFmt,
|
2020-10-04 21:07:39 +08:00
|
|
|
})
|
|
|
|
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)
|
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test create currency custom style.
|
2020-10-04 21:07:39 +08:00
|
|
|
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)
|
2021-09-28 22:02:31 +08:00
|
|
|
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set build-in scientific number format.
|
2021-09-28 22:02:31 +08:00
|
|
|
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)
|
2021-12-03 00:19:11 +08:00
|
|
|
|
|
|
|
f = NewFile()
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test currency number format.
|
2021-12-03 00:19:11 +08:00
|
|
|
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)
|
2022-04-28 15:33:25 +08:00
|
|
|
assert.Equal(t, 0, style4)
|
2021-12-03 00:19:11 +08:00
|
|
|
|
|
|
|
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)
|
2022-04-28 15:33:25 +08:00
|
|
|
assert.Equal(t, 0, style5)
|
2022-11-12 00:02:11 +08:00
|
|
|
|
|
|
|
// Test create style with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.NewStyle(&Style{NumFmt: 165})
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewConditionalStyle(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
// Test create conditional style with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
_, err := f.NewConditionalStyle(`{"font":{"color":"#9A0511"},"fill":{"type":"pattern","color":["#FEC7CE"],"pattern":1}}`)
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
2019-04-26 00:24:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetDefaultFont(t *testing.T) {
|
|
|
|
f := NewFile()
|
2022-11-12 00:02:11 +08:00
|
|
|
s, err := f.GetDefaultFont()
|
|
|
|
assert.NoError(t, err)
|
2019-04-26 00:24:25 +08:00
|
|
|
assert.Equal(t, s, "Calibri", "Default font should be Calibri")
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test get default font with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.GetDefaultFont()
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
2019-04-26 00:24:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSetDefaultFont(t *testing.T) {
|
|
|
|
f := NewFile()
|
2022-11-12 00:02:11 +08:00
|
|
|
assert.NoError(t, f.SetDefaultFont("Arial"))
|
|
|
|
styles, err := f.stylesReader()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
s, err := f.GetDefaultFont()
|
|
|
|
assert.NoError(t, err)
|
2021-11-16 00:40:44 +08:00
|
|
|
assert.Equal(t, s, "Arial", "Default font should change to Arial")
|
2019-04-26 00:24:25 +08:00
|
|
|
assert.Equal(t, *styles.CellStyles.CellStyle[0].CustomBuiltIn, true)
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set default font with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualError(t, f.SetDefaultFont("Arial"), "XML syntax error on line 1: invalid UTF-8")
|
2019-04-26 00:24:25 +08:00
|
|
|
}
|
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-12-27 23:34:14 +08:00
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
2022-11-12 00:02:11 +08:00
|
|
|
styles, err := f.stylesReader()
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
|
|
|
assert.EqualValues(t, new(xlsxStyleSheet), styles)
|
2020-03-10 00:04:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestThemeReader(t *testing.T) {
|
|
|
|
f := NewFile()
|
2021-03-30 23:02:22 +08:00
|
|
|
// Test read theme with unsupported charset.
|
2022-10-28 00:31:55 +08:00
|
|
|
f.Pkg.Store(defaultXMLPathTheme, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualValues(t, &xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}, f.themeReader())
|
2020-03-10 00:04:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSetCellStyle(t *testing.T) {
|
|
|
|
f := NewFile()
|
|
|
|
// Test set cell style on not exists worksheet.
|
2022-08-28 00:16:41 +08:00
|
|
|
assert.EqualError(t, f.SetCellStyle("SheetN", "A1", "A2", 1), "sheet SheetN does not exist")
|
2022-09-01 00:41:52 +08:00
|
|
|
// Test set cell style with invalid style ID.
|
|
|
|
assert.EqualError(t, f.SetCellStyle("Sheet1", "A1", "A2", -1), newInvalidStyleID(-1).Error())
|
|
|
|
// Test set cell style with not exists style ID.
|
|
|
|
assert.EqualError(t, f.SetCellStyle("Sheet1", "A1", "A2", 10), newInvalidStyleID(10).Error())
|
2022-11-12 00:02:11 +08:00
|
|
|
// Test set cell style with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
assert.EqualError(t, f.SetCellStyle("Sheet1", "A1", "A2", 1), "XML syntax error on line 1: invalid UTF-8")
|
2020-03-10 00:04:23 +08:00
|
|
|
}
|
2020-05-24 20:20:22 +08:00
|
|
|
|
|
|
|
func TestGetStyleID(t *testing.T) {
|
2022-11-12 00:02:11 +08:00
|
|
|
f := NewFile()
|
|
|
|
styleID, err := f.getStyleID(&xlsxStyleSheet{}, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, -1, styleID)
|
|
|
|
// Test get style ID with unsupported charset style sheet.
|
|
|
|
f.Styles = nil
|
|
|
|
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
|
|
|
_, err = f.getStyleID(&xlsxStyleSheet{
|
|
|
|
CellXfs: &xlsxCellXfs{},
|
|
|
|
Fonts: &xlsxFonts{
|
|
|
|
Font: []*xlsxFont{{}},
|
|
|
|
},
|
|
|
|
}, &Style{NumFmt: 0, Font: &Font{}})
|
|
|
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
2020-05-24 20:20:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetFillID(t *testing.T) {
|
2022-11-12 00:02:11 +08:00
|
|
|
styles, err := NewFile().stylesReader()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, -1, getFillID(styles, &Style{Fill: Fill{Type: "unknown"}}))
|
2020-05-24 20:20:22 +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
|
|
|
}
|
2021-12-01 19:11:51 +08:00
|
|
|
|
|
|
|
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")))
|
2021-12-03 00:19:11 +08:00
|
|
|
}
|