]> source.dussan.org Git - poi.git/commitdiff
(real) fix for bug #44691. Modified Pmt.java to allow for 3 arguments. Added TestPm...
authorJosh Micich <josh@apache.org>
Thu, 27 Mar 2008 21:54:21 +0000 (21:54 +0000)
committerJosh Micich <josh@apache.org>
Thu, 27 Mar 2008 21:54:21 +0000 (21:54 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@641996 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Pmt.java
src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44691.java [deleted file]

index 0ea6a7f10777a6b7ffc4ca7d6639eb41f18f6cb9..58628053c0ba19645d907d0c3cddd5bbda20263a 100644 (file)
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
-public class Pmt extends FinanceFunction {
+/**
+ * Implementation for the PMT() Excel function.<p/>
+ * 
+ * <b>Syntax:</b><br/>
+ * <b>PMT</b>(<b>rate</b>, <b>nper</b>, <b>pv</b>, fv, type)<p/>
+ * 
+ * Returns the constant repayment amount required for a loan assuming a constant interest rate.<p/>
+ * 
+ * <b>rate</b> the loan interest rate.<br/>
+ * <b>nper</b> the number of loan repayments.<br/>
+ * <b>pv</b> the present value of the future payments (or principle).<br/>
+ * <b>fv</b> the future value (default zero) surplus cash at the end of the loan lifetime.<br/>
+ * <b>type</b> whether payments are due at the beginning(1) or end(0 - default) of each payment period.<br/>
+ * 
+ */
+public final class Pmt extends FinanceFunction {
+
+       public Eval evaluate(Eval[] args, int srcRow, short srcCol) {
+               
+               if(args.length < 3 || args.length > 5) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               
+               try {
+                       // evaluate first three (always present) args
+                       double rate = evalArg(args[0], srcRow, srcCol);
+                       double nper = evalArg(args[1], srcRow, srcCol);
+                       double pv  = evalArg(args[2], srcRow, srcCol); 
+                       double fv = 0;
+                       boolean arePaymentsAtPeriodBeginning = false;
+                       
+                       switch (args.length) {
+                               case 5:
+                                       ValueEval ve = singleOperandNumericAsBoolean(args[4], srcRow, srcCol);
+                                       if (ve instanceof ErrorEval) { 
+                                               return ve;
+                                       }
+                                       arePaymentsAtPeriodBeginning = ((BoolEval) ve).getBooleanValue();
+                               case 4:
+                                       fv = evalArg(args[3], srcRow, srcCol);
+                       }
+                       double d = FinanceLib.pmt(rate, nper, pv, fv, arePaymentsAtPeriodBeginning);
+                       if (Double.isNaN(d)) {
+                               return (ValueEval) ErrorEval.VALUE_INVALID;
+                       }
+                       if (Double.isInfinite(d)) {
+                               return (ValueEval) ErrorEval.NUM_ERROR;
+                       }
+                       return new NumberEval(d);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+       }
 
-    public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
-        double rate = 0, fv = 0, nper = 0, pv = 0, d = 0;
-        boolean type = false;
-        ValueEval retval = null;
-        ValueEval ve = null;
-        
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 5:
-            ve = singleOperandNumericAsBoolean(operands[4], srcRow, srcCol);
-            if (ve instanceof ErrorEval) { retval = ErrorEval.VALUE_INVALID; break; }
-            type = ((BoolEval) ve).getBooleanValue();
-        case 4:
-            ve = singleOperandEvaluate(operands[0], srcRow, srcCol);
-            if (ve instanceof NumericValueEval) rate = ((NumericValueEval) ve).getNumberValue();
-            else { retval = ErrorEval.VALUE_INVALID; break; }
-            
-            ve = singleOperandEvaluate(operands[1], srcRow, srcCol);
-            if (ve instanceof NumericValueEval) nper  = ((NumericValueEval) ve).getNumberValue();
-            else { retval = ErrorEval.VALUE_INVALID; break; }
-            
-            ve = singleOperandEvaluate(operands[2], srcRow, srcCol);
-            if (ve instanceof NumericValueEval) pv   = ((NumericValueEval) ve).getNumberValue();
-            else { retval = ErrorEval.VALUE_INVALID; break; }
-            
-            ve = singleOperandEvaluate(operands[3], srcRow, srcCol);
-            if (ve instanceof NumericValueEval) fv = ((NumericValueEval) ve).getNumberValue();
-            else { retval = ErrorEval.VALUE_INVALID; break; }
-        }
-        
-        if (retval == null) {
-            d = FinanceLib.pmt(rate, nper, pv, fv, type);
-            retval = (Double.isNaN(d))
-                    ? (ValueEval) ErrorEval.VALUE_INVALID
-                    : (Double.isInfinite(d)) 
-                        ? (ValueEval) ErrorEval.NUM_ERROR 
-                        : new NumberEval(d);
-        }
-        return retval;
-    }
+       private double evalArg(Eval arg, int srcRow, short srcCol) throws EvaluationException {
+               ValueEval ve = singleOperandEvaluate(arg, srcRow, srcCol);
+               if(ve instanceof ErrorEval) {
+                       throw new EvaluationException((ErrorEval) ve);
+               }
+               if (ve instanceof NumericValueEval) {
+                       return ((NumericValueEval) ve).getNumberValue();
+               }
+               throw new EvaluationException(ErrorEval.VALUE_INVALID); 
+       }
 }
index d3e9c4c41220d85e8c25749ef1a353c253260ace..66d2a1d27050567ed87b50b461eee29ecee96b44 100755 (executable)
@@ -14,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record.formula.functions;
 
@@ -41,6 +40,7 @@ public final class AllIndividualFunctionEvaluationTests {
                result.addTestSuite(TestMid.class);
                result.addTestSuite(TestMathX.class);
                result.addTestSuite(TestMatch.class);
+               result.addTestSuite(TestPmt.class);
                result.addTestSuite(TestOffset.class);
                result.addTestSuite(TestRowCol.class);
                result.addTestSuite(TestSumproduct.class);
@@ -50,5 +50,4 @@ public final class AllIndividualFunctionEvaluationTests {
                result.addTestSuite(TestXYNumericFunction.class);
                return result;
        }
-
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java
new file mode 100644 (file)
index 0000000..935615a
--- /dev/null
@@ -0,0 +1,87 @@
+/* ====================================================================
+   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.record.formula.functions;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
+
+/**
+ * 
+ * @author Josh Micich
+ */
+public final class TestPmt extends TestCase {
+       
+       private static void confirm(double expected, NumberEval ne) {
+               // only asserting accuracy to 4 fractional digits
+               assertEquals(expected, ne.getNumberValue(), 0.00005);
+       }
+       private static Eval invoke(Eval[] args) {
+               return new Pmt().evaluate(args, -1, (short)-1);
+       }
+       /**
+        * Invocation when not expecting an error result
+        */
+       private static NumberEval invokeNormal(Eval[] args) {
+               Eval ev = invoke(args);
+               if(ev instanceof ErrorEval) {
+                       throw new AssertionFailedError("Normal evaluation failed with error code: "
+                                       + ev.toString());
+               }
+               return (NumberEval) ev;
+       }
+
+       private static void confirm(double expected, double rate, double nper, double pv, double fv, boolean isBeginning) {
+               Eval[] args = { 
+                               new NumberEval(rate),
+                               new NumberEval(nper),
+                               new NumberEval(pv),
+                               new NumberEval(fv),
+                               new NumberEval(isBeginning ? 1 : 0),
+               };
+               confirm(expected, invokeNormal(args));
+       }
+
+       
+       public void testBasic() {
+               confirm(-1037.0321, (0.08/12), 10, 10000, 0, false);
+               confirm(-1030.1643, (0.08/12), 10, 10000, 0, true);
+       }
+       
+       public void test3args() {
+               
+               Eval[] args = { 
+                               new NumberEval(0.005),
+                               new NumberEval(24),
+                               new NumberEval(1000),
+               };
+               Eval ev = invoke(args);
+               if(ev instanceof ErrorEval) {
+                       ErrorEval err = (ErrorEval) ev;
+                       if(err.getErrorCode() == HSSFErrorConstants.ERROR_VALUE) {
+                               throw new AssertionFailedError("Identified bug 44691");
+                       }
+               }
+               
+               confirm(-44.3206, invokeNormal(args));
+       }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44691.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44691.java
deleted file mode 100644 (file)
index 59b04b4..0000000
+++ /dev/null
@@ -1,70 +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.hssf.usermodel;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import junit.framework.TestCase;
-
-import org.apache.poi.hssf.util.CellReference;
-
-/**
- * The PMT formula seems to be giving some grief
- */
-public final class TestBug44691 extends TestCase {
-       String dirname;
-
-       protected void setUp() throws Exception {
-               super.setUp();
-               dirname = System.getProperty("HSSF.testdata.path");
-       }
-
-       public void DISABLEDtestBug44691() throws Exception {
-               HSSFWorkbook outWorkbook = new HSSFWorkbook();
-               HSSFSheet outPMTSheet = outWorkbook.createSheet("PMT Sheet");
-               HSSFRow row = outPMTSheet.createRow((short) 0);
-               HSSFCell cell = row.createCell((short) 0);
-               cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
-               cell.setCellFormula("PMT(0.09/12,48,-10000)");
-
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               outWorkbook.write(baos);
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-
-               HSSFWorkbook inWorkbook = new HSSFWorkbook(bais);
-
-               HSSFSheet inPMTSheet = inWorkbook.getSheet("PMT Sheet");
-               HSSFFormulaEvaluator evaluator = new
-               HSSFFormulaEvaluator(inPMTSheet, inWorkbook);
-               CellReference cellReference = new CellReference("A1");
-               HSSFRow inRow = inPMTSheet.getRow(cellReference.getRow());
-               HSSFCell inCell = inRow.getCell(cellReference.getCol());
-               
-               assertEquals("PMT(0.09/12,48,-10000)", 
-                               inCell.getCellFormula());
-               assertEquals(HSSFCell.CELL_TYPE_FORMULA, inCell.getCellType());
-               
-               evaluator.setCurrentRow(inRow);
-               HSSFFormulaEvaluator.CellValue inCellValue =
-                       evaluator.evaluate(inCell);
-               
-               assertEquals(0, inCellValue.getErrorValue());
-               assertEquals(HSSFCell.CELL_TYPE_NUMERIC, inCellValue.getCellType());
-               assertEquals(248.85, inCellValue.getNumberValue(), 0.0001);
-       }
-}