From 725c1a0c40971282ff924f4802a57e4c17431691 Mon Sep 17 00:00:00 2001 From: Veniamin Albaev Date: Thu, 27 Dec 2018 17:28:28 +0300 Subject: [PATCH] New feature: File.DuplicateRowTo() duplicate row to specified row position. DuplicateRowTo() is similar to DuplicateRow() but copies specified row not just after specified source row but to any other specified position below or above source row. Also I made minor modifications of tests: using filepath.Join() instead of direct unix-way paths strings to avoid possible tests fails on other OS. --- datavalidation_test.go | 5 +- excelize.go | 12 +- excelize_test.go | 532 ++++++++++++++++++++++++++++++----------- go.mod | 3 +- go.sum | 6 +- rows.go | 59 +++-- 6 files changed, 439 insertions(+), 178 deletions(-) diff --git a/datavalidation_test.go b/datavalidation_test.go index 82bc42f..fad50c2 100644 --- a/datavalidation_test.go +++ b/datavalidation_test.go @@ -10,13 +10,14 @@ package excelize import ( + "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestDataValidation(t *testing.T) { - const resultFile = "./test/TestDataValidation.xlsx" + resultFile := filepath.Join("test", "TestDataValidation.xlsx") xlsx := NewFile() @@ -50,7 +51,7 @@ func TestDataValidation(t *testing.T) { } func TestDataValidationError(t *testing.T) { - const resultFile = "./test/TestDataValidationError.xlsx" + resultFile := filepath.Join("test", "TestDataValidationError.xlsx") xlsx := NewFile() xlsx.SetCellStr("Sheet1", "E1", "E1") diff --git a/excelize.go b/excelize.go index 61f6dd6..32f0451 100644 --- a/excelize.go +++ b/excelize.go @@ -238,18 +238,16 @@ func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, rowIndex, offset int) { } for i, r := range xlsx.SheetData.Row { if r.R >= rowIndex { - f.ajustSingleRowDimensions(&xlsx.SheetData.Row[i], offset) + f.ajustSingleRowDimensions(&xlsx.SheetData.Row[i], r.R+offset) } } } -// ajustSingleRowDimensions provides a function to ajust single row -// dimensions. -func (f *File) ajustSingleRowDimensions(r *xlsxRow, offset int) { - r.R += offset +// ajustSingleRowDimensions provides a function to ajust single row dimensions. +func (f *File) ajustSingleRowDimensions(r *xlsxRow, row int) { + r.R = row for i, col := range r.C { - row, _ := strconv.Atoi(strings.Map(intOnlyMapF, col.R)) - r.C[i].R = string(strings.Map(letterOnlyMapF, col.R)) + strconv.Itoa(row+offset) + r.C[i].R = string(strings.Map(letterOnlyMapF, col.R)) + strconv.Itoa(r.R) } } diff --git a/excelize_test.go b/excelize_test.go index 1b6997a..6a106ec 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -8,6 +8,7 @@ import ( _ "image/png" "io/ioutil" "os" + "path/filepath" "strconv" "strings" "testing" @@ -18,7 +19,7 @@ import ( func TestOpenFile(t *testing.T) { // Test update a XLSX file. - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -126,16 +127,16 @@ func TestOpenFile(t *testing.T) { for i := 1; i <= 300; i++ { xlsx.SetCellStr("Sheet3", "c"+strconv.Itoa(i), strconv.Itoa(i)) } - assert.NoError(t, xlsx.SaveAs("./test/TestOpenFile.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestOpenFile.xlsx"))) } func TestSaveFile(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } - assert.NoError(t, xlsx.SaveAs("./test/TestSaveFile.xlsx")) - xlsx, err = OpenFile("./test/TestSaveFile.xlsx") + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSaveFile.xlsx"))) + xlsx, err = OpenFile(filepath.Join("test", "TestSaveFile.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -143,7 +144,7 @@ func TestSaveFile(t *testing.T) { } func TestSaveAsWrongPath(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if assert.NoError(t, err) { // Test write file to not exist directory. err = xlsx.SaveAs("") @@ -154,26 +155,26 @@ func TestSaveAsWrongPath(t *testing.T) { } func TestAddPicture(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } // Test add picture to worksheet with offset and location hyperlink. - err = xlsx.AddPicture("Sheet2", "I9", "./test/images/excel.jpg", + err = xlsx.AddPicture("Sheet2", "I9", filepath.Join("test", "images", "excel.jpg"), `{"x_offset": 140, "y_offset": 120, "hyperlink": "#Sheet2!D8", "hyperlink_type": "Location"}`) if !assert.NoError(t, err) { t.FailNow() } // Test add picture to worksheet with offset, external hyperlink and positioning. - err = xlsx.AddPicture("Sheet1", "F21", "./test/images/excel.png", + err = xlsx.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"), `{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`) if !assert.NoError(t, err) { t.FailNow() } - file, err := ioutil.ReadFile("./test/images/excel.jpg") + file, err := ioutil.ReadFile(filepath.Join("test", "images", "excel.jpg")) if !assert.NoError(t, err) { t.FailNow() } @@ -183,24 +184,24 @@ func TestAddPicture(t *testing.T) { assert.NoError(t, err) // Test write file to given path. - err = xlsx.SaveAs("./test/TestAddPicture.xlsx") + err = xlsx.SaveAs(filepath.Join("test", "TestAddPicture.xlsx")) assert.NoError(t, err) } func TestAddPictureErrors(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } // Test add picture to worksheet with invalid file path. - err = xlsx.AddPicture("Sheet1", "G21", "./test/not_exists_dir/not_exists.icon", "") + err = xlsx.AddPicture("Sheet1", "G21", filepath.Join("test", "not_exists_dir", "not_exists.icon"), "") if assert.Error(t, err) { assert.True(t, os.IsNotExist(err), "Expected os.IsNotExist(err) == true") } // Test add picture to worksheet with unsupport file type. - err = xlsx.AddPicture("Sheet1", "G21", "./test/Book1.xlsx", "") + err = xlsx.AddPicture("Sheet1", "G21", filepath.Join("test", "Book1.xlsx"), "") assert.EqualError(t, err, "unsupported image extension") err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", "jpg", make([]byte, 1)) @@ -221,12 +222,12 @@ 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, xlsx.SaveAs("./test/TestBrokenFile.SaveAsEmptyStruct.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestBrokenFile.SaveAsEmptyStruct.xlsx"))) }) t.Run("OpenBadWorkbook", func(t *testing.T) { // Test set active sheet without BookViews and Sheets maps in xl/workbook.xml. - f3, err := OpenFile("./test/BadWorkbook.xlsx") + f3, err := OpenFile(filepath.Join("test", "BadWorkbook.xlsx")) f3.GetActiveSheetIndex() f3.SetActiveSheet(2) assert.NoError(t, err) @@ -234,7 +235,7 @@ func TestBrokenFile(t *testing.T) { t.Run("OpenNotExistsFile", func(t *testing.T) { // Test open a XLSX file with given illegal path. - _, err := OpenFile("./test/NotExistsFile.xlsx") + _, err := OpenFile(filepath.Join("test", "NotExistsFile.xlsx")) if assert.Error(t, err) { assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true") } @@ -252,24 +253,25 @@ func TestNewFile(t *testing.T) { xlsx.SetActiveSheet(0) // Test add picture to sheet with scaling and positioning. - err := xlsx.AddPicture("Sheet1", "H2", "./test/images/excel.gif", `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`) + err := xlsx.AddPicture("Sheet1", "H2", filepath.Join("test", "images", "excel.gif"), + `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`) if !assert.NoError(t, err) { t.FailNow() } // Test add picture to worksheet without formatset. - err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", "") + err = xlsx.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), "") if !assert.NoError(t, err) { t.FailNow() } // Test add picture to worksheet with invalid formatset. - err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", `{`) + err = xlsx.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), `{`) if !assert.Error(t, err) { t.FailNow() } - assert.NoError(t, xlsx.SaveAs("./test/TestNewFile.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestNewFile.xlsx"))) } func TestColWidth(t *testing.T) { @@ -278,7 +280,7 @@ func TestColWidth(t *testing.T) { xlsx.SetColWidth("Sheet1", "A", "B", 12) xlsx.GetColWidth("Sheet1", "A") xlsx.GetColWidth("Sheet1", "C") - err := xlsx.SaveAs("./test/TestColWidth.xlsx") + err := xlsx.SaveAs(filepath.Join("test", "TestColWidth.xlsx")) if err != nil { t.Error(err) } @@ -291,7 +293,7 @@ func TestRowHeight(t *testing.T) { xlsx.SetRowHeight("Sheet1", 4, 90) t.Log(xlsx.GetRowHeight("Sheet1", 1)) t.Log(xlsx.GetRowHeight("Sheet1", 0)) - err := xlsx.SaveAs("./test/TestRowHeight.xlsx") + err := xlsx.SaveAs(filepath.Join("test", "TestRowHeight.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -299,7 +301,7 @@ func TestRowHeight(t *testing.T) { } func TestSetCellHyperLink(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if err != nil { t.Log(err) } @@ -311,11 +313,11 @@ func TestSetCellHyperLink(t *testing.T) { xlsx.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location") xlsx.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", "") xlsx.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location") - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellHyperLink.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellHyperLink.xlsx"))) } func TestGetCellHyperLink(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -331,7 +333,7 @@ func TestGetCellHyperLink(t *testing.T) { } func TestSetCellFormula(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -341,45 +343,45 @@ func TestSetCellFormula(t *testing.T) { // Test set cell formula with illegal rows number. xlsx.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)") - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellFormula.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula.xlsx"))) } func TestSetSheetBackground(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } - err = xlsx.SetSheetBackground("Sheet2", "./test/images/background.jpg") + err = xlsx.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")) if !assert.NoError(t, err) { t.FailNow() } - err = xlsx.SetSheetBackground("Sheet2", "./test/images/background.jpg") + err = xlsx.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")) if !assert.NoError(t, err) { t.FailNow() } - assert.NoError(t, xlsx.SaveAs("./test/TestSetSheetBackground.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetSheetBackground.xlsx"))) } func TestSetSheetBackgroundErrors(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } - err = xlsx.SetSheetBackground("Sheet2", "./test/not_exists/not_exists.png") + err = xlsx.SetSheetBackground("Sheet2", filepath.Join("test", "not_exists", "not_exists.png")) if assert.Error(t, err) { assert.True(t, os.IsNotExist(err), "Expected os.IsNotExists(err) == true") } - err = xlsx.SetSheetBackground("Sheet2", "./test/Book1.xlsx") + err = xlsx.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx")) assert.EqualError(t, err, "unsupported image extension") } func TestMergeCell(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -401,7 +403,7 @@ func TestMergeCell(t *testing.T) { xlsx.GetCellValue("Sheet2", "A6") // Merged cell ref is single coordinate. xlsx.GetCellFormula("Sheet1", "G12") - assert.NoError(t, xlsx.SaveAs("./test/TestMergeCell.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestMergeCell.xlsx"))) } func TestGetMergeCells(t *testing.T) { @@ -432,7 +434,7 @@ func TestGetMergeCells(t *testing.T) { }, } - xlsx, err := OpenFile("./test/MergeCell.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "MergeCell.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -476,7 +478,7 @@ func TestSetCellStyleAlignment(t *testing.T) { // Test get cell style with given illegal rows number. xlsx.GetCellStyle("Sheet1", "A") - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleAlignment.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleAlignment.xlsx"))) } func TestSetCellStyleBorder(t *testing.T) { @@ -514,7 +516,7 @@ func TestSetCellStyleBorder(t *testing.T) { xlsx.SetCellStyle("Sheet1", "O22", "O22", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleBorder.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleBorder.xlsx"))) } func TestSetCellStyleBorderErrors(t *testing.T) { @@ -571,7 +573,7 @@ func TestSetCellStyleNumberFormat(t *testing.T) { } xlsx.SetCellStyle("Sheet2", "L33", "L33", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleNumberFormat.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleNumberFormat.xlsx"))) } func TestSetCellStyleCurrencyNumberFormat(t *testing.T) { @@ -597,7 +599,7 @@ func TestSetCellStyleCurrencyNumberFormat(t *testing.T) { xlsx.SetCellStyle("Sheet1", "A2", "A2", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleCurrencyNumberFormat.TestBook3.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook3.xlsx"))) }) t.Run("TestBook4", func(t *testing.T) { @@ -632,7 +634,7 @@ func TestSetCellStyleCurrencyNumberFormat(t *testing.T) { } xlsx.SetCellStyle("Sheet1", "A2", "A2", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleCurrencyNumberFormat.TestBook4.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook4.xlsx"))) }) } @@ -651,7 +653,7 @@ func TestSetCellStyleCustomNumberFormat(t *testing.T) { } xlsx.SetCellStyle("Sheet1", "A2", "A2", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleCustomNumberFormat.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCustomNumberFormat.xlsx"))) } func TestSetCellStyleFill(t *testing.T) { @@ -686,7 +688,7 @@ func TestSetCellStyleFill(t *testing.T) { } xlsx.SetCellStyle("Sheet1", "O23", "O23", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleFill.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFill.xlsx"))) } func TestSetCellStyleFont(t *testing.T) { @@ -731,7 +733,7 @@ func TestSetCellStyleFont(t *testing.T) { xlsx.SetCellStyle("Sheet2", "A5", "A5", style) - assert.NoError(t, xlsx.SaveAs("./test/TestSetCellStyleFont.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFont.xlsx"))) } func TestSetCellStyleProtection(t *testing.T) { @@ -747,7 +749,7 @@ func TestSetCellStyleProtection(t *testing.T) { } xlsx.SetCellStyle("Sheet2", "A6", "A6", style) - err = xlsx.SaveAs("./test/TestSetCellStyleProtection.xlsx") + err = xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleProtection.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -761,7 +763,7 @@ func TestSetDeleteSheet(t *testing.T) { } xlsx.DeleteSheet("XLSXSheet3") - assert.NoError(t, xlsx.SaveAs("./test/TestSetDeleteSheet.TestBook3.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetDeleteSheet.TestBook3.xlsx"))) }) t.Run("TestBook4", func(t *testing.T) { @@ -772,7 +774,7 @@ func TestSetDeleteSheet(t *testing.T) { xlsx.DeleteSheet("Sheet1") xlsx.AddComment("Sheet1", "A1", "") xlsx.AddComment("Sheet1", "A1", `{"author":"Excelize: ","text":"This is a comment."}`) - assert.NoError(t, xlsx.SaveAs("./test/TestSetDeleteSheet.TestBook4.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetDeleteSheet.TestBook4.xlsx"))) }) } @@ -818,7 +820,7 @@ func TestSheetVisibility(t *testing.T) { xlsx.SetSheetVisible("Sheet1", true) xlsx.GetSheetVisible("Sheet1") - assert.NoError(t, xlsx.SaveAs("./test/TestSheetVisibility.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSheetVisibility.xlsx"))) } func TestRowVisibility(t *testing.T) { @@ -831,7 +833,7 @@ func TestRowVisibility(t *testing.T) { xlsx.SetRowVisible("Sheet3", 2, true) xlsx.GetRowVisible("Sheet3", 2) - assert.NoError(t, xlsx.SaveAs("./test/TestRowVisibility.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRowVisibility.xlsx"))) } func TestColumnVisibility(t *testing.T) { @@ -845,7 +847,7 @@ func TestColumnVisibility(t *testing.T) { xlsx.SetColVisible("Sheet1", "F", true) xlsx.GetColVisible("Sheet1", "F") xlsx.SetColVisible("Sheet3", "E", false) - assert.NoError(t, xlsx.SaveAs("./test/TestColumnVisibility.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestColumnVisibility.xlsx"))) }) t.Run("TestBook3", func(t *testing.T) { @@ -872,7 +874,7 @@ func TestCopySheet(t *testing.T) { xlsx.SetCellValue("Sheet4", "F1", "Hello") assert.NotEqual(t, "Hello", xlsx.GetCellValue("Sheet1", "F1")) - assert.NoError(t, xlsx.SaveAs("./test/TestCopySheet.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestCopySheet.xlsx"))) } func TestCopySheetError(t *testing.T) { @@ -886,7 +888,7 @@ func TestCopySheetError(t *testing.T) { t.FailNow() } - assert.NoError(t, xlsx.SaveAs("./test/TestCopySheetError.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestCopySheetError.xlsx"))) } func TestAddTable(t *testing.T) { @@ -910,7 +912,7 @@ func TestAddTable(t *testing.T) { t.FailNow() } - assert.NoError(t, xlsx.SaveAs("./test/TestAddTable.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestAddTable.xlsx"))) } func TestAddShape(t *testing.T) { @@ -925,7 +927,7 @@ func TestAddShape(t *testing.T) { xlsx.AddShape("Sheet3", "H1", `{"type":"ellipseRibbon", "color":{"line":"#4286f4","fill":"#8eb9ff"}, "paragraph":[{"font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777","underline":"single"}}], "height": 90}`) xlsx.AddShape("Sheet3", "H1", "") - assert.NoError(t, xlsx.SaveAs("./test/TestAddShape.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestAddShape.xlsx"))) } func TestAddComments(t *testing.T) { @@ -938,12 +940,14 @@ func TestAddComments(t *testing.T) { xlsx.AddComment("Sheet1", "A30", `{"author":"`+s+`","text":"`+s+`"}`) xlsx.AddComment("Sheet2", "B7", `{"author":"Excelize: ","text":"This is a comment."}`) - if assert.NoError(t, xlsx.SaveAs("./test/TestAddComments.xlsx")) { + if assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestAddComments.xlsx"))) { assert.Len(t, xlsx.GetComments(), 2) } } func TestAutoFilter(t *testing.T) { + outFile := filepath.Join("test", "TestAutoFilter%d.xlsx") + xlsx, err := prepareTestBook1() if !assert.NoError(t, err) { t.FailNow() @@ -964,7 +968,7 @@ func TestAutoFilter(t *testing.T) { t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) { err = xlsx.AutoFilter("Sheet3", "D4", "B1", format) if assert.NoError(t, err) { - assert.NoError(t, xlsx.SaveAs(fmt.Sprintf("./test/TestAutoFilter%d.xlsx", i+1))) + assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, i+1))) } }) } @@ -972,6 +976,8 @@ func TestAutoFilter(t *testing.T) { } func TestAutoFilterError(t *testing.T) { + outFile := filepath.Join("test", "TestAutoFilterError%d.xlsx") + xlsx, err := prepareTestBook1() if !assert.NoError(t, err) { t.FailNow() @@ -989,14 +995,14 @@ func TestAutoFilterError(t *testing.T) { t.Run(fmt.Sprintf("Expression%d", i+1), func(t *testing.T) { err = xlsx.AutoFilter("Sheet3", "D4", "B1", format) if assert.Error(t, err) { - assert.NoError(t, xlsx.SaveAs(fmt.Sprintf("./test/TestAutoFilterError%d.xlsx", i+1))) + assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, i+1))) } }) } } func TestAddChart(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1037,7 +1043,7 @@ func TestAddChart(t *testing.T) { xlsx.AddChart("Sheet2", "AF32", `{"type":"area3DStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Stacked Area Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) xlsx.AddChart("Sheet2", "AN32", `{"type":"area3DPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Area Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) - assert.NoError(t, xlsx.SaveAs("./test/TestAddChart.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestAddChart.xlsx"))) } func TestInsertCol(t *testing.T) { @@ -1057,7 +1063,7 @@ func TestInsertCol(t *testing.T) { xlsx.InsertCol("Sheet1", "A") - assert.NoError(t, xlsx.SaveAs("./test/TestInsertCol.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertCol.xlsx"))) } func TestRemoveCol(t *testing.T) { @@ -1075,7 +1081,7 @@ func TestRemoveCol(t *testing.T) { xlsx.RemoveCol("Sheet1", "A") xlsx.RemoveCol("Sheet1", "A") - assert.NoError(t, xlsx.SaveAs("./test/TestRemoveCol.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRemoveCol.xlsx"))) } func TestInsertRow(t *testing.T) { @@ -1090,84 +1096,321 @@ func TestInsertRow(t *testing.T) { xlsx.InsertRow("Sheet1", -1) xlsx.InsertRow("Sheet1", 4) - assert.NoError(t, xlsx.SaveAs("./test/TestInsertRow.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRow.xlsx"))) +} + +// Testing internal sructure state after insert operations. +// It is important for insert workflow to be constant to avoid side effect with functions related to internal structure. +func TestInsertRowInEmptyFile(t *testing.T) { + xlsx := NewFile() + sheet1 := xlsx.GetSheetName(1) + r := xlsx.workSheetReader(sheet1) + xlsx.InsertRow(sheet1, 0) + assert.Len(t, r.SheetData.Row, 0) + xlsx.InsertRow(sheet1, 1) + assert.Len(t, r.SheetData.Row, 0) + xlsx.InsertRow(sheet1, 99) + assert.Len(t, r.SheetData.Row, 0) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRowInEmptyFile.xlsx"))) } func TestDuplicateRow(t *testing.T) { - const ( - file = "./test/TestDuplicateRow" + - ".%s.xlsx" - sheet = "Sheet1" - a1 = "A1" - b1 = "B1" - a2 = "A2" - b2 = "B2" - a3 = "A3" - b3 = "B3" - a4 = "A4" - b4 = "B4" - a1Value = "A1 value" - a2Value = "A2 value" - a3Value = "A3 value" - bnValue = "Bn value" - ) - xlsx := NewFile() - xlsx.SetCellStr(sheet, a1, a1Value) - xlsx.SetCellStr(sheet, b1, bnValue) + const sheet = "Sheet1" + outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx") + + cells := map[string]string{ + "A1": "A1 Value", + "A2": "A2 Value", + "A3": "A3 Value", + "B1": "B1 Value", + "B2": "B2 Value", + "B3": "B3 Value", + } + + newFileWithDefaults := func() *File { + f := NewFile() + for cell, val := range cells { + f.SetCellStr(sheet, cell, val) + + } + return f + } t.Run("FromSingleRow", func(t *testing.T) { - xlsx.DuplicateRow(sheet, 1) - xlsx.DuplicateRow(sheet, 2) + xlsx := NewFile() + xlsx.SetCellStr(sheet, "A1", cells["A1"]) + xlsx.SetCellStr(sheet, "B1", cells["B1"]) - if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "TestDuplicateRow.FromSingleRow"))) { - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a2)) - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a3)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) + xlsx.DuplicateRow(sheet, 1) + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_1"))) { + t.FailNow() + } + expect := map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A1"], "B2": cells["B1"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + + xlsx.DuplicateRow(sheet, 2) + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_2"))) { + t.FailNow() + } + expect = map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A1"], "B2": cells["B1"], + "A3": cells["A1"], "B3": cells["B1"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } } }) t.Run("UpdateDuplicatedRows", func(t *testing.T) { - xlsx.SetCellStr(sheet, a2, a2Value) - xlsx.SetCellStr(sheet, a3, a3Value) + xlsx := NewFile() + xlsx.SetCellStr(sheet, "A1", cells["A1"]) + xlsx.SetCellStr(sheet, "B1", cells["B1"]) - if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "TestDuplicateRow.UpdateDuplicatedRows"))) { - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) - assert.Equal(t, a2Value, xlsx.GetCellValue(sheet, a2)) - assert.Equal(t, a3Value, xlsx.GetCellValue(sheet, a3)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) - } - }) - - t.Run("FromFirstOfMultipleRows", func(t *testing.T) { xlsx.DuplicateRow(sheet, 1) - if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "TestDuplicateRow.FromFirstOfMultipleRows"))) { - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a1)) - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a2)) - assert.Equal(t, a2Value, xlsx.GetCellValue(sheet, a3)) - assert.Equal(t, a3Value, xlsx.GetCellValue(sheet, a4)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b1)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b3)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b4)) + xlsx.SetCellStr(sheet, "A2", cells["A2"]) + xlsx.SetCellStr(sheet, "B2", cells["B2"]) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.UpdateDuplicatedRows"))) { + t.FailNow() + } + expect := map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A2"], "B2": cells["B2"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } } }) - t.Run("ZeroAndNegativeRowNum", func(t *testing.T) { - xlsx.DuplicateRow(sheet, -1) - xlsx.DuplicateRow(sheet, 0) - if assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(file, "TestDuplicateRow.ZeroAndNegativeRowNum"))) { - assert.Equal(t, "", xlsx.GetCellValue(sheet, a1)) - assert.Equal(t, "", xlsx.GetCellValue(sheet, b1)) - assert.Equal(t, a1Value, xlsx.GetCellValue(sheet, a2)) - assert.Equal(t, bnValue, xlsx.GetCellValue(sheet, b2)) + t.Run("FirstOfMultipleRows", func(t *testing.T) { + xlsx := newFileWithDefaults() + + xlsx.DuplicateRow(sheet, 1) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FirstOfMultipleRows"))) { + t.FailNow() + } + expect := map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A1"], "B2": cells["B1"], + "A3": cells["A2"], "B3": cells["B2"], + "A4": cells["A3"], "B4": cells["B3"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } } }) + + t.Run("ZeroWithNoRows", func(t *testing.T) { + xlsx := NewFile() + + xlsx.DuplicateRow(sheet, 0) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.ZeroWithNoRows"))) { + t.FailNow() + } + assert.Equal(t, "", xlsx.GetCellValue(sheet, "A1")) + assert.Equal(t, "", xlsx.GetCellValue(sheet, "B1")) + assert.Equal(t, "", xlsx.GetCellValue(sheet, "A2")) + assert.Equal(t, "", xlsx.GetCellValue(sheet, "B2")) + expect := map[string]string{ + "A1": "", "B1": "", + "A2": "", "B2": "", + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + }) + + t.Run("MiddleRowOfEmptyFile", func(t *testing.T) { + xlsx := NewFile() + + xlsx.DuplicateRow(sheet, 99) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.MiddleRowOfEmptyFile"))) { + t.FailNow() + } + expect := map[string]string{ + "A98": "", + "A99": "", + "A100": "", + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + }) + + t.Run("WithLargeOffsetToMiddleOfData", func(t *testing.T) { + xlsx := newFileWithDefaults() + + xlsx.DuplicateRowTo(sheet, 1, 3) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToMiddleOfData"))) { + t.FailNow() + } + expect := map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A2"], "B2": cells["B2"], + "A3": cells["A1"], "B3": cells["B1"], + "A4": cells["A3"], "B4": cells["B3"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + }) + + t.Run("WithLargeOffsetToEmptyRows", func(t *testing.T) { + xlsx := newFileWithDefaults() + + xlsx.DuplicateRowTo(sheet, 1, 7) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToEmptyRows"))) { + t.FailNow() + } + expect := map[string]string{ + "A1": cells["A1"], "B1": cells["B1"], + "A2": cells["A2"], "B2": cells["B2"], + "A3": cells["A3"], "B3": cells["B3"], + "A7": cells["A1"], "B7": cells["B1"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + }) + + t.Run("InsertBefore", func(t *testing.T) { + xlsx := newFileWithDefaults() + + xlsx.DuplicateRowTo(sheet, 2, 1) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBefore"))) { + t.FailNow() + } + + expect := map[string]string{ + "A1": cells["A2"], "B1": cells["B2"], + "A2": cells["A1"], "B2": cells["B1"], + "A3": cells["A2"], "B3": cells["B2"], + "A4": cells["A3"], "B4": cells["B3"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) { + t.FailNow() + } + } + }) + + t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) { + xlsx := newFileWithDefaults() + + xlsx.DuplicateRowTo(sheet, 3, 1) + + if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithLargeOffset"))) { + t.FailNow() + } + + expect := map[string]string{ + "A1": cells["A3"], "B1": cells["B3"], + "A2": cells["A1"], "B2": cells["B1"], + "A3": cells["A2"], "B3": cells["B2"], + "A4": cells["A3"], "B4": cells["B3"], + } + for cell, val := range expect { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell)) { + t.FailNow() + } + } + }) +} + +func TestDuplicateRowInvalidRownum(t *testing.T) { + const sheet = "Sheet1" + outFile := filepath.Join("test", "TestDuplicateRowInvalidRownum.%s.xlsx") + + cells := map[string]string{ + "A1": "A1 Value", + "A2": "A2 Value", + "A3": "A3 Value", + "B1": "B1 Value", + "B2": "B2 Value", + "B3": "B3 Value", + } + + testRows := []int{-2, -1} + + testRowPairs := []struct { + row1 int + row2 int + }{ + {-1, -1}, + {-1, 0}, + {-1, 1}, + {0, -1}, + {0, 0}, + {0, 1}, + {1, -1}, + {1, 1}, + {1, 0}, + } + + for i, row := range testRows { + name := fmt.Sprintf("TestRow_%d", i+1) + t.Run(name, func(t *testing.T) { + xlsx := NewFile() + for col, val := range cells { + xlsx.SetCellStr(sheet, col, val) + } + xlsx.DuplicateRow(sheet, row) + + for col, val := range cells { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, col)) { + t.FailNow() + } + } + assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, name))) + }) + } + + for i, pair := range testRowPairs { + name := fmt.Sprintf("TestRowPair_%d", i+1) + t.Run(name, func(t *testing.T) { + xlsx := NewFile() + for col, val := range cells { + xlsx.SetCellStr(sheet, col, val) + } + xlsx.DuplicateRowTo(sheet, pair.row1, pair.row2) + + for col, val := range cells { + if !assert.Equal(t, val, xlsx.GetCellValue(sheet, col)) { + t.FailNow() + } + } + assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, name))) + }) + } } func TestSetPane(t *testing.T) { @@ -1181,7 +1424,7 @@ func TestSetPane(t *testing.T) { xlsx.SetPanes("Panes 4", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`) xlsx.SetPanes("Panes 4", "") - assert.NoError(t, xlsx.SaveAs("./test/TestSetPane.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetPane.xlsx"))) } func TestRemoveRow(t *testing.T) { @@ -1208,7 +1451,7 @@ func TestRemoveRow(t *testing.T) { xlsx.RemoveRow("Sheet1", 1) xlsx.RemoveRow("Sheet1", 0) - assert.NoError(t, xlsx.SaveAs("./test/TestRemoveRow.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRemoveRow.xlsx"))) } func TestConditionalFormat(t *testing.T) { @@ -1265,7 +1508,7 @@ func TestConditionalFormat(t *testing.T) { // Test set invalid format set in conditional format xlsx.SetConditionalFormat("Sheet1", "L1:L10", "") - err = xlsx.SaveAs("./test/TestConditionalFormat.xlsx") + err = xlsx.SaveAs(filepath.Join("test", "TestConditionalFormat.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1276,7 +1519,7 @@ func TestConditionalFormat(t *testing.T) { xlsx.SetConditionalFormat("Sheet1", "K1:K10", `[{"type":"data_bar", "criteria":"", "min_type":"min","max_type":"max","bar_color":"#638EC6"}]`) // Set conditional format with file without dxfs element shold not return error. - xlsx, err = OpenFile("./test/Book1.xlsx") + xlsx, err = OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1308,7 +1551,7 @@ func TestTitleToNumber(t *testing.T) { } func TestSharedStrings(t *testing.T) { - xlsx, err := OpenFile("./test/SharedStrings.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1316,7 +1559,7 @@ func TestSharedStrings(t *testing.T) { } func TestSetSheetRow(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1326,11 +1569,11 @@ func TestSetSheetRow(t *testing.T) { xlsx.SetSheetRow("Sheet1", "B27", []interface{}{}) xlsx.SetSheetRow("Sheet1", "B27", &xlsx) - assert.NoError(t, xlsx.SaveAs("./test/TestSetSheetRow.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetSheetRow.xlsx"))) } func TestRows(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1365,7 +1608,7 @@ func TestRows(t *testing.T) { } func TestRowsError(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1383,12 +1626,12 @@ func TestOutlineLevel(t *testing.T) { xlsx.SetColOutlineLevel("Sheet2", "B", 2) xlsx.SetRowOutlineLevel("Sheet1", 2, 1) xlsx.GetRowOutlineLevel("Sheet1", 2) - err := xlsx.SaveAs("./test/TestOutlineLevel.xlsx") + err := xlsx.SaveAs(filepath.Join("test", "TestOutlineLevel.xlsx")) if !assert.NoError(t, err) { t.FailNow() } - xlsx, err = OpenFile("./test/Book1.xlsx") + xlsx, err = OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1422,7 +1665,7 @@ func TestHSL(t *testing.T) { } func TestSearchSheet(t *testing.T) { - xlsx, err := OpenFile("./test/SharedStrings.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx")) if !assert.NoError(t, err) { t.FailNow() } @@ -1445,17 +1688,17 @@ func TestProtectSheet(t *testing.T) { EditScenarios: false, }) - assert.NoError(t, xlsx.SaveAs("./test/TestProtectSheet.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestProtectSheet.xlsx"))) } func TestUnprotectSheet(t *testing.T) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if !assert.NoError(t, err) { t.FailNow() } xlsx.UnprotectSheet("Sheet1") - assert.NoError(t, xlsx.SaveAs("./test/TestUnprotectSheet.xlsx")) + assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestUnprotectSheet.xlsx"))) } func trimSliceSpace(s []string) []string { @@ -1470,25 +1713,25 @@ func trimSliceSpace(s []string) []string { } func prepareTestBook1() (*File, error) { - xlsx, err := OpenFile("./test/Book1.xlsx") + xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) if err != nil { return nil, err } - err = xlsx.AddPicture("Sheet2", "I9", "./test/images/excel.jpg", + err = xlsx.AddPicture("Sheet2", "I9", filepath.Join("test", "images", "excel.jpg"), `{"x_offset": 140, "y_offset": 120, "hyperlink": "#Sheet2!D8", "hyperlink_type": "Location"}`) if err != nil { return nil, err } // Test add picture to worksheet with offset, external hyperlink and positioning. - err = xlsx.AddPicture("Sheet1", "F21", "./test/images/excel.png", + err = xlsx.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.png"), `{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`) if err != nil { return nil, err } - file, err := ioutil.ReadFile("./test/images/excel.jpg") + file, err := ioutil.ReadFile(filepath.Join("test", "images", "excel.jpg")) if err != nil { return nil, err } @@ -1510,12 +1753,13 @@ func prepareTestBook3() (*File, error) { xlsx.SetCellStr("Sheet1", "B20", "42") xlsx.SetActiveSheet(0) - err := xlsx.AddPicture("Sheet1", "H2", "./test/images/excel.gif", `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`) + err := xlsx.AddPicture("Sheet1", "H2", filepath.Join("test", "images", "excel.gif"), + `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`) if err != nil { return nil, err } - err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", "") + err = xlsx.AddPicture("Sheet1", "C2", filepath.Join("test", "images", "excel.png"), "") if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 4ecf6ee..b96dbe2 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,5 @@ module github.com/360EntSecGroup-Skylar/excelize require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb + github.com/stretchr/testify v1.3.0 ) diff --git a/go.sum b/go.sum index 8dce13c..106a417 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,10 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb h1:cRItZejS4Ok67vfCdrbGIaqk86wmtQNOjVD7jSyS2aw= -github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/rows.go b/rows.go index d3fe6e0..3984216 100644 --- a/rows.go +++ b/rows.go @@ -376,38 +376,55 @@ func (f *File) InsertRow(sheet string, row int) { // xlsx.DuplicateRow("Sheet1", 2) // func (f *File) DuplicateRow(sheet string, row int) { - if row < 0 { + f.DuplicateRowTo(sheet, row, row+1) +} + +// DuplicateRowTo inserts a copy of specified row at specified row position +// movig down exists rows aftet target position +// +// xlsx.DuplicateRowTo("Sheet1", 2, 7) +// +func (f *File) DuplicateRowTo(sheet string, row, row2 int) { + if row <= 0 || row2 <= 0 || row == row2 { return } - row2 := row + 1 - f.adjustHelper(sheet, -1, row2, 1) - xlsx := f.workSheetReader(sheet) - idx := -1 - idx2 := -1 + ws := f.workSheetReader(sheet) - for i, r := range xlsx.SheetData.Row { + var ok bool + var rowCopy xlsxRow + + for i, r := range ws.SheetData.Row { if r.R == row { - idx = i - } else if r.R == row2 { - idx2 = i - } - if idx != -1 && idx2 != -1 { + rowCopy = ws.SheetData.Row[i] + ok = true break } } - - if idx == -1 || (idx2 == -1 && len(xlsx.SheetData.Row) >= row2) { + if !ok { return } - rowData := xlsx.SheetData.Row[idx] - cols := make([]xlsxC, 0, len(rowData.C)) - rowData.C = append(cols, rowData.C...) - f.ajustSingleRowDimensions(&rowData, 1) + + f.adjustHelper(sheet, -1, row2, 1) + + idx2 := -1 + for i, r := range ws.SheetData.Row { + if r.R == row2 { + idx2 = i + break + } + } + if idx2 == -1 && len(ws.SheetData.Row) >= row2 { + return + } + + rowCopy.C = append(make([]xlsxC, 0, len(rowCopy.C)), rowCopy.C...) + f.ajustSingleRowDimensions(&rowCopy, row2) + if idx2 != -1 { - xlsx.SheetData.Row[idx2] = rowData + ws.SheetData.Row[idx2] = rowCopy } else { - xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowData) + ws.SheetData.Row = append(ws.SheetData.Row, rowCopy) } } @@ -446,7 +463,7 @@ func checkRow(xlsx *xlsxWorksheet) { if lenCol < endCol { oldRow := xlsx.SheetData.Row[k].C xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0] - tmp := []xlsxC{} + var tmp []xlsxC for i := 0; i < endCol; i++ { buffer.WriteString(ToAlphaString(i)) buffer.WriteString(strconv.Itoa(endRow))