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.

TestHSSFFormulaEvaluator.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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 junit.framework.AssertionFailedError;
  17. import junit.framework.TestCase;
  18. import org.apache.poi.hssf.HSSFTestDataSamples;
  19. import org.apache.poi.hssf.HSSFITestDataProvider;
  20. import org.apache.poi.hssf.record.NameRecord;
  21. import org.apache.poi.hssf.record.formula.eval.NumberEval;
  22. import org.apache.poi.hssf.record.formula.eval.ValueEval;
  23. import org.apache.poi.ss.formula.EvaluationCell;
  24. import org.apache.poi.ss.formula.EvaluationListener;
  25. import org.apache.poi.ss.formula.WorkbookEvaluator;
  26. import org.apache.poi.ss.formula.WorkbookEvaluatorTestHelper;
  27. import org.apache.poi.ss.usermodel.Cell;
  28. import org.apache.poi.ss.usermodel.CellValue;
  29. import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluator;
  30. /**
  31. *
  32. * @author Josh Micich
  33. */
  34. public final class TestHSSFFormulaEvaluator extends BaseTestFormulaEvaluator {
  35. public TestHSSFFormulaEvaluator() {
  36. super(HSSFITestDataProvider.instance);
  37. }
  38. /**
  39. * Test that the HSSFFormulaEvaluator can evaluate simple named ranges
  40. * (single cells and rectangular areas)
  41. */
  42. public void testEvaluateSimple() {
  43. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
  44. HSSFSheet sheet = wb.getSheetAt(0);
  45. HSSFCell cell = sheet.getRow(8).getCell(0);
  46. HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
  47. CellValue cv = fe.evaluate(cell);
  48. assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
  49. assertEquals(3.72, cv.getNumberValue(), 0.0);
  50. }
  51. /**
  52. * Test for bug due to attempt to convert a cached formula error result to a boolean
  53. */
  54. public void testUpdateCachedFormulaResultFromErrorToNumber_bug46479() {
  55. HSSFWorkbook wb = new HSSFWorkbook();
  56. HSSFSheet sheet = wb.createSheet("Sheet1");
  57. HSSFRow row = sheet.createRow(0);
  58. HSSFCell cellA1 = row.createCell(0);
  59. HSSFCell cellB1 = row.createCell(1);
  60. cellB1.setCellFormula("A1+1");
  61. HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
  62. cellA1.setCellErrorValue((byte)HSSFErrorConstants.ERROR_NAME);
  63. fe.evaluateFormulaCell(cellB1);
  64. cellA1.setCellValue(2.5);
  65. fe.notifyUpdateCell(cellA1);
  66. try {
  67. fe.evaluateInCell(cellB1);
  68. } catch (IllegalStateException e) {
  69. if (e.getMessage().equals("Cannot get a numeric value from a error formula cell")) {
  70. throw new AssertionFailedError("Identified bug 46479a");
  71. }
  72. }
  73. assertEquals(3.5, cellB1.getNumericCellValue(), 0.0);
  74. }
  75. /**
  76. * When evaluating defined names, POI has to decide whether it is capable. Currently
  77. * (May2009) POI only supports simple cell and area refs.<br/>
  78. * The sample spreadsheet (bugzilla attachment 23508) had a name flagged as 'complex'
  79. * which contained a simple area ref. It is not clear what the 'complex' flag is used
  80. * for but POI should look elsewhere to decide whether it can evaluate the name.
  81. */
  82. public void testDefinedNameWithComplexFlag_bug47048() {
  83. // Mock up a spreadsheet to match the critical details of the sample
  84. HSSFWorkbook wb = new HSSFWorkbook();
  85. HSSFSheet sheet = wb.createSheet("Input");
  86. HSSFName definedName = wb.createName();
  87. definedName.setNameName("Is_Multicar_Vehicle");
  88. definedName.setRefersToFormula("Input!$B$17:$G$17");
  89. // Set up some data and the formula
  90. HSSFRow row17 = sheet.createRow(16);
  91. row17.createCell(0).setCellValue(25.0);
  92. row17.createCell(1).setCellValue(1.33);
  93. row17.createCell(2).setCellValue(4.0);
  94. HSSFRow row = sheet.createRow(0);
  95. HSSFCell cellA1 = row.createCell(0);
  96. cellA1.setCellFormula("SUM(Is_Multicar_Vehicle)");
  97. // Set the complex flag - POI doesn't usually manipulate this flag
  98. NameRecord nameRec = TestHSSFName.getNameRecord(definedName);
  99. nameRec.setOptionFlag((short)0x10); // 0x10 -> complex
  100. HSSFFormulaEvaluator hsf = new HSSFFormulaEvaluator(wb);
  101. CellValue value;
  102. try {
  103. value = hsf.evaluate(cellA1);
  104. } catch (RuntimeException e) {
  105. if (e.getMessage().equals("Don't now how to evalate name 'Is_Multicar_Vehicle'")) {
  106. throw new AssertionFailedError("Identified bug 47048a");
  107. }
  108. throw e;
  109. }
  110. assertEquals(Cell.CELL_TYPE_NUMERIC, value.getCellType());
  111. assertEquals(5.33, value.getNumberValue(), 0.0);
  112. }
  113. private static final class EvalCountListener extends EvaluationListener {
  114. private int _evalCount;
  115. public EvalCountListener() {
  116. _evalCount = 0;
  117. }
  118. public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry) {
  119. _evalCount++;
  120. }
  121. public int getEvalCount() {
  122. return _evalCount;
  123. }
  124. }
  125. /**
  126. * The HSSFFormula evaluator performance benefits greatly from caching of intermediate cell values
  127. */
  128. public void testShortCircuitIfEvaluation() {
  129. // Set up a simple IF() formula that has measurable evaluation cost for its operands.
  130. HSSFWorkbook wb = new HSSFWorkbook();
  131. HSSFSheet sheet = wb.createSheet("Sheet1");
  132. HSSFRow row = sheet.createRow(0);
  133. HSSFCell cellA1 = row.createCell(0);
  134. cellA1.setCellFormula("if(B1,C1,D1+E1+F1)");
  135. // populate cells B1..F1 with simple formulas instead of plain values so we can use
  136. // EvaluationListener to check which parts of the first formula get evaluated
  137. for (int i=1; i<6; i++) {
  138. // formulas are just literal constants "1".."5"
  139. row.createCell(i).setCellFormula(String.valueOf(i));
  140. }
  141. EvalCountListener evalListener = new EvalCountListener();
  142. WorkbookEvaluator evaluator = WorkbookEvaluatorTestHelper.createEvaluator(wb, evalListener);
  143. ValueEval ve = evaluator.evaluate(HSSFEvaluationTestHelper.wrapCell(cellA1));
  144. int evalCount = evalListener.getEvalCount();
  145. if (evalCount == 6) {
  146. // Without short-circuit-if evaluation, evaluating cell 'A1' takes 3 extra evaluations (for D1,E1,F1)
  147. throw new AssertionFailedError("Identifed bug 48195 - Formula evaluator should short-circuit IF() calculations.");
  148. }
  149. assertEquals(3, evalCount);
  150. assertEquals(2.0, ((NumberEval)ve).getNumberValue(), 0D);
  151. }
  152. /**
  153. * Ensures that we can handle NameXPtgs in the formulas
  154. * we parse.
  155. */
  156. public void testXRefs() throws Exception {
  157. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
  158. HSSFWorkbook wbData = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
  159. Cell cell;
  160. // VLookup on a name in another file
  161. cell = wb.getSheetAt(0).getRow(1).getCell(2);
  162. assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
  163. assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
  164. assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
  165. // WARNING - this is wrong!
  166. // The file name should be showing, but bug #45970 is fixed
  167. // we seem to loose it
  168. assertEquals("VLOOKUP(PART,COSTS,2,FALSE)", cell.getCellFormula());
  169. // Simple reference to a name in another file
  170. cell = wb.getSheetAt(0).getRow(1).getCell(4);
  171. assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
  172. assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
  173. assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
  174. // WARNING - this is wrong!
  175. // The file name should be showing, but bug #45970 is fixed
  176. // we seem to loose it
  177. assertEquals("Cost*Markup_Cost", cell.getCellFormula());
  178. // Evaluate the cells
  179. HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
  180. HSSFFormulaEvaluator.setupEnvironment(
  181. new String[] { "XRefCalc.xls", "XRefCalcData.xls" },
  182. new HSSFFormulaEvaluator[] {
  183. eval,
  184. new HSSFFormulaEvaluator(wbData)
  185. }
  186. );
  187. eval.evaluateFormulaCell(
  188. wb.getSheetAt(0).getRow(1).getCell(2)
  189. );
  190. eval.evaluateFormulaCell(
  191. wb.getSheetAt(0).getRow(1).getCell(4)
  192. );
  193. // Re-check VLOOKUP one
  194. cell = wb.getSheetAt(0).getRow(1).getCell(2);
  195. assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
  196. assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
  197. assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
  198. // Re-check ref one
  199. cell = wb.getSheetAt(0).getRow(1).getCell(4);
  200. assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
  201. assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
  202. assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
  203. }
  204. public void testSharedFormulas(){
  205. baseTestSharedFormulas("shared_formulas.xls");
  206. }
  207. }