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.

TestHSSFWorkbook.java 45KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234
  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.hssf.usermodel;
  16. import static org.apache.poi.POITestCase.assertContains;
  17. import static org.apache.poi.hssf.HSSFTestDataSamples.openSampleWorkbook;
  18. import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
  19. import static org.junit.jupiter.api.Assertions.assertEquals;
  20. import static org.junit.jupiter.api.Assertions.assertFalse;
  21. import static org.junit.jupiter.api.Assertions.assertNotNull;
  22. import static org.junit.jupiter.api.Assertions.assertNull;
  23. import static org.junit.jupiter.api.Assertions.assertThrows;
  24. import static org.junit.jupiter.api.Assertions.assertTrue;
  25. import static org.junit.jupiter.api.Assertions.fail;
  26. import java.io.ByteArrayOutputStream;
  27. import java.io.File;
  28. import java.io.FileInputStream;
  29. import java.io.FileOutputStream;
  30. import java.io.IOException;
  31. import java.io.InputStream;
  32. import java.io.OutputStream;
  33. import java.util.ArrayList;
  34. import java.util.Collection;
  35. import java.util.List;
  36. import java.util.Map;
  37. import java.util.function.Supplier;
  38. import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
  39. import org.apache.poi.POIDataSamples;
  40. import org.apache.poi.ddf.EscherBSERecord;
  41. import org.apache.poi.hpsf.ClassID;
  42. import org.apache.poi.hssf.HSSFITestDataProvider;
  43. import org.apache.poi.hssf.HSSFTestDataSamples;
  44. import org.apache.poi.hssf.OldExcelFormatException;
  45. import org.apache.poi.hssf.model.HSSFFormulaParser;
  46. import org.apache.poi.hssf.model.InternalSheet;
  47. import org.apache.poi.hssf.model.InternalWorkbook;
  48. import org.apache.poi.hssf.record.CFRuleRecord;
  49. import org.apache.poi.hssf.record.HSSFRecordTypes;
  50. import org.apache.poi.hssf.record.NameRecord;
  51. import org.apache.poi.hssf.record.Record;
  52. import org.apache.poi.hssf.record.RecordBase;
  53. import org.apache.poi.hssf.record.WindowOneRecord;
  54. import org.apache.poi.poifs.filesystem.DirectoryEntry;
  55. import org.apache.poi.poifs.filesystem.DirectoryNode;
  56. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  57. import org.apache.poi.ss.formula.ptg.Area3DPtg;
  58. import org.apache.poi.ss.usermodel.BaseTestWorkbook;
  59. import org.apache.poi.ss.usermodel.Cell;
  60. import org.apache.poi.ss.usermodel.CellReferenceType;
  61. import org.apache.poi.ss.usermodel.ConditionalFormatting;
  62. import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
  63. import org.apache.poi.ss.usermodel.Name;
  64. import org.apache.poi.ss.usermodel.Row;
  65. import org.apache.poi.ss.usermodel.Sheet;
  66. import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
  67. import org.apache.poi.ss.usermodel.Workbook;
  68. import org.apache.poi.ss.usermodel.WorkbookFactory;
  69. import org.apache.poi.ss.util.CellRangeAddress;
  70. import org.apache.poi.util.IOUtils;
  71. import org.apache.poi.util.TempFile;
  72. import org.junit.jupiter.api.Disabled;
  73. import org.junit.jupiter.api.Test;
  74. import org.junit.jupiter.params.ParameterizedTest;
  75. import org.junit.jupiter.params.provider.CsvSource;
  76. /**
  77. * Tests for {@link HSSFWorkbook}
  78. */
  79. public final class TestHSSFWorkbook extends BaseTestWorkbook {
  80. private static final HSSFITestDataProvider _testDataProvider = HSSFITestDataProvider.instance;
  81. private static final POIDataSamples samples = POIDataSamples.getSpreadSheetInstance();
  82. public TestHSSFWorkbook() {
  83. super(_testDataProvider);
  84. }
  85. /**
  86. * gives test code access to the {@link InternalWorkbook} within {@link HSSFWorkbook}
  87. */
  88. public static InternalWorkbook getInternalWorkbook(HSSFWorkbook wb) {
  89. return wb.getWorkbook();
  90. }
  91. /**
  92. * Tests for {@link HSSFWorkbook#isHidden()} etc
  93. */
  94. @Test
  95. void hidden() throws IOException {
  96. HSSFWorkbook wb = new HSSFWorkbook();
  97. WindowOneRecord w1 = wb.getWorkbook().getWindowOne();
  98. assertFalse(wb.isHidden());
  99. assertFalse(w1.getHidden());
  100. wb.setHidden(true);
  101. assertTrue(wb.isHidden());
  102. assertTrue(w1.getHidden());
  103. HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb);
  104. w1 = wbBack.getWorkbook().getWindowOne();
  105. wbBack.setHidden(true);
  106. assertTrue(wbBack.isHidden());
  107. assertTrue(w1.getHidden());
  108. wbBack.setHidden(false);
  109. assertFalse(wbBack.isHidden());
  110. assertFalse(w1.getHidden());
  111. wbBack.close();
  112. wb.close();
  113. }
  114. @Test
  115. void readWriteWithCharts() throws IOException {
  116. Sheet s;
  117. // Single chart, two sheets
  118. HSSFWorkbook b1 = openSampleWorkbook("44010-SingleChart.xls");
  119. assertEquals(2, b1.getNumberOfSheets());
  120. assertEquals("Graph2", b1.getSheetName(1));
  121. s = b1.getSheetAt(1);
  122. assertEquals(0, s.getFirstRowNum());
  123. assertEquals(8, s.getLastRowNum());
  124. // Has chart on 1st sheet??
  125. // FIXME
  126. assertNotNull(b1.getSheetAt(0).getDrawingPatriarch());
  127. assertNull(b1.getSheetAt(1).getDrawingPatriarch());
  128. assertFalse(b1.getSheetAt(0).getDrawingPatriarch().containsChart());
  129. b1.close();
  130. // We've now called getDrawingPatriarch() so
  131. // everything will be all screwy
  132. // So, start again
  133. HSSFWorkbook b2 = openSampleWorkbook("44010-SingleChart.xls");
  134. HSSFWorkbook b3 = HSSFTestDataSamples.writeOutAndReadBack(b2);
  135. b2.close();
  136. assertEquals(2, b3.getNumberOfSheets());
  137. s = b3.getSheetAt(1);
  138. assertEquals(0, s.getFirstRowNum());
  139. assertEquals(8, s.getLastRowNum());
  140. b3.close();
  141. // Two charts, three sheets
  142. HSSFWorkbook b4 = openSampleWorkbook("44010-TwoCharts.xls");
  143. assertEquals(3, b4.getNumberOfSheets());
  144. s = b4.getSheetAt(1);
  145. assertEquals(0, s.getFirstRowNum());
  146. assertEquals(8, s.getLastRowNum());
  147. s = b4.getSheetAt(2);
  148. assertEquals(0, s.getFirstRowNum());
  149. assertEquals(8, s.getLastRowNum());
  150. // Has chart on 1st sheet??
  151. // FIXME
  152. assertNotNull(b4.getSheetAt(0).getDrawingPatriarch());
  153. assertNull(b4.getSheetAt(1).getDrawingPatriarch());
  154. assertNull(b4.getSheetAt(2).getDrawingPatriarch());
  155. assertFalse(b4.getSheetAt(0).getDrawingPatriarch().containsChart());
  156. b4.close();
  157. // We've now called getDrawingPatriarch() so
  158. // everything will be all screwy
  159. // So, start again
  160. HSSFWorkbook b5 = openSampleWorkbook("44010-TwoCharts.xls");
  161. Workbook b6 = HSSFTestDataSamples.writeOutAndReadBack(b5);
  162. b5.close();
  163. assertEquals(3, b6.getNumberOfSheets());
  164. s = b6.getSheetAt(1);
  165. assertEquals(0, s.getFirstRowNum());
  166. assertEquals(8, s.getLastRowNum());
  167. s = b6.getSheetAt(2);
  168. assertEquals(0, s.getFirstRowNum());
  169. assertEquals(8, s.getLastRowNum());
  170. b6.close();
  171. }
  172. @Test
  173. void selectedSheet_bug44523() throws IOException {
  174. HSSFWorkbook wb=new HSSFWorkbook();
  175. HSSFSheet sheet1 = wb.createSheet("Sheet1");
  176. HSSFSheet sheet2 = wb.createSheet("Sheet2");
  177. HSSFSheet sheet3 = wb.createSheet("Sheet3");
  178. HSSFSheet sheet4 = wb.createSheet("Sheet4");
  179. confirmActiveSelected(sheet1, true);
  180. confirmActiveSelected(sheet2, false);
  181. confirmActiveSelected(sheet3, false);
  182. confirmActiveSelected(sheet4, false);
  183. wb.setSelectedTab(1);
  184. // Demonstrate bug 44525:
  185. // Well... not quite, since isActive + isSelected were also added in the same bug fix
  186. assertFalse(sheet1.isSelected(), "Identified bug 44523 a");
  187. wb.setActiveSheet(1);
  188. assertFalse(sheet1.isActive(), "Identified bug 44523 b");
  189. confirmActiveSelected(sheet1, false);
  190. confirmActiveSelected(sheet2, true);
  191. confirmActiveSelected(sheet3, false);
  192. confirmActiveSelected(sheet4, false);
  193. wb.close();
  194. }
  195. private static List<Integer> arrayToList(int[] array) {
  196. List<Integer> list = new ArrayList<>(array.length);
  197. for ( Integer element : array ) {
  198. list.add(element);
  199. }
  200. return list;
  201. }
  202. private static void assertCollectionsEquals(Collection<Integer> expected, Collection<Integer> actual) {
  203. assertEquals(expected.size(), actual.size());
  204. for (int e : expected) {
  205. assertTrue(actual.contains(e));
  206. }
  207. for (int a : actual) {
  208. assertTrue(expected.contains(a));
  209. }
  210. }
  211. @Test
  212. void selectMultiple() throws IOException {
  213. HSSFWorkbook wb = new HSSFWorkbook();
  214. HSSFSheet sheet0 = wb.createSheet("Sheet0");
  215. HSSFSheet sheet1 = wb.createSheet("Sheet1");
  216. HSSFSheet sheet2 = wb.createSheet("Sheet2");
  217. HSSFSheet sheet3 = wb.createSheet("Sheet3");
  218. HSSFSheet sheet4 = wb.createSheet("Sheet4");
  219. HSSFSheet sheet5 = wb.createSheet("Sheet5");
  220. List<Integer> selected = arrayToList(new int[] { 0, 2, 3 });
  221. wb.setSelectedTabs(selected);
  222. assertCollectionsEquals(selected, wb.getSelectedTabs());
  223. assertTrue(sheet0.isSelected());
  224. assertFalse(sheet1.isSelected());
  225. assertTrue(sheet2.isSelected());
  226. assertTrue(sheet3.isSelected());
  227. assertFalse(sheet4.isSelected());
  228. assertFalse(sheet5.isSelected());
  229. selected = arrayToList(new int[] { 1, 3, 5 });
  230. wb.setSelectedTabs(selected);
  231. // previous selection should be cleared
  232. assertCollectionsEquals(selected, wb.getSelectedTabs());
  233. assertFalse(sheet0.isSelected());
  234. assertTrue(sheet1.isSelected());
  235. assertFalse(sheet2.isSelected());
  236. assertTrue(sheet3.isSelected());
  237. assertFalse(sheet4.isSelected());
  238. assertTrue(sheet5.isSelected());
  239. assertTrue(sheet0.isActive());
  240. assertFalse(sheet2.isActive());
  241. wb.setActiveSheet(2);
  242. assertFalse(sheet0.isActive());
  243. assertTrue(sheet2.isActive());
  244. wb.close();
  245. }
  246. @Test
  247. void activeSheetAfterDelete_bug40414() throws IOException {
  248. HSSFWorkbook wb=new HSSFWorkbook();
  249. HSSFSheet sheet0 = wb.createSheet("Sheet0");
  250. HSSFSheet sheet1 = wb.createSheet("Sheet1");
  251. HSSFSheet sheet2 = wb.createSheet("Sheet2");
  252. HSSFSheet sheet3 = wb.createSheet("Sheet3");
  253. HSSFSheet sheet4 = wb.createSheet("Sheet4");
  254. // confirm default activation/selection
  255. confirmActiveSelected(sheet0, true);
  256. confirmActiveSelected(sheet1, false);
  257. confirmActiveSelected(sheet2, false);
  258. confirmActiveSelected(sheet3, false);
  259. confirmActiveSelected(sheet4, false);
  260. wb.setActiveSheet(3);
  261. wb.setSelectedTab(3);
  262. confirmActiveSelected(sheet0, false);
  263. confirmActiveSelected(sheet1, false);
  264. confirmActiveSelected(sheet2, false);
  265. confirmActiveSelected(sheet3, true);
  266. confirmActiveSelected(sheet4, false);
  267. wb.removeSheetAt(3);
  268. // after removing the only active/selected sheet, another should be active/selected in its place
  269. assertTrue(sheet4.isSelected(), "identified bug 40414 a");
  270. assertTrue(sheet4.isActive(), "identified bug 40414 b");
  271. confirmActiveSelected(sheet0, false);
  272. confirmActiveSelected(sheet1, false);
  273. confirmActiveSelected(sheet2, false);
  274. confirmActiveSelected(sheet4, true);
  275. sheet3 = sheet4; // re-align local vars in this test case
  276. // Some more cases of removing sheets
  277. // Starting with a multiple selection, and different active sheet
  278. wb.setSelectedTabs(new int[] { 1, 3, });
  279. wb.setActiveSheet(2);
  280. confirmActiveSelected(sheet0, false, false);
  281. confirmActiveSelected(sheet1, false, true);
  282. confirmActiveSelected(sheet2, true, false);
  283. confirmActiveSelected(sheet3, false, true);
  284. // removing a sheet that is not active, and not the only selected sheet
  285. wb.removeSheetAt(3);
  286. confirmActiveSelected(sheet0, false, false);
  287. confirmActiveSelected(sheet1, false, true);
  288. confirmActiveSelected(sheet2, true, false);
  289. // removing the only selected sheet
  290. wb.removeSheetAt(1);
  291. confirmActiveSelected(sheet0, false, false);
  292. confirmActiveSelected(sheet2, true, true);
  293. // The last remaining sheet should always be active+selected
  294. wb.removeSheetAt(1);
  295. confirmActiveSelected(sheet0, true, true);
  296. wb.close();
  297. }
  298. private static void confirmActiveSelected(HSSFSheet sheet, boolean expected) {
  299. confirmActiveSelected(sheet, expected, expected);
  300. }
  301. private static void confirmActiveSelected(HSSFSheet sheet,
  302. boolean expectedActive, boolean expectedSelected) {
  303. assertEquals(expectedActive, sheet.isActive(), "active");
  304. assertEquals(expectedSelected, sheet.isSelected(), "selected");
  305. }
  306. /**
  307. * If Sheet.getSize() returns a different result to Sheet.serialize(), this will cause the BOF
  308. * records to be written with invalid offset indexes. Excel does not like this, and such
  309. * errors are particularly hard to track down. This test ensures that HSSFWorkbook throws
  310. * a specific exception as soon as the situation is detected. See bugzilla 45066
  311. */
  312. @Test
  313. void sheetSerializeSizeMismatch_bug45066() throws IOException {
  314. try (HSSFWorkbook wb = new HSSFWorkbook()) {
  315. InternalSheet sheet = wb.createSheet("Sheet1").getSheet();
  316. List<RecordBase> sheetRecords = sheet.getRecords();
  317. // one way (of many) to cause the discrepancy is with a badly behaved record:
  318. sheetRecords.add(new BadlyBehavedRecord());
  319. // There is also much logic inside Sheet that (if buggy) might also cause the discrepancy
  320. IllegalStateException e = assertThrows(IllegalStateException.class, wb::getBytes, "Identified bug 45066 a");
  321. assertTrue(e.getMessage().startsWith("Actual serialized sheet size"));
  322. }
  323. }
  324. /**
  325. * Checks that us and HSSFName play nicely with named ranges
  326. * that point to deleted sheets
  327. */
  328. @Test
  329. void namesToDeleteSheets() throws IOException {
  330. HSSFWorkbook b = openSampleWorkbook("30978-deleted.xls");
  331. assertEquals(3, b.getNumberOfNames());
  332. // Sheet 2 is deleted
  333. assertEquals("Sheet1", b.getSheetName(0));
  334. assertEquals("Sheet3", b.getSheetName(1));
  335. Area3DPtg ptg;
  336. NameRecord nr;
  337. HSSFName n;
  338. /* ======= Name pointing to deleted sheet ====== */
  339. // First at low level
  340. nr = b.getWorkbook().getNameRecord(0);
  341. assertEquals("On2", nr.getNameText());
  342. assertEquals(0, nr.getSheetNumber());
  343. assertEquals(1, nr.getExternSheetNumber());
  344. assertEquals(1, nr.getNameDefinition().length);
  345. ptg = (Area3DPtg)nr.getNameDefinition()[0];
  346. assertEquals(1, ptg.getExternSheetIndex());
  347. assertEquals(0, ptg.getFirstColumn());
  348. assertEquals(0, ptg.getFirstRow());
  349. assertEquals(0, ptg.getLastColumn());
  350. assertEquals(2, ptg.getLastRow());
  351. // Now at high level
  352. n = b.getNameAt(0);
  353. assertEquals("On2", n.getNameName());
  354. assertEquals("", n.getSheetName());
  355. assertEquals("#REF!$A$1:$A$3", n.getRefersToFormula());
  356. /* ======= Name pointing to 1st sheet ====== */
  357. // First at low level
  358. nr = b.getWorkbook().getNameRecord(1);
  359. assertEquals("OnOne", nr.getNameText());
  360. assertEquals(0, nr.getSheetNumber());
  361. assertEquals(0, nr.getExternSheetNumber());
  362. assertEquals(1, nr.getNameDefinition().length);
  363. ptg = (Area3DPtg)nr.getNameDefinition()[0];
  364. assertEquals(0, ptg.getExternSheetIndex());
  365. assertEquals(0, ptg.getFirstColumn());
  366. assertEquals(2, ptg.getFirstRow());
  367. assertEquals(0, ptg.getLastColumn());
  368. assertEquals(3, ptg.getLastRow());
  369. // Now at high level
  370. n = b.getNameAt(1);
  371. assertEquals("OnOne", n.getNameName());
  372. assertEquals("Sheet1", n.getSheetName());
  373. assertEquals("Sheet1!$A$3:$A$4", n.getRefersToFormula());
  374. /* ======= Name pointing to 3rd sheet ====== */
  375. // First at low level
  376. nr = b.getWorkbook().getNameRecord(2);
  377. assertEquals("OnSheet3", nr.getNameText());
  378. assertEquals(0, nr.getSheetNumber());
  379. assertEquals(2, nr.getExternSheetNumber());
  380. assertEquals(1, nr.getNameDefinition().length);
  381. ptg = (Area3DPtg)nr.getNameDefinition()[0];
  382. assertEquals(2, ptg.getExternSheetIndex());
  383. assertEquals(0, ptg.getFirstColumn());
  384. assertEquals(0, ptg.getFirstRow());
  385. assertEquals(0, ptg.getLastColumn());
  386. assertEquals(1, ptg.getLastRow());
  387. // Now at high level
  388. n = b.getNameAt(2);
  389. assertEquals("OnSheet3", n.getNameName());
  390. assertEquals("Sheet3", n.getSheetName());
  391. assertEquals("Sheet3!$A$1:$A$2", n.getRefersToFormula());
  392. b.close();
  393. }
  394. /**
  395. * result returned by getRecordSize() differs from result returned by serialize()
  396. */
  397. private static final class BadlyBehavedRecord extends Record {
  398. BadlyBehavedRecord() {
  399. //
  400. }
  401. @Override
  402. public short getSid() {
  403. return 0x777;
  404. }
  405. @Override
  406. public int serialize(int offset, byte[] data) {
  407. return 4;
  408. }
  409. @Override
  410. public int getRecordSize() {
  411. return 8;
  412. }
  413. @Override
  414. public BadlyBehavedRecord copy() {
  415. return null;
  416. }
  417. @Override
  418. public HSSFRecordTypes getGenericRecordType() {
  419. return null;
  420. }
  421. @Override
  422. public Map<String, Supplier<?>> getGenericProperties() {
  423. return null;
  424. }
  425. }
  426. /**
  427. * The sample file provided with bug 45582 seems to have one extra byte after the EOFRecord
  428. */
  429. @Test
  430. void extraDataAfterEOFRecord() throws IOException {
  431. // bug 45582 - RecordFormatException - getCause() instanceof LittleEndian.BufferUnderrunException
  432. try (HSSFWorkbook wb = openSampleWorkbook("ex45582-22397.xls")) {
  433. assertNotNull(wb);
  434. }
  435. }
  436. /**
  437. * Test to make sure that NameRecord.getSheetNumber() is interpreted as a
  438. * 1-based sheet tab index (not a 1-based extern sheet index)
  439. */
  440. @Test
  441. void findBuiltInNameRecord() throws IOException {
  442. // testRRaC has multiple (3) built-in name records
  443. // The second print titles name record has getSheetNumber()==4
  444. HSSFWorkbook wb1 = openSampleWorkbook("testRRaC.xls");
  445. NameRecord nr;
  446. assertEquals(3, wb1.getWorkbook().getNumNames());
  447. nr = wb1.getWorkbook().getNameRecord(2);
  448. // TODO - render full row and full column refs properly
  449. assertEquals("Sheet2!$A$1:$IV$1", HSSFFormulaParser.toFormulaString(wb1, nr.getNameDefinition())); // 1:1
  450. try {
  451. wb1.getSheetAt(3).setRepeatingRows(CellRangeAddress.valueOf("9:12"));
  452. wb1.getSheetAt(3).setRepeatingColumns(CellRangeAddress.valueOf("E:F"));
  453. } catch (RuntimeException e) {
  454. if (e.getMessage().equals("Builtin (7) already exists for sheet (4)")) {
  455. // there was a problem in the code which locates the existing print titles name record
  456. fail("Identified bug 45720b");
  457. }
  458. wb1.close();
  459. throw e;
  460. }
  461. HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1);
  462. wb1.close();
  463. assertEquals(3, wb2.getWorkbook().getNumNames());
  464. nr = wb2.getWorkbook().getNameRecord(2);
  465. assertEquals("Sheet2!E:F,Sheet2!$A$9:$IV$12", HSSFFormulaParser.toFormulaString(wb2, nr.getNameDefinition())); // E:F,9:12
  466. wb2.close();
  467. }
  468. /**
  469. * Test that the storage clsid property is preserved
  470. */
  471. @Test
  472. void bug47920() throws IOException {
  473. try (POIFSFileSystem fs1 = new POIFSFileSystem(samples.openResourceAsStream("47920.xls"));
  474. HSSFWorkbook wb = new HSSFWorkbook(fs1)) {
  475. ClassID clsid1 = fs1.getRoot().getStorageClsid();
  476. UnsynchronizedByteArrayOutputStream out = UnsynchronizedByteArrayOutputStream.builder().setBufferSize(4096).get();
  477. wb.write(out);
  478. try (POIFSFileSystem fs2 = new POIFSFileSystem(out.toInputStream())) {
  479. ClassID clsid2 = fs2.getRoot().getStorageClsid();
  480. assertEquals(clsid1, clsid2);
  481. }
  482. }
  483. }
  484. /**
  485. * If we try to open an old (pre-97) workbook, we get a helpful
  486. * Exception give to explain what we've done wrong
  487. */
  488. @ParameterizedTest
  489. @CsvSource({
  490. "testEXCEL_4.xls,BIFF4",
  491. "testEXCEL_5.xls,BIFF5",
  492. "testEXCEL_95.xls,BIFF5"
  493. })
  494. void helpfulExceptionOnOldFiles(String file, String format) throws Exception {
  495. try (InputStream is = samples.openResourceAsStream(file)) {
  496. OldExcelFormatException e = assertThrows(OldExcelFormatException.class, () -> new HSSFWorkbook(is),
  497. "Shouldn't be able to load an Excel " + format + " file");
  498. assertContains(e.getMessage(), format);
  499. }
  500. }
  501. /**
  502. * Tests that we can work with both {@link POIFSFileSystem}
  503. * and {@link POIFSFileSystem}
  504. */
  505. @Test
  506. void differentPOIFS() throws Exception {
  507. // Open the two filesystems
  508. DirectoryNode[] files = new DirectoryNode[2];
  509. try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("Simple.xls"))) {
  510. files[0] = poifsFileSystem.getRoot();
  511. try (POIFSFileSystem poifsFileSystem2 = new POIFSFileSystem(HSSFTestDataSamples.getSampleFile("Simple.xls"))) {
  512. files[1] = poifsFileSystem2.getRoot();
  513. // Open without preserving nodes
  514. for (DirectoryNode dir : files) {
  515. HSSFWorkbook workbook = new HSSFWorkbook(dir, false);
  516. HSSFSheet sheet = workbook.getSheetAt(0);
  517. HSSFCell cell = sheet.getRow(0).getCell(0);
  518. assertEquals("replaceMe", cell.getRichStringCellValue().getString());
  519. workbook.close();
  520. }
  521. // Now re-check with preserving
  522. for (DirectoryNode dir : files) {
  523. HSSFWorkbook workbook = new HSSFWorkbook(dir, true);
  524. HSSFSheet sheet = workbook.getSheetAt(0);
  525. HSSFCell cell = sheet.getRow(0).getCell(0);
  526. assertEquals("replaceMe", cell.getRichStringCellValue().getString());
  527. workbook.close();
  528. }
  529. }
  530. }
  531. }
  532. @Test
  533. void wordDocEmbeddedInXls() throws IOException {
  534. // Open the two filesystems
  535. DirectoryNode[] files = new DirectoryNode[2];
  536. try (POIFSFileSystem poifsFileSystem = new POIFSFileSystem(HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls"))) {
  537. files[0] = poifsFileSystem.getRoot();
  538. try (POIFSFileSystem poifsFileSystem2 = new POIFSFileSystem(HSSFTestDataSamples.getSampleFile("WithEmbeddedObjects.xls"))) {
  539. files[1] = poifsFileSystem2.getRoot();
  540. // Check the embedded parts
  541. for (DirectoryNode root : files) {
  542. HSSFWorkbook hw = new HSSFWorkbook(root, true);
  543. List<HSSFObjectData> objects = hw.getAllEmbeddedObjects();
  544. boolean found = false;
  545. for (HSSFObjectData embeddedObject : objects) {
  546. if (embeddedObject.hasDirectoryEntry()) {
  547. DirectoryEntry dir = embeddedObject.getDirectory();
  548. if (dir instanceof DirectoryNode) {
  549. DirectoryNode dNode = (DirectoryNode) dir;
  550. if (dNode.hasEntry("WordDocument")) {
  551. found = true;
  552. break;
  553. }
  554. }
  555. }
  556. }
  557. assertTrue(found);
  558. hw.close();
  559. }
  560. }
  561. }
  562. }
  563. /**
  564. * Checks that we can open a workbook with POIFS, and write it out
  565. * again (via POIFS) and have it be valid
  566. */
  567. @Test
  568. void writeWorkbookFromPOIFS() throws IOException {
  569. try (InputStream is = HSSFTestDataSamples.openSampleFileStream("WithEmbeddedObjects.xls");
  570. POIFSFileSystem fs = new POIFSFileSystem(is)) {
  571. HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true);
  572. assertEquals(3, wb.getNumberOfSheets());
  573. assertEquals("Root xls", wb.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
  574. HSSFWorkbook wbBack = HSSFTestDataSamples.writeOutAndReadBack(wb);
  575. assertEquals(3, wbBack.getNumberOfSheets());
  576. assertEquals("Root xls", wbBack.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
  577. wbBack.close();
  578. wb.close();
  579. }
  580. }
  581. @Test
  582. void cellStylesLimit() throws IOException {
  583. try (Workbook wb = new HSSFWorkbook()) {
  584. int numBuiltInStyles = wb.getNumCellStyles();
  585. int MAX_STYLES = 4030;
  586. int limit = MAX_STYLES - numBuiltInStyles;
  587. for (int i = 0; i < limit; i++) {
  588. wb.createCellStyle();
  589. }
  590. assertEquals(MAX_STYLES, wb.getNumCellStyles());
  591. IllegalStateException e = assertThrows(IllegalStateException.class, wb::createCellStyle);
  592. assertEquals("The maximum number of cell styles was exceeded. " +
  593. "You can define up to 4000 styles in a .xls workbook", e.getMessage());
  594. assertEquals(MAX_STYLES, wb.getNumCellStyles());
  595. }
  596. }
  597. @Test
  598. void setSheetOrderHSSF() throws IOException{
  599. Workbook wb = new HSSFWorkbook();
  600. Sheet s1 = wb.createSheet("first sheet");
  601. Sheet s2 = wb.createSheet("other sheet");
  602. Name name1 = wb.createName();
  603. name1.setNameName("name1");
  604. name1.setRefersToFormula("'first sheet'!D1");
  605. Name name2 = wb.createName();
  606. name2.setNameName("name2");
  607. name2.setRefersToFormula("'other sheet'!C1");
  608. Row s1r1 = s1.createRow(2);
  609. Cell c1 = s1r1.createCell(3);
  610. c1.setCellValue(30);
  611. Cell c2 = s1r1.createCell(2);
  612. c2.setCellFormula("SUM('other sheet'!C1,'first sheet'!C1)");
  613. Row s2r1 = s2.createRow(0);
  614. Cell c3 = s2r1.createCell(1);
  615. c3.setCellFormula("'first sheet'!D3");
  616. Cell c4 = s2r1.createCell(2);
  617. c4.setCellFormula("'other sheet'!D3");
  618. // conditional formatting
  619. SheetConditionalFormatting sheetCF = s1.getSheetConditionalFormatting();
  620. ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(
  621. CFRuleRecord.ComparisonOperator.BETWEEN, "'first sheet'!D1", "'other sheet'!D1");
  622. ConditionalFormattingRule [] cfRules = { rule1 };
  623. CellRangeAddress[] regions = {
  624. new CellRangeAddress(2, 4, 0, 0), // A3:A5
  625. };
  626. sheetCF.addConditionalFormatting(regions, cfRules);
  627. wb.setSheetOrder("other sheet", 0);
  628. // names
  629. //noinspection ConstantConditions
  630. assertEquals("'first sheet'!D1", wb.getName("name1").getRefersToFormula());
  631. //noinspection ConstantConditions
  632. assertEquals("'other sheet'!C1", wb.getName("name2").getRefersToFormula());
  633. // cells
  634. assertEquals("SUM('other sheet'!C1,'first sheet'!C1)", c2.getCellFormula());
  635. assertEquals("'first sheet'!D3", c3.getCellFormula());
  636. assertEquals("'other sheet'!D3", c4.getCellFormula());
  637. // conditional formatting
  638. ConditionalFormatting cf = sheetCF.getConditionalFormattingAt(0);
  639. assertEquals("'first sheet'!D1", cf.getRule(0).getFormula1());
  640. assertEquals("'other sheet'!D1", cf.getRule(0).getFormula2());
  641. wb.close();
  642. }
  643. @Test
  644. void clonePictures() throws IOException {
  645. HSSFWorkbook wb = openSampleWorkbook("SimpleWithImages.xls");
  646. InternalWorkbook iwb = wb.getWorkbook();
  647. iwb.findDrawingGroup();
  648. for(int pictureIndex=1; pictureIndex <= 4; pictureIndex++){
  649. EscherBSERecord bse = iwb.getBSERecord(pictureIndex);
  650. assertEquals(1, bse.getRef());
  651. }
  652. wb.cloneSheet(0);
  653. for(int pictureIndex=1; pictureIndex <= 4; pictureIndex++){
  654. EscherBSERecord bse = iwb.getBSERecord(pictureIndex);
  655. assertEquals(2, bse.getRef());
  656. }
  657. wb.cloneSheet(0);
  658. for(int pictureIndex=1; pictureIndex <= 4; pictureIndex++){
  659. EscherBSERecord bse = iwb.getBSERecord(pictureIndex);
  660. assertEquals(3, bse.getRef());
  661. }
  662. wb.close();
  663. }
  664. // Should throw exception about invalid POIFSFileSystem
  665. @Test
  666. void emptyDirectoryNode() throws IOException {
  667. try (POIFSFileSystem fs = new POIFSFileSystem()) {
  668. assertThrows(IllegalArgumentException.class, () -> new HSSFWorkbook(fs).close());
  669. }
  670. }
  671. @Test
  672. void selectedSheetShort() throws IOException {
  673. HSSFWorkbook wb=new HSSFWorkbook();
  674. HSSFSheet sheet1 = wb.createSheet("Sheet1");
  675. HSSFSheet sheet2 = wb.createSheet("Sheet2");
  676. HSSFSheet sheet3 = wb.createSheet("Sheet3");
  677. HSSFSheet sheet4 = wb.createSheet("Sheet4");
  678. confirmActiveSelected(sheet1, true);
  679. confirmActiveSelected(sheet2, false);
  680. confirmActiveSelected(sheet3, false);
  681. confirmActiveSelected(sheet4, false);
  682. wb.setSelectedTab((short)1);
  683. // Demonstrate bug 44525:
  684. // Well... not quite, since isActive + isSelected were also added in the same bug fix
  685. assertFalse(sheet1.isSelected(), "Identified bug 44523 a");
  686. wb.setActiveSheet(1);
  687. assertFalse(sheet1.isActive(), "Identified bug 44523 b");
  688. confirmActiveSelected(sheet1, false);
  689. confirmActiveSelected(sheet2, true);
  690. confirmActiveSelected(sheet3, false);
  691. confirmActiveSelected(sheet4, false);
  692. assertEquals(0, wb.getFirstVisibleTab());
  693. wb.setFirstVisibleTab((short)2);
  694. assertEquals(2, wb.getFirstVisibleTab());
  695. wb.close();
  696. }
  697. @Test
  698. void names() throws IOException {
  699. HSSFWorkbook wb=new HSSFWorkbook();
  700. IllegalStateException ex1 = assertThrows(IllegalStateException.class, () -> wb.getNameAt(0));
  701. assertTrue(ex1.getMessage().contains("no defined names"));
  702. HSSFName name = wb.createName();
  703. assertNotNull(name);
  704. assertNull(wb.getName("somename"));
  705. name.setNameName("myname");
  706. assertNotNull(wb.getName("myname"));
  707. assertEquals(0, wb.getNameIndex(name));
  708. assertEquals(0, wb.getNameIndex("myname"));
  709. IllegalArgumentException ex2 = assertThrows(IllegalArgumentException.class, () -> wb.getNameAt(5));
  710. assertTrue(ex2.getMessage().contains("outside the allowable range"));
  711. IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> wb.getNameAt(-3));
  712. assertTrue(ex.getMessage().contains("outside the allowable range"));
  713. wb.close();
  714. }
  715. @Test
  716. void testMethods() throws IOException {
  717. try (HSSFWorkbook wb=new HSSFWorkbook()) {
  718. assertDoesNotThrow(wb::insertChartRecord);
  719. //wb.dumpDrawingGroupRecords(true);
  720. //wb.dumpDrawingGroupRecords(false);
  721. }
  722. }
  723. @Test
  724. void writeProtection() throws IOException {
  725. HSSFWorkbook wb=new HSSFWorkbook();
  726. assertFalse(wb.isWriteProtected());
  727. wb.writeProtectWorkbook("mypassword", "myuser");
  728. assertTrue(wb.isWriteProtected());
  729. wb.unwriteProtectWorkbook();
  730. assertFalse(wb.isWriteProtected());
  731. wb.close();
  732. }
  733. @Test
  734. void bug50298() throws Exception {
  735. HSSFWorkbook wb = openSampleWorkbook("50298.xls");
  736. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  737. HSSFSheet sheet = wb.cloneSheet(0);
  738. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received", "Invoice (2)");
  739. wb.setSheetName(wb.getSheetIndex(sheet), "copy");
  740. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received", "copy");
  741. wb.setSheetOrder("copy", 0);
  742. assertSheetOrder(wb, "copy", "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  743. wb.removeSheetAt(0);
  744. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  745. // check that the overall workbook serializes with its correct size
  746. int expected = wb.getWorkbook().getSize();
  747. int written = wb.getWorkbook().serialize(0, new byte[expected*2]);
  748. assertEquals(expected, written, "Did not have the expected size when writing the workbook");
  749. HSSFWorkbook read = HSSFTestDataSamples.writeOutAndReadBack(wb);
  750. assertSheetOrder(read, "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  751. read.close();
  752. wb.close();
  753. }
  754. @Test
  755. void bug50298a() throws Exception {
  756. HSSFWorkbook wb = openSampleWorkbook("50298.xls");
  757. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  758. HSSFSheet sheet = wb.cloneSheet(0);
  759. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received", "Invoice (2)");
  760. wb.setSheetName(wb.getSheetIndex(sheet), "copy");
  761. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received", "copy");
  762. wb.setSheetOrder("copy", 0);
  763. assertSheetOrder(wb, "copy", "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  764. wb.removeSheetAt(0);
  765. assertSheetOrder(wb, "Invoice", "Invoice1", "Digest", "Deferred", "Received");
  766. wb.removeSheetAt(1);
  767. assertSheetOrder(wb, "Invoice", "Digest", "Deferred", "Received");
  768. wb.setSheetOrder("Digest", 3);
  769. assertSheetOrder(wb, "Invoice", "Deferred", "Received", "Digest");
  770. // check that the overall workbook serializes with its correct size
  771. int expected = wb.getWorkbook().getSize();
  772. int written = wb.getWorkbook().serialize(0, new byte[expected*2]);
  773. assertEquals(expected, written, "Did not have the expected size when writing the workbook");
  774. HSSFWorkbook read = HSSFTestDataSamples.writeOutAndReadBack(wb);
  775. assertSheetOrder(read, "Invoice", "Deferred", "Received", "Digest");
  776. read.close();
  777. wb.close();
  778. }
  779. @Test
  780. void bug54500() throws Exception {
  781. String nameName = "AName";
  782. String sheetName = "ASheet";
  783. HSSFWorkbook wb = openSampleWorkbook("54500.xls");
  784. assertSheetOrder(wb, "Sheet1", "Sheet2", "Sheet3");
  785. wb.createSheet(sheetName);
  786. assertSheetOrder(wb, "Sheet1", "Sheet2", "Sheet3", "ASheet");
  787. Name n = wb.createName();
  788. n.setNameName(nameName);
  789. n.setSheetIndex(3);
  790. n.setRefersToFormula(sheetName + "!A1");
  791. assertSheetOrder(wb, "Sheet1", "Sheet2", "Sheet3", "ASheet");
  792. final HSSFName name = wb.getName(nameName);
  793. assertNotNull(name);
  794. assertEquals("ASheet!A1", name.getRefersToFormula());
  795. UnsynchronizedByteArrayOutputStream stream = UnsynchronizedByteArrayOutputStream.builder().get();
  796. wb.write(stream);
  797. assertSheetOrder(wb, "Sheet1", "Sheet2", "Sheet3", "ASheet");
  798. assertEquals("ASheet!A1", name.getRefersToFormula());
  799. wb.removeSheetAt(1);
  800. assertSheetOrder(wb, "Sheet1", "Sheet3", "ASheet");
  801. assertEquals("ASheet!A1", name.getRefersToFormula());
  802. UnsynchronizedByteArrayOutputStream stream2 = UnsynchronizedByteArrayOutputStream.builder().get();
  803. wb.write(stream2);
  804. assertSheetOrder(wb, "Sheet1", "Sheet3", "ASheet");
  805. assertEquals("ASheet!A1", name.getRefersToFormula());
  806. HSSFWorkbook wb2 = new HSSFWorkbook(stream.toInputStream());
  807. expectName(wb2, nameName, "ASheet!A1");
  808. HSSFWorkbook wb3 = new HSSFWorkbook(stream2.toInputStream());
  809. expectName(wb3, nameName, "ASheet!A1");
  810. wb3.close();
  811. wb2.close();
  812. wb.close();
  813. }
  814. @SuppressWarnings("SameParameterValue")
  815. private void expectName(HSSFWorkbook wb, String name, String expect) {
  816. final HSSFName hssfName = wb.getName(name);
  817. assertNotNull(hssfName);
  818. assertEquals(expect, hssfName.getRefersToFormula());
  819. }
  820. @Test
  821. void test49423() throws Exception
  822. {
  823. HSSFWorkbook workbook = openSampleWorkbook("49423.xls");
  824. boolean found = false;
  825. int numSheets = workbook.getNumberOfSheets();
  826. for (int i = 0; i < numSheets; i++) {
  827. HSSFSheet sheet = workbook.getSheetAt(i);
  828. List<HSSFShape> shapes = sheet.getDrawingPatriarch().getChildren();
  829. for(HSSFShape shape : shapes){
  830. HSSFAnchor anchor = shape.getAnchor();
  831. if(anchor instanceof HSSFClientAnchor){
  832. // absolute coordinates
  833. HSSFClientAnchor clientAnchor = (HSSFClientAnchor)anchor;
  834. assertNotNull(clientAnchor);
  835. //System.out.println(clientAnchor.getRow1() + "," + clientAnchor.getRow2());
  836. found = true;
  837. } else if (anchor instanceof HSSFChildAnchor){
  838. // shape is grouped and the anchor is expressed in the coordinate system of the group
  839. HSSFChildAnchor childAnchor = (HSSFChildAnchor)anchor;
  840. assertNotNull(childAnchor);
  841. //System.out.println(childAnchor.getDy1() + "," + childAnchor.getDy2());
  842. found = true;
  843. }
  844. }
  845. }
  846. assertTrue(found, "Should find some images via Client or Child anchors, but did not find any at all");
  847. workbook.close();
  848. }
  849. @Test
  850. void testRewriteFileBug58480() throws IOException {
  851. final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls");
  852. try {
  853. // create new workbook
  854. {
  855. final Workbook workbook = new HSSFWorkbook();
  856. final Sheet sheet = workbook.createSheet("foo");
  857. final Row row = sheet.createRow(1);
  858. row.createCell(1).setCellValue("bar");
  859. writeAndCloseWorkbook(workbook, file);
  860. }
  861. // edit the workbook
  862. {
  863. try (POIFSFileSystem fs = new POIFSFileSystem(file, false)) {
  864. DirectoryNode root = fs.getRoot();
  865. final Workbook workbook = new HSSFWorkbook(root, true);
  866. final Sheet sheet = workbook.getSheet("foo");
  867. sheet.getRow(1).createCell(2).setCellValue("baz");
  868. writeAndCloseWorkbook(workbook, file);
  869. }
  870. }
  871. } finally {
  872. assertTrue(file.exists());
  873. assertTrue(file.delete());
  874. }
  875. }
  876. private void writeAndCloseWorkbook(Workbook workbook, File file)
  877. throws IOException {
  878. final UnsynchronizedByteArrayOutputStream bytesOut = UnsynchronizedByteArrayOutputStream.builder().get();
  879. workbook.write(bytesOut);
  880. workbook.close();
  881. final byte[] byteArray = bytesOut.toByteArray();
  882. bytesOut.close();
  883. final FileOutputStream fileOut = new FileOutputStream(file);
  884. fileOut.write(byteArray);
  885. fileOut.close();
  886. }
  887. @Test
  888. void closeDoesNotModifyWorkbook() throws IOException {
  889. final String filename = "SampleSS.xls";
  890. final File file = samples.getFile(filename);
  891. Workbook wb;
  892. // File via POIFileStream (java.nio)
  893. wb = new HSSFWorkbook(new POIFSFileSystem(file));
  894. assertCloseDoesNotModifyFile(filename, wb);
  895. // InputStream
  896. wb = new HSSFWorkbook(new FileInputStream(file));
  897. assertCloseDoesNotModifyFile(filename, wb);
  898. }
  899. @Test
  900. void setSheetOrderToEnd() throws Exception {
  901. try (HSSFWorkbook workbook = new HSSFWorkbook()) {
  902. workbook.createSheet("A");
  903. workbook.createSheet("B");
  904. assertEquals("A", workbook.getSheetName(0));
  905. workbook.setSheetOrder("A", 1);
  906. assertEquals("A", workbook.getSheetName(1));
  907. }
  908. }
  909. @Test
  910. void invalidInPlaceWrite() throws Exception {
  911. // Can't work for new files
  912. try (HSSFWorkbook wb = new HSSFWorkbook()) {
  913. assertThrows(IllegalStateException.class, wb::write, "Shouldn't work for new files");
  914. }
  915. // Can't work for InputStream opened files
  916. try (InputStream is = samples.openResourceAsStream("SampleSS.xls");
  917. HSSFWorkbook wb = new HSSFWorkbook(is)) {
  918. assertThrows(IllegalStateException.class, wb::write, "Shouldn't work for InputStream");
  919. }
  920. // Can't work for Read-Only files
  921. try (POIFSFileSystem fs = new POIFSFileSystem(samples.getFile("SampleSS.xls"), true);
  922. HSSFWorkbook wb = new HSSFWorkbook(fs)) {
  923. assertThrows(IllegalStateException.class, wb::write, "Shouldn't work for Read Only");
  924. }
  925. }
  926. @Test
  927. void inPlaceWrite() throws Exception {
  928. // Setup as a copy of a known-good file
  929. final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls");
  930. try (InputStream inputStream = samples.openResourceAsStream("SampleSS.xls");
  931. FileOutputStream outputStream = new FileOutputStream(file)) {
  932. IOUtils.copy(inputStream, outputStream);
  933. }
  934. // Open from the temp file in read-write mode
  935. HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(file, false));
  936. assertEquals(3, wb.getNumberOfSheets());
  937. // Change
  938. wb.removeSheetAt(2);
  939. wb.removeSheetAt(1);
  940. wb.getSheetAt(0).getRow(0).getCell(0).setCellValue("Changed!");
  941. // Save in-place, close, re-open and check
  942. wb.write();
  943. wb.close();
  944. wb = new HSSFWorkbook(new POIFSFileSystem(file));
  945. assertEquals(1, wb.getNumberOfSheets());
  946. assertEquals("Changed!", wb.getSheetAt(0).getRow(0).getCell(0).toString());
  947. wb.close();
  948. }
  949. @Test
  950. void testWriteToNewFile() throws Exception {
  951. // Save to a new temp file
  952. final File file = TempFile.createTempFile("TestHSSFWorkbook", ".xls");
  953. // Open from a Stream
  954. try (HSSFWorkbook wb = new HSSFWorkbook(
  955. samples.openResourceAsStream("SampleSS.xls"))) {
  956. wb.write(file);
  957. }
  958. // Read and check
  959. try (HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(file))) {
  960. assertEquals(3, wb.getNumberOfSheets());
  961. }
  962. }
  963. @Test
  964. void checkExistingFileForR1C1Refs() throws IOException {
  965. try (
  966. UnsynchronizedByteArrayOutputStream bos = UnsynchronizedByteArrayOutputStream.builder().get();
  967. HSSFWorkbook wb = openSampleWorkbook("49423.xls")
  968. ) {
  969. assertEquals(CellReferenceType.A1, wb.getCellReferenceType());
  970. wb.setCellReferenceType(CellReferenceType.R1C1);
  971. assertEquals(CellReferenceType.R1C1, wb.getCellReferenceType());
  972. wb.write(bos);
  973. try (HSSFWorkbook wb2 = new HSSFWorkbook(bos.toInputStream())) {
  974. assertEquals(CellReferenceType.R1C1, wb2.getCellReferenceType());
  975. }
  976. }
  977. }
  978. @Test
  979. void checkNewFileForR1C1Refs() throws IOException {
  980. try (
  981. UnsynchronizedByteArrayOutputStream bos = UnsynchronizedByteArrayOutputStream.builder().get();
  982. HSSFWorkbook wb = new HSSFWorkbook()
  983. ) {
  984. assertEquals(CellReferenceType.UNKNOWN, wb.getCellReferenceType());
  985. HSSFSheet sheet = wb.createSheet();
  986. assertEquals(CellReferenceType.A1, wb.getCellReferenceType());
  987. wb.setCellReferenceType(CellReferenceType.R1C1);
  988. assertEquals(CellReferenceType.R1C1, wb.getCellReferenceType());
  989. wb.write(bos);
  990. try (HSSFWorkbook wb2 = new HSSFWorkbook(bos.toInputStream())) {
  991. assertEquals(CellReferenceType.R1C1, wb2.getCellReferenceType());
  992. }
  993. }
  994. }
  995. @Disabled
  996. void createDrawing() {
  997. // the dimensions for this image are different than for XSSF and SXSSF
  998. }
  999. @Test
  1000. void writeInvalidFile() throws Exception {
  1001. try (Workbook wb = WorkbookFactory.create(
  1002. samples.getFile("clusterfuzz-testcase-minimized-POIHSSFFuzzer-5786329142919168.xls"),
  1003. null, true)) {
  1004. try (OutputStream out = new ByteArrayOutputStream()) {
  1005. wb.write(out);
  1006. }
  1007. }
  1008. }
  1009. }