pivotTable_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package excelize
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "path/filepath"
  6. "strings"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestAddPivotTable(t *testing.T) {
  11. f := NewFile()
  12. // Create some data in a sheet
  13. month := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
  14. year := []int{2017, 2018, 2019}
  15. types := []string{"Meat", "Dairy", "Beverages", "Produce"}
  16. region := []string{"East", "West", "North", "South"}
  17. assert.NoError(t, f.SetSheetRow("Sheet1", "A1", &[]string{"Month", "Year", "Type", "Sales", "Region"}))
  18. for i := 0; i < 30; i++ {
  19. assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+2), month[rand.Intn(12)]))
  20. assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+2), year[rand.Intn(3)]))
  21. assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), types[rand.Intn(4)]))
  22. assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+2), rand.Intn(5000)))
  23. assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+2), region[rand.Intn(4)]))
  24. }
  25. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  26. DataRange: "Sheet1!$A$1:$E$31",
  27. PivotTableRange: "Sheet1!$G$2:$M$34",
  28. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  29. Filter: []PivotTableField{{Data: "Region"}},
  30. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  31. Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Summarize by Sum"}},
  32. RowGrandTotals: true,
  33. ColGrandTotals: true,
  34. ShowDrill: true,
  35. ShowRowHeaders: true,
  36. ShowColHeaders: true,
  37. ShowLastColumn: true,
  38. ShowError: true,
  39. }))
  40. // Use different order of coordinate tests
  41. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  42. DataRange: "Sheet1!$A$1:$E$31",
  43. PivotTableRange: "Sheet1!$U$34:$O$2",
  44. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  45. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  46. Data: []PivotTableField{{Data: "Sales", Subtotal: "Average", Name: "Summarize by Average"}},
  47. RowGrandTotals: true,
  48. ColGrandTotals: true,
  49. ShowDrill: true,
  50. ShowRowHeaders: true,
  51. ShowColHeaders: true,
  52. ShowLastColumn: true,
  53. }))
  54. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  55. DataRange: "Sheet1!$A$1:$E$31",
  56. PivotTableRange: "Sheet1!$W$2:$AC$34",
  57. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  58. Columns: []PivotTableField{{Data: "Region"}},
  59. Data: []PivotTableField{{Data: "Sales", Subtotal: "Count", Name: "Summarize by Count"}},
  60. RowGrandTotals: true,
  61. ColGrandTotals: true,
  62. ShowDrill: true,
  63. ShowRowHeaders: true,
  64. ShowColHeaders: true,
  65. ShowLastColumn: true,
  66. }))
  67. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  68. DataRange: "Sheet1!$A$1:$E$31",
  69. PivotTableRange: "Sheet1!$G$37:$W$50",
  70. Rows: []PivotTableField{{Data: "Month"}},
  71. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Year"}},
  72. Data: []PivotTableField{{Data: "Sales", Subtotal: "CountNums", Name: "Summarize by CountNums"}},
  73. RowGrandTotals: true,
  74. ColGrandTotals: true,
  75. ShowDrill: true,
  76. ShowRowHeaders: true,
  77. ShowColHeaders: true,
  78. ShowLastColumn: true,
  79. }))
  80. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  81. DataRange: "Sheet1!$A$1:$E$31",
  82. PivotTableRange: "Sheet1!$AE$2:$AG$33",
  83. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  84. Data: []PivotTableField{{Data: "Sales", Subtotal: "Max", Name: "Summarize by Max"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
  85. RowGrandTotals: true,
  86. ColGrandTotals: true,
  87. ShowDrill: true,
  88. ShowRowHeaders: true,
  89. ShowColHeaders: true,
  90. ShowLastColumn: true,
  91. }))
  92. // Create pivot table with empty subtotal field name and specified style
  93. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  94. DataRange: "Sheet1!$A$1:$E$31",
  95. PivotTableRange: "Sheet1!$AJ$2:$AP1$35",
  96. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  97. Filter: []PivotTableField{{Data: "Region"}},
  98. Columns: []PivotTableField{},
  99. Data: []PivotTableField{{Subtotal: "Sum", Name: "Summarize by Sum"}},
  100. RowGrandTotals: true,
  101. ColGrandTotals: true,
  102. ShowDrill: true,
  103. ShowRowHeaders: true,
  104. ShowColHeaders: true,
  105. ShowLastColumn: true,
  106. PivotTableStyleName: "PivotStyleLight19",
  107. }))
  108. f.NewSheet("Sheet2")
  109. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  110. DataRange: "Sheet1!$A$1:$E$31",
  111. PivotTableRange: "Sheet2!$A$1:$AR$15",
  112. Rows: []PivotTableField{{Data: "Month"}},
  113. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type", DefaultSubtotal: true}, {Data: "Year"}},
  114. Data: []PivotTableField{{Data: "Sales", Subtotal: "Min", Name: "Summarize by Min"}},
  115. RowGrandTotals: true,
  116. ColGrandTotals: true,
  117. ShowDrill: true,
  118. ShowRowHeaders: true,
  119. ShowColHeaders: true,
  120. ShowLastColumn: true,
  121. }))
  122. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  123. DataRange: "Sheet1!$A$1:$E$31",
  124. PivotTableRange: "Sheet2!$A$18:$AR$54",
  125. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Type"}},
  126. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Year"}},
  127. Data: []PivotTableField{{Data: "Sales", Subtotal: "Product", Name: "Summarize by Product"}},
  128. RowGrandTotals: true,
  129. ColGrandTotals: true,
  130. ShowDrill: true,
  131. ShowRowHeaders: true,
  132. ShowColHeaders: true,
  133. ShowLastColumn: true,
  134. }))
  135. // Create pivot table with many data, many rows, many cols and defined name
  136. assert.NoError(t, f.SetDefinedName(&DefinedName{
  137. Name: "dataRange",
  138. RefersTo: "Sheet1!$A$1:$E$31",
  139. Comment: "Pivot Table Data Range",
  140. Scope: "Sheet2",
  141. }))
  142. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  143. DataRange: "dataRange",
  144. PivotTableRange: "Sheet2!$A$57:$AJ$91",
  145. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  146. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type"}},
  147. Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Sum of Sales"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
  148. RowGrandTotals: true,
  149. ColGrandTotals: true,
  150. ShowDrill: true,
  151. ShowRowHeaders: true,
  152. ShowColHeaders: true,
  153. ShowLastColumn: true,
  154. }))
  155. // Test empty pivot table options
  156. assert.EqualError(t, f.AddPivotTable(nil), "parameter is required")
  157. // Test invalid data range
  158. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  159. DataRange: "Sheet1!$A$1:$A$1",
  160. PivotTableRange: "Sheet1!$U$34:$O$2",
  161. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  162. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  163. Data: []PivotTableField{{Data: "Sales"}},
  164. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  165. // Test the data range of the worksheet that is not declared
  166. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  167. DataRange: "$A$1:$E$31",
  168. PivotTableRange: "Sheet1!$U$34:$O$2",
  169. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  170. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  171. Data: []PivotTableField{{Data: "Sales"}},
  172. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  173. // Test the worksheet declared in the data range does not exist
  174. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  175. DataRange: "SheetN!$A$1:$E$31",
  176. PivotTableRange: "Sheet1!$U$34:$O$2",
  177. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  178. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  179. Data: []PivotTableField{{Data: "Sales"}},
  180. }), "sheet SheetN is not exist")
  181. // Test the pivot table range of the worksheet that is not declared
  182. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  183. DataRange: "Sheet1!$A$1:$E$31",
  184. PivotTableRange: "$U$34:$O$2",
  185. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  186. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  187. Data: []PivotTableField{{Data: "Sales"}},
  188. }), `parameter 'PivotTableRange' parsing error: parameter is invalid`)
  189. // Test the worksheet declared in the pivot table range does not exist
  190. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  191. DataRange: "Sheet1!$A$1:$E$31",
  192. PivotTableRange: "SheetN!$U$34:$O$2",
  193. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  194. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  195. Data: []PivotTableField{{Data: "Sales"}},
  196. }), "sheet SheetN is not exist")
  197. // Test not exists worksheet in data range
  198. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  199. DataRange: "SheetN!$A$1:$E$31",
  200. PivotTableRange: "Sheet1!$U$34:$O$2",
  201. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  202. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  203. Data: []PivotTableField{{Data: "Sales"}},
  204. }), "sheet SheetN is not exist")
  205. // Test invalid row number in data range
  206. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  207. DataRange: "Sheet1!$A$0:$E$31",
  208. PivotTableRange: "Sheet1!$U$34:$O$2",
  209. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  210. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  211. Data: []PivotTableField{{Data: "Sales"}},
  212. }), `parameter 'DataRange' parsing error: cannot convert cell "A0" to coordinates: invalid cell name "A0"`)
  213. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPivotTable1.xlsx")))
  214. // Test with field names that exceed the length limit and invalid subtotal
  215. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  216. DataRange: "Sheet1!$A$1:$E$31",
  217. PivotTableRange: "Sheet1!$G$2:$M$34",
  218. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  219. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  220. Data: []PivotTableField{{Data: "Sales", Subtotal: "-", Name: strings.Repeat("s", 256)}},
  221. }))
  222. // Test adjust range with invalid range
  223. _, _, err := f.adjustRange("")
  224. assert.EqualError(t, err, "parameter is required")
  225. // Test adjust range with incorrect range
  226. _, _, err = f.adjustRange("sheet1!")
  227. assert.EqualError(t, err, "parameter is invalid")
  228. // Test get pivot fields order with empty data range
  229. _, err = f.getPivotFieldsOrder(&PivotTableOption{})
  230. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  231. // Test add pivot cache with empty data range
  232. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{}, nil), "parameter 'DataRange' parsing error: parameter is required")
  233. // Test add pivot cache with invalid data range
  234. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{
  235. DataRange: "$A$1:$E$31",
  236. PivotTableRange: "Sheet1!$U$34:$O$2",
  237. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  238. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  239. Data: []PivotTableField{{Data: "Sales"}},
  240. }, nil), "parameter 'DataRange' parsing error: parameter is invalid")
  241. // Test add pivot table with empty options
  242. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  243. // Test add pivot table with invalid data range
  244. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  245. // Test add pivot fields with empty data range
  246. assert.EqualError(t, f.addPivotFields(nil, &PivotTableOption{
  247. DataRange: "$A$1:$E$31",
  248. PivotTableRange: "Sheet1!$U$34:$O$2",
  249. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  250. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  251. Data: []PivotTableField{{Data: "Sales"}},
  252. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  253. // Test get pivot fields index with empty data range
  254. _, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOption{})
  255. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  256. }
  257. func TestAddPivotRowFields(t *testing.T) {
  258. f := NewFile()
  259. // Test invalid data range
  260. assert.EqualError(t, f.addPivotRowFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  261. DataRange: "Sheet1!$A$1:$A$1",
  262. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  263. }
  264. func TestAddPivotPageFields(t *testing.T) {
  265. f := NewFile()
  266. // Test invalid data range
  267. assert.EqualError(t, f.addPivotPageFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  268. DataRange: "Sheet1!$A$1:$A$1",
  269. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  270. }
  271. func TestAddPivotDataFields(t *testing.T) {
  272. f := NewFile()
  273. // Test invalid data range
  274. assert.EqualError(t, f.addPivotDataFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  275. DataRange: "Sheet1!$A$1:$A$1",
  276. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  277. }
  278. func TestAddPivotColFields(t *testing.T) {
  279. f := NewFile()
  280. // Test invalid data range
  281. assert.EqualError(t, f.addPivotColFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  282. DataRange: "Sheet1!$A$1:$A$1",
  283. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  284. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  285. }
  286. func TestGetPivotFieldsOrder(t *testing.T) {
  287. f := NewFile()
  288. // Test get pivot fields order with not exist worksheet
  289. _, err := f.getPivotFieldsOrder(&PivotTableOption{DataRange: "SheetN!$A$1:$E$31"})
  290. assert.EqualError(t, err, "sheet SheetN is not exist")
  291. }
  292. func TestInStrSlice(t *testing.T) {
  293. assert.EqualValues(t, -1, inStrSlice([]string{}, ""))
  294. }
  295. func TestGetPivotTableFieldName(t *testing.T) {
  296. f := NewFile()
  297. f.getPivotTableFieldName("-", []PivotTableField{})
  298. }