| /* ==================================================================== |
| 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.ss.formula.ptg.AbstractFunctionPtg; |
| import org.apache.poi.ss.formula.ptg.FuncVarPtg; |
| import org.apache.poi.ss.formula.ptg.Ptg; |
| import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| |
| /** |
| * Tests specific formula examples in <tt>OperandClassTransformer</tt>. |
| * |
| * @author Josh Micich |
| */ |
| public final class TestOperandClassTransformer extends TestCase { |
| |
| private static Ptg[] parseFormula(String formula) { |
| Ptg[] result = HSSFFormulaParser.parse(formula, (HSSFWorkbook)null); |
| assertNotNull("Ptg array should not be null", result); |
| return result; |
| } |
| |
| public void testMdeterm() { |
| String formula = "MDETERM(ABS(A1))"; |
| Ptg[] ptgs = parseFormula(formula); |
| |
| confirmTokenClass(ptgs, 0, Ptg.CLASS_ARRAY); |
| confirmFuncClass(ptgs, 1, "ABS", Ptg.CLASS_ARRAY); |
| confirmFuncClass(ptgs, 2, "MDETERM", Ptg.CLASS_VALUE); |
| } |
| |
| /** |
| * In the example: <code>INDEX(PI(),1)</code>, Excel encodes PI() as 'array'. It is not clear |
| * what rule justifies this. POI currently encodes it as 'value' which Excel(2007) seems to |
| * tolerate. Changing the metadata for INDEX to have first parameter as 'array' class breaks |
| * other formulas involving INDEX. It seems like a special case needs to be made. Perhaps an |
| * important observation is that INDEX is one of very few functions that returns 'reference' type. |
| * |
| * This test has been added but disabled in order to document this issue. |
| */ |
| public void DISABLED_testIndexPi1() { |
| String formula = "INDEX(PI(),1)"; |
| Ptg[] ptgs = parseFormula(formula); |
| |
| confirmFuncClass(ptgs, 1, "PI", Ptg.CLASS_ARRAY); // fails as of POI 3.1 |
| confirmFuncClass(ptgs, 2, "INDEX", Ptg.CLASS_VALUE); |
| } |
| |
| /** |
| * Even though count expects args of type R, because A1 is a direct operand of a |
| * value operator it must get type V |
| */ |
| public void testDirectOperandOfValueOperator() { |
| String formula = "COUNT(A1*1)"; |
| Ptg[] ptgs = parseFormula(formula); |
| if (ptgs[0].getPtgClass() == Ptg.CLASS_REF) { |
| throw new AssertionFailedError("Identified bug 45348"); |
| } |
| |
| confirmTokenClass(ptgs, 0, Ptg.CLASS_VALUE); |
| confirmTokenClass(ptgs, 3, Ptg.CLASS_VALUE); |
| } |
| |
| /** |
| * A cell ref passed to a function expecting type V should be converted to type V |
| */ |
| public void testRtoV() { |
| |
| String formula = "lookup(A1, A3:A52, B3:B52)"; |
| Ptg[] ptgs = parseFormula(formula); |
| confirmTokenClass(ptgs, 0, Ptg.CLASS_VALUE); |
| } |
| |
| public void testComplexIRR_bug45041() { |
| String formula = "(1+IRR(SUMIF(A:A,ROW(INDIRECT(MIN(A:A)&\":\"&MAX(A:A))),B:B),0))^365-1"; |
| Ptg[] ptgs = parseFormula(formula); |
| |
| FuncVarPtg rowFunc = (FuncVarPtg) ptgs[10]; |
| FuncVarPtg sumifFunc = (FuncVarPtg) ptgs[12]; |
| assertEquals("ROW", rowFunc.getName()); |
| assertEquals("SUMIF", sumifFunc.getName()); |
| |
| if (rowFunc.getPtgClass() == Ptg.CLASS_VALUE || sumifFunc.getPtgClass() == Ptg.CLASS_VALUE) { |
| throw new AssertionFailedError("Identified bug 45041"); |
| } |
| confirmTokenClass(ptgs, 1, Ptg.CLASS_REF); |
| confirmTokenClass(ptgs, 2, Ptg.CLASS_REF); |
| confirmFuncClass(ptgs, 3, "MIN", Ptg.CLASS_VALUE); |
| confirmTokenClass(ptgs, 6, Ptg.CLASS_REF); |
| confirmFuncClass(ptgs, 7, "MAX", Ptg.CLASS_VALUE); |
| confirmFuncClass(ptgs, 9, "INDIRECT", Ptg.CLASS_REF); |
| confirmFuncClass(ptgs, 10, "ROW", Ptg.CLASS_ARRAY); |
| confirmTokenClass(ptgs, 11, Ptg.CLASS_REF); |
| confirmFuncClass(ptgs, 12, "SUMIF", Ptg.CLASS_ARRAY); |
| confirmFuncClass(ptgs, 14, "IRR", Ptg.CLASS_VALUE); |
| } |
| |
| private void confirmFuncClass(Ptg[] ptgs, int i, String expectedFunctionName, byte operandClass) { |
| confirmTokenClass(ptgs, i, operandClass); |
| AbstractFunctionPtg afp = (AbstractFunctionPtg) ptgs[i]; |
| assertEquals(expectedFunctionName, afp.getName()); |
| } |
| |
| private void confirmTokenClass(Ptg[] ptgs, int i, byte operandClass) { |
| Ptg ptg = ptgs[i]; |
| if (ptg.isBaseToken()) { |
| throw new AssertionFailedError("ptg[" + i + "] is a base token"); |
| } |
| if (operandClass != ptg.getPtgClass()) { |
| throw new AssertionFailedError("Wrong operand class for ptg (" |
| + ptg.toString() + "). Expected " + getOperandClassName(operandClass) |
| + " but got " + getOperandClassName(ptg.getPtgClass())); |
| } |
| } |
| |
| private static String getOperandClassName(byte ptgClass) { |
| switch (ptgClass) { |
| case Ptg.CLASS_REF: |
| return "R"; |
| case Ptg.CLASS_VALUE: |
| return "V"; |
| case Ptg.CLASS_ARRAY: |
| return "A"; |
| } |
| throw new RuntimeException("Unknown operand class (" + ptgClass + ")"); |
| } |
| } |