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.

TestXSSFFormulaParser.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  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.Assert.assertEquals;
  17. import static org.junit.Assert.assertNotNull;
  18. import static org.junit.Assert.assertTrue;
  19. import static org.junit.Assert.fail;
  20. import org.apache.poi.hssf.HSSFTestDataSamples;
  21. import org.apache.poi.hssf.usermodel.HSSFCell;
  22. import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
  23. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  24. import org.apache.poi.ss.formula.FormulaParseException;
  25. import org.apache.poi.ss.formula.FormulaParser;
  26. import org.apache.poi.ss.formula.FormulaParsingWorkbook;
  27. import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
  28. import org.apache.poi.ss.formula.FormulaType;
  29. import org.apache.poi.ss.formula.WorkbookDependentFormula;
  30. import org.apache.poi.ss.formula.ptg.*;
  31. import org.apache.poi.ss.usermodel.*;
  32. import org.apache.poi.ss.util.CellReference;
  33. import org.apache.poi.xssf.XSSFTestDataSamples;
  34. import org.junit.Test;
  35. import java.util.Arrays;
  36. public final class TestXSSFFormulaParser {
  37. private static Ptg[] parse(FormulaParsingWorkbook fpb, String fmla) {
  38. return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1);
  39. }
  40. @Test
  41. public void basicParsing() {
  42. XSSFWorkbook wb = new XSSFWorkbook();
  43. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  44. Ptg[] ptgs;
  45. ptgs = parse(fpb, "ABC10");
  46. assertEquals(1, ptgs.length);
  47. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  48. ptgs = parse(fpb, "A500000");
  49. assertEquals(1, ptgs.length);
  50. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  51. ptgs = parse(fpb, "ABC500000");
  52. assertEquals(1, ptgs.length);
  53. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  54. //highest allowed rows and column (XFD and 0x100000)
  55. ptgs = parse(fpb, "XFD1048576");
  56. assertEquals(1, ptgs.length);
  57. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  58. //column greater than XFD
  59. try {
  60. /*ptgs =*/ parse(fpb, "XFE10");
  61. fail("expected exception");
  62. } catch (FormulaParseException e){
  63. assertEquals("Specified named range 'XFE10' does not exist in the current workbook.", e.getMessage());
  64. }
  65. //row greater than 0x100000
  66. try {
  67. /*ptgs =*/ parse(fpb, "XFD1048577");
  68. fail("expected exception");
  69. } catch (FormulaParseException e){
  70. assertEquals("Specified named range 'XFD1048577' does not exist in the current workbook.", e.getMessage());
  71. }
  72. // Formula referencing one cell
  73. ptgs = parse(fpb, "ISEVEN(A1)");
  74. assertEquals(3, ptgs.length);
  75. assertEquals(NameXPxg.class, ptgs[0].getClass());
  76. assertEquals(RefPtg.class, ptgs[1].getClass());
  77. assertEquals(FuncVarPtg.class, ptgs[2].getClass());
  78. assertEquals("ISEVEN", ptgs[0].toFormulaString());
  79. assertEquals("A1", ptgs[1].toFormulaString());
  80. assertEquals("#external#", ptgs[2].toFormulaString());
  81. // Formula referencing an area
  82. ptgs = parse(fpb, "SUM(A1:B3)");
  83. assertEquals(2, ptgs.length);
  84. assertEquals(AreaPtg.class, ptgs[0].getClass());
  85. assertEquals(AttrPtg.class, ptgs[1].getClass());
  86. assertEquals("A1:B3", ptgs[0].toFormulaString());
  87. assertEquals("SUM", ptgs[1].toFormulaString());
  88. // Formula referencing one cell in a different sheet
  89. ptgs = parse(fpb, "SUM(Sheet1!A1)");
  90. assertEquals(2, ptgs.length);
  91. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  92. assertEquals(AttrPtg.class, ptgs[1].getClass());
  93. assertEquals("Sheet1!A1", ptgs[0].toFormulaString());
  94. assertEquals("SUM", ptgs[1].toFormulaString());
  95. // Formula referencing an area in a different sheet
  96. ptgs = parse(fpb, "SUM(Sheet1!A1:B3)");
  97. assertEquals(2, ptgs.length);
  98. assertEquals(Area3DPxg.class,ptgs[0].getClass());
  99. assertEquals(AttrPtg.class, ptgs[1].getClass());
  100. assertEquals("Sheet1!A1:B3", ptgs[0].toFormulaString());
  101. assertEquals("SUM", ptgs[1].toFormulaString());
  102. }
  103. @Test
  104. public void builtInFormulas() {
  105. XSSFWorkbook wb = new XSSFWorkbook();
  106. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  107. Ptg[] ptgs;
  108. ptgs = parse(fpb, "LOG10");
  109. assertEquals(1, ptgs.length);
  110. assertTrue("",(ptgs[0] instanceof RefPtg));
  111. ptgs = parse(fpb, "LOG10(100)");
  112. assertEquals(2, ptgs.length);
  113. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof IntPtg);
  114. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof FuncPtg);
  115. }
  116. @Test
  117. public void formaulReferncesSameWorkbook() {
  118. // Use a test file with "other workbook" style references
  119. // to itself
  120. XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
  121. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  122. Ptg[] ptgs;
  123. // Reference to a named range in our own workbook, as if it
  124. // were defined in a different workbook
  125. ptgs = parse(fpb, "[0]!NR_Global_B2");
  126. assertEquals(1, ptgs.length);
  127. assertEquals(NameXPxg.class, ptgs[0].getClass());
  128. assertEquals(0, ((NameXPxg)ptgs[0]).getExternalWorkbookNumber());
  129. assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
  130. assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
  131. assertEquals("[0]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
  132. }
  133. @Test
  134. public void formulaReferencesOtherSheets() {
  135. // Use a test file with the named ranges in place
  136. XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
  137. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  138. Ptg[] ptgs;
  139. // Reference to a single cell in a different sheet
  140. ptgs = parse(fpb, "Uses!A1");
  141. assertEquals(1, ptgs.length);
  142. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  143. assertEquals(-1, ((Ref3DPxg)ptgs[0]).getExternalWorkbookNumber());
  144. assertEquals("A1", ((Ref3DPxg)ptgs[0]).format2DRefAsString());
  145. assertEquals("Uses!A1", ((Ref3DPxg)ptgs[0]).toFormulaString());
  146. // Reference to a single cell in a different sheet, which needs quoting
  147. ptgs = parse(fpb, "'Testing 47100'!A1");
  148. assertEquals(1, ptgs.length);
  149. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  150. assertEquals(-1, ((Ref3DPxg)ptgs[0]).getExternalWorkbookNumber());
  151. assertEquals("Testing 47100", ((Ref3DPxg)ptgs[0]).getSheetName());
  152. assertEquals("A1", ((Ref3DPxg)ptgs[0]).format2DRefAsString());
  153. assertEquals("'Testing 47100'!A1", ((Ref3DPxg)ptgs[0]).toFormulaString());
  154. // Reference to a sheet scoped named range from another sheet
  155. ptgs = parse(fpb, "Defines!NR_To_A1");
  156. assertEquals(1, ptgs.length);
  157. assertEquals(NameXPxg.class, ptgs[0].getClass());
  158. assertEquals(-1, ((NameXPxg)ptgs[0]).getExternalWorkbookNumber());
  159. assertEquals("Defines", ((NameXPxg)ptgs[0]).getSheetName());
  160. assertEquals("NR_To_A1",((NameXPxg)ptgs[0]).getNameName());
  161. assertEquals("Defines!NR_To_A1",((NameXPxg)ptgs[0]).toFormulaString());
  162. // Reference to a workbook scoped named range
  163. ptgs = parse(fpb, "NR_Global_B2");
  164. assertEquals(1, ptgs.length);
  165. assertEquals(NamePtg.class, ptgs[0].getClass());
  166. assertEquals("NR_Global_B2",((NamePtg)ptgs[0]).toFormulaString(fpb));
  167. }
  168. @Test
  169. public void formulaReferencesOtherWorkbook() {
  170. // Use a test file with the external linked table in place
  171. XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
  172. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  173. Ptg[] ptgs;
  174. // Reference to a single cell in a different workbook
  175. ptgs = parse(fpb, "[1]Uses!$A$1");
  176. assertEquals(1, ptgs.length);
  177. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  178. assertEquals(1, ((Ref3DPxg)ptgs[0]).getExternalWorkbookNumber());
  179. assertEquals("Uses",((Ref3DPxg)ptgs[0]).getSheetName());
  180. assertEquals("$A$1",((Ref3DPxg)ptgs[0]).format2DRefAsString());
  181. assertEquals("[1]Uses!$A$1",((Ref3DPxg)ptgs[0]).toFormulaString());
  182. // Reference to a sheet-scoped named range in a different workbook
  183. ptgs = parse(fpb, "[1]Defines!NR_To_A1");
  184. assertEquals(1, ptgs.length);
  185. assertEquals(NameXPxg.class, ptgs[0].getClass());
  186. assertEquals(1, ((NameXPxg)ptgs[0]).getExternalWorkbookNumber());
  187. assertEquals("Defines", ((NameXPxg)ptgs[0]).getSheetName());
  188. assertEquals("NR_To_A1",((NameXPxg)ptgs[0]).getNameName());
  189. assertEquals("[1]Defines!NR_To_A1",((NameXPxg)ptgs[0]).toFormulaString());
  190. // Reference to a global named range in a different workbook
  191. ptgs = parse(fpb, "[1]!NR_Global_B2");
  192. assertEquals(1, ptgs.length);
  193. assertEquals(NameXPxg.class, ptgs[0].getClass());
  194. assertEquals(1, ((NameXPxg)ptgs[0]).getExternalWorkbookNumber());
  195. assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
  196. assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
  197. assertEquals("[1]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
  198. }
  199. /**
  200. * A handful of functions (such as SUM, COUNTA, MIN) support
  201. * multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from
  202. * Sheets 1 through Sheet 3) and multi-sheet area references
  203. * (eg Sheet1:Sheet3!A1:B2 = Cells A1 through B2 from Sheets
  204. * 1 through Sheet 3).
  205. * This test, based on common test files for HSSF and XSSF, checks
  206. * that we can read and parse these kinds of references
  207. * (but not evaluate - that's elsewhere in the test suite)
  208. */
  209. @Test
  210. public void multiSheetReferencesHSSFandXSSF() throws Exception {
  211. Workbook[] wbs = new Workbook[] {
  212. HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
  213. XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx")
  214. };
  215. for (Workbook wb : wbs) {
  216. Sheet s1 = wb.getSheetAt(0);
  217. Ptg[] ptgs;
  218. // Check the contents
  219. Cell sumF = s1.getRow(2).getCell(0);
  220. assertNotNull(sumF);
  221. assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula());
  222. Cell avgF = s1.getRow(2).getCell(1);
  223. assertNotNull(avgF);
  224. assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula());
  225. Cell countAF = s1.getRow(2).getCell(2);
  226. assertNotNull(countAF);
  227. assertEquals("COUNTA(Sheet1:Sheet3!C1)", countAF.getCellFormula());
  228. Cell maxF = s1.getRow(4).getCell(1);
  229. assertNotNull(maxF);
  230. assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula());
  231. Cell sumFA = s1.getRow(2).getCell(7);
  232. assertNotNull(sumFA);
  233. assertEquals("SUM(Sheet1:Sheet3!A1:B2)", sumFA.getCellFormula());
  234. Cell avgFA = s1.getRow(2).getCell(8);
  235. assertNotNull(avgFA);
  236. assertEquals("AVERAGE(Sheet1:Sheet3!A1:B2)", avgFA.getCellFormula());
  237. Cell maxFA = s1.getRow(4).getCell(8);
  238. assertNotNull(maxFA);
  239. assertEquals("MAX(Sheet1:Sheet3!A$1:B$2)", maxFA.getCellFormula());
  240. Cell countFA = s1.getRow(5).getCell(8);
  241. assertNotNull(countFA);
  242. assertEquals("COUNT(Sheet1:Sheet3!$A$1:$B$2)", countFA.getCellFormula());
  243. // Create a formula parser
  244. final FormulaParsingWorkbook fpb;
  245. if (wb instanceof HSSFWorkbook)
  246. fpb = HSSFEvaluationWorkbook.create((HSSFWorkbook)wb);
  247. else
  248. fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook)wb);
  249. // Check things parse as expected:
  250. // SUM to one cell over 3 workbooks, relative reference
  251. ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1)");
  252. assertEquals(2, ptgs.length);
  253. if (wb instanceof HSSFWorkbook) {
  254. assertEquals(Ref3DPtg.class, ptgs[0].getClass());
  255. } else {
  256. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  257. }
  258. assertEquals("Sheet1:Sheet3!A1", toFormulaString(ptgs[0], fpb));
  259. assertEquals(AttrPtg.class, ptgs[1].getClass());
  260. assertEquals("SUM", toFormulaString(ptgs[1], fpb));
  261. // MAX to one cell over 3 workbooks, absolute row reference
  262. ptgs = parse(fpb, "MAX(Sheet1:Sheet3!A$1)");
  263. assertEquals(2, ptgs.length);
  264. if (wb instanceof HSSFWorkbook) {
  265. assertEquals(Ref3DPtg.class, ptgs[0].getClass());
  266. } else {
  267. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  268. }
  269. assertEquals("Sheet1:Sheet3!A$1", toFormulaString(ptgs[0], fpb));
  270. assertEquals(FuncVarPtg.class, ptgs[1].getClass());
  271. assertEquals("MAX", toFormulaString(ptgs[1], fpb));
  272. // MIN to one cell over 3 workbooks, absolute reference
  273. ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1)");
  274. assertEquals(2, ptgs.length);
  275. if (wb instanceof HSSFWorkbook) {
  276. assertEquals(Ref3DPtg.class, ptgs[0].getClass());
  277. } else {
  278. assertEquals(Ref3DPxg.class, ptgs[0].getClass());
  279. }
  280. assertEquals("Sheet1:Sheet3!$A$1", toFormulaString(ptgs[0], fpb));
  281. assertEquals(FuncVarPtg.class, ptgs[1].getClass());
  282. assertEquals("MIN", toFormulaString(ptgs[1], fpb));
  283. // SUM to a range of cells over 3 workbooks
  284. ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1:B2)");
  285. assertEquals(2, ptgs.length);
  286. if (wb instanceof HSSFWorkbook) {
  287. assertEquals(Area3DPtg.class, ptgs[0].getClass());
  288. } else {
  289. assertEquals(Area3DPxg.class, ptgs[0].getClass());
  290. }
  291. assertEquals("Sheet1:Sheet3!A1:B2", toFormulaString(ptgs[0], fpb));
  292. assertEquals(AttrPtg.class, ptgs[1].getClass());
  293. assertEquals("SUM", toFormulaString(ptgs[1], fpb));
  294. // MIN to a range of cells over 3 workbooks, absolute reference
  295. ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1:$B$2)");
  296. assertEquals(2, ptgs.length);
  297. if (wb instanceof HSSFWorkbook) {
  298. assertEquals(Area3DPtg.class, ptgs[0].getClass());
  299. } else {
  300. assertEquals(Area3DPxg.class, ptgs[0].getClass());
  301. }
  302. assertEquals("Sheet1:Sheet3!$A$1:$B$2", toFormulaString(ptgs[0], fpb));
  303. assertEquals(FuncVarPtg.class, ptgs[1].getClass());
  304. assertEquals("MIN", toFormulaString(ptgs[1], fpb));
  305. // Check we can round-trip - try to set a new one to a new single cell
  306. Cell newF = s1.getRow(0).createCell(10, Cell.CELL_TYPE_FORMULA);
  307. newF.setCellFormula("SUM(Sheet2:Sheet3!A1)");
  308. assertEquals("SUM(Sheet2:Sheet3!A1)", newF.getCellFormula());
  309. // Check we can round-trip - try to set a new one to a cell range
  310. newF = s1.getRow(0).createCell(11, Cell.CELL_TYPE_FORMULA);
  311. newF.setCellFormula("MIN(Sheet1:Sheet2!A1:B2)");
  312. assertEquals("MIN(Sheet1:Sheet2!A1:B2)", newF.getCellFormula());
  313. }
  314. }
  315. private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) {
  316. if (ptg instanceof WorkbookDependentFormula) {
  317. return ((WorkbookDependentFormula)ptg).toFormulaString((FormulaRenderingWorkbook)wb);
  318. }
  319. return ptg.toFormulaString();
  320. }
  321. @Test
  322. public void test58648Single() {
  323. XSSFWorkbook wb = new XSSFWorkbook();
  324. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  325. Ptg[] ptgs;
  326. ptgs = parse(fpb, "(ABC10 )");
  327. assertEquals("Had: " + Arrays.toString(ptgs),
  328. 2, ptgs.length);
  329. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  330. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  331. }
  332. @Test
  333. public void test58648Basic() {
  334. XSSFWorkbook wb = new XSSFWorkbook();
  335. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  336. Ptg[] ptgs;
  337. // verify whitespaces in different places
  338. ptgs = parse(fpb, "(ABC10)");
  339. assertEquals("Had: " + Arrays.toString(ptgs),
  340. 2, ptgs.length);
  341. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  342. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  343. ptgs = parse(fpb, "( ABC10)");
  344. assertEquals("Had: " + Arrays.toString(ptgs),
  345. 2, ptgs.length);
  346. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  347. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  348. ptgs = parse(fpb, "(ABC10 )");
  349. assertEquals("Had: " + Arrays.toString(ptgs),
  350. 2, ptgs.length);
  351. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  352. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  353. ptgs = parse(fpb, "((ABC10))");
  354. assertEquals("Had: " + Arrays.toString(ptgs),
  355. 3, ptgs.length);
  356. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  357. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  358. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof ParenthesisPtg);
  359. ptgs = parse(fpb, "((ABC10) )");
  360. assertEquals("Had: " + Arrays.toString(ptgs),
  361. 3, ptgs.length);
  362. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  363. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  364. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof ParenthesisPtg);
  365. ptgs = parse(fpb, "( (ABC10))");
  366. assertEquals("Had: " + Arrays.toString(ptgs),
  367. 3, ptgs.length);
  368. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
  369. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
  370. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof ParenthesisPtg);
  371. }
  372. @Test
  373. public void test58648FormulaParsing() {
  374. Workbook wb = XSSFTestDataSamples.openSampleWorkbook("58648.xlsx");
  375. FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
  376. for (int i = 0; i < wb.getNumberOfSheets(); i++) {
  377. Sheet xsheet = wb.getSheetAt(i);
  378. for (Row row : xsheet) {
  379. for (Cell cell : row) {
  380. if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
  381. try {
  382. evaluator.evaluateFormulaCell(cell);
  383. } catch (Exception e) {
  384. CellReference cellRef = new CellReference(cell.getRowIndex(), cell.getColumnIndex());
  385. throw new RuntimeException("error at: " + cellRef.toString(), e);
  386. }
  387. }
  388. }
  389. }
  390. }
  391. Sheet sheet = wb.getSheet("my-sheet");
  392. Cell cell = sheet.getRow(1).getCell(4);
  393. assertEquals(5d, cell.getNumericCellValue(), 0d);
  394. }
  395. @Test
  396. public void testWhitespaceInFormula() {
  397. XSSFWorkbook wb = new XSSFWorkbook();
  398. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  399. Ptg[] ptgs;
  400. // verify whitespaces in different places
  401. ptgs = parse(fpb, "INTERCEPT(A2:A5, B2:B5)");
  402. assertEquals("Had: " + Arrays.toString(ptgs),
  403. 3, ptgs.length);
  404. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof AreaPtg);
  405. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
  406. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof FuncPtg);
  407. ptgs = parse(fpb, " INTERCEPT ( \t \r A2 : \nA5 , B2 : B5 ) \t");
  408. assertEquals("Had: " + Arrays.toString(ptgs),
  409. 3, ptgs.length);
  410. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof AreaPtg);
  411. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
  412. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof FuncPtg);
  413. ptgs = parse(fpb, "(VLOOKUP(\"item1\", A2:B3, 2, FALSE) - VLOOKUP(\"item2\", A2:B3, 2, FALSE) )");
  414. assertEquals("Had: " + Arrays.toString(ptgs),
  415. 12, ptgs.length);
  416. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof StringPtg);
  417. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
  418. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof IntPtg);
  419. ptgs = parse(fpb, "A1:B1 B1:B2");
  420. assertEquals("Had: " + Arrays.toString(ptgs),
  421. 4, ptgs.length);
  422. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof MemAreaPtg);
  423. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
  424. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
  425. assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof IntersectionPtg);
  426. ptgs = parse(fpb, "A1:B1 B1:B2");
  427. assertEquals("Had: " + Arrays.toString(ptgs),
  428. 4, ptgs.length);
  429. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof MemAreaPtg);
  430. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
  431. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
  432. assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof IntersectionPtg);
  433. }
  434. @Test
  435. public void testWhitespaceInComplexFormula() {
  436. XSSFWorkbook wb = new XSSFWorkbook();
  437. XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
  438. Ptg[] ptgs;
  439. // verify whitespaces in different places
  440. ptgs = parse(fpb, "SUM(A1:INDEX(1:1048576,MAX(IFERROR(MATCH(99^99,B:B,1),0),IFERROR(MATCH(\"zzzz\",B:B,1),0)),MAX(IFERROR(MATCH(99^99,1:1,1),0),IFERROR(MATCH(\"zzzz\",1:1,1),0))))");
  441. assertEquals("Had: " + Arrays.toString(ptgs),
  442. 40, ptgs.length);
  443. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof MemFuncPtg);
  444. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof RefPtg);
  445. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
  446. assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof NameXPxg);
  447. ptgs = parse(fpb, "SUM ( A1 : INDEX( 1 : 1048576 , MAX( IFERROR ( MATCH ( 99 ^ 99 , B : B , 1 ) , 0 ) , IFERROR ( MATCH ( \"zzzz\" , B:B , 1 ) , 0 ) ) , MAX ( IFERROR ( MATCH ( 99 ^ 99 , 1 : 1 , 1 ) , 0 ) , IFERROR ( MATCH ( \"zzzz\" , 1 : 1 , 1 ) , 0 ) ) ) )");
  448. assertEquals("Had: " + Arrays.toString(ptgs),
  449. 40, ptgs.length);
  450. assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof MemFuncPtg);
  451. assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof RefPtg);
  452. assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
  453. assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof NameXPxg);
  454. }
  455. }