diff --git a/src/testcases/org/apache/poi/hssf/model/AllModelTests.java b/src/testcases/org/apache/poi/hssf/model/AllModelTests.java index 19ef43706..15f9b1b40 100755 --- a/src/testcases/org/apache/poi/hssf/model/AllModelTests.java +++ b/src/testcases/org/apache/poi/hssf/model/AllModelTests.java @@ -33,6 +33,7 @@ public final class AllModelTests { result.addTestSuite(TestDrawingManager2.class); result.addTestSuite(TestFormulaParser.class); result.addTestSuite(TestFormulaParserEval.class); + result.addTestSuite(TestFormulaParserIf.class); result.addTestSuite(TestSheet.class); result.addTestSuite(TestSheetAdditional.class); return result; diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index 29619501e..929279a3c 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java @@ -33,12 +33,9 @@ import org.apache.poi.hssf.record.formula.ErrPtg; import org.apache.poi.hssf.record.formula.FuncPtg; import org.apache.poi.hssf.record.formula.FuncVarPtg; import org.apache.poi.hssf.record.formula.IntPtg; -import org.apache.poi.hssf.record.formula.LessEqualPtg; -import org.apache.poi.hssf.record.formula.LessThanPtg; import org.apache.poi.hssf.record.formula.MissingArgPtg; import org.apache.poi.hssf.record.formula.MultiplyPtg; import org.apache.poi.hssf.record.formula.NamePtg; -import org.apache.poi.hssf.record.formula.NotEqualPtg; import org.apache.poi.hssf.record.formula.NumberPtg; import org.apache.poi.hssf.record.formula.PercentPtg; import org.apache.poi.hssf.record.formula.PowerPtg; @@ -62,10 +59,8 @@ public final class TestFormulaParser extends TestCase { /** * @return parsed token array already confirmed not null */ - private static Ptg[] parseFormula(String s) { - FormulaParser fp = new FormulaParser(s, null); - fp.parse(); - Ptg[] result = fp.getRPNPtg(); + /* package */ static Ptg[] parseFormula(String formula) { + Ptg[] result = FormulaParser.parse(formula, null); assertNotNull("Ptg array should not be null", result); return result; } @@ -105,83 +100,6 @@ public final class TestFormulaParser extends TestCase { assertEquals(true, flag.getValue()); } - public void testYN() { - Ptg[] ptgs = parseFormula("IF(TRUE,\"Y\",\"N\")"); - assertEquals(7, ptgs.length); - - BoolPtg flag = (BoolPtg) ptgs[0]; - AttrPtg funif = (AttrPtg) ptgs[1]; - StringPtg y = (StringPtg) ptgs[2]; - AttrPtg goto1 = (AttrPtg) ptgs[3]; - StringPtg n = (StringPtg) ptgs[4]; - - - assertEquals(true, flag.getValue()); - assertEquals("Y", y.getValue()); - assertEquals("N", n.getValue()); - assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null)); - assertTrue("Goto ptg exists", goto1.isGoto()); - } - - public void testSimpleIf() { - String formula = "IF(1=1,0,1)"; - - Class[] expectedClasses = { - IntPtg.class, - IntPtg.class, - EqualPtg.class, - AttrPtg.class, - IntPtg.class, - AttrPtg.class, - IntPtg.class, - AttrPtg.class, - FuncVarPtg.class, - }; - confirmTokenClasses(formula, expectedClasses); - - Ptg[] ptgs = parseFormula(formula); - - AttrPtg ifPtg = (AttrPtg) ptgs[3]; - AttrPtg ptgGoto= (AttrPtg) ptgs[5]; - assertEquals("Goto 1 Length", 10, ptgGoto.getData()); - - AttrPtg ptgGoto2 = (AttrPtg) ptgs[7]; - assertEquals("Goto 2 Length", 3, ptgGoto2.getData()); - assertEquals("If FALSE offset", 7, ifPtg.getData()); - } - - /** - * Make sure the ptgs are generated properly with two functions embedded - * - */ - public void testNestedFunctionIf() { - Ptg[] ptgs = parseFormula("IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))"); - assertEquals(11, ptgs.length); - - assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg)); - AttrPtg ifFunc = (AttrPtg)ptgs[3]; - assertTrue("It is not an if", ifFunc.isOptimizedIf()); - - assertTrue("Average Function set correctly", (ptgs[5] instanceof FuncVarPtg)); - } - - public void testIfSingleCondition(){ - Ptg[] ptgs = parseFormula("IF(1=1,10)"); - assertEquals(7, ptgs.length); - - assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg)); - AttrPtg ifFunc = (AttrPtg)ptgs[3]; - assertTrue("It is not an if", ifFunc.isOptimizedIf()); - - assertTrue("Single Value is not an IntPtg", (ptgs[4] instanceof IntPtg)); - IntPtg intPtg = (IntPtg)ptgs[4]; - assertEquals("Result", (short)10, intPtg.getValue()); - - assertTrue("Ptg is not a Variable Function", (ptgs[6] instanceof FuncVarPtg)); - FuncVarPtg funcPtg = (FuncVarPtg)ptgs[6]; - assertEquals("Arguments", 2, funcPtg.getNumberOfOperands()); - } - public void testSumIf() { Ptg[] ptgs = parseFormula("SUMIF(A1:A5,\">4000\",B1:B5)"); assertEquals(4, ptgs.length); @@ -203,33 +121,9 @@ public final class TestFormulaParser extends TestCase { //the PTG order isn't 100% correct but it still works - dmui } - public void testSimpleLogical() { - Ptg[] ptgs = parseFormula("IF(A1=1,\"*\",IF(4<>1,\"first\",\"second\"))"); - assertEquals(17, ptgs.length); - - assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass()); - assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass()); - assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass()); - } - public void testMacroFunction() { HSSFWorkbook w = new HSSFWorkbook(); - FormulaParser fp = new FormulaParser("FOO()", w); - fp.parse(); - Ptg[] ptg = fp.getRPNPtg(); + Ptg[] ptg = FormulaParser.parse("FOO()", w); // the name gets encoded as the first arg NamePtg tname = (NamePtg) ptg[0]; @@ -597,7 +491,7 @@ public final class TestFormulaParser extends TestCase { confirmTokenClasses("2^200%", expClss); } - private static void confirmTokenClasses(String formula, Class[] expectedClasses) { + /* package */ static Ptg[] confirmTokenClasses(String formula, Class[] expectedClasses) { Ptg[] ptgs = parseFormula(formula); assertEquals(expectedClasses.length, ptgs.length); for (int i = 0; i < expectedClasses.length; i++) { @@ -607,6 +501,7 @@ public final class TestFormulaParser extends TestCase { + ptgs[i].getClass().getName() + ")"); } } + return ptgs; } public void testPower() { diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserIf.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserIf.java new file mode 100644 index 000000000..ba05c1621 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserIf.java @@ -0,0 +1,239 @@ +/* ==================================================================== + 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.model; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.formula.AddPtg; +import org.apache.poi.hssf.record.formula.AttrPtg; +import org.apache.poi.hssf.record.formula.BoolPtg; +import org.apache.poi.hssf.record.formula.FuncPtg; +import org.apache.poi.hssf.record.formula.FuncVarPtg; +import org.apache.poi.hssf.record.formula.IntPtg; +import org.apache.poi.hssf.record.formula.LessEqualPtg; +import org.apache.poi.hssf.record.formula.LessThanPtg; +import org.apache.poi.hssf.record.formula.MultiplyPtg; +import org.apache.poi.hssf.record.formula.NotEqualPtg; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.record.formula.ReferencePtg; +import org.apache.poi.hssf.record.formula.StringPtg; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * Tests FormulaParser specifically with respect to IF() functions + */ +public final class TestFormulaParserIf extends TestCase { + private static Ptg[] parseFormula(String formula) { + return TestFormulaParser.parseFormula(formula); + } + + private static Ptg[] confirmTokenClasses(String formula, Class[] expectedClasses) { + return TestFormulaParser.confirmTokenClasses(formula, expectedClasses); + } + + private static void confirmAttrData(Ptg[] ptgs, int i, int expectedData) { + Ptg ptg = ptgs[i]; + if (!(ptg instanceof AttrPtg)) { + throw new AssertionFailedError("Token[" + i + "] was not AttrPtg as expected"); + } + AttrPtg attrPtg = (AttrPtg) ptg; + assertEquals(expectedData, attrPtg.getData()); + } + + public void testSimpleIf() { + + Class[] expClss; + + expClss = new Class[] { + ReferencePtg.class, + AttrPtg.class, // tAttrIf + IntPtg.class, + AttrPtg.class, // tAttrSkip + IntPtg.class, + AttrPtg.class, // tAttrSkip + FuncVarPtg.class, + }; + + Ptg[] ptgs = confirmTokenClasses("if(A1,1,2)", expClss); + + confirmAttrData(ptgs, 1, 7); + confirmAttrData(ptgs, 3, 10); + confirmAttrData(ptgs, 5, 3); + } + + public void testSimpleIfNoFalseParam() { + + Class[] expClss; + + expClss = new Class[] { + ReferencePtg.class, + AttrPtg.class, // tAttrIf + ReferencePtg.class, + AttrPtg.class, // tAttrSkip + FuncVarPtg.class, + }; + + Ptg[] ptgs = confirmTokenClasses("if(A1,B1)", expClss); + + confirmAttrData(ptgs, 1, 9); + confirmAttrData(ptgs, 3, 3); + } + + public void testIfWithLargeParams() { + + Class[] expClss; + + expClss = new Class[] { + ReferencePtg.class, + AttrPtg.class, // tAttrIf + + ReferencePtg.class, + IntPtg.class, + MultiplyPtg.class, + ReferencePtg.class, + IntPtg.class, + AddPtg.class, + FuncPtg.class, + AttrPtg.class, // tAttrSkip + + ReferencePtg.class, + ReferencePtg.class, + FuncPtg.class, + + AttrPtg.class, // tAttrSkip + FuncVarPtg.class, + }; + + Ptg[] ptgs = confirmTokenClasses("if(A1,round(B1*100,C1+2),round(B1,C1))", expClss); + + confirmAttrData(ptgs, 1, 25); + confirmAttrData(ptgs, 9, 20); + confirmAttrData(ptgs, 13, 3); + } + + public void testNestedIf() { + + Class[] expClss; + + expClss = new Class[] { + + ReferencePtg.class, + AttrPtg.class, // A tAttrIf + ReferencePtg.class, + AttrPtg.class, // B tAttrIf + IntPtg.class, + AttrPtg.class, // B tAttrSkip + IntPtg.class, + AttrPtg.class, // B tAttrSkip + FuncVarPtg.class, + AttrPtg.class, // A tAttrSkip + ReferencePtg.class, + AttrPtg.class, // C tAttrIf + IntPtg.class, + AttrPtg.class, // C tAttrSkip + IntPtg.class, + AttrPtg.class, // C tAttrSkip + FuncVarPtg.class, + AttrPtg.class, // A tAttrSkip + FuncVarPtg.class, + }; + + Ptg[] ptgs = confirmTokenClasses("if(A1,if(B1,1,2),if(C1,3,4))", expClss); + confirmAttrData(ptgs, 1, 31); + confirmAttrData(ptgs, 3, 7); + confirmAttrData(ptgs, 5, 10); + confirmAttrData(ptgs, 7, 3); + confirmAttrData(ptgs, 9, 34); + confirmAttrData(ptgs, 11, 7); + confirmAttrData(ptgs, 13, 10); + confirmAttrData(ptgs, 15, 3); + confirmAttrData(ptgs, 17, 3); + } + + public void testEmbeddedIf() { + Ptg[] ptgs = parseFormula("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))"); + assertEquals(17, ptgs.length); + + assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass()); + assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass()); + assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass()); + } + + + public void testSimpleLogical() { + Ptg[] ptgs = parseFormula("IF(A1