pivotTable_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. //Test Pivot table with many data, many rows, many cols
  136. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  137. DataRange: "Sheet1!$A$1:$E$31",
  138. PivotTableRange: "Sheet2!$A$56:$AG$90",
  139. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  140. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type"}},
  141. Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Sum of Sales"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
  142. RowGrandTotals: true,
  143. ColGrandTotals: true,
  144. ShowDrill: true,
  145. ShowRowHeaders: true,
  146. ShowColHeaders: true,
  147. ShowLastColumn: true,
  148. }))
  149. // Test empty pivot table options
  150. assert.EqualError(t, f.AddPivotTable(nil), "parameter is required")
  151. // Test invalid data range
  152. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  153. DataRange: "Sheet1!$A$1:$A$1",
  154. PivotTableRange: "Sheet1!$U$34:$O$2",
  155. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  156. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  157. Data: []PivotTableField{{Data: "Sales"}},
  158. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  159. // Test the data range of the worksheet that is not declared
  160. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  161. DataRange: "$A$1:$E$31",
  162. PivotTableRange: "Sheet1!$U$34:$O$2",
  163. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  164. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  165. Data: []PivotTableField{{Data: "Sales"}},
  166. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  167. // Test the worksheet declared in the data range does not exist
  168. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  169. DataRange: "SheetN!$A$1:$E$31",
  170. PivotTableRange: "Sheet1!$U$34:$O$2",
  171. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  172. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  173. Data: []PivotTableField{{Data: "Sales"}},
  174. }), "sheet SheetN is not exist")
  175. // Test the pivot table range of the worksheet that is not declared
  176. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  177. DataRange: "Sheet1!$A$1:$E$31",
  178. PivotTableRange: "$U$34:$O$2",
  179. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  180. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  181. Data: []PivotTableField{{Data: "Sales"}},
  182. }), `parameter 'PivotTableRange' parsing error: parameter is invalid`)
  183. // Test the worksheet declared in the pivot table range does not exist
  184. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  185. DataRange: "Sheet1!$A$1:$E$31",
  186. PivotTableRange: "SheetN!$U$34:$O$2",
  187. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  188. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  189. Data: []PivotTableField{{Data: "Sales"}},
  190. }), "sheet SheetN is not exist")
  191. // Test not exists worksheet in data range
  192. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  193. DataRange: "SheetN!$A$1:$E$31",
  194. PivotTableRange: "Sheet1!$U$34:$O$2",
  195. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  196. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  197. Data: []PivotTableField{{Data: "Sales"}},
  198. }), "sheet SheetN is not exist")
  199. // Test invalid row number in data range
  200. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  201. DataRange: "Sheet1!$A$0:$E$31",
  202. PivotTableRange: "Sheet1!$U$34:$O$2",
  203. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  204. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  205. Data: []PivotTableField{{Data: "Sales"}},
  206. }), `parameter 'DataRange' parsing error: cannot convert cell "A0" to coordinates: invalid cell name "A0"`)
  207. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPivotTable1.xlsx")))
  208. // Test with field names that exceed the length limit and invalid subtotal
  209. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  210. DataRange: "Sheet1!$A$1:$E$31",
  211. PivotTableRange: "Sheet1!$G$2:$M$34",
  212. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  213. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  214. Data: []PivotTableField{{Data: "Sales", Subtotal: "-", Name: strings.Repeat("s", 256)}},
  215. }))
  216. // Test adjust range with invalid range
  217. _, _, err := f.adjustRange("")
  218. assert.EqualError(t, err, "parameter is required")
  219. // Test get pivot fields order with empty data range
  220. _, err = f.getPivotFieldsOrder("")
  221. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  222. // Test add pivot cache with empty data range
  223. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{}, nil), "parameter 'DataRange' parsing error: parameter is required")
  224. // Test add pivot cache with invalid data range
  225. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{
  226. DataRange: "$A$1:$E$31",
  227. PivotTableRange: "Sheet1!$U$34:$O$2",
  228. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  229. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  230. Data: []PivotTableField{{Data: "Sales"}},
  231. }, nil), "parameter 'DataRange' parsing error: parameter is invalid")
  232. // Test add pivot table with empty options
  233. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  234. // Test add pivot table with invalid data range
  235. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  236. // Test add pivot fields with empty data range
  237. assert.EqualError(t, f.addPivotFields(nil, &PivotTableOption{
  238. DataRange: "$A$1:$E$31",
  239. PivotTableRange: "Sheet1!$U$34:$O$2",
  240. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  241. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  242. Data: []PivotTableField{{Data: "Sales"}},
  243. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  244. // Test get pivot fields index with empty data range
  245. _, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOption{})
  246. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  247. }
  248. func TestAddPivotRowFields(t *testing.T) {
  249. f := NewFile()
  250. // Test invalid data range
  251. assert.EqualError(t, f.addPivotRowFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  252. DataRange: "Sheet1!$A$1:$A$1",
  253. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  254. }
  255. func TestAddPivotPageFields(t *testing.T) {
  256. f := NewFile()
  257. // Test invalid data range
  258. assert.EqualError(t, f.addPivotPageFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  259. DataRange: "Sheet1!$A$1:$A$1",
  260. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  261. }
  262. func TestAddPivotDataFields(t *testing.T) {
  263. f := NewFile()
  264. // Test invalid data range
  265. assert.EqualError(t, f.addPivotDataFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  266. DataRange: "Sheet1!$A$1:$A$1",
  267. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  268. }
  269. func TestAddPivotColFields(t *testing.T) {
  270. f := NewFile()
  271. // Test invalid data range
  272. assert.EqualError(t, f.addPivotColFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  273. DataRange: "Sheet1!$A$1:$A$1",
  274. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  275. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  276. }
  277. func TestGetPivotFieldsOrder(t *testing.T) {
  278. f := NewFile()
  279. // Test get pivot fields order with not exist worksheet
  280. _, err := f.getPivotFieldsOrder("SheetN!$A$1:$E$31")
  281. assert.EqualError(t, err, "sheet SheetN is not exist")
  282. }
  283. func TestInStrSlice(t *testing.T) {
  284. assert.EqualValues(t, -1, inStrSlice([]string{}, ""))
  285. }
  286. func TestGetPivotTableFieldName(t *testing.T) {
  287. f := NewFile()
  288. f.getPivotTableFieldName("-", []PivotTableField{})
  289. }