sheet_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. package excelize
  2. import (
  3. "fmt"
  4. "path/filepath"
  5. "strconv"
  6. "strings"
  7. "testing"
  8. "github.com/mohae/deepcopy"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. func ExampleFile_SetPageLayout() {
  12. f := NewFile()
  13. if err := f.SetPageLayout(
  14. "Sheet1",
  15. BlackAndWhite(true),
  16. FirstPageNumber(2),
  17. PageLayoutOrientation(OrientationLandscape),
  18. PageLayoutPaperSize(10),
  19. FitToHeight(2),
  20. FitToWidth(2),
  21. PageLayoutScale(50),
  22. ); err != nil {
  23. fmt.Println(err)
  24. }
  25. // Output:
  26. }
  27. func ExampleFile_GetPageLayout() {
  28. f := NewFile()
  29. var (
  30. blackAndWhite BlackAndWhite
  31. firstPageNumber FirstPageNumber
  32. orientation PageLayoutOrientation
  33. paperSize PageLayoutPaperSize
  34. fitToHeight FitToHeight
  35. fitToWidth FitToWidth
  36. scale PageLayoutScale
  37. )
  38. if err := f.GetPageLayout("Sheet1", &blackAndWhite); err != nil {
  39. fmt.Println(err)
  40. }
  41. if err := f.GetPageLayout("Sheet1", &firstPageNumber); err != nil {
  42. fmt.Println(err)
  43. }
  44. if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
  45. fmt.Println(err)
  46. }
  47. if err := f.GetPageLayout("Sheet1", &paperSize); err != nil {
  48. fmt.Println(err)
  49. }
  50. if err := f.GetPageLayout("Sheet1", &fitToHeight); err != nil {
  51. fmt.Println(err)
  52. }
  53. if err := f.GetPageLayout("Sheet1", &fitToWidth); err != nil {
  54. fmt.Println(err)
  55. }
  56. if err := f.GetPageLayout("Sheet1", &scale); err != nil {
  57. fmt.Println(err)
  58. }
  59. fmt.Println("Defaults:")
  60. fmt.Printf("- print black and white: %t\n", blackAndWhite)
  61. fmt.Printf("- page number for first printed page: %d\n", firstPageNumber)
  62. fmt.Printf("- orientation: %q\n", orientation)
  63. fmt.Printf("- paper size: %d\n", paperSize)
  64. fmt.Printf("- fit to height: %d\n", fitToHeight)
  65. fmt.Printf("- fit to width: %d\n", fitToWidth)
  66. fmt.Printf("- scale: %d\n", scale)
  67. // Output:
  68. // Defaults:
  69. // - print black and white: false
  70. // - page number for first printed page: 1
  71. // - orientation: "portrait"
  72. // - paper size: 1
  73. // - fit to height: 1
  74. // - fit to width: 1
  75. // - scale: 100
  76. }
  77. func TestNewSheet(t *testing.T) {
  78. f := NewFile()
  79. f.NewSheet("Sheet2")
  80. sheetID := f.NewSheet("sheet2")
  81. f.SetActiveSheet(sheetID)
  82. // delete original sheet
  83. f.DeleteSheet(f.GetSheetName(f.GetSheetIndex("Sheet1")))
  84. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestNewSheet.xlsx")))
  85. // create new worksheet with already exists name
  86. assert.Equal(t, f.GetSheetIndex("Sheet2"), f.NewSheet("Sheet2"))
  87. }
  88. func TestSetPane(t *testing.T) {
  89. f := NewFile()
  90. assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
  91. f.NewSheet("Panes 2")
  92. 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. f.NewSheet("Panes 3")
  94. assert.NoError(t, f.SetPanes("Panes 3", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`))
  95. f.NewSheet("Panes 4")
  96. assert.NoError(t, f.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"}]}`))
  97. assert.NoError(t, f.SetPanes("Panes 4", ""))
  98. assert.EqualError(t, f.SetPanes("SheetN", ""), "sheet SheetN is not exist")
  99. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetPane.xlsx")))
  100. }
  101. func TestPageLayoutOption(t *testing.T) {
  102. const sheet = "Sheet1"
  103. testData := []struct {
  104. container PageLayoutOptionPtr
  105. nonDefault PageLayoutOption
  106. }{
  107. {new(BlackAndWhite), BlackAndWhite(true)},
  108. {new(FirstPageNumber), FirstPageNumber(2)},
  109. {new(PageLayoutOrientation), PageLayoutOrientation(OrientationLandscape)},
  110. {new(PageLayoutPaperSize), PageLayoutPaperSize(10)},
  111. {new(FitToHeight), FitToHeight(2)},
  112. {new(FitToWidth), FitToWidth(2)},
  113. {new(PageLayoutScale), PageLayoutScale(50)},
  114. }
  115. for i, test := range testData {
  116. t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
  117. opt := test.nonDefault
  118. t.Logf("option %T", opt)
  119. def := deepcopy.Copy(test.container).(PageLayoutOptionPtr)
  120. val1 := deepcopy.Copy(def).(PageLayoutOptionPtr)
  121. val2 := deepcopy.Copy(def).(PageLayoutOptionPtr)
  122. f := NewFile()
  123. // Get the default value
  124. assert.NoError(t, f.GetPageLayout(sheet, def), opt)
  125. // Get again and check
  126. assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
  127. if !assert.Equal(t, val1, def, opt) {
  128. t.FailNow()
  129. }
  130. // Set the same value
  131. assert.NoError(t, f.SetPageLayout(sheet, val1), opt)
  132. // Get again and check
  133. assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
  134. if !assert.Equal(t, val1, def, "%T: value should not have changed", opt) {
  135. t.FailNow()
  136. }
  137. // Set a different value
  138. assert.NoError(t, f.SetPageLayout(sheet, test.nonDefault), opt)
  139. assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
  140. // Get again and compare
  141. assert.NoError(t, f.GetPageLayout(sheet, val2), opt)
  142. if !assert.Equal(t, val1, val2, "%T: value should not have changed", opt) {
  143. t.FailNow()
  144. }
  145. // Value should not be the same as the default
  146. if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opt) {
  147. t.FailNow()
  148. }
  149. // Restore the default value
  150. assert.NoError(t, f.SetPageLayout(sheet, def), opt)
  151. assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
  152. if !assert.Equal(t, def, val1) {
  153. t.FailNow()
  154. }
  155. })
  156. }
  157. }
  158. func TestSearchSheet(t *testing.T) {
  159. f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
  160. if !assert.NoError(t, err) {
  161. t.FailNow()
  162. }
  163. // Test search in a not exists worksheet.
  164. _, err = f.SearchSheet("Sheet4", "")
  165. assert.EqualError(t, err, "sheet Sheet4 is not exist")
  166. var expected []string
  167. // Test search a not exists value.
  168. result, err := f.SearchSheet("Sheet1", "X")
  169. assert.NoError(t, err)
  170. assert.EqualValues(t, expected, result)
  171. result, err = f.SearchSheet("Sheet1", "A")
  172. assert.NoError(t, err)
  173. assert.EqualValues(t, []string{"A1"}, result)
  174. // Test search the coordinates where the numerical value in the range of
  175. // "0-9" of Sheet1 is described by regular expression:
  176. result, err = f.SearchSheet("Sheet1", "[0-9]", true)
  177. assert.NoError(t, err)
  178. assert.EqualValues(t, expected, result)
  179. // Test search worksheet data after set cell value
  180. f = NewFile()
  181. assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
  182. _, err = f.SearchSheet("Sheet1", "")
  183. assert.NoError(t, err)
  184. }
  185. func TestSetPageLayout(t *testing.T) {
  186. f := NewFile()
  187. // Test set page layout on not exists worksheet.
  188. assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN is not exist")
  189. }
  190. func TestGetPageLayout(t *testing.T) {
  191. f := NewFile()
  192. // Test get page layout on not exists worksheet.
  193. assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN is not exist")
  194. }
  195. func TestSetHeaderFooter(t *testing.T) {
  196. f := NewFile()
  197. assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
  198. // Test set header and footer on not exists worksheet.
  199. assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN is not exist")
  200. // Test set header and footer with illegal setting.
  201. assert.EqualError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
  202. OddHeader: strings.Repeat("c", 256),
  203. }), "field OddHeader must be less than 255 characters")
  204. assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
  205. assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
  206. DifferentFirst: true,
  207. DifferentOddEven: true,
  208. OddHeader: "&R&P",
  209. OddFooter: "&C&F",
  210. EvenHeader: "&L&P",
  211. EvenFooter: "&L&D&R&T",
  212. FirstHeader: `&CCenter &"-,Bold"Bold&"-,Regular"HeaderU+000A&D`,
  213. }))
  214. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetHeaderFooter.xlsx")))
  215. }
  216. func TestDefinedName(t *testing.T) {
  217. f := NewFile()
  218. assert.NoError(t, f.SetDefinedName(&DefinedName{
  219. Name: "Amount",
  220. RefersTo: "Sheet1!$A$2:$D$5",
  221. Comment: "defined name comment",
  222. Scope: "Sheet1",
  223. }))
  224. assert.NoError(t, f.SetDefinedName(&DefinedName{
  225. Name: "Amount",
  226. RefersTo: "Sheet1!$A$2:$D$5",
  227. Comment: "defined name comment",
  228. }))
  229. assert.EqualError(t, f.SetDefinedName(&DefinedName{
  230. Name: "Amount",
  231. RefersTo: "Sheet1!$A$2:$D$5",
  232. Comment: "defined name comment",
  233. }), "the same name already exists on the scope")
  234. assert.EqualError(t, f.DeleteDefinedName(&DefinedName{
  235. Name: "No Exist Defined Name",
  236. }), "no defined name on the scope")
  237. assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
  238. assert.NoError(t, f.DeleteDefinedName(&DefinedName{
  239. Name: "Amount",
  240. }))
  241. assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
  242. assert.Exactly(t, 1, len(f.GetDefinedName()))
  243. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
  244. }
  245. func TestGroupSheets(t *testing.T) {
  246. f := NewFile()
  247. sheets := []string{"Sheet2", "Sheet3"}
  248. for _, sheet := range sheets {
  249. f.NewSheet(sheet)
  250. }
  251. assert.EqualError(t, f.GroupSheets([]string{"Sheet1", "SheetN"}), "sheet SheetN is not exist")
  252. assert.EqualError(t, f.GroupSheets([]string{"Sheet2", "Sheet3"}), "group worksheet must contain an active worksheet")
  253. assert.NoError(t, f.GroupSheets([]string{"Sheet1", "Sheet2"}))
  254. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestGroupSheets.xlsx")))
  255. }
  256. func TestUngroupSheets(t *testing.T) {
  257. f := NewFile()
  258. sheets := []string{"Sheet2", "Sheet3", "Sheet4", "Sheet5"}
  259. for _, sheet := range sheets {
  260. f.NewSheet(sheet)
  261. }
  262. assert.NoError(t, f.UngroupSheets())
  263. }
  264. func TestInsertPageBreak(t *testing.T) {
  265. f := NewFile()
  266. assert.NoError(t, f.InsertPageBreak("Sheet1", "A1"))
  267. assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
  268. assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
  269. assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
  270. assert.EqualError(t, f.InsertPageBreak("Sheet1", "A"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
  271. assert.EqualError(t, f.InsertPageBreak("SheetN", "C3"), "sheet SheetN is not exist")
  272. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestInsertPageBreak.xlsx")))
  273. }
  274. func TestRemovePageBreak(t *testing.T) {
  275. f := NewFile()
  276. assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))
  277. assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
  278. assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
  279. assert.NoError(t, f.RemovePageBreak("Sheet1", "A1"))
  280. assert.NoError(t, f.RemovePageBreak("Sheet1", "B2"))
  281. assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
  282. assert.NoError(t, f.RemovePageBreak("Sheet1", "C3"))
  283. assert.NoError(t, f.InsertPageBreak("Sheet1", "A3"))
  284. assert.NoError(t, f.RemovePageBreak("Sheet1", "B3"))
  285. assert.NoError(t, f.RemovePageBreak("Sheet1", "A3"))
  286. f.NewSheet("Sheet2")
  287. assert.NoError(t, f.InsertPageBreak("Sheet2", "B2"))
  288. assert.NoError(t, f.InsertPageBreak("Sheet2", "C2"))
  289. assert.NoError(t, f.RemovePageBreak("Sheet2", "B2"))
  290. assert.EqualError(t, f.RemovePageBreak("Sheet1", "A"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
  291. assert.EqualError(t, f.RemovePageBreak("SheetN", "C3"), "sheet SheetN is not exist")
  292. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestRemovePageBreak.xlsx")))
  293. }
  294. func TestGetSheetName(t *testing.T) {
  295. f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
  296. assert.NoError(t, err)
  297. assert.Equal(t, "Sheet1", f.GetSheetName(0))
  298. assert.Equal(t, "Sheet2", f.GetSheetName(1))
  299. assert.Equal(t, "", f.GetSheetName(-1))
  300. assert.Equal(t, "", f.GetSheetName(2))
  301. }
  302. func TestGetSheetMap(t *testing.T) {
  303. expectedMap := map[int]string{
  304. 1: "Sheet1",
  305. 2: "Sheet2",
  306. }
  307. f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
  308. assert.NoError(t, err)
  309. sheetMap := f.GetSheetMap()
  310. for idx, name := range sheetMap {
  311. assert.Equal(t, expectedMap[idx], name)
  312. }
  313. assert.Equal(t, len(sheetMap), 2)
  314. }
  315. func TestSetActiveSheet(t *testing.T) {
  316. f := NewFile()
  317. f.WorkBook.BookViews = nil
  318. f.SetActiveSheet(1)
  319. f.WorkBook.BookViews = &xlsxBookViews{WorkBookView: []xlsxWorkBookView{}}
  320. ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
  321. assert.True(t, ok)
  322. ws.(*xlsxWorksheet).SheetViews = &xlsxSheetViews{SheetView: []xlsxSheetView{}}
  323. f.SetActiveSheet(1)
  324. ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
  325. assert.True(t, ok)
  326. ws.(*xlsxWorksheet).SheetViews = nil
  327. f.SetActiveSheet(1)
  328. f = NewFile()
  329. f.SetActiveSheet(-1)
  330. assert.Equal(t, f.GetActiveSheetIndex(), 0)
  331. }
  332. func TestSetSheetName(t *testing.T) {
  333. f := NewFile()
  334. // Test set workksheet with the same name.
  335. f.SetSheetName("Sheet1", "Sheet1")
  336. assert.Equal(t, "Sheet1", f.GetSheetName(0))
  337. }
  338. func TestGetWorkbookPath(t *testing.T) {
  339. f := NewFile()
  340. f.Pkg.Delete("_rels/.rels")
  341. assert.Equal(t, "", f.getWorkbookPath())
  342. }
  343. func TestGetWorkbookRelsPath(t *testing.T) {
  344. f := NewFile()
  345. f.Pkg.Delete("xl/_rels/.rels")
  346. f.Pkg.Store("_rels/.rels", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument" Target="/workbook.xml"/></Relationships>`))
  347. assert.Equal(t, "_rels/workbook.xml.rels", f.getWorkbookRelsPath())
  348. }
  349. func TestDeleteSheet(t *testing.T) {
  350. f := NewFile()
  351. f.SetActiveSheet(f.NewSheet("Sheet2"))
  352. f.NewSheet("Sheet3")
  353. f.DeleteSheet("Sheet1")
  354. assert.Equal(t, "Sheet2", f.GetSheetName(f.GetActiveSheetIndex()))
  355. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteSheet.xlsx")))
  356. // Test with auto filter defined names
  357. f = NewFile()
  358. f.NewSheet("Sheet2")
  359. f.NewSheet("Sheet3")
  360. assert.NoError(t, f.SetCellValue("Sheet1", "A1", "A"))
  361. assert.NoError(t, f.SetCellValue("Sheet2", "A1", "A"))
  362. assert.NoError(t, f.SetCellValue("Sheet3", "A1", "A"))
  363. assert.NoError(t, f.AutoFilter("Sheet1", "A1", "A1", ""))
  364. assert.NoError(t, f.AutoFilter("Sheet2", "A1", "A1", ""))
  365. assert.NoError(t, f.AutoFilter("Sheet3", "A1", "A1", ""))
  366. f.DeleteSheet("Sheet2")
  367. f.DeleteSheet("Sheet1")
  368. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteSheet2.xlsx")))
  369. }
  370. func BenchmarkNewSheet(b *testing.B) {
  371. b.RunParallel(func(pb *testing.PB) {
  372. for pb.Next() {
  373. newSheetWithSet()
  374. }
  375. })
  376. }
  377. func newSheetWithSet() {
  378. file := NewFile()
  379. file.NewSheet("sheet1")
  380. for i := 0; i < 1000; i++ {
  381. _ = file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
  382. }
  383. file = nil
  384. }
  385. func BenchmarkFile_SaveAs(b *testing.B) {
  386. b.RunParallel(func(pb *testing.PB) {
  387. for pb.Next() {
  388. newSheetWithSave()
  389. }
  390. })
  391. }
  392. func newSheetWithSave() {
  393. file := NewFile()
  394. file.NewSheet("sheet1")
  395. for i := 0; i < 1000; i++ {
  396. _ = file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
  397. }
  398. _ = file.Save()
  399. }