Bug 46898: Convert unit tests for circular references to also run for XSSF
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1649122 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
12edcc5ed2
commit
ffcc20f60e
@ -0,0 +1,31 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.eval;
|
||||||
|
|
||||||
|
import org.apache.poi.xssf.XSSFITestDataProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests XSSFFormulaEvaluator for its handling of cell formula circular references.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestXSSFCircularReferences extends BaseTestCircularReferences {
|
||||||
|
public TestXSSFCircularReferences() {
|
||||||
|
super(XSSFITestDataProvider.instance);
|
||||||
|
}
|
||||||
|
}
|
@ -19,19 +19,21 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf;
|
package org.apache.poi.xssf;
|
||||||
|
|
||||||
import org.apache.poi.POIDataSamples;
|
|
||||||
import org.apache.poi.ss.ITestDataProvider;
|
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
|
||||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.apache.poi.POIDataSamples;
|
||||||
|
import org.apache.poi.ss.ITestDataProvider;
|
||||||
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Yegor Kozlov
|
* @author Yegor Kozlov
|
||||||
*/
|
*/
|
||||||
@ -43,6 +45,7 @@ public final class SXSSFITestDataProvider implements ITestDataProvider {
|
|||||||
private SXSSFITestDataProvider() {
|
private SXSSFITestDataProvider() {
|
||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public Workbook openSampleWorkbook(String sampleFileName) {
|
public Workbook openSampleWorkbook(String sampleFileName) {
|
||||||
XSSFWorkbook xssfWorkbook = XSSFITestDataProvider.instance.openSampleWorkbook(sampleFileName);
|
XSSFWorkbook xssfWorkbook = XSSFITestDataProvider.instance.openSampleWorkbook(sampleFileName);
|
||||||
SXSSFWorkbook swb = new SXSSFWorkbook(xssfWorkbook);
|
SXSSFWorkbook swb = new SXSSFWorkbook(xssfWorkbook);
|
||||||
@ -66,17 +69,25 @@ public final class SXSSFITestDataProvider implements ITestDataProvider {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SXSSFWorkbook createWorkbook(){
|
public SXSSFWorkbook createWorkbook(){
|
||||||
SXSSFWorkbook wb = new SXSSFWorkbook();
|
SXSSFWorkbook wb = new SXSSFWorkbook();
|
||||||
instances.add(wb);
|
instances.add(wb);
|
||||||
return wb;
|
return wb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FormulaEvaluator createFormulaEvaluator(Workbook wb) {
|
||||||
|
return new XSSFFormulaEvaluator(((SXSSFWorkbook) wb).getXSSFWorkbook());
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getTestDataFileContent(String fileName) {
|
public byte[] getTestDataFileContent(String fileName) {
|
||||||
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpreadsheetVersion getSpreadsheetVersion(){
|
public SpreadsheetVersion getSpreadsheetVersion(){
|
||||||
return SpreadsheetVersion.EXCEL2007;
|
return SpreadsheetVersion.EXCEL2007;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStandardFileNameExtension() {
|
public String getStandardFileNameExtension() {
|
||||||
return "xlsx";
|
return "xlsx";
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ package org.apache.poi.xssf;
|
|||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
import org.apache.poi.ss.ITestDataProvider;
|
import org.apache.poi.ss.ITestDataProvider;
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,24 +34,34 @@ public final class XSSFITestDataProvider implements ITestDataProvider {
|
|||||||
private XSSFITestDataProvider() {
|
private XSSFITestDataProvider() {
|
||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public XSSFWorkbook openSampleWorkbook(String sampleFileName) {
|
public XSSFWorkbook openSampleWorkbook(String sampleFileName) {
|
||||||
return XSSFTestDataSamples.openSampleWorkbook(sampleFileName);
|
return XSSFTestDataSamples.openSampleWorkbook(sampleFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XSSFWorkbook writeOutAndReadBack(Workbook original) {
|
public XSSFWorkbook writeOutAndReadBack(Workbook original) {
|
||||||
if(!(original instanceof XSSFWorkbook)) {
|
if(!(original instanceof XSSFWorkbook)) {
|
||||||
throw new IllegalArgumentException("Expected an instance of XSSFWorkbook");
|
throw new IllegalArgumentException("Expected an instance of XSSFWorkbook");
|
||||||
}
|
}
|
||||||
return XSSFTestDataSamples.writeOutAndReadBack((XSSFWorkbook)original);
|
return XSSFTestDataSamples.writeOutAndReadBack((XSSFWorkbook)original);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XSSFWorkbook createWorkbook(){
|
public XSSFWorkbook createWorkbook(){
|
||||||
return new XSSFWorkbook();
|
return new XSSFWorkbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FormulaEvaluator createFormulaEvaluator(Workbook wb) {
|
||||||
|
return new XSSFFormulaEvaluator((XSSFWorkbook) wb);
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getTestDataFileContent(String fileName) {
|
public byte[] getTestDataFileContent(String fileName) {
|
||||||
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpreadsheetVersion getSpreadsheetVersion(){
|
public SpreadsheetVersion getSpreadsheetVersion(){
|
||||||
return SpreadsheetVersion.EXCEL2007;
|
return SpreadsheetVersion.EXCEL2007;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStandardFileNameExtension() {
|
public String getStandardFileNameExtension() {
|
||||||
return "xlsx";
|
return "xlsx";
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
package org.apache.poi.hssf;
|
package org.apache.poi.hssf;
|
||||||
|
|
||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.ITestDataProvider;
|
import org.apache.poi.ss.ITestDataProvider;
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,24 +34,34 @@ public final class HSSFITestDataProvider implements ITestDataProvider {
|
|||||||
private HSSFITestDataProvider(){
|
private HSSFITestDataProvider(){
|
||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public HSSFWorkbook openSampleWorkbook(String sampleFileName) {
|
public HSSFWorkbook openSampleWorkbook(String sampleFileName) {
|
||||||
return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
|
return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HSSFWorkbook writeOutAndReadBack(Workbook original) {
|
public HSSFWorkbook writeOutAndReadBack(Workbook original) {
|
||||||
if(!(original instanceof HSSFWorkbook)) {
|
if(!(original instanceof HSSFWorkbook)) {
|
||||||
throw new IllegalArgumentException("Expected an instance of HSSFWorkbook");
|
throw new IllegalArgumentException("Expected an instance of HSSFWorkbook");
|
||||||
}
|
}
|
||||||
return HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)original);
|
return HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)original);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HSSFWorkbook createWorkbook(){
|
public HSSFWorkbook createWorkbook(){
|
||||||
return new HSSFWorkbook();
|
return new HSSFWorkbook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FormulaEvaluator createFormulaEvaluator(Workbook wb) {
|
||||||
|
return new HSSFFormulaEvaluator((HSSFWorkbook) wb);
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getTestDataFileContent(String fileName) {
|
public byte[] getTestDataFileContent(String fileName) {
|
||||||
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
return POIDataSamples.getSpreadSheetInstance().readFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpreadsheetVersion getSpreadsheetVersion(){
|
public SpreadsheetVersion getSpreadsheetVersion(){
|
||||||
return SpreadsheetVersion.EXCEL97;
|
return SpreadsheetVersion.EXCEL97;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStandardFileNameExtension() {
|
public String getStandardFileNameExtension() {
|
||||||
return "xls";
|
return "xls";
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.ss;
|
package org.apache.poi.ss;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,6 +46,15 @@ public interface ITestDataProvider {
|
|||||||
*/
|
*/
|
||||||
Workbook createWorkbook();
|
Workbook createWorkbook();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the corresponding {@link FormulaEvaluator} for the
|
||||||
|
* type of Workbook handled by this Provider.
|
||||||
|
*
|
||||||
|
* @param wb The workbook to base the formula evaluator on.
|
||||||
|
* @return A new instance of a matching type of formula evaluator.
|
||||||
|
*/
|
||||||
|
FormulaEvaluator createFormulaEvaluator(Workbook wb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a sample file from the standard HSSF test data directory
|
* Opens a sample file from the standard HSSF test data directory
|
||||||
*
|
*
|
||||||
|
@ -30,7 +30,7 @@ public class AllFormulaEvalTests {
|
|||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
|
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
|
||||||
result.addTestSuite(TestAreaEval.class);
|
result.addTestSuite(TestAreaEval.class);
|
||||||
result.addTestSuite(TestCircularReferences.class);
|
result.addTestSuite(TestHSSFCircularReferences.class);
|
||||||
result.addTestSuite(TestDivideEval.class);
|
result.addTestSuite(TestDivideEval.class);
|
||||||
result.addTestSuite(TestEqualEval.class);
|
result.addTestSuite(TestEqualEval.class);
|
||||||
result.addTestSuite(TestExternalFunction.class);
|
result.addTestSuite(TestExternalFunction.class);
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
package org.apache.poi.ss.formula.eval;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.ITestDataProvider;
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common superclass for testing cases of circular references
|
||||||
|
* both for HSSF and XSSF
|
||||||
|
*/
|
||||||
|
public abstract class BaseTestCircularReferences extends TestCase {
|
||||||
|
|
||||||
|
protected final ITestDataProvider _testDataProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param testDataProvider an object that provides test data in HSSF / XSSF specific way
|
||||||
|
*/
|
||||||
|
protected BaseTestCircularReferences(ITestDataProvider testDataProvider) {
|
||||||
|
_testDataProvider = testDataProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates StackOverflowError into AssertionFailedError
|
||||||
|
*/
|
||||||
|
private CellValue evaluateWithCycles(Workbook wb, Cell testCell)
|
||||||
|
throws AssertionFailedError {
|
||||||
|
FormulaEvaluator evaluator = _testDataProvider.createFormulaEvaluator(wb);
|
||||||
|
try {
|
||||||
|
return evaluator.evaluate(testCell);
|
||||||
|
} catch (StackOverflowError e) {
|
||||||
|
throw new AssertionFailedError( "circular reference caused stack overflow error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Makes sure that the specified evaluated cell value represents a circular reference error.
|
||||||
|
*/
|
||||||
|
private static void confirmCycleErrorCode(CellValue cellValue) {
|
||||||
|
assertTrue(cellValue.getCellType() == Cell.CELL_TYPE_ERROR);
|
||||||
|
assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cellValue.getErrorValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASF Bugzilla Bug 44413
|
||||||
|
* "INDEX() formula cannot contain its own location in the data array range"
|
||||||
|
*/
|
||||||
|
public void testIndexFormula() {
|
||||||
|
|
||||||
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
|
Sheet sheet = wb.createSheet("Sheet1");
|
||||||
|
|
||||||
|
int colB = 1;
|
||||||
|
sheet.createRow(0).createCell(colB).setCellValue(1);
|
||||||
|
sheet.createRow(1).createCell(colB).setCellValue(2);
|
||||||
|
sheet.createRow(2).createCell(colB).setCellValue(3);
|
||||||
|
Row row4 = sheet.createRow(3);
|
||||||
|
Cell testCell = row4.createCell(0);
|
||||||
|
// This formula should evaluate to the contents of B2,
|
||||||
|
testCell.setCellFormula("INDEX(A1:B4,2,2)");
|
||||||
|
// However the range A1:B4 also includes the current cell A4. If the other parameters
|
||||||
|
// were 4 and 1, this would represent a circular reference. Prior to v3.2 POI would
|
||||||
|
// 'fully' evaluate ref arguments before invoking operators, which raised the possibility of
|
||||||
|
// cycles / StackOverflowErrors.
|
||||||
|
|
||||||
|
|
||||||
|
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
||||||
|
|
||||||
|
assertTrue(cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC);
|
||||||
|
assertEquals(2, cellValue.getNumberValue(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cell A1 has formula "=A1"
|
||||||
|
*/
|
||||||
|
public void testSimpleCircularReference() {
|
||||||
|
|
||||||
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
|
Sheet sheet = wb.createSheet("Sheet1");
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
Cell testCell = row.createCell(0);
|
||||||
|
testCell.setCellFormula("A1");
|
||||||
|
|
||||||
|
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
||||||
|
|
||||||
|
confirmCycleErrorCode(cellValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A1=B1, B1=C1, C1=D1, D1=A1
|
||||||
|
*/
|
||||||
|
public void testMultiLevelCircularReference() {
|
||||||
|
|
||||||
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
|
Sheet sheet = wb.createSheet("Sheet1");
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
row.createCell(0).setCellFormula("B1");
|
||||||
|
row.createCell(1).setCellFormula("C1");
|
||||||
|
row.createCell(2).setCellFormula("D1");
|
||||||
|
Cell testCell = row.createCell(3);
|
||||||
|
testCell.setCellFormula("A1");
|
||||||
|
|
||||||
|
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
||||||
|
|
||||||
|
confirmCycleErrorCode(cellValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIntermediateCircularReferenceResults_bug46898() {
|
||||||
|
Workbook wb = _testDataProvider.createWorkbook();
|
||||||
|
Sheet sheet = wb.createSheet("Sheet1");
|
||||||
|
|
||||||
|
Row row = sheet.createRow(0);
|
||||||
|
|
||||||
|
Cell cellA1 = row.createCell(0);
|
||||||
|
Cell cellB1 = row.createCell(1);
|
||||||
|
Cell cellC1 = row.createCell(2);
|
||||||
|
Cell cellD1 = row.createCell(3);
|
||||||
|
Cell cellE1 = row.createCell(4);
|
||||||
|
|
||||||
|
cellA1.setCellFormula("IF(FALSE, 1+B1, 42)");
|
||||||
|
cellB1.setCellFormula("1+C1");
|
||||||
|
cellC1.setCellFormula("1+D1");
|
||||||
|
cellD1.setCellFormula("1+E1");
|
||||||
|
cellE1.setCellFormula("1+A1");
|
||||||
|
|
||||||
|
FormulaEvaluator fe = _testDataProvider.createFormulaEvaluator(wb);
|
||||||
|
CellValue cv;
|
||||||
|
|
||||||
|
// Happy day flow - evaluate A1 first
|
||||||
|
cv = fe.evaluate(cellA1);
|
||||||
|
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
|
assertEquals(42.0, cv.getNumberValue(), 0.0);
|
||||||
|
cv = fe.evaluate(cellB1); // no circ-ref-error because A1 result is cached
|
||||||
|
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
|
assertEquals(46.0, cv.getNumberValue(), 0.0);
|
||||||
|
|
||||||
|
// Show the bug - evaluate another cell from the loop first
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
cv = fe.evaluate(cellB1);
|
||||||
|
if (cv.getCellType() == ErrorEval.CIRCULAR_REF_ERROR.getErrorCode()) {
|
||||||
|
throw new AssertionFailedError("Identified bug 46898");
|
||||||
|
}
|
||||||
|
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
|
assertEquals(46.0, cv.getNumberValue(), 0.0);
|
||||||
|
|
||||||
|
// start evaluation on another cell
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
cv = fe.evaluate(cellE1);
|
||||||
|
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
|
assertEquals(43.0, cv.getNumberValue(), 0.0);
|
||||||
|
}
|
||||||
|
}
|
@ -1,169 +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.eval;
|
|
||||||
|
|
||||||
import junit.framework.AssertionFailedError;
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
|
||||||
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.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
|
||||||
/**
|
|
||||||
* Tests HSSFFormulaEvaluator for its handling of cell formula circular references.
|
|
||||||
*
|
|
||||||
* @author Josh Micich
|
|
||||||
*/
|
|
||||||
public final class TestCircularReferences extends TestCase {
|
|
||||||
/**
|
|
||||||
* Translates StackOverflowError into AssertionFailedError
|
|
||||||
*/
|
|
||||||
private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFCell testCell)
|
|
||||||
throws AssertionFailedError {
|
|
||||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
|
|
||||||
try {
|
|
||||||
return evaluator.evaluate(testCell);
|
|
||||||
} catch (StackOverflowError e) {
|
|
||||||
throw new AssertionFailedError( "circular reference caused stack overflow error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Makes sure that the specified evaluated cell value represents a circular reference error.
|
|
||||||
*/
|
|
||||||
private static void confirmCycleErrorCode(CellValue cellValue) {
|
|
||||||
assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_ERROR);
|
|
||||||
assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cellValue.getErrorValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASF Bugzilla Bug 44413
|
|
||||||
* "INDEX() formula cannot contain its own location in the data array range"
|
|
||||||
*/
|
|
||||||
public void testIndexFormula() {
|
|
||||||
|
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
|
||||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
|
||||||
|
|
||||||
int colB = 1;
|
|
||||||
sheet.createRow(0).createCell(colB).setCellValue(1);
|
|
||||||
sheet.createRow(1).createCell(colB).setCellValue(2);
|
|
||||||
sheet.createRow(2).createCell(colB).setCellValue(3);
|
|
||||||
HSSFRow row4 = sheet.createRow(3);
|
|
||||||
HSSFCell testCell = row4.createCell(0);
|
|
||||||
// This formula should evaluate to the contents of B2,
|
|
||||||
testCell.setCellFormula("INDEX(A1:B4,2,2)");
|
|
||||||
// However the range A1:B4 also includes the current cell A4. If the other parameters
|
|
||||||
// were 4 and 1, this would represent a circular reference. Prior to v3.2 POI would
|
|
||||||
// 'fully' evaluate ref arguments before invoking operators, which raised the possibility of
|
|
||||||
// cycles / StackOverflowErrors.
|
|
||||||
|
|
||||||
|
|
||||||
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
|
||||||
|
|
||||||
assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_NUMERIC);
|
|
||||||
assertEquals(2, cellValue.getNumberValue(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cell A1 has formula "=A1"
|
|
||||||
*/
|
|
||||||
public void testSimpleCircularReference() {
|
|
||||||
|
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
|
||||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
|
||||||
|
|
||||||
HSSFRow row = sheet.createRow(0);
|
|
||||||
HSSFCell testCell = row.createCell(0);
|
|
||||||
testCell.setCellFormula("A1");
|
|
||||||
|
|
||||||
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
|
||||||
|
|
||||||
confirmCycleErrorCode(cellValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A1=B1, B1=C1, C1=D1, D1=A1
|
|
||||||
*/
|
|
||||||
public void testMultiLevelCircularReference() {
|
|
||||||
|
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
|
||||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
|
||||||
|
|
||||||
HSSFRow row = sheet.createRow(0);
|
|
||||||
row.createCell(0).setCellFormula("B1");
|
|
||||||
row.createCell(1).setCellFormula("C1");
|
|
||||||
row.createCell(2).setCellFormula("D1");
|
|
||||||
HSSFCell testCell = row.createCell(3);
|
|
||||||
testCell.setCellFormula("A1");
|
|
||||||
|
|
||||||
CellValue cellValue = evaluateWithCycles(wb, testCell);
|
|
||||||
|
|
||||||
confirmCycleErrorCode(cellValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIntermediateCircularReferenceResults_bug46898() {
|
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
|
||||||
HSSFSheet sheet = wb.createSheet("Sheet1");
|
|
||||||
|
|
||||||
HSSFRow row = sheet.createRow(0);
|
|
||||||
|
|
||||||
HSSFCell cellA1 = row.createCell(0);
|
|
||||||
HSSFCell cellB1 = row.createCell(1);
|
|
||||||
HSSFCell cellC1 = row.createCell(2);
|
|
||||||
HSSFCell cellD1 = row.createCell(3);
|
|
||||||
HSSFCell cellE1 = row.createCell(4);
|
|
||||||
|
|
||||||
cellA1.setCellFormula("IF(FALSE, 1+B1, 42)");
|
|
||||||
cellB1.setCellFormula("1+C1");
|
|
||||||
cellC1.setCellFormula("1+D1");
|
|
||||||
cellD1.setCellFormula("1+E1");
|
|
||||||
cellE1.setCellFormula("1+A1");
|
|
||||||
|
|
||||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
|
||||||
CellValue cv;
|
|
||||||
|
|
||||||
// Happy day flow - evaluate A1 first
|
|
||||||
cv = fe.evaluate(cellA1);
|
|
||||||
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
|
||||||
assertEquals(42.0, cv.getNumberValue(), 0.0);
|
|
||||||
cv = fe.evaluate(cellB1); // no circ-ref-error because A1 result is cached
|
|
||||||
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
|
||||||
assertEquals(46.0, cv.getNumberValue(), 0.0);
|
|
||||||
|
|
||||||
// Show the bug - evaluate another cell from the loop first
|
|
||||||
fe.clearAllCachedResultValues();
|
|
||||||
cv = fe.evaluate(cellB1);
|
|
||||||
if (cv.getCellType() == ErrorEval.CIRCULAR_REF_ERROR.getErrorCode()) {
|
|
||||||
throw new AssertionFailedError("Identified bug 46898");
|
|
||||||
}
|
|
||||||
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
|
||||||
assertEquals(46.0, cv.getNumberValue(), 0.0);
|
|
||||||
|
|
||||||
// start evaluation on another cell
|
|
||||||
fe.clearAllCachedResultValues();
|
|
||||||
cv = fe.evaluate(cellE1);
|
|
||||||
assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType());
|
|
||||||
assertEquals(43.0, cv.getNumberValue(), 0.0);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,31 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.eval;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFITestDataProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests HSSFFormulaEvaluator for its handling of cell formula circular references.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestHSSFCircularReferences extends BaseTestCircularReferences {
|
||||||
|
public TestHSSFCircularReferences() {
|
||||||
|
super(HSSFITestDataProvider.instance);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user