pivotTable_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. }))
  39. // Use different order of coordinate tests
  40. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  41. DataRange: "Sheet1!$A$1:$E$31",
  42. PivotTableRange: "Sheet1!$U$34:$O$2",
  43. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  44. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  45. Data: []PivotTableField{{Data: "Sales", Subtotal: "Average", Name: "Summarize by Average"}},
  46. RowGrandTotals: true,
  47. ColGrandTotals: true,
  48. ShowDrill: true,
  49. ShowRowHeaders: true,
  50. ShowColHeaders: true,
  51. ShowLastColumn: true,
  52. }))
  53. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  54. DataRange: "Sheet1!$A$1:$E$31",
  55. PivotTableRange: "Sheet1!$W$2:$AC$34",
  56. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  57. Columns: []PivotTableField{{Data: "Region"}},
  58. Data: []PivotTableField{{Data: "Sales", Subtotal: "Count", Name: "Summarize by Count"}},
  59. RowGrandTotals: true,
  60. ColGrandTotals: true,
  61. ShowDrill: true,
  62. ShowRowHeaders: true,
  63. ShowColHeaders: true,
  64. ShowLastColumn: true,
  65. }))
  66. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  67. DataRange: "Sheet1!$A$1:$E$31",
  68. PivotTableRange: "Sheet1!$G$37:$W$50",
  69. Rows: []PivotTableField{{Data: "Month"}},
  70. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Year"}},
  71. Data: []PivotTableField{{Data: "Sales", Subtotal: "CountNums", Name: "Summarize by CountNums"}},
  72. RowGrandTotals: true,
  73. ColGrandTotals: true,
  74. ShowDrill: true,
  75. ShowRowHeaders: true,
  76. ShowColHeaders: true,
  77. ShowLastColumn: true,
  78. }))
  79. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  80. DataRange: "Sheet1!$A$1:$E$31",
  81. PivotTableRange: "Sheet1!$AE$2:$AG$33",
  82. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  83. Data: []PivotTableField{{Data: "Sales", Subtotal: "Max", Name: "Summarize by Max"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
  84. RowGrandTotals: true,
  85. ColGrandTotals: true,
  86. ShowDrill: true,
  87. ShowRowHeaders: true,
  88. ShowColHeaders: true,
  89. ShowLastColumn: true,
  90. }))
  91. // Create pivot table with empty subtotal field name and specified style
  92. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  93. DataRange: "Sheet1!$A$1:$E$31",
  94. PivotTableRange: "Sheet1!$AJ$2:$AP1$35",
  95. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  96. Filter: []PivotTableField{{Data: "Region"}},
  97. Columns: []PivotTableField{},
  98. Data: []PivotTableField{{Subtotal: "Sum", Name: "Summarize by Sum"}},
  99. RowGrandTotals: true,
  100. ColGrandTotals: true,
  101. ShowDrill: true,
  102. ShowRowHeaders: true,
  103. ShowColHeaders: true,
  104. ShowLastColumn: true,
  105. PivotTableStyleName: "PivotStyleLight19",
  106. }))
  107. f.NewSheet("Sheet2")
  108. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  109. DataRange: "Sheet1!$A$1:$E$31",
  110. PivotTableRange: "Sheet2!$A$1:$AR$15",
  111. Rows: []PivotTableField{{Data: "Month"}},
  112. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type", DefaultSubtotal: true}, {Data: "Year"}},
  113. Data: []PivotTableField{{Data: "Sales", Subtotal: "Min", Name: "Summarize by Min"}},
  114. RowGrandTotals: true,
  115. ColGrandTotals: true,
  116. ShowDrill: true,
  117. ShowRowHeaders: true,
  118. ShowColHeaders: true,
  119. ShowLastColumn: true,
  120. }))
  121. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  122. DataRange: "Sheet1!$A$1:$E$31",
  123. PivotTableRange: "Sheet2!$A$18:$AR$54",
  124. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Type"}},
  125. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Year"}},
  126. Data: []PivotTableField{{Data: "Sales", Subtotal: "Product", Name: "Summarize by Product"}},
  127. RowGrandTotals: true,
  128. ColGrandTotals: true,
  129. ShowDrill: true,
  130. ShowRowHeaders: true,
  131. ShowColHeaders: true,
  132. ShowLastColumn: true,
  133. }))
  134. //Test Pivot table with many data, many rows, many cols
  135. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  136. DataRange: "Sheet1!$A$1:$E$31",
  137. PivotTableRange: "Sheet2!$A$56:$AG$90",
  138. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  139. Columns: []PivotTableField{{Data: "Region", DefaultSubtotal: true}, {Data: "Type"}},
  140. Data: []PivotTableField{{Data: "Sales", Subtotal: "Sum", Name: "Sum of Sales"}, {Data: "Sales", Subtotal: "Average", Name: "Average of Sales"}},
  141. RowGrandTotals: true,
  142. ColGrandTotals: true,
  143. ShowDrill: true,
  144. ShowRowHeaders: true,
  145. ShowColHeaders: true,
  146. ShowLastColumn: true,
  147. }))
  148. // Test empty pivot table options
  149. assert.EqualError(t, f.AddPivotTable(nil), "parameter is required")
  150. // Test invalid data range
  151. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  152. DataRange: "Sheet1!$A$1:$A$1",
  153. PivotTableRange: "Sheet1!$U$34:$O$2",
  154. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  155. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  156. Data: []PivotTableField{{Data: "Sales"}},
  157. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  158. // Test the data range of the worksheet that is not declared
  159. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  160. DataRange: "$A$1:$E$31",
  161. PivotTableRange: "Sheet1!$U$34:$O$2",
  162. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  163. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  164. Data: []PivotTableField{{Data: "Sales"}},
  165. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  166. // Test the worksheet declared in the data range does not exist
  167. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  168. DataRange: "SheetN!$A$1:$E$31",
  169. PivotTableRange: "Sheet1!$U$34:$O$2",
  170. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  171. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  172. Data: []PivotTableField{{Data: "Sales"}},
  173. }), "sheet SheetN is not exist")
  174. // Test the pivot table range of the worksheet that is not declared
  175. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  176. DataRange: "Sheet1!$A$1:$E$31",
  177. PivotTableRange: "$U$34:$O$2",
  178. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  179. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  180. Data: []PivotTableField{{Data: "Sales"}},
  181. }), `parameter 'PivotTableRange' parsing error: parameter is invalid`)
  182. // Test the worksheet declared in the pivot table range does not exist
  183. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  184. DataRange: "Sheet1!$A$1:$E$31",
  185. PivotTableRange: "SheetN!$U$34:$O$2",
  186. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  187. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  188. Data: []PivotTableField{{Data: "Sales"}},
  189. }), "sheet SheetN is not exist")
  190. // Test not exists worksheet in data range
  191. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  192. DataRange: "SheetN!$A$1:$E$31",
  193. PivotTableRange: "Sheet1!$U$34:$O$2",
  194. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  195. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  196. Data: []PivotTableField{{Data: "Sales"}},
  197. }), "sheet SheetN is not exist")
  198. // Test invalid row number in data range
  199. assert.EqualError(t, f.AddPivotTable(&PivotTableOption{
  200. DataRange: "Sheet1!$A$0:$E$31",
  201. PivotTableRange: "Sheet1!$U$34:$O$2",
  202. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  203. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  204. Data: []PivotTableField{{Data: "Sales"}},
  205. }), `parameter 'DataRange' parsing error: cannot convert cell "A0" to coordinates: invalid cell name "A0"`)
  206. assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPivotTable1.xlsx")))
  207. // Test with field names that exceed the length limit and invalid subtotal
  208. assert.NoError(t, f.AddPivotTable(&PivotTableOption{
  209. DataRange: "Sheet1!$A$1:$E$31",
  210. PivotTableRange: "Sheet1!$G$2:$M$34",
  211. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  212. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  213. Data: []PivotTableField{{Data: "Sales", Subtotal: "-", Name: strings.Repeat("s", 256)}},
  214. }))
  215. // Test adjust range with invalid range
  216. _, _, err := f.adjustRange("")
  217. assert.EqualError(t, err, "parameter is required")
  218. // Test get pivot fields order with empty data range
  219. _, err = f.getPivotFieldsOrder("")
  220. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  221. // Test add pivot cache with empty data range
  222. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{}, nil), "parameter 'DataRange' parsing error: parameter is required")
  223. // Test add pivot cache with invalid data range
  224. assert.EqualError(t, f.addPivotCache(0, "", &PivotTableOption{
  225. DataRange: "$A$1:$E$31",
  226. PivotTableRange: "Sheet1!$U$34:$O$2",
  227. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  228. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  229. Data: []PivotTableField{{Data: "Sales"}},
  230. }, nil), "parameter 'DataRange' parsing error: parameter is invalid")
  231. // Test add pivot table with empty options
  232. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  233. // Test add pivot table with invalid data range
  234. assert.EqualError(t, f.addPivotTable(0, 0, "", &PivotTableOption{}), "parameter 'PivotTableRange' parsing error: parameter is required")
  235. // Test add pivot fields with empty data range
  236. assert.EqualError(t, f.addPivotFields(nil, &PivotTableOption{
  237. DataRange: "$A$1:$E$31",
  238. PivotTableRange: "Sheet1!$U$34:$O$2",
  239. Rows: []PivotTableField{{Data: "Month", DefaultSubtotal: true}, {Data: "Year"}},
  240. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  241. Data: []PivotTableField{{Data: "Sales"}},
  242. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  243. // Test get pivot fields index with empty data range
  244. _, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOption{})
  245. assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
  246. }
  247. func TestAddPivotRowFields(t *testing.T) {
  248. f := NewFile()
  249. // Test invalid data range
  250. assert.EqualError(t, f.addPivotRowFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  251. DataRange: "Sheet1!$A$1:$A$1",
  252. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  253. }
  254. func TestAddPivotPageFields(t *testing.T) {
  255. f := NewFile()
  256. // Test invalid data range
  257. assert.EqualError(t, f.addPivotPageFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  258. DataRange: "Sheet1!$A$1:$A$1",
  259. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  260. }
  261. func TestAddPivotDataFields(t *testing.T) {
  262. f := NewFile()
  263. // Test invalid data range
  264. assert.EqualError(t, f.addPivotDataFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  265. DataRange: "Sheet1!$A$1:$A$1",
  266. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  267. }
  268. func TestAddPivotColFields(t *testing.T) {
  269. f := NewFile()
  270. // Test invalid data range
  271. assert.EqualError(t, f.addPivotColFields(&xlsxPivotTableDefinition{}, &PivotTableOption{
  272. DataRange: "Sheet1!$A$1:$A$1",
  273. Columns: []PivotTableField{{Data: "Type", DefaultSubtotal: true}},
  274. }), `parameter 'DataRange' parsing error: parameter is invalid`)
  275. }
  276. func TestGetPivotFieldsOrder(t *testing.T) {
  277. f := NewFile()
  278. // Test get pivot fields order with not exist worksheet
  279. _, err := f.getPivotFieldsOrder("SheetN!$A$1:$E$31")
  280. assert.EqualError(t, err, "sheet SheetN is not exist")
  281. }
  282. func TestInStrSlice(t *testing.T) {
  283. assert.EqualValues(t, -1, inStrSlice([]string{}, ""))
  284. }
  285. func TestGetPivotTableFieldName(t *testing.T) {
  286. f := NewFile()
  287. f.getPivotTableFieldName("-", []PivotTableField{})
  288. }