extend cell value load to support custom datetime format (#703)

* extend cell value load to support custom datetime format

* cleanup incorrect imports

* fix numeric values conversion as done in legacy Excel

* fix tests coverage

* revert temporary package name fix

* remove personal info from test XLSX files

* remove unused dependencies

* update format conversion in parseTime

* new UT to increase code coverage

* Resolve code review issue for PR #703

* Rename broken file name generated by unit test

Co-authored-by: xuri <xuri.me@gmail.com>
This commit is contained in:
Artem Kustikov 2020-10-04 16:07:39 +03:00 committed by GitHub
parent 9055a835a8
commit f2b8798a34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 452 additions and 248 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
~$*.xlsx
test/Test*.xlsx
test/Test*.xlsm
*.out
*.test
.idea

18
cell.go
View File

@ -762,9 +762,23 @@ func (f *File) formattedValue(s int, v string) string {
return v
}
styleSheet := f.stylesReader()
ok := builtInNumFmtFunc[*styleSheet.CellXfs.Xf[s].NumFmtID]
if s >= len(styleSheet.CellXfs.Xf) {
return v
}
numFmtId := *styleSheet.CellXfs.Xf[s].NumFmtID
ok := builtInNumFmtFunc[numFmtId]
if ok != nil {
return ok(*styleSheet.CellXfs.Xf[s].NumFmtID, v)
return ok(v, builtInNumFmt[numFmtId])
}
for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
if xlsxFmt.NumFmtID == numFmtId {
format := strings.ToLower(xlsxFmt.FormatCode)
if strings.Contains(format, "y") || strings.Contains(format, "m") || strings.Contains(format, "d") || strings.Contains(format, "h") {
return parseTime(v, format)
}
return v
}
}
return v
}

View File

@ -111,6 +111,23 @@ func TestSetCellValue(t *testing.T) {
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Duration(1e13)), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
}
func TestSetCellValues(t *testing.T) {
f := NewFile()
err := f.SetCellValue("Sheet1", "A1", time.Date(2010, time.December, 31, 0, 0, 0, 0, time.UTC))
assert.NoError(t, err)
v, err := f.GetCellValue("Sheet1", "A1")
assert.NoError(t, err)
assert.Equal(t, v, "12/31/10 12:00")
// test date value lower than min date supported by Excel
err = f.SetCellValue("Sheet1", "A1", time.Date(1600, time.December, 31, 0, 0, 0, 0, time.UTC))
assert.NoError(t, err)
_, err = f.GetCellValue("Sheet1", "A1")
assert.EqualError(t, err, `strconv.ParseFloat: parsing "1600-12-31T00:00:00Z": invalid syntax`)
}
func TestSetCellBool(t *testing.T) {
f := NewFile()
assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
@ -264,3 +281,22 @@ func TestSetCellRichText(t *testing.T) {
// Test set cell rich text with illegal cell coordinates
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
}
func TestFormattedValue(t *testing.T) {
f := NewFile()
v := f.formattedValue(0, "43528")
assert.Equal(t, "43528", v)
v = f.formattedValue(15, "43528")
assert.Equal(t, "43528", v)
v = f.formattedValue(1, "43528")
assert.Equal(t, "43528", v)
customNumFmt := "[$-409]MM/DD/YYYY"
_, err := f.NewStyle(&Style{
CustomNumFmt: &customNumFmt,
})
assert.NoError(t, err)
v = f.formattedValue(1, "43528")
assert.Equal(t, "03/04/2019", v)
}

View File

@ -19,5 +19,5 @@ import (
func TestEncrypt(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
assert.NoError(t, err)
assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestEncrypt.xlsx"), Options{Password: "password"}), "not support encryption currently")
assert.EqualError(t, f.SaveAs(filepath.Join("test", "BadEncrypt.xlsx"), Options{Password: "password"}), "not support encryption currently")
}

View File

@ -158,7 +158,7 @@ func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
}
if s == 0 {
style, _ := f.NewStyle(&Style{NumFmt: format})
_ = f.SetCellStyle(sheet, axis, axis, style)
err = f.SetCellStyle(sheet, axis, axis, style)
}
return err
}

View File

