You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestXSSFSheetRowGrouping.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf.usermodel;
  16. import static org.junit.jupiter.api.Assertions.assertEquals;
  17. import static org.junit.jupiter.api.Assertions.assertNotNull;
  18. import java.io.IOException;
  19. import org.apache.poi.ss.usermodel.Cell;
  20. import org.apache.poi.ss.usermodel.Row;
  21. import org.apache.poi.ss.usermodel.Sheet;
  22. import org.apache.poi.ss.usermodel.Workbook;
  23. import org.apache.poi.xssf.XSSFTestDataSamples;
  24. import org.junit.jupiter.api.Test;
  25. public final class TestXSSFSheetRowGrouping {
  26. private static final int ROWS_NUMBER = 200;
  27. private static final int GROUP_SIZE = 5;
  28. @Test
  29. void test55640() {
  30. //long startTime = System.currentTimeMillis();
  31. Workbook wb = new XSSFWorkbook();
  32. fillData(wb);
  33. writeToFile(wb);
  34. //System.out.println("Number of groups: " + o_groupsNumber);
  35. //System.out.println("Execution time: " + (System.currentTimeMillis()-startTime) + " ms");
  36. }
  37. private void fillData(Workbook p_wb) {
  38. Sheet sheet = p_wb.createSheet("sheet123");
  39. sheet.setRowSumsBelow(false);
  40. for (int i = 0; i < ROWS_NUMBER; i++) {
  41. Row row = sheet.createRow(i);
  42. Cell cell = row.createCell(0);
  43. cell.setCellValue(i+1);
  44. }
  45. int i = 1;
  46. while (i < ROWS_NUMBER) {
  47. int end = i+(GROUP_SIZE-2);
  48. int start = i; // natural order
  49. // int start = end - 1; // reverse order
  50. while (start < end) { // natural order
  51. // while (start >= i) { // reverse order
  52. sheet.groupRow(start, end);
  53. //o_groupsNumber++;
  54. boolean collapsed = isCollapsed();
  55. //System.out.println("Set group " + start + "->" + end + " to " + collapsed);
  56. sheet.setRowGroupCollapsed(start, collapsed);
  57. start++; // natural order
  58. // start--; // reverse order
  59. }
  60. i += GROUP_SIZE;
  61. }
  62. }
  63. private boolean isCollapsed() {
  64. return Math.random() > 0.5d;
  65. }
  66. private void writeToFile(Workbook p_wb) {
  67. // FileOutputStream fileOut = new FileOutputStream("/tmp/55640.xlsx");
  68. // try {
  69. // p_wb.write(fileOut);
  70. // } finally {
  71. // fileOut.close();
  72. // }
  73. assertNotNull(XSSFTestDataSamples.writeOutAndReadBack(p_wb));
  74. }
  75. @Test
  76. void test55640reduce1() {
  77. Workbook wb = new XSSFWorkbook();
  78. Sheet sheet = wb.createSheet("sheet123");
  79. sheet.setRowSumsBelow(false);
  80. for (int i = 0; i < ROWS_NUMBER; i++) {
  81. Row row = sheet.createRow(i);
  82. Cell cell = row.createCell(0);
  83. cell.setCellValue(i+1);
  84. }
  85. int i = 1;
  86. while (i < ROWS_NUMBER) {
  87. int end = i+(GROUP_SIZE-2);
  88. int start = i; // natural order
  89. while (start < end) { // natural order
  90. sheet.groupRow(start, end);
  91. //o_groupsNumber++;
  92. boolean collapsed = (start % 2) != 0;
  93. //System.out.println("Set group " + start + "->" + end + " to " + collapsed);
  94. sheet.setRowGroupCollapsed(start, collapsed);
  95. start++; // natural order
  96. }
  97. i += GROUP_SIZE;
  98. }
  99. writeToFile(wb);
  100. }
  101. @Test
  102. void test55640_VerifyCases() {
  103. // NOTE: This is currently based on current behavior of POI, somehow
  104. // what POI returns in the calls to collapsed/hidden is not fully matching
  105. // the examples in the spec or I did not fully understand how POI stores the data internally...
  106. // all expanded
  107. verifyGroupCollapsed(
  108. // level1, level2, level3
  109. false, false, false,
  110. // collapsed:
  111. new Boolean[] { false, false, false, false, false},
  112. // hidden:
  113. new boolean[] { false, false, false, false, false},
  114. // outlineLevel
  115. new int[] { 1, 2, 3, 3, 3 }
  116. );
  117. // Level 1 collapsed, others expanded, should only have 4 rows, all hidden:
  118. verifyGroupCollapsed(
  119. // level1, level2, level3
  120. true, false, false,
  121. // collapsed:
  122. new Boolean[] { false, false, false, false, false},
  123. // hidden:
  124. new boolean[] { true, true, true, true, true},
  125. // outlineLevel
  126. new int[] { 1, 2, 3, 3, 3 }
  127. );
  128. // Level 1 and 2 collapsed, Level 3 expanded,
  129. verifyGroupCollapsed(
  130. // level1, level2, level3
  131. true, true, false,
  132. // collapsed:
  133. new Boolean[] { false, false, false, false, true, false},
  134. // hidden:
  135. new boolean[] { true, true, true, true, true, false},
  136. // outlineLevel
  137. new int[] { 1, 2, 3, 3, 3, 0 }
  138. );
  139. // Level 1 collapsed, Level 2 expanded, Level 3 collapsed
  140. verifyGroupCollapsed(
  141. // level1, level2, level3
  142. true, false, true,
  143. // collapsed:
  144. new Boolean[] { false, false, false, false, false, true},
  145. // hidden:
  146. new boolean[] { true, true, true, true, true, false},
  147. // outlineLevel
  148. new int[] { 1, 2, 3, 3, 3, 0 }
  149. );
  150. // Level 2 collapsed, others expanded:
  151. verifyGroupCollapsed(
  152. // level1, level2, level3
  153. false, true, false,
  154. // collapsed:
  155. new Boolean[] { false, false, false, false, false, false},
  156. // hidden:
  157. new boolean[] { false, true, true, true, true, false},
  158. // outlineLevel
  159. new int[] { 1, 2, 3, 3, 3, 0 }
  160. );
  161. // Level 3 collapsed, others expanded
  162. verifyGroupCollapsed(
  163. // level1, level2, level3
  164. false, false, true,
  165. // collapsed:
  166. new Boolean[] { false, false, false, false, false, true},
  167. // hidden:
  168. new boolean[] { false, false, true, true, true, false},
  169. // outlineLevel
  170. new int[] { 1, 2, 3, 3, 3, 0 }
  171. );
  172. // All collapsed
  173. verifyGroupCollapsed(
  174. // level1, level2, level3
  175. true, true, true,
  176. // collapsed:
  177. new Boolean[] { false, false, false, false, true, true},
  178. // hidden:
  179. new boolean[] { true, true, true, true, true, false},
  180. // outlineLevel
  181. new int[] { 1, 2, 3, 3, 3, 0 }
  182. );
  183. }
  184. private void verifyGroupCollapsed(boolean level1, boolean level2, boolean level3,
  185. Boolean[] collapsed, boolean[] hidden, int[] outlineLevel) {
  186. Workbook wb = new XSSFWorkbook();
  187. Sheet sheet = wb.createSheet("sheet123");
  188. for (int i = 0; i < 4; i++) {
  189. sheet.createRow(i);
  190. }
  191. sheet.groupRow(0, 4);
  192. sheet.groupRow(1, 4);
  193. sheet.groupRow(2, 4);
  194. sheet.setRowGroupCollapsed(0, level1);
  195. sheet.setRowGroupCollapsed(1, level2);
  196. sheet.setRowGroupCollapsed(2, level3);
  197. checkWorkbookGrouping(wb, collapsed, hidden, outlineLevel);
  198. }
  199. @Test
  200. void test55640_VerifyCasesSpec() {
  201. // NOTE: This is currently based on current behavior of POI, somehow
  202. // what POI returns in the calls to collapsed/hidden is not fully matching
  203. // the examples in the spec or I did not fully understand how POI stores the data internally...
  204. // all expanded
  205. verifyGroupCollapsedSpec(
  206. // level3, level2, level1
  207. false, false, false,
  208. // collapsed:
  209. new Boolean[] { false, false, false, false},
  210. // hidden:
  211. new boolean[] { false, false, false, false},
  212. // outlineLevel
  213. new int[] { 3, 3, 2, 1 }
  214. );
  215. verifyGroupCollapsedSpec(
  216. // level3, level2, level1
  217. false, false, true,
  218. // collapsed:
  219. new Boolean[] { false, false, false, true},
  220. // hidden:
  221. new boolean[] { true, true, true, false},
  222. // outlineLevel
  223. new int[] { 3, 3, 2, 1 }
  224. );
  225. verifyGroupCollapsedSpec(
  226. // level3, level2, level1
  227. false, true, false,
  228. // collapsed:
  229. new Boolean[] { false, false, true, false},
  230. // hidden:
  231. new boolean[] { true, true, true, false},
  232. // outlineLevel
  233. new int[] { 3, 3, 2, 1 }
  234. );
  235. verifyGroupCollapsedSpec(
  236. // level3, level2, level1
  237. false, true, true,
  238. // collapsed:
  239. new Boolean[] { false, false, true, true},
  240. // hidden:
  241. new boolean[] { true, true, true, false},
  242. // outlineLevel
  243. new int[] { 3, 3, 2, 1 }
  244. );
  245. }
  246. @SuppressWarnings("SameParameterValue")
  247. private void verifyGroupCollapsedSpec(boolean level1, boolean level2, boolean level3,
  248. Boolean[] collapsed, boolean[] hidden, int[] outlineLevel) {
  249. Workbook wb = new XSSFWorkbook();
  250. Sheet sheet = wb.createSheet("sheet123");
  251. for (int i = 5; i < 9; i++) {
  252. sheet.createRow(i);
  253. }
  254. sheet.groupRow(5, 6);
  255. sheet.groupRow(5, 7);
  256. sheet.groupRow(5, 8);
  257. sheet.setRowGroupCollapsed(6, level1);
  258. sheet.setRowGroupCollapsed(7, level2);
  259. sheet.setRowGroupCollapsed(8, level3);
  260. checkWorkbookGrouping(wb, collapsed, hidden, outlineLevel);
  261. }
  262. private void checkWorkbookGrouping(Workbook wb, Boolean[] collapsed, boolean[] hidden, int[] outlineLevel) {
  263. Sheet sheet = wb.getSheetAt(0);
  264. assertEquals(collapsed.length, hidden.length);
  265. assertEquals(collapsed.length, outlineLevel.length);
  266. assertEquals(collapsed.length, sheet.getLastRowNum()-sheet.getFirstRowNum()+1,
  267. "Expected " + collapsed.length + " rows with collapsed state, but had " + (sheet.getLastRowNum()-sheet.getFirstRowNum()+1) + " rows ("
  268. + sheet.getFirstRowNum() + "-" + sheet.getLastRowNum() + ")");
  269. for(int i = sheet.getFirstRowNum(); i < sheet.getLastRowNum();i++) {
  270. if(collapsed[i-sheet.getFirstRowNum()] == null) {
  271. continue;
  272. }
  273. XSSFRow row = (XSSFRow) sheet.getRow(i);
  274. assertNotNull(row, "Could not read row " + i);
  275. assertNotNull(row.getCTRow(), "Could not read row " + i);
  276. assertEquals(collapsed[i - sheet.getFirstRowNum()], row.getCTRow().getCollapsed(), "Row: " + i + ": collapsed");
  277. assertEquals(hidden[i-sheet.getFirstRowNum()], row.getCTRow().getHidden(), "Row: " + i + ": hidden");
  278. assertEquals(outlineLevel[i-sheet.getFirstRowNum()], row.getCTRow().getOutlineLevel(), "Row: " + i + ": level");
  279. }
  280. writeToFile(wb);
  281. }
  282. @Test
  283. void test55640working() {
  284. Workbook wb = new XSSFWorkbook();
  285. Sheet sheet = wb.createSheet("sheet123");
  286. sheet.groupRow(1, 4);
  287. sheet.groupRow(2, 5);
  288. sheet.groupRow(3, 6);
  289. sheet.setRowGroupCollapsed(1, true);
  290. sheet.setRowGroupCollapsed(2, false);
  291. sheet.setRowGroupCollapsed(3, false);
  292. writeToFile(wb);
  293. }
  294. @Test
  295. void testGroupingTest() throws IOException {
  296. try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("GroupTest.xlsx")) {
  297. assertEquals(31, wb.getSheetAt(0).getLastRowNum());
  298. // NOTE: This is currently based on current behavior of POI, somehow
  299. // what POI returns in the calls to collapsed/hidden is not fully matching
  300. // the examples in the spec or I did not fully understand how POI stores the data internally...
  301. checkWorkbookGrouping(wb,
  302. new Boolean[]{
  303. // 0-4
  304. false, false, false, false, false, null, null,
  305. // 7-11
  306. false, false, true, true, true, null, null,
  307. // 14-18
  308. false, false, true, false, false, null,
  309. // 20-24
  310. false, false, true, true, false, null, null,
  311. // 27-31
  312. false, false, false, true, false},
  313. new boolean[]{
  314. // 0-4
  315. false, false, false, false, false, false, false,
  316. // 7-11
  317. true, true, true, true, false, false, false,
  318. // 14-18
  319. true, true, false, false, false, false,
  320. // 20-24
  321. true, true, true, false, false, false, false,
  322. // 27-31
  323. true, true, true, true, false},
  324. // outlineLevel
  325. new int[]{
  326. // 0-4
  327. 3, 3, 2, 1, 0, 0, 0,
  328. // 7-11
  329. 3, 3, 2, 1, 0, 0, 0,
  330. // 14-18
  331. 3, 3, 2, 1, 0, 0,
  332. // 20-24
  333. 3, 3, 2, 1, 0, 0, 0,
  334. // 27-31
  335. 3, 3, 2, 1, 0,
  336. }
  337. );
  338. }
  339. /*
  340. Row: 0: Level: 3 Collapsed: false Hidden: false
  341. Row: 1: Level: 3 Collapsed: false Hidden: false
  342. Row: 2: Level: 2 Collapsed: false Hidden: false
  343. Row: 3: Level: 1 Collapsed: false Hidden: false
  344. Row: 4: Level: 0 Collapsed: false Hidden: false
  345. Row: 7: Level: 3 Collapsed: false Hidden: true
  346. Row: 8: Level: 3 Collapsed: false Hidden: true
  347. Row: 9: Level: 2 Collapsed: true Hidden: true
  348. Row: 10: Level: 1 Collapsed: true Hidden: true
  349. Row: 11: Level: 0 Collapsed: true Hidden: false
  350. Row: 14: Level: 3 Collapsed: false Hidden: true
  351. Row: 15: Level: 3 Collapsed: false Hidden: true
  352. Row: 16: Level: 2 Collapsed: true Hidden: false
  353. Row: 17: Level: 1 Collapsed: false Hidden: false
  354. Row: 18: Level: 0 Collapsed: false Hidden: false
  355. Row: 20: Level: 3 Collapsed: false Hidden: true
  356. Row: 21: Level: 3 Collapsed: false Hidden: true
  357. Row: 22: Level: 2 Collapsed: true Hidden: true
  358. Row: 23: Level: 1 Collapsed: true Hidden: false
  359. Row: 24: Level: 0 Collapsed: false Hidden: false
  360. Row: 27: Level: 3 Collapsed: false Hidden: true
  361. Row: 28: Level: 3 Collapsed: false Hidden: true
  362. Row: 29: Level: 2 Collapsed: false Hidden: true
  363. Row: 30: Level: 1 Collapsed: true Hidden: true
  364. Row: 31: Level: 0 Collapsed: true Hidden: false
  365. */
  366. }
  367. }