From: Dominik Stadler Date: Fri, 9 Jan 2015 16:51:02 +0000 (+0000) Subject: Bug 57196: Resolve RefEval to it's inner ValueEval in Hex2Dec X-Git-Tag: REL_3_12_BETA1~33 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ffdf1ba216d753eb9aaab5b7cdf1a63c9929aea6;p=poi.git Bug 57196: Resolve RefEval to it's inner ValueEval in Hex2Dec git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1650597 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/ss/formula/functions/Hex2Dec.java b/src/java/org/apache/poi/ss/formula/functions/Hex2Dec.java index ccd641eaef..907b62916f 100644 --- a/src/java/org/apache/poi/ss/formula/functions/Hex2Dec.java +++ b/src/java/org/apache/poi/ss/formula/functions/Hex2Dec.java @@ -43,7 +43,13 @@ public class Hex2Dec extends Fixed1ArgFunction implements FreeRefFunction { static final int MAX_NUMBER_OF_PLACES = 10; public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval numberVE) { - String hex = OperandResolver.coerceValueToString(numberVE); + final String hex; + if (numberVE instanceof RefEval) { + RefEval re = (RefEval) numberVE; + hex = OperandResolver.coerceValueToString(re.getInnerValueEval(re.getFirstSheetIndex())); + } else { + hex = OperandResolver.coerceValueToString(numberVE); + } try { return new NumberEval(BaseNumberUtils.convertToDecimal(hex, HEXADECIMAL_BASE, MAX_NUMBER_OF_PLACES)); } catch (IllegalArgumentException e) { diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java index 48d8bae0bb..49683edb06 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -35,6 +35,7 @@ import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLProperties; import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; @@ -1924,4 +1925,88 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals(expect, value.formatAsString()); } + + @Test + public void testBug57196() throws IOException { + Workbook wb = XSSFTestDataSamples.openSampleWorkbook("57196.xlsx"); + Sheet sheet = wb.getSheet("Feuil1"); + Row mod=sheet.getRow(1); + mod.getCell(1).setCellValue(3); + HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); +// FileOutputStream fileOutput = new FileOutputStream("/tmp/57196.xlsx"); +// wb.write(fileOutput); +// fileOutput.close(); + wb.close(); + } + + @Test + public void test57196_Detail() { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet("Sheet1"); + XSSFRow row = sheet.createRow(0); + XSSFCell cell = row.createCell(0); + cell.setCellFormula("DEC2HEX(HEX2DEC(O8)-O2+D2)"); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + CellValue cv = fe.evaluate(cell); + + assertNotNull(cv); + } + + @Test + public void test57196_Detail2() { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet("Sheet1"); + XSSFRow row = sheet.createRow(0); + XSSFCell cell = row.createCell(0); + cell.setCellFormula("DEC2HEX(O2+D2)"); + XSSFFormulaEvaluator fe = new XSSFFormulaEvaluator(wb); + CellValue cv = fe.evaluate(cell); + + assertNotNull(cv); + } + + @Test + public void test57196_WorkbookEvaluator() { + //System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.SystemOutLogger"); + //System.setProperty("poi.log.level", "3"); + try { + XSSFWorkbook wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet("Sheet1"); + XSSFRow row = sheet.createRow(0); + XSSFCell cell = row.createCell(0); + + // simple formula worked + cell.setCellFormula("DEC2HEX(O2+D2)"); + + WorkbookEvaluator workbookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(wb), null, null); + workbookEvaluator.setDebugEvaluationOutputForNextEval(true); + workbookEvaluator.evaluate(new XSSFEvaluationCell(cell)); + + // this already failed! Hex2Dec did not correctly handle RefEval + cell.setCellFormula("HEX2DEC(O8)"); + workbookEvaluator.clearAllCachedResultValues(); + + workbookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(wb), null, null); + workbookEvaluator.setDebugEvaluationOutputForNextEval(true); + workbookEvaluator.evaluate(new XSSFEvaluationCell(cell)); + + // slightly more complex one failed + cell.setCellFormula("HEX2DEC(O8)-O2+D2"); + workbookEvaluator.clearAllCachedResultValues(); + + workbookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(wb), null, null); + workbookEvaluator.setDebugEvaluationOutputForNextEval(true); + workbookEvaluator.evaluate(new XSSFEvaluationCell(cell)); + + // more complicated failed + cell.setCellFormula("DEC2HEX(HEX2DEC(O8)-O2+D2)"); + workbookEvaluator.clearAllCachedResultValues(); + + workbookEvaluator.setDebugEvaluationOutputForNextEval(true); + workbookEvaluator.evaluate(new XSSFEvaluationCell(cell)); + } finally { + System.clearProperty("org.apache.poi.util.POILogger"); + System.clearProperty("poi.log.level"); + } + } } diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index fc5dd837ab..ce017f7ed2 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java @@ -18,6 +18,9 @@ package org.apache.poi.hssf.model; import static org.junit.Assert.assertArrayEquals; + +import java.io.IOException; + import junit.framework.AssertionFailedError; import junit.framework.TestCase; @@ -37,44 +40,12 @@ import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.formula.FormulaParser; import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.constant.ErrorConstant; -import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg; -import org.apache.poi.ss.formula.ptg.AddPtg; -import org.apache.poi.ss.formula.ptg.Area3DPtg; -import org.apache.poi.ss.formula.ptg.AreaI; -import org.apache.poi.ss.formula.ptg.AreaPtg; -import org.apache.poi.ss.formula.ptg.AreaPtgBase; -import org.apache.poi.ss.formula.ptg.ArrayPtg; -import org.apache.poi.ss.formula.ptg.AttrPtg; -import org.apache.poi.ss.formula.ptg.BoolPtg; -import org.apache.poi.ss.formula.ptg.ConcatPtg; -import org.apache.poi.ss.formula.ptg.DividePtg; -import org.apache.poi.ss.formula.ptg.EqualPtg; -import org.apache.poi.ss.formula.ptg.ErrPtg; -import org.apache.poi.ss.formula.ptg.FuncPtg; -import org.apache.poi.ss.formula.ptg.FuncVarPtg; -import org.apache.poi.ss.formula.ptg.IntPtg; -import org.apache.poi.ss.formula.ptg.MemAreaPtg; -import org.apache.poi.ss.formula.ptg.MemFuncPtg; -import org.apache.poi.ss.formula.ptg.MissingArgPtg; -import org.apache.poi.ss.formula.ptg.MultiplyPtg; -import org.apache.poi.ss.formula.ptg.NamePtg; -import org.apache.poi.ss.formula.ptg.NumberPtg; -import org.apache.poi.ss.formula.ptg.ParenthesisPtg; -import org.apache.poi.ss.formula.ptg.PercentPtg; -import org.apache.poi.ss.formula.ptg.PowerPtg; -import org.apache.poi.ss.formula.ptg.Ptg; -import org.apache.poi.ss.formula.ptg.RangePtg; -import org.apache.poi.ss.formula.ptg.Ref3DPtg; -import org.apache.poi.ss.formula.ptg.RefPtg; -import org.apache.poi.ss.formula.ptg.StringPtg; -import org.apache.poi.ss.formula.ptg.SubtractPtg; -import org.apache.poi.ss.formula.ptg.UnaryMinusPtg; -import org.apache.poi.ss.formula.ptg.UnaryPlusPtg; -import org.apache.poi.ss.formula.ptg.UnionPtg; +import org.apache.poi.ss.formula.ptg.*; import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues; import org.apache.poi.ss.usermodel.Name; import org.apache.poi.util.HexRead; import org.apache.poi.util.LittleEndianByteArrayInputStream; +import org.junit.Test; /** * Test the low level formula parser functionality. High level tests are to @@ -166,7 +137,7 @@ public final class TestFormulaParser extends TestCase { StringPtg.class, StringPtg.class, FuncVarPtg.class); } - public void testWorksheetReferences() { + public void testWorksheetReferences() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("NoQuotesNeeded"); @@ -181,6 +152,8 @@ public final class TestFormulaParser extends TestCase { cell = row.createCell(1); cell.setCellFormula("'Quotes Needed Here &#$@'!A1"); + + wb.close(); } public void testUnaryMinus() { @@ -256,8 +229,9 @@ public final class TestFormulaParser extends TestCase { confirmTokenClasses("40000/2", IntPtg.class, IntPtg.class, DividePtg.class); } - /** bug 35027, underscore in sheet name */ - public void testUnderscore() { + /** bug 35027, underscore in sheet name + * @throws IOException */ + public void testUnderscore() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("Cash_Flow"); @@ -268,10 +242,13 @@ public final class TestFormulaParser extends TestCase { cell = row.createCell(0); cell.setCellFormula("Cash_Flow!A1"); + + wb.close(); } - /** bug 49725, defined names with underscore */ - public void testNamesWithUnderscore() { + /** bug 49725, defined names with underscore + * @throws IOException */ + public void testNamesWithUnderscore() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); //or new XSSFWorkbook(); HSSFSheet sheet = wb.createSheet("NamesWithUnderscore"); @@ -312,6 +289,8 @@ public final class TestFormulaParser extends TestCase { cell.setCellFormula("INDEX(DA6_LEO_WBS_Name,MATCH($A3,DA6_LEO_WBS_Number,0))"); assertEquals("INDEX(DA6_LEO_WBS_Name,MATCH($A3,DA6_LEO_WBS_Number,0))", cell.getCellFormula()); + + wb.close(); } // bug 38396 : Formula with exponential numbers not parsed correctly. @@ -321,7 +300,7 @@ public final class TestFormulaParser extends TestCase { confirmTokenClasses("1.3E1/2", NumberPtg.class, IntPtg.class, DividePtg.class); } - public void testExponentialInSheet() { + public void testExponentialInSheet() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("Cash_Flow"); @@ -390,9 +369,11 @@ public final class TestFormulaParser extends TestCase { cell.setCellFormula("-10E-1/3.1E2*4E3/3E4"); formula = cell.getCellFormula(); assertEquals("Exponential formula string", "-1/310*4000/30000", formula); + + wb.close(); } - public void testNumbers() { + public void testNumbers() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("Cash_Flow"); @@ -429,9 +410,11 @@ public final class TestFormulaParser extends TestCase { cell.setCellFormula("10E-1"); formula = cell.getCellFormula(); assertEquals("1", formula); + + wb.close(); } - public void testRanges() { + public void testRanges() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("Cash_Flow"); @@ -452,9 +435,11 @@ public final class TestFormulaParser extends TestCase { cell.setCellFormula("A1...A2"); formula = cell.getCellFormula(); assertEquals("A1:A2", formula); + + wb.close(); } - public void testMultiSheetReference() { + public void testMultiSheetReference() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); wb.createSheet("Cash_Flow"); @@ -500,6 +485,8 @@ public final class TestFormulaParser extends TestCase { cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1:B2"); formula = cell.getCellFormula(); assertEquals("Cash_Flow:\'Test Sheet\'!A1:B2", formula); + + wb.close(); } /** @@ -660,7 +647,7 @@ public final class TestFormulaParser extends TestCase { StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class); assertEquals(expectedValue, sp.getValue()); } - public void testParseStringLiterals_bug28754() { + public void testParseStringLiterals_bug28754() throws IOException { StringPtg sp; try { @@ -674,17 +661,21 @@ public final class TestFormulaParser extends TestCase { assertEquals("test\"ing", sp.getValue()); HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - wb.setSheetName(0, "Sheet1"); - - HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell(0); - cell.setCellFormula("right(\"test\"\"ing\", 3)"); - String actualCellFormula = cell.getCellFormula(); - if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) { - throw new AssertionFailedError("Identified bug 28754b"); + try { + HSSFSheet sheet = wb.createSheet(); + wb.setSheetName(0, "Sheet1"); + + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); + cell.setCellFormula("right(\"test\"\"ing\", 3)"); + String actualCellFormula = cell.getCellFormula(); + if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) { + throw new AssertionFailedError("Identified bug 28754b"); + } + assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula); + } finally { + wb.close(); } - assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula); } public void testParseStringLiterals() { @@ -735,7 +726,7 @@ public final class TestFormulaParser extends TestCase { } } - public void testSetFormulaWithRowBeyond32768_Bug44539() { + public void testSetFormulaWithRowBeyond32768_Bug44539() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); @@ -748,6 +739,8 @@ public final class TestFormulaParser extends TestCase { fail("Identified bug 44539"); } assertEquals("SUM(A32769:A32770)", cell.getCellFormula()); + + wb.close(); } public void testSpaceAtStartOfFormula() { @@ -984,7 +977,7 @@ public final class TestFormulaParser extends TestCase { assertEquals(-5.0, ((Double)element).doubleValue(), 0.0); } - public void testRangeOperator() { + public void testRangeOperator() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); @@ -1004,16 +997,19 @@ public final class TestFormulaParser extends TestCase { wb.setSheetName(0, "A1...A2"); cell.setCellFormula("A1...A2!B1"); assertEquals("A1...A2!B1", cell.getCellFormula()); + + wb.close(); } - public void testBooleanNamedSheet() { - + public void testBooleanNamedSheet() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("true"); HSSFCell cell = sheet.createRow(0).createCell(0); cell.setCellFormula("'true'!B2"); assertEquals("'true'!B2", cell.getCellFormula()); + + wb.close(); } public void testParseExternalWorkbookReference() { @@ -1087,8 +1083,9 @@ public final class TestFormulaParser extends TestCase { assertEquals(15, mf.getLenRefSubexpression()); } - /** Named ranges with backslashes, e.g. 'POI\\2009' */ - public void testBackSlashInNames() { + /** Named ranges with backslashes, e.g. 'POI\\2009' + * @throws IOException */ + public void testBackSlashInNames() throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); HSSFName name = wb.createName(); @@ -1105,6 +1102,8 @@ public final class TestFormulaParser extends TestCase { HSSFCell cell_D1 = row.createCell(2); cell_D1.setCellFormula("NOT(POI\\2009=\"3.5-final\")"); assertEquals("NOT(POI\\2009=\"3.5-final\")", cell_D1.getCellFormula()); + + wb.close(); } /** @@ -1353,4 +1352,36 @@ public final class TestFormulaParser extends TestCase { private static void confirmParseException(FormulaParseException e, String expMsg) { assertEquals(expMsg, e.getMessage()); } + + @Test + public void test57196_Formula() { + HSSFWorkbook wb = new HSSFWorkbook(); + Ptg[] ptgs = HSSFFormulaParser.parse("DEC2HEX(HEX2DEC(O8)-O2+D2)", wb, FormulaType.CELL, -1); + assertNotNull("Ptg array should not be null", ptgs); + + confirmTokenClasses(ptgs, + NameXPtg.class, // ?? + NameXPtg.class, // ?? + RefPtg.class, // O8 + FuncVarPtg.class, // HEX2DEC + RefPtg.class, // O2 + SubtractPtg.class, + RefPtg.class, // D2 + AddPtg.class, + FuncVarPtg.class // DEC2HEX + ); + + RefPtg o8 = (RefPtg) ptgs[2]; + FuncVarPtg hex2Dec = (FuncVarPtg) ptgs[3]; + RefPtg o2 = (RefPtg) ptgs[4]; + RefPtg d2 = (RefPtg) ptgs[6]; + FuncVarPtg dec2Hex = (FuncVarPtg) ptgs[8]; + + assertEquals("O8", o8.toFormulaString()); + assertEquals(255, hex2Dec.getFunctionIndex()); + //assertEquals("", hex2Dec.toString()); + assertEquals("O2", o2.toFormulaString()); + assertEquals("D2", d2.toFormulaString()); + assertEquals(255, dec2Hex.getFunctionIndex()); + } } diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestHex2Dec.java b/src/testcases/org/apache/poi/ss/formula/functions/TestHex2Dec.java index 7c04157416..b7ca30cd51 100644 --- a/src/testcases/org/apache/poi/ss/formula/functions/TestHex2Dec.java +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestHex2Dec.java @@ -18,6 +18,12 @@ package org.apache.poi.ss.formula.functions; import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.formula.IStabilityClassifier; +import org.apache.poi.ss.formula.OperationEvaluationContext; +import org.apache.poi.ss.formula.WorkbookEvaluator; import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.StringEval; @@ -57,4 +63,49 @@ public final class TestHex2Dec extends TestCase { confirmValueError("not a valid octal number","GGGGGGG", ErrorEval.NUM_ERROR); confirmValueError("not a valid octal number","3.14159", ErrorEval.NUM_ERROR); } + + public void testEvalOperationEvaluationContext() { + OperationEvaluationContext ctx = createContext(); + + ValueEval[] args = new ValueEval[] { ctx.getRefEval(0, 0) }; + ValueEval result = new Hex2Dec().evaluate(args, ctx); + + assertEquals(NumberEval.class, result.getClass()); + assertEquals("0", ((NumberEval) result).getStringValue()); + } + + public void testEvalOperationEvaluationContextFails() { + OperationEvaluationContext ctx = createContext(); + + ValueEval[] args = new ValueEval[] { ctx.getRefEval(0, 0), ctx.getRefEval(0, 0) }; + ValueEval result = new Hex2Dec().evaluate(args, ctx); + + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + + private OperationEvaluationContext createContext() { + HSSFWorkbook wb = new HSSFWorkbook(); + wb.createSheet(); + HSSFEvaluationWorkbook workbook = HSSFEvaluationWorkbook.create(wb); + WorkbookEvaluator workbookEvaluator = new WorkbookEvaluator(workbook, new IStabilityClassifier() { + + public boolean isCellFinal(int sheetIndex, int rowIndex, int columnIndex) { + return true; + } + }, null); + OperationEvaluationContext ctx = new OperationEvaluationContext(workbookEvaluator, + workbook, 0, 0, 0, null); + return ctx; + } + + public void testRefs() { + OperationEvaluationContext ctx = createContext(); + + ValueEval[] args = new ValueEval[] { ctx.getRefEval(0, 0) }; + ValueEval result = new Hex2Dec().evaluate(args, -1, -1); + + assertEquals(NumberEval.class, result.getClass()); + assertEquals("0", ((NumberEval) result).getStringValue()); + } } diff --git a/test-data/spreadsheet/57196.xlsx b/test-data/spreadsheet/57196.xlsx new file mode 100644 index 0000000000..ed2b65e343 Binary files /dev/null and b/test-data/spreadsheet/57196.xlsx differ