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.

TestFormulaParser.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.ss.formula;
  20. import java.io.File;
  21. import java.io.FileOutputStream;
  22. import java.util.Locale;
  23. import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
  24. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  25. import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg;
  26. import org.apache.poi.ss.formula.ptg.NameXPxg;
  27. import org.apache.poi.ss.formula.ptg.Ptg;
  28. import org.apache.poi.ss.formula.ptg.StringPtg;
  29. import org.apache.poi.xssf.XSSFTestDataSamples;
  30. import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
  31. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  32. import junit.framework.TestCase;
  33. /**
  34. * Test {@link FormulaParser}'s handling of row numbers at the edge of the
  35. * HSSF/XSSF ranges.
  36. *
  37. * @author David North
  38. */
  39. public class TestFormulaParser extends TestCase {
  40. public void testHSSFFailsForOver65536() {
  41. FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
  42. try {
  43. FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
  44. fail("Expected exception");
  45. }
  46. catch (FormulaParseException expected) {
  47. }
  48. }
  49. public void testHSSFPassCase() {
  50. FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
  51. FormulaParser.parse("Sheet1!1:65536", workbook, FormulaType.CELL, 0);
  52. }
  53. public void testXSSFWorksForOver65536() {
  54. FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
  55. FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
  56. }
  57. public void testXSSFFailCase() {
  58. FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
  59. try {
  60. FormulaParser.parse("Sheet1!1:1048577", workbook, FormulaType.CELL, 0); // one more than max rows.
  61. fail("Expected exception");
  62. }
  63. catch (FormulaParseException expected) {
  64. }
  65. }
  66. // copied from org.apache.poi.hssf.model.TestFormulaParser
  67. public void testMacroFunction() throws Exception {
  68. // testNames.xlsm contains a VB function called 'myFunc'
  69. final String testFile = "testNames.xlsm";
  70. XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFile);
  71. try {
  72. XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
  73. //Expected ptg stack: [NamePtg(myFunc), StringPtg(arg), (additional operands would go here...), FunctionPtg(myFunc)]
  74. Ptg[] ptg = FormulaParser.parse("myFunc(\"arg\")", workbook, FormulaType.CELL, -1);
  75. assertEquals(3, ptg.length);
  76. // the name gets encoded as the first operand on the stack
  77. NameXPxg tname = (NameXPxg) ptg[0];
  78. assertEquals("myFunc", tname.toFormulaString());
  79. // the function's arguments are pushed onto the stack from left-to-right as OperandPtgs
  80. StringPtg arg = (StringPtg) ptg[1];
  81. assertEquals("arg", arg.getValue());
  82. // The external FunctionPtg is the last Ptg added to the stack
  83. // During formula evaluation, this Ptg pops off the the appropriate number of
  84. // arguments (getNumberOfOperands()) and pushes the result on the stack
  85. AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[2];
  86. assertTrue(tfunc.isExternalFunction());
  87. // confirm formula parsing is case-insensitive
  88. FormulaParser.parse("mYfUnC(\"arg\")", workbook, FormulaType.CELL, -1);
  89. // confirm formula parsing doesn't care about argument count or type
  90. // this should only throw an error when evaluating the formula.
  91. FormulaParser.parse("myFunc()", workbook, FormulaType.CELL, -1);
  92. FormulaParser.parse("myFunc(\"arg\", 0, TRUE)", workbook, FormulaType.CELL, -1);
  93. // A completely unknown formula name (not saved in workbook) should still be parseable and renderable
  94. // but will throw an NotImplementedFunctionException or return a #NAME? error value if evaluated.
  95. FormulaParser.parse("yourFunc(\"arg\")", workbook, FormulaType.CELL, -1);
  96. // Make sure workbook can be written and read
  97. XSSFTestDataSamples.writeOutAndReadBack(wb).close();
  98. // Manually check to make sure file isn't corrupted
  99. final File fileIn = XSSFTestDataSamples.getSampleFile(testFile);
  100. final File reSavedFile = new File(fileIn.getParentFile(), fileIn.getName().replace(".xlsm", "-saved.xlsm"));
  101. final FileOutputStream fos = new FileOutputStream(reSavedFile);
  102. wb.write(fos);
  103. fos.close();
  104. } finally {
  105. wb.close();
  106. }
  107. }
  108. public void testParserErrors() throws Exception {
  109. XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("testNames.xlsm");
  110. try {
  111. XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
  112. parseExpectedException("(");
  113. parseExpectedException(")");
  114. parseExpectedException("+");
  115. parseExpectedException("42+");
  116. parseExpectedException("IF()");
  117. parseExpectedException("IF("); //no closing paren
  118. parseExpectedException("myFunc(", workbook); //no closing paren
  119. } finally {
  120. wb.close();
  121. }
  122. }
  123. private static void parseExpectedException(String formula) {
  124. parseExpectedException(formula, null);
  125. }
  126. /** confirm formula has invalid syntax and parsing the formula results in FormulaParseException
  127. * @param formula
  128. * @param wb
  129. */
  130. private static void parseExpectedException(String formula, FormulaParsingWorkbook wb) {
  131. try {
  132. FormulaParser.parse(formula, wb, FormulaType.CELL, -1);
  133. fail("Expected FormulaParseException: " + formula);
  134. } catch (final FormulaParseException e) {
  135. // expected during successful test
  136. assertNotNull(e.getMessage());
  137. }
  138. }
  139. }