git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@885007 13f79535-47bb-0310-9956-ffa450edef68pull/1/head
@@ -20,6 +20,7 @@ package org.apache.poi.hssf.model; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.formula.FormulaParser; | |||
import org.apache.poi.ss.formula.FormulaParsingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaRenderer; | |||
@@ -41,17 +42,18 @@ public final class HSSFFormulaParser { | |||
} | |||
/** | |||
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int)} | |||
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int, int)} | |||
*/ | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook) { | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook) throws FormulaParseException { | |||
return parse(formula, workbook, FormulaType.CELL); | |||
} | |||
/** | |||
* @param formulaType a constant from {@link FormulaType} | |||
* @return the parsed formula tokens | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) { | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) throws FormulaParseException { | |||
return parse(formula, workbook, formulaType, -1); | |||
} | |||
@@ -64,8 +66,9 @@ public final class HSSFFormulaParser { | |||
* the scope of the name will be ignored and the parser will match named ranges only by name | |||
* | |||
* @return the parsed formula tokens | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) { | |||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) throws FormulaParseException { | |||
return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType, sheetIndex); | |||
} | |||
@@ -81,7 +81,7 @@ public class HSSFCell implements Cell { | |||
*/ | |||
public static final int LAST_COLUMN_NUMBER = SpreadsheetVersion.EXCEL97.getLastColumnIndex(); // 2^8 - 1 | |||
private static final String LAST_COLUMN_NAME = SpreadsheetVersion.EXCEL97.getLastColumnName(); | |||
public final static short ENCODING_UNCHANGED = -1; | |||
public final static short ENCODING_COMPRESSED_UNICODE = 0; | |||
public final static short ENCODING_UTF_16 = 1; | |||
@@ -507,7 +507,7 @@ public class HSSFCell implements Cell { | |||
} | |||
/** | |||
* set a string value for the cell. | |||
* set a string value for the cell. | |||
* | |||
* @param value value to set the cell to. For formulas we'll set the formula | |||
* cached string result, for String cells we'll set its value. For other types we will | |||
@@ -573,17 +573,6 @@ public class HSSFCell implements Cell { | |||
_stringValue.setUnicodeString(_book.getWorkbook().getSSTString(index)); | |||
} | |||
/** | |||
* Sets formula for this cell. | |||
* <p> | |||
* Note, this method only sets the formula string and does not calculate the formula value. | |||
* To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)} | |||
* </p> | |||
* | |||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>. | |||
* If the argument is <code>null</code> then the current formula is removed. | |||
* @throws IllegalArgumentException if the formula is unparsable | |||
*/ | |||
public void setCellFormula(String formula) { | |||
int row=_record.getRow(); | |||
short col=_record.getColumn(); | |||
@@ -918,8 +907,8 @@ public class HSSFCell implements Cell { | |||
*/ | |||
private static void checkBounds(int cellIndex) { | |||
if (cellIndex < 0 || cellIndex > LAST_COLUMN_NUMBER) { | |||
throw new IllegalArgumentException("Invalid column index (" + cellIndex | |||
+ "). Allowable column range for " + FILE_FORMAT_NAME + " is (0.." | |||
throw new IllegalArgumentException("Invalid column index (" + cellIndex | |||
+ "). Allowable column range for " + FILE_FORMAT_NAME + " is (0.." | |||
+ LAST_COLUMN_NUMBER + ") or ('A'..'" + LAST_COLUMN_NAME + "')"); | |||
} | |||
} |
@@ -29,6 +29,7 @@ import org.apache.poi.ss.formula.EvaluationCell; | |||
import org.apache.poi.ss.formula.EvaluationName; | |||
import org.apache.poi.ss.formula.EvaluationSheet; | |||
import org.apache.poi.ss.formula.EvaluationWorkbook; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.formula.FormulaParsingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
@@ -129,7 +130,7 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E | |||
// to make sure that all formulas POI can evaluate can also be parsed. | |||
try { | |||
return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet())); | |||
} catch (RuntimeException e) { | |||
} catch (FormulaParseException e) { | |||
// Note - as of Bugzilla 48036 (svn r828244, r828247) POI is capable of evaluating | |||
// IntesectionPtg. However it is still not capable of parsing it. | |||
// So FormulaEvalTestData.xls now contains a few formulas that produce errors here. |
@@ -0,0 +1,33 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.ss.formula; | |||
/** | |||
* This exception thrown when a supplied formula has incorrect syntax (or syntax currently not | |||
* supported by POI). It is primarily used by test code to confirm specific parsing exceptions. | |||
* Application code should also handle this exception if it potentially supplies formula text | |||
* that is not guaranteed to be well-formed. | |||
* | |||
* @author Josh Micich | |||
*/ | |||
public final class FormulaParseException extends RuntimeException { | |||
FormulaParseException(String msg) { | |||
super(msg); | |||
} | |||
} |
@@ -24,7 +24,6 @@ import java.util.regex.Pattern; | |||
import org.apache.poi.hssf.record.UnicodeString; | |||
import org.apache.poi.hssf.record.constant.ErrorConstant; | |||
import org.apache.poi.hssf.record.formula.*; | |||
import org.apache.poi.hssf.record.formula.ValueOperatorPtg; | |||
import org.apache.poi.hssf.record.formula.function.FunctionMetadata; | |||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry; | |||
import org.apache.poi.hssf.usermodel.HSSFErrorConstants; | |||
@@ -42,6 +41,10 @@ import org.apache.poi.ss.SpreadsheetVersion; | |||
* <term> ::= <factor> [ <mulop> <factor> ]* | |||
* <factor> ::= <number> | (<expression>) | <cellRef> | <function> | |||
* <function> ::= <functionName> ([expression [, expression]*]) | |||
* <p/> | |||
* For POI internal use only | |||
* <p/> | |||
* | |||
* | |||
* @author Avik Sengupta <avik at apache dot org> | |||
* @author Andrew C. oliver (acoliver at apache dot org) | |||
@@ -111,20 +114,6 @@ public final class FormulaParser { | |||
} | |||
} | |||
/** | |||
* Specific exception thrown when a supplied formula does not parse properly.<br/> | |||
* Primarily used by test cases when testing for specific parsing exceptions.</p> | |||
* | |||
*/ | |||
static final class FormulaParseException extends RuntimeException { | |||
// This class was given package scope until it would become clear that it is useful to | |||
// general client code. | |||
public FormulaParseException(String msg) { | |||
super(msg); | |||
} | |||
} | |||
private final String _formulaString; | |||
private final int _formulaLength; | |||
/** points at the next character to be read (after the {@link #look} char) */ | |||
@@ -141,7 +130,7 @@ public final class FormulaParser { | |||
private char look; | |||
private FormulaParsingWorkbook _book; | |||
private SpreadsheetVersion _ssVersion; | |||
private SpreadsheetVersion _ssVersion; | |||
private int _sheetIndex; | |||
@@ -162,19 +151,11 @@ public final class FormulaParser { | |||
_formulaString = formula; | |||
_pointer=0; | |||
_book = book; | |||
_ssVersion = book == null ? SpreadsheetVersion.EXCEL97 : book.getSpreadsheetVersion(); | |||
_formulaLength = _formulaString.length(); | |||
_ssVersion = book == null ? SpreadsheetVersion.EXCEL97 : book.getSpreadsheetVersion(); | |||
_formulaLength = _formulaString.length(); | |||
_sheetIndex = sheetIndex; | |||
} | |||
public static Ptg[] parse(String formula, FormulaParsingWorkbook book) { | |||
return parse(formula, book, FormulaType.CELL); | |||
} | |||
public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType) { | |||
return parse(formula, workbook, formulaType, -1); | |||
} | |||
/** | |||
* Parse a formula into a array of tokens | |||
* | |||
@@ -186,7 +167,7 @@ public final class FormulaParser { | |||
* the scope of the name will be ignored and the parser will match names only by name | |||
* | |||
* @return array of parsed tokens | |||
* @throws FormulaParseException if the formula is unparsable | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType, int sheetIndex) { | |||
FormulaParser fp = new FormulaParser(formula, workbook, sheetIndex); | |||
@@ -702,7 +683,7 @@ public final class FormulaParser { | |||
if (!isValidCellReference(rep)) { | |||
return null; | |||
} | |||
} else if (hasLetters) { | |||
} else if (hasLetters) { | |||
if (!CellReference.isColumnWithnRange(rep.replace("$", ""), _ssVersion)) { | |||
return null; | |||
} | |||
@@ -881,29 +862,29 @@ public final class FormulaParser { | |||
* @return <code>true</code> if the specified name is a valid cell reference | |||
*/ | |||
private boolean isValidCellReference(String str) { | |||
//check range bounds against grid max | |||
boolean result = CellReference.classifyCellReference(str, _ssVersion) == NameType.CELL; | |||
if(result){ | |||
/** | |||
* Check if the argument is a function. Certain names can be either a cell reference or a function name | |||
* depending on the contenxt. Compare the following examples in Excel 2007: | |||
* (a) LOG10(100) + 1 | |||
* (b) LOG10 + 1 | |||
* In (a) LOG10 is a name of a built-in function. In (b) LOG10 is a cell reference | |||
*/ | |||
boolean isFunc = FunctionMetadataRegistry.getFunctionByName(str.toUpperCase()) != null; | |||
if(isFunc){ | |||
int savePointer = _pointer; | |||
resetPointer(_pointer + str.length()); | |||
SkipWhite(); | |||
// open bracket indicates that the argument is a function, | |||
// the returning value should be false, i.e. "not a valid cell reference" | |||
result = look != '('; | |||
resetPointer(savePointer); | |||
} | |||
} | |||
return result; | |||
//check range bounds against grid max | |||
boolean result = CellReference.classifyCellReference(str, _ssVersion) == NameType.CELL; | |||
if(result){ | |||
/** | |||
* Check if the argument is a function. Certain names can be either a cell reference or a function name | |||
* depending on the contenxt. Compare the following examples in Excel 2007: | |||
* (a) LOG10(100) + 1 | |||
* (b) LOG10 + 1 | |||
* In (a) LOG10 is a name of a built-in function. In (b) LOG10 is a cell reference | |||
*/ | |||
boolean isFunc = FunctionMetadataRegistry.getFunctionByName(str.toUpperCase()) != null; | |||
if(isFunc){ | |||
int savePointer = _pointer; | |||
resetPointer(_pointer + str.length()); | |||
SkipWhite(); | |||
// open bracket indicates that the argument is a function, | |||
// the returning value should be false, i.e. "not a valid cell reference" | |||
result = look != '('; | |||
resetPointer(savePointer); | |||
} | |||
} | |||
return result; | |||
} | |||
@@ -20,6 +20,8 @@ package org.apache.poi.ss.usermodel; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
/** | |||
* High level representation of a cell in a row of a spreadsheet. | |||
* <p> | |||
@@ -76,7 +78,7 @@ public interface Cell { | |||
* @see #getCellType() | |||
*/ | |||
public final static int CELL_TYPE_ERROR = 5; | |||
/** | |||
* Returns column index of this cell | |||
* | |||
@@ -158,7 +160,7 @@ public interface Cell { | |||
* data type is now something besides {@link Cell#CELL_TYPE_NUMERIC}. POI | |||
* does not attempt to replicate this behaviour. To make a numeric cell | |||
* display as a date, use {@link #setCellStyle(CellStyle)} etc. | |||
* | |||
* | |||
* @param value the numeric value to set this cell to. For formulas we'll set the | |||
* precalculated value, for numerics we'll set its value. For other types we | |||
* will change the cell to a numerics cell and set its value. | |||
@@ -203,6 +205,7 @@ public interface Cell { | |||
*/ | |||
void setCellValue(String value); | |||
/** | |||
* Sets formula for this cell. | |||
* <p> | |||
@@ -210,11 +213,11 @@ public interface Cell { | |||
* To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)} | |||
* </p> | |||
* | |||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>. | |||
* @param formula the formula to set, e.g. <code>"SUM(C4:E4)"</code>. | |||
* If the argument is <code>null</code> then the current formula is removed. | |||
* @throws IllegalArgumentException if the formula is unparsable | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
void setCellFormula(String formula); | |||
void setCellFormula(String formula) throws FormulaParseException; | |||
/** | |||
* Return a formula for the cell, for example, <code>SUM(C4:E4)</code> |
@@ -362,17 +362,6 @@ public final class XSSFCell implements Cell { | |||
return FormulaRenderer.toFormulaString(fpb, fmla); | |||
} | |||
/** | |||
* Sets formula for this cell. | |||
* <p> | |||
* Note, this method only sets the formula string and does not calculate the formula value. | |||
* To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)} | |||
* </p> | |||
* | |||
* @param formula the formula to set, e.g. <code>SUM(C4:E4)</code>. | |||
* If the argument is <code>null</code> then the current formula is removed. | |||
* @throws IllegalArgumentException if the formula is invalid | |||
*/ | |||
public void setCellFormula(String formula) { | |||
XSSFWorkbook wb = _row.getSheet().getWorkbook(); | |||
if (formula == null) { |
@@ -23,55 +23,53 @@ import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.RefPtg; | |||
import org.apache.poi.hssf.record.formula.IntPtg; | |||
import org.apache.poi.hssf.record.formula.FuncPtg; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.formula.FormulaParser; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
public final class TestXSSFFormulaParser extends TestCase { | |||
private static Ptg[] parse(XSSFEvaluationWorkbook fpb, String fmla) { | |||
return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1); | |||
} | |||
public void testParse() { | |||
XSSFWorkbook wb = new XSSFWorkbook(); | |||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb); | |||
String fmla; | |||
Ptg[] ptgs; | |||
fmla = "ABC10"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "ABC10"); | |||
assertEquals(1, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof RefPtg)); | |||
assertTrue("", ptgs[0] instanceof RefPtg); | |||
fmla = "A500000"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "A500000"); | |||
assertEquals(1, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof RefPtg)); | |||
assertTrue("", ptgs[0] instanceof RefPtg); | |||
fmla = "ABC500000"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "ABC500000"); | |||
assertEquals(1, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof RefPtg)); | |||
assertTrue("", ptgs[0] instanceof RefPtg); | |||
//highest allowed rows and column (XFD and 0x100000) | |||
fmla = "XFD1048576"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "XFD1048576"); | |||
assertEquals(1, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof RefPtg)); | |||
assertTrue("", ptgs[0] instanceof RefPtg); | |||
//column greater than XFD | |||
fmla = "XFE10"; | |||
try { | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "XFE10"); | |||
fail("expected exception"); | |||
} catch (Exception e){ | |||
} catch (FormulaParseException e){ | |||
assertEquals("Specified named range 'XFE10' does not exist in the current workbook.", e.getMessage()); | |||
} | |||
//row greater than 0x100000 | |||
fmla = "XFD1048577"; | |||
try { | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "XFD1048577"); | |||
fail("expected exception"); | |||
} catch (Exception e){ | |||
} catch (FormulaParseException e){ | |||
assertEquals("Specified named range 'XFD1048577' does not exist in the current workbook.", e.getMessage()); | |||
} | |||
} | |||
@@ -79,19 +77,15 @@ public final class TestXSSFFormulaParser extends TestCase { | |||
public void testBuiltInFormulas() { | |||
XSSFWorkbook wb = new XSSFWorkbook(); | |||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb); | |||
String fmla; | |||
Ptg[] ptgs; | |||
fmla = "LOG10"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "LOG10"); | |||
assertEquals(1, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof RefPtg)); | |||
fmla = "LOG10(100)"; | |||
ptgs = FormulaParser.parse(fmla, fpb, FormulaType.CELL); | |||
ptgs = parse(fpb, "LOG10(100)"); | |||
assertEquals(2, ptgs.length); | |||
assertTrue("",(ptgs[0] instanceof IntPtg)); | |||
assertTrue("",(ptgs[1] instanceof FuncPtg)); | |||
assertTrue("", ptgs[0] instanceof IntPtg); | |||
assertTrue("", ptgs[1] instanceof FuncPtg); | |||
} | |||
} | |||
} |
@@ -65,8 +65,9 @@ import org.apache.poi.hssf.usermodel.HSSFRow; | |||
import org.apache.poi.hssf.usermodel.HSSFSheet; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.hssf.usermodel.TestHSSFName; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.formula.FormulaParser; | |||
import org.apache.poi.ss.formula.FormulaParserTestHelper; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues; | |||
import org.apache.poi.ss.usermodel.Name; | |||
@@ -684,9 +685,9 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
parseFormula(formula); | |||
throw new AssertionFailedError("expected parse exception"); | |||
} catch (RuntimeException e) { | |||
} catch (FormulaParseException e) { | |||
// expected during successful test | |||
FormulaParserTestHelper.confirmParseException(e); | |||
assertNotNull(e.getMessage()); | |||
} | |||
} | |||
@@ -782,8 +783,8 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
HSSFFormulaParser.parse(formula, book); | |||
throw new AssertionFailedError("Didn't get parse exception as expected"); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, expectedMessage); | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, expectedMessage); | |||
} | |||
} | |||
@@ -792,16 +793,16 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
parseFormula("round(3.14;2)"); | |||
throw new AssertionFailedError("Didn't get parse exception as expected"); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, | |||
"Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'"); | |||
} | |||
try { | |||
parseFormula(" =2+2"); | |||
throw new AssertionFailedError("Didn't get parse exception as expected"); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, | |||
"The specified formula ' =2+2' starts with an equals sign which is not allowed."); | |||
} | |||
} | |||
@@ -853,8 +854,8 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
cell.setCellFormula("count(pf1)"); | |||
throw new AssertionFailedError("Expected formula parse execption"); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, | |||
"Specified named range 'pf1' does not exist in the current workbook."); | |||
} | |||
cell.setCellFormula("count(fp1)"); // plain cell ref, col is in range | |||
@@ -962,7 +963,7 @@ public final class TestFormulaParser extends TestCase { | |||
String formula = "Sheet1!$B$2:$C$3,OFFSET(Sheet1!$E$2:$E$4,1,Sheet1!$A$1),Sheet1!$D$6"; | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
wb.createSheet("Sheet1"); | |||
Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb)); | |||
Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb), FormulaType.CELL, -1); | |||
Class<?>[] expectedClasses = { | |||
// TODO - AttrPtg.class, // Excel prepends this | |||
@@ -985,7 +986,7 @@ public final class TestFormulaParser extends TestCase { | |||
String formula = "Sheet1!A1:Sheet1!B3"; | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
wb.createSheet("Sheet1"); | |||
Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb)); | |||
Ptg[] ptgs = FormulaParser.parse(formula, HSSFEvaluationWorkbook.create(wb), FormulaType.CELL, -1); | |||
if (ptgs.length == 3) { | |||
confirmTokenClasses(ptgs, new Class[] { Ref3DPtg.class, Ref3DPtg.class, RangePtg.class,}); | |||
@@ -1195,8 +1196,8 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
HSSFFormulaParser.parse(formula, wb); | |||
throw new AssertionFailedError("Expected formula parse execption"); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, expectedMessage); | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, expectedMessage); | |||
} | |||
} | |||
@@ -1220,8 +1221,7 @@ public final class TestFormulaParser extends TestCase { | |||
Ptg[] result; | |||
try { | |||
result = HSSFFormulaParser.parse("1+foo", wb); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e); | |||
} catch (FormulaParseException e) { | |||
if (e.getMessage().equals("Specified name 'foo' is not a range as expected.")) { | |||
throw new AssertionFailedError("Identified bug 47078c"); | |||
} | |||
@@ -1247,9 +1247,9 @@ public final class TestFormulaParser extends TestCase { | |||
HSSFFormulaParser.parse(badCellRef, wb); | |||
throw new AssertionFailedError("Identified bug 47312b - Shouldn't be able to parse cell ref '" | |||
+ badCellRef + "'."); | |||
} catch (RuntimeException e) { | |||
} catch (FormulaParseException e) { | |||
// expected during successful test | |||
FormulaParserTestHelper.confirmParseException(e, "Specified named range '" | |||
confirmParseException(e, "Specified named range '" | |||
+ badCellRef + "' does not exist in the current workbook."); | |||
} | |||
@@ -1257,8 +1257,8 @@ public final class TestFormulaParser extends TestCase { | |||
try { | |||
ptgs = HSSFFormulaParser.parse(leadingZeroCellRef, wb); | |||
assertEquals("B1", ((RefPtg) ptgs[0]).toFormulaString()); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e, "Specified named range '" | |||
} catch (FormulaParseException e) { | |||
confirmParseException(e, "Specified named range '" | |||
+ leadingZeroCellRef + "' does not exist in the current workbook."); | |||
// close but no cigar | |||
throw new AssertionFailedError("Identified bug 47312c - '" | |||
@@ -1272,4 +1272,8 @@ public final class TestFormulaParser extends TestCase { | |||
ptgs = HSSFFormulaParser.parse("B0", wb); | |||
assertEquals(NamePtg.class, ptgs[0].getClass()); | |||
} | |||
private static void confirmParseException(FormulaParseException e, String expMsg) { | |||
assertEquals(expMsg, e.getMessage()); | |||
} | |||
} |
@@ -29,12 +29,12 @@ import org.apache.poi.hssf.usermodel.HSSFName; | |||
import org.apache.poi.hssf.usermodel.HSSFRow; | |||
import org.apache.poi.hssf.usermodel.HSSFSheet; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.formula.FormulaParserTestHelper; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.usermodel.CellValue; | |||
/** | |||
* Test the low level formula parser functionality, | |||
* but using parts which need to use | |||
* but using parts which need to use | |||
* HSSFFormulaEvaluator. | |||
*/ | |||
public final class TestFormulaParserEval extends TestCase { | |||
@@ -56,11 +56,11 @@ public final class TestFormulaParserEval extends TestCase { | |||
// Now make it a single cell | |||
name.setRefersToFormula("C3"); | |||
confirmParseFormula(workbook); | |||
// And make it non-contiguous | |||
// using area unions | |||
name.setRefersToFormula("A1:A2,C3"); | |||
confirmParseFormula(workbook); | |||
} | |||
@@ -75,11 +75,11 @@ public final class TestFormulaParserEval extends TestCase { | |||
} | |||
public void testEvaluateFormulaWithRowBeyond32768_Bug44539() { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet(); | |||
wb.setSheetName(0, "Sheet1"); | |||
HSSFRow row = sheet.createRow(0); | |||
HSSFCell cell = row.createCell(0); | |||
cell.setCellFormula("SUM(A32769:A32770)"); | |||
@@ -87,13 +87,12 @@ public final class TestFormulaParserEval extends TestCase { | |||
// put some values in the cells to make the evaluation more interesting | |||
sheet.createRow(32768).createCell(0).setCellValue(31); | |||
sheet.createRow(32769).createCell(0).setCellValue(11); | |||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||
CellValue result; | |||
try { | |||
result = fe.evaluate(cell); | |||
} catch (RuntimeException e) { | |||
FormulaParserTestHelper.confirmParseException(e); | |||
} catch (FormulaParseException e) { | |||
if (!e.getMessage().equals("Found reference to named range \"A\", but that named range wasn't defined!")) { | |||
throw new AssertionFailedError("Identifed bug 44539"); | |||
} |
@@ -28,6 +28,7 @@ import org.apache.poi.hssf.usermodel.*; | |||
import org.apache.poi.ss.usermodel.CellValue; | |||
import org.apache.poi.ss.formula.FormulaParser; | |||
import org.apache.poi.ss.formula.FormulaRenderer; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
import org.apache.poi.util.LittleEndianInput; | |||
/** | |||
@@ -101,7 +102,7 @@ public final class TestSharedFormulaRecord extends TestCase { | |||
HSSFEvaluationWorkbook fpb = HSSFEvaluationWorkbook.create(wb); | |||
Ptg[] sharedFormula, convertedFormula; | |||
sharedFormula = FormulaParser.parse("A2", fpb); | |||
sharedFormula = FormulaParser.parse("A2", fpb, FormulaType.CELL, -1); | |||
convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 0, 0); | |||
confirmOperandClasses(sharedFormula, convertedFormula); | |||
//conversion relative to [0,0] should return the original formula | |||
@@ -117,7 +118,7 @@ public final class TestSharedFormulaRecord extends TestCase { | |||
//one row down and one cell right | |||
assertEquals("B3", FormulaRenderer.toFormulaString(fpb, convertedFormula)); | |||
sharedFormula = FormulaParser.parse("SUM(A1:C1)", fpb); | |||
sharedFormula = FormulaParser.parse("SUM(A1:C1)", fpb, FormulaType.CELL, -1); | |||
convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 0, 0); | |||
confirmOperandClasses(sharedFormula, convertedFormula); | |||
assertEquals("SUM(A1:C1)", FormulaRenderer.toFormulaString(fpb, convertedFormula)); | |||
@@ -139,22 +140,22 @@ public final class TestSharedFormulaRecord extends TestCase { | |||
HSSFSheet sheet; | |||
HSSFCell cellB32769; | |||
HSSFCell cellC32769; | |||
// Reading directly from XLS file | |||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS); | |||
sheet = wb.getSheetAt(0); | |||
cellB32769 = sheet.getRow(32768).getCell(1); | |||
cellC32769 = sheet.getRow(32768).getCell(2); | |||
// check reading of formulas which are shared (two cells from a 1R x 8C range) | |||
assertEquals("B32770*2", cellB32769.getCellFormula()); | |||
// check reading of formulas which are shared (two cells from a 1R x 8C range) | |||
assertEquals("B32770*2", cellB32769.getCellFormula()); | |||
assertEquals("C32770*2", cellC32769.getCellFormula()); | |||
confirmCellEvaluation(wb, cellB32769, 4); | |||
confirmCellEvaluation(wb, cellC32769, 6); | |||
// Confirm this example really does have SharedFormulas. | |||
// there are 3 others besides the one at A32769:H32769 | |||
assertEquals(4, countSharedFormulas(sheet)); | |||
assertEquals(4, countSharedFormulas(sheet)); | |||
// Re-serialize and check again | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
@@ -164,18 +165,18 @@ public final class TestSharedFormulaRecord extends TestCase { | |||
confirmCellEvaluation(wb, cellB32769, 4); | |||
assertEquals(4, countSharedFormulas(sheet)); | |||
} | |||
public void testUnshareFormulaDueToChangeFormula() { | |||
HSSFWorkbook wb; | |||
HSSFSheet sheet; | |||
HSSFCell cellB32769; | |||
HSSFCell cellC32769; | |||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS); | |||
sheet = wb.getSheetAt(0); | |||
cellB32769 = sheet.getRow(32768).getCell(1); | |||
cellC32769 = sheet.getRow(32768).getCell(2); | |||
// Updating cell formula, causing it to become unshared | |||
cellB32769.setCellFormula("1+1"); | |||
confirmCellEvaluation(wb, cellB32769, 2); | |||
@@ -194,25 +195,25 @@ public final class TestSharedFormulaRecord extends TestCase { | |||
// changing shared formula cell to blank | |||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS); | |||
sheet = wb.getSheetAt(0); | |||
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula()); | |||
cell = sheet.getRow(ROW_IX).getCell(1); | |||
cell.setCellType(HSSFCell.CELL_TYPE_BLANK); | |||
assertEquals(3, countSharedFormulas(sheet)); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula()); | |||
// deleting shared formula cell | |||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS); | |||
sheet = wb.getSheetAt(0); | |||
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula()); | |||
cell = sheet.getRow(ROW_IX).getCell(1); | |||
sheet.getRow(ROW_IX).removeCell(cell); | |||
assertEquals(3, countSharedFormulas(sheet)); | |||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb); | |||
sheet = wb.getSheetAt(0); | |||
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula()); |
@@ -1,55 +0,0 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.ss.formula; | |||
import junit.framework.Assert; | |||
import junit.framework.AssertionFailedError; | |||
import org.apache.poi.ss.formula.FormulaParser.FormulaParseException; | |||
/** | |||
* Avoids making {@link FormulaParseException} public | |||
* | |||
* @author Josh Micich | |||
*/ | |||
public class FormulaParserTestHelper { | |||
/** | |||
* @throws AssertionFailedError if <tt>e</tt> is not a formula parser exception | |||
* or if the exception message doesn't match. | |||
*/ | |||
public static void confirmParseException(RuntimeException e, String expectedMessage) { | |||
checkType(e); | |||
Assert.assertEquals(expectedMessage, e.getMessage()); | |||
} | |||
/** | |||
* @throws AssertionFailedError if <tt>e</tt> is not a formula parser exception | |||
* or if <tt>e</tt> has no message. | |||
*/ | |||
public static void confirmParseException(RuntimeException e) { | |||
checkType(e); | |||
Assert.assertNotNull(e.getMessage()); | |||
} | |||
private static void checkType(RuntimeException e) throws AssertionFailedError { | |||
if (!(e instanceof FormulaParseException)) { | |||
String failMsg = "Expected FormulaParseException, but got (" | |||
+ e.getClass().getName() + "):"; | |||
System.err.println(failMsg); | |||
e.printStackTrace(); | |||
throw new AssertionFailedError(failMsg); | |||
} | |||
} | |||
} |