@ -257,7 +257,7 @@ func TestBrokenFile(t *testing.T) {
t.Run("SaveAsEmptyStruct", func(t *testing.T) {
// Test write file with broken file struct with given path.
assert.NoError(t, f.SaveAs(filepath.Join("test", "BrokenFile.SaveAsEmptyStruct.xlsx")))
assert.NoError(t, f.SaveAs(filepath.Join("test", "BadWorkbook.SaveAsEmptyStruct.xlsx")))
})
t.Run("OpenBadWorkbook", func(t *testing.T) {
@ -1175,6 +1175,9 @@ func TestSetDefaultTimeStyle(t *testing.T) {
f := NewFile()
// Test set default time style on not exists worksheet.
assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN is not exist")
// Test set default time style on invalid cell
assert.EqualError(t, f.setDefaultTimeStyle("Sheet1", "", 42), "cannot convert cell \"\" to coordinates: invalid cell name \"\"")
}
func TestAddVBAProject(t *testing.T) {

View File

@ -123,7 +123,7 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
}
}
if f.options != nil {
if f.options != nil && f.options.Password != "" {
if err := zw.Close(); err != nil {
return buf, err
}

19
rows.go
View File

@ -345,6 +345,25 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
}
return f.formattedValue(xlsx.S, xlsx.V), nil
default:
// correct numeric values as legacy Excel app
// https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel
// In the top figure the fraction 1/9000 in Excel is displayed.
// Although this number has a decimal representation that is an infinite string of ones,
// Excel displays only the leading 15 figures. In the second line, the number one is added to the fraction, and again Excel displays only 15 figures.
const precision = 1000000000000000
if len(xlsx.V) > 16 {
num, err := strconv.ParseFloat(xlsx.V, 64)
if err != nil {
return "", err
}
num = math.Round(num*precision) / precision
val := fmt.Sprintf("%g", num)
if val != xlsx.V {
return f.formattedValue(xlsx.S, val), nil
}
}
return f.formattedValue(xlsx.S, xlsx.V), nil
}
}

View File

@ -817,7 +817,7 @@ func TestDuplicateMergeCells(t *testing.T) {
assert.EqualError(t, f.duplicateMergeCells("SheetN", xlsx, 1, 2), "sheet SheetN is not exist")
}
func TestGetValueFrom(t *testing.T) {
func TestGetValueFromInlineStr(t *testing.T) {
c := &xlsxC{T: "inlineStr"}
f := NewFile()
d := &xlsxSST{}
@ -826,6 +826,20 @@ func TestGetValueFrom(t *testing.T) {
assert.Equal(t, "", val)
}
func TestGetValueFromNumber(t *testing.T) {
c := &xlsxC{T: "n", V: "2.2200000000000002"}
f := NewFile()
d := &xlsxSST{}
val, err := c.getValueFrom(f, d)
assert.NoError(t, err)
assert.Equal(t, "2.22", val)
c = &xlsxC{T: "n", V: "2.220000ddsf0000000002-r"}
val, err = c.getValueFrom(f, d)
assert.NotNil(t, err)
assert.Equal(t, "strconv.ParseFloat: parsing \"2.220000ddsf0000000002-r\": invalid syntax", err.Error())
}
func TestErrSheetNotExistError(t *testing.T) {
err := ErrSheetNotExist{SheetName: "Sheet1"}
assert.EqualValues(t, err.Error(), "sheet Sheet1 is not exist")
@ -842,6 +856,27 @@ func TestCheckRow(t *testing.T) {
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", false), `cannot convert cell "-" to coordinates: invalid cell name "-"`)
}
func TestNumberFormats(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
cells := make([][]string, 0)
cols, err := f.Cols("Sheet2")
if !assert.NoError(t, err) {
t.FailNow()
}
for cols.Next() {
col, err := cols.Rows()
assert.NoError(t, err)
if err != nil {
break
}
cells = append(cells, col)
}
assert.Equal(t, []string{"", "200", "450", "200", "510", "315", "127", "89", "348", "53", "37"}, cells[3])
}
func BenchmarkRows(b *testing.B) {
f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
for i := 0; i < b.N; i++ {

View File

@ -1,4 +1,4 @@
package excelize_test
package excelize
import (
"fmt"
@ -6,26 +6,24 @@ import (
"strings"
"testing"
"github.com/360EntSecGroup-Skylar/excelize/v2"
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
)
func ExampleFile_SetPageLayout() {
f := excelize.NewFile()
f := NewFile()
if err := f.SetPageLayout(
"Sheet1",
excelize.PageLayoutOrientation(excelize.OrientationLandscape),
PageLayoutOrientation(OrientationLandscape),
); err != nil {
fmt.Println(err)
}
if err := f.SetPageLayout(
"Sheet1",
excelize.PageLayoutPaperSize(10),
excelize.FitToHeight(2),
excelize.FitToWidth(2),
PageLayoutPaperSize(10),
FitToHeight(2),
FitToWidth(2),
); err != nil {
fmt.Println(err)
}
@ -33,12 +31,12 @@ func ExampleFile_SetPageLayout() {
}
func ExampleFile_GetPageLayout() {
f := excelize.NewFile()
f := NewFile()
var (
orientation excelize.PageLayoutOrientation
paperSize excelize.PageLayoutPaperSize
fitToHeight excelize.FitToHeight
fitToWidth excelize.FitToWidth
orientation PageLayoutOrientation
paperSize PageLayoutPaperSize
fitToHeight FitToHeight
fitToWidth FitToWidth
)
if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
fmt.Println(err)
@ -67,7 +65,7 @@ func ExampleFile_GetPageLayout() {
}
func TestNewSheet(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
sheetID := f.NewSheet("Sheet2")
f.SetActiveSheet(sheetID)
// delete original sheet
@ -76,7 +74,7 @@ func TestNewSheet(t *testing.T) {
}
func TestSetPane(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
f.NewSheet("Panes 2")
assert.NoError(t, f.SetPanes("Panes 2", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`))
@ -93,13 +91,13 @@ func TestPageLayoutOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container excelize.PageLayoutOptionPtr
nonDefault excelize.PageLayoutOption
container PageLayoutOptionPtr
nonDefault PageLayoutOption
}{
{new(excelize.PageLayoutOrientation), excelize.PageLayoutOrientation(excelize.OrientationLandscape)},
{new(excelize.PageLayoutPaperSize), excelize.PageLayoutPaperSize(10)},
{new(excelize.FitToHeight), excelize.FitToHeight(2)},
{new(excelize.FitToWidth), excelize.FitToWidth(2)},
{new(PageLayoutOrientation), PageLayoutOrientation(OrientationLandscape)},
{new(PageLayoutPaperSize), PageLayoutPaperSize(10)},
{new(FitToHeight), FitToHeight(2)},
{new(FitToWidth), FitToWidth(2)},
}
for i, test := range testData {
@ -108,11 +106,11 @@ func TestPageLayoutOption(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
def := deepcopy.Copy(test.container).(excelize.PageLayoutOptionPtr)
val1 := deepcopy.Copy(def).(excelize.PageLayoutOptionPtr)
val2 := deepcopy.Copy(def).(excelize.PageLayoutOptionPtr)
def := deepcopy.Copy(test.container).(PageLayoutOptionPtr)
val1 := deepcopy.Copy(def).(PageLayoutOptionPtr)
val2 := deepcopy.Copy(def).(PageLayoutOptionPtr)
f := excelize.NewFile()
f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageLayout(sheet, def), opt)
// Get again and check
@ -150,7 +148,7 @@ func TestPageLayoutOption(t *testing.T) {
}
func TestSearchSheet(t *testing.T) {
f, err := excelize.OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
@ -172,36 +170,36 @@ func TestSearchSheet(t *testing.T) {
assert.EqualValues(t, expected, result)
// Test search worksheet data after set cell value
f = excelize.NewFile()
f = NewFile()
assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
_, err = f.SearchSheet("Sheet1", "")
assert.NoError(t, err)
}
func TestSetPageLayout(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test set page layout on not exists worksheet.
assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN is not exist")
}
func TestGetPageLayout(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test get page layout on not exists worksheet.
assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN is not exist")
}
func TestSetHeaderFooter(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
// Test set header and footer on not exists worksheet.
assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN is not exist")
// Test set header and footer with illegal setting.
assert.EqualError(t, f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
assert.EqualError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
OddHeader: strings.Repeat("c", 256),
}), "field OddHeader must be less than 255 characters")
assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
assert.NoError(t, f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
DifferentFirst: true,
DifferentOddEven: true,
OddHeader: "&R&P",
@ -214,28 +212,28 @@ func TestSetHeaderFooter(t *testing.T) {
}
func TestDefinedName(t *testing.T) {
f := excelize.NewFile()
assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
f := NewFile()
assert.NoError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
Scope: "Sheet1",
}))
assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
assert.NoError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
}))
assert.EqualError(t, f.SetDefinedName(&excelize.DefinedName{
assert.EqualError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
}), "the same name already exists on the scope")
assert.EqualError(t, f.DeleteDefinedName(&excelize.DefinedName{
assert.EqualError(t, f.DeleteDefinedName(&DefinedName{
Name: "No Exist Defined Name",
}), "no defined name on the scope")
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
assert.NoError(t, f.DeleteDefinedName(&excelize.DefinedName{
assert.NoError(t, f.DeleteDefinedName(&DefinedName{
Name: "Amount",
}))
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
@ -244,7 +242,7 @@ func TestDefinedName(t *testing.T) {
}
func TestGroupSheets(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
sheets := []string{"Sheet2", "Sheet3"}
for _, sheet := range sheets {
f.NewSheet(sheet)
@ -256,7 +254,7 @@ func TestGroupSheets(t *testing.T) {
}
func TestUngroupSheets(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
sheets := []string{"Sheet2", "Sheet3", "Sheet4", "Sheet5"}
for _, sheet := range sheets {
f.NewSheet(sheet)
@ -265,7 +263,7 @@ func TestUngroupSheets(t *testing.T) {
}
func TestInsertPageBreak(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.InsertPageBreak("Sheet1", "A1"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
@ -276,7 +274,7 @@ func TestInsertPageBreak(t *testing.T) {
}
func TestRemovePageBreak(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
@ -302,7 +300,7 @@ func TestRemovePageBreak(t *testing.T) {
}
func TestGetSheetName(t *testing.T) {
f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.Equal(t, "Sheet1", f.GetSheetName(0))
assert.Equal(t, "Sheet2", f.GetSheetName(1))
assert.Equal(t, "", f.GetSheetName(-1))
@ -314,7 +312,7 @@ func TestGetSheetMap(t *testing.T) {
1: "Sheet1",
2: "Sheet2",
}
f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
sheetMap := f.GetSheetMap()
for idx, name := range sheetMap {
assert.Equal(t, expectedMap[idx], name)

View File

@ -1,4 +1,4 @@
package excelize_test
package excelize
import (
"fmt"
@ -6,39 +6,37 @@ import (
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)
var _ = []excelize.SheetPrOption{
excelize.CodeName("hello"),
excelize.EnableFormatConditionsCalculation(false),
excelize.Published(false),
excelize.FitToPage(true),
excelize.AutoPageBreaks(true),
excelize.OutlineSummaryBelow(true),
var _ = []SheetPrOption{
CodeName("hello"),
EnableFormatConditionsCalculation(false),
Published(false),
FitToPage(true),
AutoPageBreaks(true),
OutlineSummaryBelow(true),
}
var _ = []excelize.SheetPrOptionPtr{
(*excelize.CodeName)(nil),
(*excelize.EnableFormatConditionsCalculation)(nil),
(*excelize.Published)(nil),
(*excelize.FitToPage)(nil),
(*excelize.AutoPageBreaks)(nil),
(*excelize.OutlineSummaryBelow)(nil),
var _ = []SheetPrOptionPtr{
(*CodeName)(nil),
(*EnableFormatConditionsCalculation)(nil),
(*Published)(nil),
(*FitToPage)(nil),
(*AutoPageBreaks)(nil),
(*OutlineSummaryBelow)(nil),
}
func ExampleFile_SetSheetPrOptions() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetPrOptions(sheet,
excelize.CodeName("code"),
excelize.EnableFormatConditionsCalculation(false),
excelize.Published(false),
excelize.FitToPage(true),
excelize.AutoPageBreaks(true),
excelize.OutlineSummaryBelow(false),
CodeName("code"),
EnableFormatConditionsCalculation(false),
Published(false),
FitToPage(true),
AutoPageBreaks(true),
OutlineSummaryBelow(false),
); err != nil {
fmt.Println(err)
}
@ -46,16 +44,16 @@ func ExampleFile_SetSheetPrOptions() {
}
func ExampleFile_GetSheetPrOptions() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
var (
codeName excelize.CodeName
enableFormatConditionsCalculation excelize.EnableFormatConditionsCalculation
published excelize.Published
fitToPage excelize.FitToPage
autoPageBreaks excelize.AutoPageBreaks
outlineSummaryBelow excelize.OutlineSummaryBelow
codeName CodeName
enableFormatConditionsCalculation EnableFormatConditionsCalculation
published Published
fitToPage FitToPage
autoPageBreaks AutoPageBreaks
outlineSummaryBelow OutlineSummaryBelow
)
if err := f.GetSheetPrOptions(sheet,
@ -89,15 +87,15 @@ func TestSheetPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container excelize.SheetPrOptionPtr
nonDefault excelize.SheetPrOption
container SheetPrOptionPtr
nonDefault SheetPrOption
}{
{new(excelize.CodeName), excelize.CodeName("xx")},
{new(excelize.EnableFormatConditionsCalculation), excelize.EnableFormatConditionsCalculation(false)},
{new(excelize.Published), excelize.Published(false)},
{new(excelize.FitToPage), excelize.FitToPage(true)},
{new(excelize.AutoPageBreaks), excelize.AutoPageBreaks(true)},
{new(excelize.OutlineSummaryBelow), excelize.OutlineSummaryBelow(false)},
{new(CodeName), CodeName("xx")},
{new(EnableFormatConditionsCalculation), EnableFormatConditionsCalculation(false)},
{new(Published), Published(false)},
{new(FitToPage), FitToPage(true)},
{new(AutoPageBreaks), AutoPageBreaks(true)},
{new(OutlineSummaryBelow), OutlineSummaryBelow(false)},
}
for i, test := range testData {
@ -106,11 +104,11 @@ func TestSheetPrOptions(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
def := deepcopy.Copy(test.container).(excelize.SheetPrOptionPtr)
val1 := deepcopy.Copy(def).(excelize.SheetPrOptionPtr)
val2 := deepcopy.Copy(def).(excelize.SheetPrOptionPtr)
def := deepcopy.Copy(test.container).(SheetPrOptionPtr)
val1 := deepcopy.Copy(def).(SheetPrOptionPtr)
val2 := deepcopy.Copy(def).(SheetPrOptionPtr)
f := excelize.NewFile()
f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetPrOptions(sheet, def), opt)
// Get again and check
@ -148,46 +146,46 @@ func TestSheetPrOptions(t *testing.T) {
}
func TestSetSheetrOptions(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test SetSheetrOptions on not exists worksheet.
assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
}
func TestGetSheetPrOptions(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test GetSheetPrOptions on not exists worksheet.
assert.EqualError(t, f.GetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
}
var _ = []excelize.PageMarginsOptions{
excelize.PageMarginBottom(1.0),
excelize.PageMarginFooter(1.0),
excelize.PageMarginHeader(1.0),
excelize.PageMarginLeft(1.0),
excelize.PageMarginRight(1.0),
excelize.PageMarginTop(1.0),
var _ = []PageMarginsOptions{
PageMarginBottom(1.0),
PageMarginFooter(1.0),
PageMarginHeader(1.0),
PageMarginLeft(1.0),
PageMarginRight(1.0),
PageMarginTop(1.0),
}
var _ = []excelize.PageMarginsOptionsPtr{
(*excelize.PageMarginBottom)(nil),
(*excelize.PageMarginFooter)(nil),
(*excelize.PageMarginHeader)(nil),
(*excelize.PageMarginLeft)(nil),
(*excelize.PageMarginRight)(nil),
(*excelize.PageMarginTop)(nil),
var _ = []PageMarginsOptionsPtr{
(*PageMarginBottom)(nil),
(*PageMarginFooter)(nil),
(*PageMarginHeader)(nil),
(*PageMarginLeft)(nil),
(*PageMarginRight)(nil),
(*PageMarginTop)(nil),
}
func ExampleFile_SetPageMargins() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
if err := f.SetPageMargins(sheet,
excelize.PageMarginBottom(1.0),
excelize.PageMarginFooter(1.0),
excelize.PageMarginHeader(1.0),
excelize.PageMarginLeft(1.0),
excelize.PageMarginRight(1.0),
excelize.PageMarginTop(1.0),
PageMarginBottom(1.0),
PageMarginFooter(1.0),
PageMarginHeader(1.0),
PageMarginLeft(1.0),
PageMarginRight(1.0),
PageMarginTop(1.0),
); err != nil {
fmt.Println(err)
}
@ -195,16 +193,16 @@ func ExampleFile_SetPageMargins() {
}
func ExampleFile_GetPageMargins() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
var (
marginBottom excelize.PageMarginBottom
marginFooter excelize.PageMarginFooter
marginHeader excelize.PageMarginHeader
marginLeft excelize.PageMarginLeft
marginRight excelize.PageMarginRight
marginTop excelize.PageMarginTop
marginBottom PageMarginBottom
marginFooter PageMarginFooter
marginHeader PageMarginHeader
marginLeft PageMarginLeft
marginRight PageMarginRight
marginTop PageMarginTop
)
if err := f.GetPageMargins(sheet,
@ -238,15 +236,15 @@ func TestPageMarginsOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container excelize.PageMarginsOptionsPtr
nonDefault excelize.PageMarginsOptions
container PageMarginsOptionsPtr
nonDefault PageMarginsOptions
}{
{new(excelize.PageMarginTop), excelize.PageMarginTop(1.0)},
{new(excelize.PageMarginBottom), excelize.PageMarginBottom(1.0)},
{new(excelize.PageMarginLeft), excelize.PageMarginLeft(1.0)},
{new(excelize.PageMarginRight), excelize.PageMarginRight(1.0)},
{new(excelize.PageMarginHeader), excelize.PageMarginHeader(1.0)},
{new(excelize.PageMarginFooter), excelize.PageMarginFooter(1.0)},
{new(PageMarginTop), PageMarginTop(1.0)},
{new(PageMarginBottom), PageMarginBottom(1.0)},
{new(PageMarginLeft), PageMarginLeft(1.0)},
{new(PageMarginRight), PageMarginRight(1.0)},
{new(PageMarginHeader), PageMarginHeader(1.0)},
{new(PageMarginFooter), PageMarginFooter(1.0)},
}
for i, test := range testData {
@ -255,11 +253,11 @@ func TestPageMarginsOption(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
def := deepcopy.Copy(test.container).(excelize.PageMarginsOptionsPtr)
val1 := deepcopy.Copy(def).(excelize.PageMarginsOptionsPtr)
val2 := deepcopy.Copy(def).(excelize.PageMarginsOptionsPtr)
def := deepcopy.Copy(test.container).(PageMarginsOptionsPtr)
val1 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
val2 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
f := excelize.NewFile()
f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageMargins(sheet, def), opt)
// Get again and check
@ -297,29 +295,29 @@ func TestPageMarginsOption(t *testing.T) {
}
func TestSetPageMargins(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test set page margins on not exists worksheet.
assert.EqualError(t, f.SetPageMargins("SheetN"), "sheet SheetN is not exist")
}
func TestGetPageMargins(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
// Test get page margins on not exists worksheet.
assert.EqualError(t, f.GetPageMargins("SheetN"), "sheet SheetN is not exist")
}
func ExampleFile_SetSheetFormatPr() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetFormatPr(sheet,
excelize.BaseColWidth(1.0),
excelize.DefaultColWidth(1.0),
excelize.DefaultRowHeight(1.0),
excelize.CustomHeight(true),
excelize.ZeroHeight(true),
excelize.ThickTop(true),
excelize.ThickBottom(true),
BaseColWidth(1.0),
DefaultColWidth(1.0),
DefaultRowHeight(1.0),
CustomHeight(true),
ZeroHeight(true),
ThickTop(true),
ThickBottom(true),
); err != nil {
fmt.Println(err)
}
@ -327,17 +325,17 @@ func ExampleFile_SetSheetFormatPr() {
}
func ExampleFile_GetSheetFormatPr() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
var (
baseColWidth excelize.BaseColWidth
defaultColWidth excelize.DefaultColWidth
defaultRowHeight excelize.DefaultRowHeight
customHeight excelize.CustomHeight
zeroHeight excelize.ZeroHeight
thickTop excelize.ThickTop
thickBottom excelize.ThickBottom
baseColWidth BaseColWidth
defaultColWidth DefaultColWidth
defaultRowHeight DefaultRowHeight
customHeight CustomHeight
zeroHeight ZeroHeight
thickTop ThickTop
thickBottom ThickBottom
)
if err := f.GetSheetFormatPr(sheet,
@ -374,16 +372,16 @@ func TestSheetFormatPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
container excelize.SheetFormatPrOptionsPtr
nonDefault excelize.SheetFormatPrOptions
container SheetFormatPrOptionsPtr
nonDefault SheetFormatPrOptions
}{
{new(excelize.BaseColWidth), excelize.BaseColWidth(1.0)},
{new(excelize.DefaultColWidth), excelize.DefaultColWidth(1.0)},
{new(excelize.DefaultRowHeight), excelize.DefaultRowHeight(1.0)},
{new(excelize.CustomHeight), excelize.CustomHeight(true)},
{new(excelize.ZeroHeight), excelize.ZeroHeight(true)},
{new(excelize.ThickTop), excelize.ThickTop(true)},
{new(excelize.ThickBottom), excelize.ThickBottom(true)},
{new(BaseColWidth), BaseColWidth(1.0)},
{new(DefaultColWidth), DefaultColWidth(1.0)},
{new(DefaultRowHeight), DefaultRowHeight(1.0)},
{new(CustomHeight), CustomHeight(true)},
{new(ZeroHeight), ZeroHeight(true)},
{new(ThickTop), ThickTop(true)},
{new(ThickBottom), ThickBottom(true)},
}
for i, test := range testData {
@ -392,11 +390,11 @@ func TestSheetFormatPrOptions(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
def := deepcopy.Copy(test.container).(excelize.SheetFormatPrOptionsPtr)
val1 := deepcopy.Copy(def).(excelize.SheetFormatPrOptionsPtr)
val2 := deepcopy.Copy(def).(excelize.SheetFormatPrOptionsPtr)
def := deepcopy.Copy(test.container).(SheetFormatPrOptionsPtr)
val1 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
val2 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
f := excelize.NewFile()
f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetFormatPr(sheet, def), opt)
// Get again and check
@ -434,26 +432,26 @@ func TestSheetFormatPrOptions(t *testing.T) {
}
func TestSetSheetFormatPr(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
assert.NoError(t, f.SetSheetFormatPr("Sheet1", excelize.BaseColWidth(1.0)))
assert.NoError(t, f.SetSheetFormatPr("Sheet1", BaseColWidth(1.0)))
// Test set formatting properties on not exists worksheet.
assert.EqualError(t, f.SetSheetFormatPr("SheetN"), "sheet SheetN is not exist")
}
func TestGetSheetFormatPr(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
var (
baseColWidth excelize.BaseColWidth
defaultColWidth excelize.DefaultColWidth
defaultRowHeight excelize.DefaultRowHeight
customHeight excelize.CustomHeight
zeroHeight excelize.ZeroHeight
thickTop excelize.ThickTop
thickBottom excelize.ThickBottom
baseColWidth BaseColWidth
defaultColWidth DefaultColWidth
defaultRowHeight DefaultRowHeight
customHeight CustomHeight
zeroHeight ZeroHeight
thickTop ThickTop
thickBottom ThickBottom
)
assert.NoError(t, f.GetSheetFormatPr("Sheet1",
&baseColWidth,

View File

@ -1,60 +1,58 @@
package excelize_test
package excelize
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)
var _ = []excelize.SheetViewOption{
excelize.DefaultGridColor(true),
excelize.RightToLeft(false),
excelize.ShowFormulas(false),
excelize.ShowGridLines(true),
excelize.ShowRowColHeaders(true),
excelize.TopLeftCell("B2"),
var _ = []SheetViewOption{
DefaultGridColor(true),
RightToLeft(false),
ShowFormulas(false),
ShowGridLines(true),
ShowRowColHeaders(true),
TopLeftCell("B2"),
// SheetViewOptionPtr are also SheetViewOption
new(excelize.DefaultGridColor),
new(excelize.RightToLeft),
new(excelize.ShowFormulas),
new(excelize.ShowGridLines),
new(excelize.ShowRowColHeaders),
new(excelize.TopLeftCell),
new(DefaultGridColor),
new(RightToLeft),
new(ShowFormulas),
new(ShowGridLines),
new(ShowRowColHeaders),
new(TopLeftCell),
}
var _ = []excelize.SheetViewOptionPtr{
(*excelize.DefaultGridColor)(nil),
(*excelize.RightToLeft)(nil),
(*excelize.ShowFormulas)(nil),
(*excelize.ShowGridLines)(nil),
(*excelize.ShowRowColHeaders)(nil),
(*excelize.TopLeftCell)(nil),
var _ = []SheetViewOptionPtr{
(*DefaultGridColor)(nil),
(*RightToLeft)(nil),
(*ShowFormulas)(nil),
(*ShowGridLines)(nil),
(*ShowRowColHeaders)(nil),
(*TopLeftCell)(nil),
}
func ExampleFile_SetSheetViewOptions() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetViewOptions(sheet, 0,
excelize.DefaultGridColor(false),
excelize.RightToLeft(false),
excelize.ShowFormulas(true),
excelize.ShowGridLines(true),
excelize.ShowRowColHeaders(true),
excelize.ZoomScale(80),
excelize.TopLeftCell("C3"),
DefaultGridColor(false),
RightToLeft(false),
ShowFormulas(true),
ShowGridLines(true),
ShowRowColHeaders(true),
ZoomScale(80),
TopLeftCell("C3"),
); err != nil {
fmt.Println(err)
}
var zoomScale excelize.ZoomScale
var zoomScale ZoomScale
fmt.Println("Default:")
fmt.Println("- zoomScale: 80")
if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(500)); err != nil {
if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(500)); err != nil {
fmt.Println(err)
}
@ -65,7 +63,7 @@ func ExampleFile_SetSheetViewOptions() {
fmt.Println("Used out of range value:")
fmt.Println("- zoomScale:", zoomScale)
if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(123)); err != nil {
if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(123)); err != nil {
fmt.Println(err)
}
@ -87,18 +85,18 @@ func ExampleFile_SetSheetViewOptions() {
}
func ExampleFile_GetSheetViewOptions() {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
var (
defaultGridColor excelize.DefaultGridColor
rightToLeft excelize.RightToLeft
showFormulas excelize.ShowFormulas
showGridLines excelize.ShowGridLines
showZeros excelize.ShowZeros
showRowColHeaders excelize.ShowRowColHeaders
zoomScale excelize.ZoomScale
topLeftCell excelize.TopLeftCell
defaultGridColor DefaultGridColor
rightToLeft RightToLeft
showFormulas ShowFormulas
showGridLines ShowGridLines
showZeros ShowZeros
showRowColHeaders ShowRowColHeaders
zoomScale ZoomScale
topLeftCell TopLeftCell
)
if err := f.GetSheetViewOptions(sheet, 0,
@ -124,7 +122,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println("- zoomScale:", zoomScale)
fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`)
if err := f.SetSheetViewOptions(sheet, 0, excelize.TopLeftCell("B2")); err != nil {
if err := f.SetSheetViewOptions(sheet, 0, TopLeftCell("B2")); err != nil {
fmt.Println(err)
}
@ -132,7 +130,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println(err)
}
if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowGridLines(false)); err != nil {
if err := f.SetSheetViewOptions(sheet, 0, ShowGridLines(false)); err != nil {
fmt.Println(err)
}
@ -140,7 +138,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println(err)
}
if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowZeros(false)); err != nil {
if err := f.SetSheetViewOptions(sheet, 0, ShowZeros(false)); err != nil {
fmt.Println(err)
}
@ -170,7 +168,7 @@ func ExampleFile_GetSheetViewOptions() {
}
func TestSheetViewOptionsErrors(t *testing.T) {
f := excelize.NewFile()
f := NewFile()
const sheet = "Sheet1"
assert.NoError(t, f.GetSheetViewOptions(sheet, 0))

104
styles.go
View File

@ -21,6 +21,7 @@ import (
"log"
"math"
"reflect"
"regexp"
"strconv"
"strings"
)
@ -755,7 +756,7 @@ var currencyNumFmt = map[int]string{
// builtInNumFmtFunc defined the format conversion functions map. Partial format
// code doesn't support currently and will return original string.
var builtInNumFmtFunc = map[int]func(i int, v string) string{
var builtInNumFmtFunc = map[int]func(v string, format string) string{
0: formatToString,
1: formatToInt,
2: formatToFloat,
@ -847,14 +848,14 @@ var criteriaType = map[string]string{
// formatToString provides a function to return original string by given
// built-in number formats code and cell string.
func formatToString(i int, v string) string {
func formatToString(v string, format string) string {
return v
}
// formatToInt provides a function to convert original string to integer
// format as string type by given built-in number formats code and cell
// string.
func formatToInt(i int, v string) string {
func formatToInt(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -865,7 +866,7 @@ func formatToInt(i int, v string) string {
// formatToFloat provides a function to convert original string to float
// format as string type by given built-in number formats code and cell
// string.
func formatToFloat(i int, v string) string {
func formatToFloat(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -875,7 +876,7 @@ func formatToFloat(i int, v string) string {
// formatToA provides a function to convert original string to special format
// as string type by given built-in number formats code and cell string.
func formatToA(i int, v string) string {
func formatToA(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -890,7 +891,7 @@ func formatToA(i int, v string) string {
// formatToB provides a function to convert original string to special format
// as string type by given built-in number formats code and cell string.
func formatToB(i int, v string) string {
func formatToB(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -903,7 +904,7 @@ func formatToB(i int, v string) string {
// formatToC provides a function to convert original string to special format
// as string type by given built-in number formats code and cell string.
func formatToC(i int, v string) string {
func formatToC(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -914,7 +915,7 @@ func formatToC(i int, v string) string {
// formatToD provides a function to convert original string to special format
// as string type by given built-in number formats code and cell string.
func formatToD(i int, v string) string {
func formatToD(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -925,7 +926,7 @@ func formatToD(i int, v string) string {
// formatToE provides a function to convert original string to special format
// as string type by given built-in number formats code and cell string.
func formatToE(i int, v string) string {
func formatToE(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@ -933,6 +934,8 @@ func formatToE(i int, v string) string {
return fmt.Sprintf("%.e", f)
}
var dateTimeFormatsCache = map[string]string{}
// parseTime provides a function to returns a string parsed using time.Time.
// Replace Excel placeholders with Go time placeholders. For example, replace
// yyyy with 2006. These are in a specific order, due to the fact that m is
@ -944,15 +947,46 @@ func formatToE(i int, v string) string {
// arbitrary characters unused in Excel Date formats, and then at the end,
// turn them to what they should actually be. Based off:
// http://www.ozgrid.com/Excel/CustomFormats.htm
func parseTime(i int, v string) string {
f, err := strconv.ParseFloat(v, 64)
func parseTime(v string, format string) string {
var (
f float64
err error
goFmt string
)
f, err = strconv.ParseFloat(v, 64)
if err != nil {
return v
}
val := timeFromExcelTime(f, false)
format := builtInNumFmt[i]
if format == "" {
return v
}
goFmt, found := dateTimeFormatsCache[format]
if found {
return val.Format(goFmt)
}
goFmt = format
if strings.Contains(goFmt, "[") {
var re = regexp.MustCompile(`\[.+\]`)
goFmt = re.ReplaceAllLiteralString(goFmt, "")
}
// use only first variant
if strings.Contains(goFmt, ";") {
goFmt = goFmt[:strings.IndexByte(goFmt, ';')]
}
replacements := []struct{ xltime, gotime string }{
{"YYYY", "2006"},
{"YY", "06"},
{"MM", "01"},
{"M", "1"},
{"DD", "02"},
{"D", "2"},
{"yyyy", "2006"},
{"yy", "06"},
{"mmmm", "%%%%"},
@ -962,38 +996,59 @@ func parseTime(i int, v string) string {
{"mmm", "Jan"},
{"mmss", "0405"},
{"ss", "05"},
{"s", "5"},
{"mm:", "04:"},
{":mm", ":04"},
{"m:", "4:"},
{":m", ":4"},
{"mm", "01"},
{"am/pm", "pm"},
{"m/", "1/"},
{"%%%%", "January"},
{"&&&&", "Monday"},
}
replacementsGlobal := []struct{ xltime, gotime string }{
{"\\-", "-"},
{"\\ ", " "},
{"\\.", "."},
{"\\", ""},
}
// It is the presence of the "am/pm" indicator that determines if this is
// a 12 hour or 24 hours time format, not the number of 'h' characters.
if is12HourTime(format) {
format = strings.Replace(format, "hh", "03", 1)
format = strings.Replace(format, "h", "3", 1)
goFmt = strings.Replace(goFmt, "hh", "3", 1)
goFmt = strings.Replace(goFmt, "h", "3", 1)
goFmt = strings.Replace(goFmt, "HH", "3", 1)
goFmt = strings.Replace(goFmt, "H", "3", 1)
} else {
format = strings.Replace(format, "hh", "15", 1)
format = strings.Replace(format, "h", "15", 1)
goFmt = strings.Replace(goFmt, "hh", "15", 1)
goFmt = strings.Replace(goFmt, "h", "3", 1)
goFmt = strings.Replace(goFmt, "HH", "15", 1)
goFmt = strings.Replace(goFmt, "H", "3", 1)
}
for _, repl := range replacements {
format = strings.Replace(format, repl.xltime, repl.gotime, 1)
goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, 1)
}
for _, repl := range replacementsGlobal {
goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, -1)
}
// If the hour is optional, strip it out, along with the possible dangling
// colon that would remain.
if val.Hour() < 1 {
format = strings.Replace(format, "]:", "]", 1)
format = strings.Replace(format, "[03]", "", 1)
format = strings.Replace(format, "[3]", "", 1)
format = strings.Replace(format, "[15]", "", 1)
goFmt = strings.Replace(goFmt, "]:", "]", 1)
goFmt = strings.Replace(goFmt, "[03]", "", 1)
goFmt = strings.Replace(goFmt, "[3]", "", 1)
goFmt = strings.Replace(goFmt, "[15]", "", 1)
} else {
format = strings.Replace(format, "[3]", "3", 1)
format = strings.Replace(format, "[15]", "15", 1)
goFmt = strings.Replace(goFmt, "[3]", "3", 1)
goFmt = strings.Replace(goFmt, "[15]", "15", 1)
}
return val.Format(format)
dateTimeFormatsCache[format] = goFmt
return val.Format(goFmt)
}
// is12HourTime checks whether an Excel time format string is a 12 hours form.
@ -2226,6 +2281,7 @@ func newNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
// setCustomNumFmt provides a function to set custom number format code.
func setCustomNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
nf := xlsxNumFmt{FormatCode: *style.CustomNumFmt}
if styleSheet.NumFmts != nil {
nf.NumFmtID = styleSheet.NumFmts.NumFmt[len(styleSheet.NumFmts.NumFmt)-1].NumFmtID + 1
styleSheet.NumFmts.NumFmt = append(styleSheet.NumFmts.NumFmt, &nf)

View File

@ -201,10 +201,44 @@ func TestNewStyle(t *testing.T) {
assert.NoError(t, err)
_, err = f.NewStyle(Style{})
assert.EqualError(t, err, "invalid parameter type")
_, 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")
// 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)
}
func TestGetDefaultFont(t *testing.T) {
@ -250,3 +284,15 @@ func TestGetStyleID(t *testing.T) {
func TestGetFillID(t *testing.T) {
assert.Equal(t, -1, getFillID(NewFile().stylesReader(), &Style{Fill: Fill{Type: "unknown"}}))
}
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"))
}