diff options
author | Nick Burch <nick@apache.org> | 2008-03-29 18:23:33 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2008-03-29 18:23:33 +0000 |
commit | 43a82fd2e9ef9f5488b83154947b386e753948cc (patch) | |
tree | f60660bf208af823f0d869dd0d2ac789e788462f /src/testcases/org/apache/poi/hssf/usermodel | |
parent | 7daf4f2184a6e15b084a47a9b6a87fbb38540f5f (diff) | |
download | poi-43a82fd2e9ef9f5488b83154947b386e753948cc.tar.gz poi-43a82fd2e9ef9f5488b83154947b386e753948cc.zip |
Move the FormulaEvaluator code out of scratchpad
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@642574 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/testcases/org/apache/poi/hssf/usermodel')
4 files changed, 527 insertions, 0 deletions
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java new file mode 100644 index 0000000000..c849fd4369 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java @@ -0,0 +1,94 @@ +/* ==================================================================== + 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.hssf.usermodel; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.hssf.util.CellReference; + +public final class TestBug42464 extends TestCase { + String dirname; + + protected void setUp() throws Exception { + super.setUp(); + dirname = System.getProperty("HSSF.testdata.path"); + } + + public void testOKFile() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook( + new FileInputStream(new File(dirname,"42464-ExpPtg-ok.xls")) + ); + process(wb); + } + public void testExpSharedBadFile() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook( + new FileInputStream(new File(dirname,"42464-ExpPtg-bad.xls")) + ); + process(wb); + } + + protected void process(HSSFWorkbook wb) { + for(int i=0; i<wb.getNumberOfSheets(); i++) { + HSSFSheet s = wb.getSheetAt(i); + HSSFFormulaEvaluator eval = + new HSSFFormulaEvaluator(s, wb); + + Iterator it = s.rowIterator(); + while(it.hasNext()) { + HSSFRow r = (HSSFRow)it.next(); + eval.setCurrentRow(r); + process(r, eval); + } + } + } + + protected void process(HSSFRow row, HSSFFormulaEvaluator eval) { + Iterator it = row.cellIterator(); + while(it.hasNext()) { + HSSFCell cell = (HSSFCell)it.next(); + if(cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) { + continue; + } + FormulaRecordAggregate record = (FormulaRecordAggregate) cell.getCellValueRecord(); + FormulaRecord r = record.getFormulaRecord(); + List ptgs = r.getParsedExpression(); + + String cellRef = new CellReference(row.getRowNum(), cell.getCellNum(), false, false).formatAsString(); + if(false && cellRef.equals("BP24")) { // TODO - replace System.out.println()s with asserts + System.out.print(cellRef); + System.out.println(" - has " + r.getNumberOfExpressionTokens() + + " ptgs over " + r.getExpressionLength() + " tokens:"); + for(int i=0; i<ptgs.size(); i++) { + String c = ptgs.get(i).getClass().toString(); + System.out.println("\t" + c.substring(c.lastIndexOf('.')+1) ); + } + System.out.println("-> " + cell.getCellFormula()); + } + + CellValue evalResult = eval.evaluate(cell); + assertNotNull(evalResult); + } + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java new file mode 100644 index 0000000000..ce072e9e01 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBug43093.java @@ -0,0 +1,59 @@ +/* ==================================================================== + 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.hssf.usermodel; + +import junit.framework.TestCase; + +public class TestBug43093 extends TestCase { + + private static void addNewSheetWithCellsA1toD4(HSSFWorkbook book, int sheet) { + + HSSFSheet sht = book .createSheet("s" + sheet); + for (short r=0; r < 4; r++) { + + HSSFRow row = sht.createRow (r); + for (short c=0; c < 4; c++) { + + HSSFCell cel = row.createCell(c); + /**/ cel.setCellValue(sheet*100 + r*10 + c); + } + } + } + + public void testBug43093() throws Exception { + HSSFWorkbook xlw = new HSSFWorkbook(); + + addNewSheetWithCellsA1toD4(xlw, 1); + addNewSheetWithCellsA1toD4(xlw, 2); + addNewSheetWithCellsA1toD4(xlw, 3); + addNewSheetWithCellsA1toD4(xlw, 4); + + HSSFSheet s2 = xlw.getSheet("s2"); + HSSFRow s2r3 = s2.getRow(3); + HSSFCell s2E4 = s2r3.createCell((short)4); + /**/ s2E4.setCellFormula("SUM(s3!B2:C3)"); + + HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(s2, xlw); + eva.setCurrentRow(s2r3); + double d = eva.evaluate(s2E4).getNumberValue(); + + // internalEvaluate(...) Area3DEval.: 311+312+321+322 expected + assertEquals(d, (double)(311+312+321+322), 0.0000001); + // System.out.println("Area3DEval ok.: 311+312+321+322=" + d); + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java new file mode 100644 index 0000000000..87a760f714 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java @@ -0,0 +1,257 @@ +/* ==================================================================== + 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.hssf.usermodel; + +import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.hssf.record.formula.FuncVarPtg; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +public final class TestFormulaEvaluatorBugs extends TestCase { + private String dirName; + private String tmpDirName; + + protected void setUp() throws Exception { + super.setUp(); + dirName = System.getProperty("HSSF.testdata.path"); + tmpDirName = System.getProperty("java.io.tmpdir"); + } + + /** + * An odd problem with evaluateFormulaCell giving the + * right values when file is opened, but changes + * to the source data in some versions of excel + * doesn't cause them to be updated. However, other + * versions of excel, and gnumeric, work just fine + * WARNING - tedious bug where you actually have to + * open up excel + */ + public void test44636() throws Exception { + // Open the existing file, tweak one value and + // re-calculate + FileInputStream in = new FileInputStream(new File(dirName,"44636.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + HSSFSheet sheet = wb.getSheetAt (0); + HSSFRow row = sheet.getRow (0); + + row.getCell((short)0).setCellValue(4.2); + row.getCell((short)2).setCellValue(25); + + HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); + assertEquals(4.2*25, row.getCell((short)3).getNumericCellValue(), 0.0001); + + // Save + File existing = new File(tmpDirName,"44636-existing.xls"); + FileOutputStream out = new FileOutputStream(existing); + wb.write(out); + out.close(); + System.err.println("Existing file for bug #44636 written to " + existing.toString()); + + + // Now, do a new file from scratch + wb = new HSSFWorkbook(); + sheet = wb.createSheet(); + + row = sheet.createRow(0); + row.createCell((short)0).setCellValue(1.2); + row.createCell((short)1).setCellValue(4.2); + + row = sheet.createRow(1); + row.createCell((short)0).setCellFormula("SUM(A1:B1)"); + + HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); + assertEquals(5.4, row.getCell((short)0).getNumericCellValue(), 0.0001); + + // Save + File scratch = new File(tmpDirName,"44636-scratch.xls"); + out = new FileOutputStream(scratch); + wb.write(out); + out.close(); + System.err.println("New file for bug #44636 written to " + scratch.toString()); + } + + /** + * Bug 44297: 32767+32768 is evaluated to -1 + * Fix: IntPtg must operate with unsigned short. Reading signed short results in incorrect formula calculation + * if a formula has values in the interval [Short.MAX_VALUE, (Short.MAX_VALUE+1)*2] + * + * @author Yegor Kozlov + */ + public void test44297() throws IOException { + FileInputStream in = new FileInputStream(new File(dirName, "44297.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + HSSFRow row; + HSSFCell cell; + + HSSFSheet sheet = wb.getSheetAt(0); + + HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb); + + row = (HSSFRow)sheet.getRow(0); + cell = row.getCell((short)0); + assertEquals("31+46", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(77, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(1); + cell = row.getCell((short)0); + assertEquals("30+53", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(83, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(2); + cell = row.getCell((short)0); + assertEquals("SUM(A1:A2)", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(160, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(4); + cell = row.getCell((short)0); + assertEquals("32767+32768", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(65535, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(7); + cell = row.getCell((short)0); + assertEquals("32744+42333", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(75077, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(8); + cell = row.getCell((short)0); + assertEquals("327680.0/32768", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(10, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(9); + cell = row.getCell((short)0); + assertEquals("32767+32769", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(65536, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(10); + cell = row.getCell((short)0); + assertEquals("35000+36000", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(71000, eva.evaluate(cell).getNumberValue(), 0); + + row = (HSSFRow)sheet.getRow(11); + cell = row.getCell((short)0); + assertEquals("-1000000.0-3000000.0", cell.getCellFormula()); + eva.setCurrentRow(row); + assertEquals(-4000000, eva.evaluate(cell).getNumberValue(), 0); + } + + /** + * Bug 44410: SUM(C:C) is valid in excel, and means a sum + * of all the rows in Column C + * + * @author Nick Burch + */ + public void test44410() throws IOException { + FileInputStream in = new FileInputStream(new File(dirName, "SingleLetterRanges.xls")); + HSSFWorkbook wb = new HSSFWorkbook(in); + in.close(); + + HSSFSheet sheet = wb.getSheetAt(0); + + HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb); + + // =index(C:C,2,1) -> 2 + HSSFRow rowIDX = (HSSFRow)sheet.getRow(3); + // =sum(C:C) -> 6 + HSSFRow rowSUM = (HSSFRow)sheet.getRow(4); + // =sum(C:D) -> 66 + HSSFRow rowSUM2D = (HSSFRow)sheet.getRow(5); + + // Test the sum + HSSFCell cellSUM = rowSUM.getCell((short)0); + + FormulaRecordAggregate frec = + (FormulaRecordAggregate)cellSUM.getCellValueRecord(); + List ops = frec.getFormulaRecord().getParsedExpression(); + assertEquals(2, ops.size()); + assertEquals(AreaPtg.class, ops.get(0).getClass()); + assertEquals(FuncVarPtg.class, ops.get(1).getClass()); + + // Actually stored as C1 to C65536 + // (last row is -1 === 65535) + AreaPtg ptg = (AreaPtg)ops.get(0); + assertEquals(2, ptg.getFirstColumn()); + assertEquals(2, ptg.getLastColumn()); + assertEquals(0, ptg.getFirstRow()); + assertEquals(65535, ptg.getLastRow()); + assertEquals("C:C", ptg.toFormulaString(wb.getWorkbook())); + + // Will show as C:C, but won't know how many + // rows it covers as we don't have the sheet + // to hand when turning the Ptgs into a string + assertEquals("SUM(C:C)", cellSUM.getCellFormula()); + eva.setCurrentRow(rowSUM); + + // But the evaluator knows the sheet, so it + // can do it properly + assertEquals(6, eva.evaluate(cellSUM).getNumberValue(), 0); + + + // Test the index + // Again, the formula string will be right but + // lacking row count, evaluated will be right + HSSFCell cellIDX = rowIDX.getCell((short)0); + assertEquals("INDEX(C:C,2,1)", cellIDX.getCellFormula()); + eva.setCurrentRow(rowIDX); + assertEquals(2, eva.evaluate(cellIDX).getNumberValue(), 0); + + // Across two colums + HSSFCell cellSUM2D = rowSUM2D.getCell((short)0); + assertEquals("SUM(C:D)", cellSUM2D.getCellFormula()); + eva.setCurrentRow(rowSUM2D); + assertEquals(66, eva.evaluate(cellSUM2D).getNumberValue(), 0); + } + + /** + * Tests that we can evaluate boolean cells properly + */ + public void testEvaluateBooleanInCell_bug44508() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + wb.setSheetName(0, "Sheet1"); + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell((short)0); + + cell.setCellFormula("1=1"); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); + fe.setCurrentRow(row); + try { + fe.evaluateInCell(cell); + } catch (NumberFormatException e) { + fail("Identified bug 44508"); + } + assertEquals(true, cell.getBooleanCellValue()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java new file mode 100644 index 0000000000..6c2e3b6412 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorDocs.java @@ -0,0 +1,117 @@ +package org.apache.poi.hssf.usermodel; + +import java.util.Iterator; + +import junit.framework.TestCase; + +/** + * Tests to show that our documentation at + * http://poi.apache.org/hssf/eval.html + * all actually works as we'd expect them to + */ +public class TestFormulaEvaluatorDocs extends TestCase { + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * http://poi.apache.org/hssf/eval.html#EvaluateAll + */ + public void testEvaluateAll() throws Exception { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet s1 = wb.createSheet(); + HSSFSheet s2 = wb.createSheet(); + wb.setSheetName(0, "S1"); + wb.setSheetName(1, "S2"); + + HSSFRow s1r1 = s1.createRow(0); + HSSFRow s1r2 = s1.createRow(1); + HSSFRow s2r1 = s2.createRow(0); + + HSSFCell s1r1c1 = s1r1.createCell((short)0); + HSSFCell s1r1c2 = s1r1.createCell((short)1); + HSSFCell s1r1c3 = s1r1.createCell((short)2); + s1r1c1.setCellValue(22.3); + s1r1c2.setCellValue(33.4); + s1r1c3.setCellFormula("SUM(A1:B1)"); + + HSSFCell s1r2c1 = s1r2.createCell((short)0); + HSSFCell s1r2c2 = s1r2.createCell((short)1); + HSSFCell s1r2c3 = s1r2.createCell((short)2); + s1r2c1.setCellValue(-1.2); + s1r2c2.setCellValue(-3.4); + s1r2c3.setCellFormula("SUM(A2:B2)"); + + HSSFCell s2r1c1 = s2r1.createCell((short)0); + s2r1c1.setCellFormula("S1!A1"); + + // Not evaluated yet + assertEquals(0.0, s1r1c3.getNumericCellValue(), 0); + assertEquals(0.0, s1r2c3.getNumericCellValue(), 0); + assertEquals(0.0, s2r1c1.getNumericCellValue(), 0); + + // Do a full evaluate, as per our docs + // uses evaluateFormulaCell() + for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) { + HSSFSheet sheet = wb.getSheetAt(sheetNum); + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); + + for(Iterator rit = sheet.rowIterator(); rit.hasNext();) { + HSSFRow r = (HSSFRow)rit.next(); + evaluator.setCurrentRow(r); + + for(Iterator cit = r.cellIterator(); cit.hasNext();) { + HSSFCell c = (HSSFCell)cit.next(); + if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) { + evaluator.evaluateFormulaCell(c); + + // For testing - all should be numeric + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, evaluator.evaluateFormulaCell(c)); + } + } + } + } + + // Check now as expected + assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0); + assertEquals("SUM(A1:B1)", wb.getSheetAt(0).getRow(0).getCell((short)2).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType()); + + assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0); + assertEquals("SUM(A2:B2)", wb.getSheetAt(0).getRow(1).getCell((short)2).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType()); + + assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0); + assertEquals("'S1'!A1", wb.getSheetAt(1).getRow(0).getCell((short)0).getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_FORMULA, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType()); + + + // Now do the alternate call, which zaps the formulas + // uses evaluateInCell() + for(int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) { + HSSFSheet sheet = wb.getSheetAt(sheetNum); + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); + + for(Iterator rit = sheet.rowIterator(); rit.hasNext();) { + HSSFRow r = (HSSFRow)rit.next(); + evaluator.setCurrentRow(r); + + for(Iterator cit = r.cellIterator(); cit.hasNext();) { + HSSFCell c = (HSSFCell)cit.next(); + if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) { + evaluator.evaluateInCell(c); + } + } + } + } + + assertEquals(55.7, wb.getSheetAt(0).getRow(0).getCell((short)2).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(0).getCell((short)2).getCellType()); + + assertEquals(-4.6, wb.getSheetAt(0).getRow(1).getCell((short)2).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(0).getRow(1).getCell((short)2).getCellType()); + + assertEquals(22.3, wb.getSheetAt(1).getRow(0).getCell((short)0).getNumericCellValue(), 0); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, wb.getSheetAt(1).getRow(0).getCell((short)0).getCellType()); + } +} |