From: Yegor Kozlov Date: Sun, 21 Nov 2010 11:41:38 +0000 (+0000) Subject: moved common formula-related code to org.apache.poi.ss.formula, eliminated dependenci... X-Git-Tag: REL_3_8_BETA1~124 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6ef7d140269b668dc4aa115c19854bb90b4fde2c;p=poi.git moved common formula-related code to org.apache.poi.ss.formula, eliminated dependencies on HSSF, reduced the number of eclipse warnings git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1037426 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index 7471f46699..5f9a31bd4f 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -46,7 +46,7 @@ import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; import org.apache.poi.hssf.record.aggregates.PageSettingsBlock; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; -import org.apache.poi.hssf.record.formula.FormulaShifter; +import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; diff --git a/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java index 1547f94565..cb99f53acd 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java @@ -24,7 +24,7 @@ import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.RefPtg; -import org.apache.poi.hssf.record.formula.SharedFormula; +import org.apache.poi.ss.formula.SharedFormula; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.formula.FormulaParser; diff --git a/src/testcases/org/apache/poi/hssf/record/formula/AllFormulaTests.java b/src/testcases/org/apache/poi/hssf/record/formula/AllFormulaTests.java index 248f7ca59d..837afa41b8 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/AllFormulaTests.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/AllFormulaTests.java @@ -17,9 +17,11 @@ package org.apache.poi.hssf.record.formula; -import org.apache.poi.hssf.record.formula.eval.AllFormulaEvalTests; -import org.apache.poi.hssf.record.formula.function.AllFormulaFunctionTests; -import org.apache.poi.hssf.record.formula.functions.AllIndividualFunctionEvaluationTests; +import org.apache.poi.ss.formula.TestFormulaShifter; +import org.apache.poi.ss.formula.TestSheetNameFormatter; +import org.apache.poi.ss.formula.eval.AllFormulaEvalTests; +import org.apache.poi.ss.formula.function.AllFormulaFunctionTests; +import org.apache.poi.ss.formula.functions.AllIndividualFunctionEvaluationTests; import junit.framework.Test; import junit.framework.TestSuite; diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestFormulaShifter.java b/src/testcases/org/apache/poi/hssf/record/formula/TestFormulaShifter.java deleted file mode 100644 index 55f79e6dff..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestFormulaShifter.java +++ /dev/null @@ -1,115 +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.record.formula; - -import junit.framework.TestCase; - -/** - * Tests for {@link FormulaShifter}. - * - * @author Josh Micich - */ -public final class TestFormulaShifter extends TestCase { - // Note - the expected result row coordinates here were determined/verified - // in Excel 2007 by manually testing. - - /** - * Tests what happens to area refs when a range of rows from inside, or overlapping are - * moved - */ - public void testShiftAreasSourceRows() { - - // all these operations are on an area ref spanning rows 10 to 20 - AreaPtg aptg = createAreaPtg(10, 20); - - confirmAreaShift(aptg, 9, 21, 20, 30, 40); - confirmAreaShift(aptg, 10, 21, 20, 30, 40); - confirmAreaShift(aptg, 9, 20, 20, 30, 40); - - confirmAreaShift(aptg, 8, 11, -3, 7, 20); // simple expansion of top - // rows containing area top being shifted down: - confirmAreaShift(aptg, 8, 11, 3, 13, 20); - confirmAreaShift(aptg, 8, 11, 7, 17, 20); - confirmAreaShift(aptg, 8, 11, 8, 18, 20); - confirmAreaShift(aptg, 8, 11, 9, 12, 20); // note behaviour changes here - confirmAreaShift(aptg, 8, 11, 10, 12, 21); - confirmAreaShift(aptg, 8, 11, 12, 12, 23); - confirmAreaShift(aptg, 8, 11, 13, 10, 20); // ignored - - // rows from within being moved: - confirmAreaShift(aptg, 12, 16, 3, 10, 20); // stay within - no change - confirmAreaShift(aptg, 11, 19, 20, 10, 20); // move completely out - no change - confirmAreaShift(aptg, 16, 17, -6, 10, 20); // moved exactly to top - no change - confirmAreaShift(aptg, 16, 17, -7, 11, 20); // truncation at top - confirmAreaShift(aptg, 12, 16, 4, 10, 20); // moved exactly to bottom - no change - confirmAreaShift(aptg, 12, 16, 6, 10, 17); // truncation at bottom - - // rows containing area bottom being shifted up: - confirmAreaShift(aptg, 18, 22, -1, 10, 19); // simple contraction at bottom - confirmAreaShift(aptg, 18, 22, -7, 10, 13); // simple contraction at bottom - confirmAreaShift(aptg, 18, 22, -8, 10, 17); // top calculated differently here - confirmAreaShift(aptg, 18, 22, -9, 9, 17); - confirmAreaShift(aptg, 18, 22,-15, 10, 20); // no change because range would be turned inside out - confirmAreaShift(aptg, 15, 19, -7, 13, 20); // dest truncates top (even though src is from inside range) - confirmAreaShift(aptg, 19, 23,-12, 7, 18); // complex: src encloses bottom, dest encloses top - - confirmAreaShift(aptg, 18, 22, 5, 10, 25); // simple expansion at bottom - } - /** - * Tests what happens to an area ref when some outside rows are moved to overlap - * that area ref - */ - public void testShiftAreasDestRows() { - // all these operations are on an area ref spanning rows 20 to 25 - AreaPtg aptg = createAreaPtg(20, 25); - - // no change because no overlap: - confirmAreaShift(aptg, 5, 10, 9, 20, 25); - confirmAreaShift(aptg, 5, 10, 21, 20, 25); - - confirmAreaShift(aptg, 11, 14, 10, 20, 25); - - confirmAreaShift(aptg, 7, 17, 10, -1, -1); // converted to DeletedAreaRef - confirmAreaShift(aptg, 5, 15, 7, 23, 25); // truncation at top - confirmAreaShift(aptg, 13, 16, 10, 20, 22); // truncation at bottom - } - - private static void confirmAreaShift(AreaPtg aptg, - int firstRowMoved, int lastRowMoved, int numberRowsMoved, - int expectedAreaFirstRow, int expectedAreaLastRow) { - - FormulaShifter fs = FormulaShifter.createForRowShift(0, firstRowMoved, lastRowMoved, numberRowsMoved); - boolean expectedChanged = aptg.getFirstRow() != expectedAreaFirstRow || aptg.getLastRow() != expectedAreaLastRow; - - AreaPtg copyPtg = (AreaPtg) aptg.copy(); // clone so we can re-use aptg in calling method - Ptg[] ptgs = { copyPtg, }; - boolean actualChanged = fs.adjustFormula(ptgs, 0); - if (expectedAreaFirstRow < 0) { - assertEquals(AreaErrPtg.class, ptgs[0].getClass()); - return; - } - assertEquals(expectedChanged, actualChanged); - assertEquals(copyPtg, ptgs[0]); // expected to change in place (although this is not a strict requirement) - assertEquals(expectedAreaFirstRow, copyPtg.getFirstRow()); - assertEquals(expectedAreaLastRow, copyPtg.getLastRow()); - - } - private static AreaPtg createAreaPtg(int initialAreaFirstRow, int initialAreaLastRow) { - return new AreaPtg(initialAreaFirstRow, initialAreaLastRow, 2, 5, false, false, false, false); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestSheetNameFormatter.java b/src/testcases/org/apache/poi/hssf/record/formula/TestSheetNameFormatter.java deleted file mode 100644 index b7c1664eee..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestSheetNameFormatter.java +++ /dev/null @@ -1,107 +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.record.formula; - -import junit.framework.TestCase; - -/** - * Tests for {@link SheetNameFormatter} - * - * @author Josh Micich - */ -public final class TestSheetNameFormatter extends TestCase { - - private static void confirmFormat(String rawSheetName, String expectedSheetNameEncoding) { - assertEquals(expectedSheetNameEncoding, SheetNameFormatter.format(rawSheetName)); - } - - /** - * Tests main public method 'format' - */ - public void testFormat() { - - confirmFormat("abc", "abc"); - confirmFormat("123", "'123'"); - - confirmFormat("my sheet", "'my sheet'"); // space - confirmFormat("A:MEM", "'A:MEM'"); // colon - - confirmFormat("O'Brian", "'O''Brian'"); // single quote gets doubled - - - confirmFormat("3rdTimeLucky", "'3rdTimeLucky'"); // digit in first pos - confirmFormat("_", "_"); // plain underscore OK - confirmFormat("my_3rd_sheet", "my_3rd_sheet"); // underscores and digits OK - confirmFormat("A12220", "'A12220'"); - confirmFormat("TAXRETURN19980415", "TAXRETURN19980415"); - } - - public void testBooleanLiterals() { - confirmFormat("TRUE", "'TRUE'"); - confirmFormat("FALSE", "'FALSE'"); - confirmFormat("True", "'True'"); - confirmFormat("fAlse", "'fAlse'"); - - confirmFormat("Yes", "Yes"); - confirmFormat("No", "No"); - } - - private static void confirmCellNameMatch(String rawSheetName, boolean expected) { - assertEquals(expected, SheetNameFormatter.nameLooksLikePlainCellReference(rawSheetName)); - } - - /** - * Tests functionality to determine whether a sheet name containing only letters and digits - * would look (to Excel) like a cell name. - */ - public void testLooksLikePlainCellReference() { - - confirmCellNameMatch("A1", true); - confirmCellNameMatch("a111", true); - confirmCellNameMatch("AA", false); - confirmCellNameMatch("aa1", true); - confirmCellNameMatch("A1A", false); - confirmCellNameMatch("A1A1", false); - confirmCellNameMatch("Sh3", false); - confirmCellNameMatch("SALES20080101", false); // out of range - } - - private static void confirmCellRange(String text, int numberOfPrefixLetters, boolean expected) { - String prefix = text.substring(0, numberOfPrefixLetters); - String suffix = text.substring(numberOfPrefixLetters); - assertEquals(expected, SheetNameFormatter.cellReferenceIsWithinRange(prefix, suffix)); - } - - /** - * Tests exact boundaries for names that look very close to cell names (i.e. contain 1 or more - * letters followed by one or more digits). - */ - public void testCellRange() { - confirmCellRange("A1", 1, true); - confirmCellRange("a111", 1, true); - confirmCellRange("A65536", 1, true); - confirmCellRange("A65537", 1, false); - confirmCellRange("iv1", 2, true); - confirmCellRange("IW1", 2, false); - confirmCellRange("AAA1", 3, false); - confirmCellRange("a111", 1, true); - confirmCellRange("Sheet1", 6, false); - confirmCellRange("iV65536", 2, true); // max cell in Excel 97-2003 - confirmCellRange("IW65537", 2, false); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestRandBetween.java b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestRandBetween.java deleted file mode 100644 index 6be56bad64..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestRandBetween.java +++ /dev/null @@ -1,193 +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.record.formula.atp; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.FormulaEvaluator; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; - -/** - * Testcase for 'Analysis Toolpak' function RANDBETWEEN() - * - * @author Brendan Nolan - */ -public class TestRandBetween extends TestCase { - - private Workbook wb; - private FormulaEvaluator evaluator; - private Cell bottomValueCell; - private Cell topValueCell; - private Cell formulaCell; - - @Override - protected void setUp() throws Exception { - super.setUp(); - wb = HSSFTestDataSamples.openSampleWorkbook("TestRandBetween.xls"); - evaluator = wb.getCreationHelper().createFormulaEvaluator(); - - Sheet sheet = wb.createSheet("RandBetweenSheet"); - Row row = sheet.createRow(0); - bottomValueCell = row.createCell(0); - topValueCell = row.createCell(1); - formulaCell = row.createCell(2, Cell.CELL_TYPE_FORMULA); - } - - @Override - protected void tearDown() throws Exception { - // TODO Auto-generated method stub - super.tearDown(); - } - - /** - * Check where values are the same - */ - public void testRandBetweenSameValues() { - - evaluator.clearAllCachedResultValues(); - formulaCell.setCellFormula("RANDBETWEEN(1,1)"); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(1, formulaCell.getNumericCellValue(), 0); - evaluator.clearAllCachedResultValues(); - formulaCell.setCellFormula("RANDBETWEEN(-1,-1)"); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(-1, formulaCell.getNumericCellValue(), 0); - - } - - /** - * Check special case where rounded up bottom value is greater than - * top value. - */ - public void testRandBetweenSpecialCase() { - - - bottomValueCell.setCellValue(0.05); - topValueCell.setCellValue(0.1); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(1, formulaCell.getNumericCellValue(), 0); - bottomValueCell.setCellValue(-0.1); - topValueCell.setCellValue(-0.05); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(0, formulaCell.getNumericCellValue(), 0); - bottomValueCell.setCellValue(-1.1); - topValueCell.setCellValue(-1.05); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(-1, formulaCell.getNumericCellValue(), 0); - bottomValueCell.setCellValue(-1.1); - topValueCell.setCellValue(-1.1); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(-1, formulaCell.getNumericCellValue(), 0); - } - - /** - * Check top value of BLANK which Excel will evaluate as 0 - */ - public void testRandBetweenTopBlank() { - - bottomValueCell.setCellValue(-1); - topValueCell.setCellType(Cell.CELL_TYPE_BLANK); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertTrue(formulaCell.getNumericCellValue() == 0 || formulaCell.getNumericCellValue() == -1); - - } - /** - * Check where input values are of wrong type - */ - public void testRandBetweenWrongInputTypes() { - // Check case where bottom input is of the wrong type - bottomValueCell.setCellValue("STRING"); - topValueCell.setCellValue(1); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); - assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); - - - // Check case where top input is of the wrong type - bottomValueCell.setCellValue(1); - topValueCell.setCellValue("STRING"); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); - assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); - - // Check case where both inputs are of wrong type - bottomValueCell.setCellValue("STRING"); - topValueCell.setCellValue("STRING"); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); - assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); - - } - - /** - * Check case where bottom is greater than top - */ - public void testRandBetweenBottomGreaterThanTop() { - - // Check case where bottom is greater than top - bottomValueCell.setCellValue(1); - topValueCell.setCellValue(0); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); - assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), formulaCell.getErrorCellValue()); - bottomValueCell.setCellValue(1); - topValueCell.setCellType(Cell.CELL_TYPE_BLANK); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); - assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), formulaCell.getErrorCellValue()); - } - - /** - * Boundary check of Double MIN and MAX values - */ - public void testRandBetweenBoundaryCheck() { - - bottomValueCell.setCellValue(Double.MIN_VALUE); - topValueCell.setCellValue(Double.MAX_VALUE); - formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); - evaluator.clearAllCachedResultValues(); - evaluator.evaluateFormulaCell(formulaCell); - assertTrue(formulaCell.getNumericCellValue() >= Double.MIN_VALUE && formulaCell.getNumericCellValue() <= Double.MAX_VALUE); - - } - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java deleted file mode 100644 index bd580f06c6..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java +++ /dev/null @@ -1,67 +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.record.formula.atp; - -import java.util.Calendar; -import java.util.GregorianCalendar; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.EvaluationException; -import org.apache.poi.ss.usermodel.DateUtil; - -/** - * Specific test cases for YearFracCalculator - */ -public final class TestYearFracCalculator extends TestCase { - - public void testBasis1() { - confirm(md(1999, 1, 1), md(1999, 4, 5), 1, 0.257534247); - confirm(md(1999, 4, 1), md(1999, 4, 5), 1, 0.010958904); - confirm(md(1999, 4, 1), md(1999, 4, 4), 1, 0.008219178); - confirm(md(1999, 4, 2), md(1999, 4, 5), 1, 0.008219178); - confirm(md(1999, 3, 31), md(1999, 4, 3), 1, 0.008219178); - confirm(md(1999, 4, 5), md(1999, 4, 8), 1, 0.008219178); - confirm(md(1999, 4, 4), md(1999, 4, 7), 1, 0.008219178); - confirm(md(2000, 2, 5), md(2000, 6, 1), 0, 0.322222222); - } - - private void confirm(double startDate, double endDate, int basis, double expectedValue) { - double actualValue; - try { - actualValue = YearFracCalculator.calculate(startDate, endDate, basis); - } catch (EvaluationException e) { - throw new RuntimeException(e); - } - double diff = actualValue - expectedValue; - if (Math.abs(diff) > 0.000000001) { - double hours = diff * 365 * 24; - System.out.println(startDate + " " + endDate + " off by " + hours + " hours"); - assertEquals(expectedValue, actualValue, 0.000000001); - } - - } - - private static double md(int year, int month, int day) { - Calendar c = new GregorianCalendar(); - - c.set(year, month-1, day, 0, 0, 0); - c.set(Calendar.MILLISECOND, 0); - return DateUtil.getExcelDate(c.getTime()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java deleted file mode 100644 index 37d1bb314b..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculatorFromSpreadsheet.java +++ /dev/null @@ -1,178 +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.record.formula.atp; - -import java.io.PrintStream; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Iterator; - -import junit.framework.Assert; -import junit.framework.AssertionFailedError; -import junit.framework.ComparisonFailure; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.eval.EvaluationException; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; - -/** - * Tests YearFracCalculator using test-cases listed in a sample spreadsheet - * - * @author Josh Micich - */ -public final class TestYearFracCalculatorFromSpreadsheet extends TestCase { - - private static final class SS { - - public static final int BASIS_COLUMN = 1; // "B" - public static final int START_YEAR_COLUMN = 2; // "C" - public static final int END_YEAR_COLUMN = 5; // "F" - public static final int YEARFRAC_FORMULA_COLUMN = 11; // "L" - public static final int EXPECTED_RESULT_COLUMN = 13; // "N" - } - - public void testAll() { - - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("yearfracExamples.xls"); - HSSFSheet sheet = wb.getSheetAt(0); - HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(wb); - int nSuccess = 0; - int nFailures = 0; - int nUnexpectedErrors = 0; - Iterator rowIterator = sheet.rowIterator(); - while(rowIterator.hasNext()) { - HSSFRow row = (HSSFRow) rowIterator.next(); - - HSSFCell cell = row.getCell(SS.YEARFRAC_FORMULA_COLUMN); - if (cell == null || cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) { - continue; - } - try { - processRow(row, cell, formulaEvaluator); - nSuccess++; - } catch (RuntimeException e) { - nUnexpectedErrors ++; - printShortStackTrace(System.err, e); - } catch (AssertionFailedError e) { - nFailures ++; - printShortStackTrace(System.err, e); - } - } - if (nUnexpectedErrors + nFailures > 0) { - String msg = nFailures + " failures(s) and " + nUnexpectedErrors - + " unexpected errors(s) occurred. See stderr for details"; - throw new AssertionFailedError(msg); - } - if (nSuccess < 1) { - throw new RuntimeException("No test sample cases found"); - } - } - - private static void processRow(HSSFRow row, HSSFCell cell, HSSFFormulaEvaluator formulaEvaluator) { - - double startDate = makeDate(row, SS.START_YEAR_COLUMN); - double endDate = makeDate(row, SS.END_YEAR_COLUMN); - - int basis = getIntCell(row, SS.BASIS_COLUMN); - - double expectedValue = getDoubleCell(row, SS.EXPECTED_RESULT_COLUMN); - - double actualValue; - try { - actualValue = YearFracCalculator.calculate(startDate, endDate, basis); - } catch (EvaluationException e) { - throw new RuntimeException(e); - } - if (expectedValue != actualValue) { - throw new ComparisonFailure("Direct calculate failed - row " + (row.getRowNum()+1), - String.valueOf(expectedValue), String.valueOf(actualValue)); - } - actualValue = formulaEvaluator.evaluate(cell).getNumberValue(); - if (expectedValue != actualValue) { - throw new ComparisonFailure("Formula evaluate failed - row " + (row.getRowNum()+1), - String.valueOf(expectedValue), String.valueOf(actualValue)); - } - } - - private static double makeDate(HSSFRow row, int yearColumn) { - int year = getIntCell(row, yearColumn + 0); - int month = getIntCell(row, yearColumn + 1); - int day = getIntCell(row, yearColumn + 2); - Calendar c = new GregorianCalendar(year, month-1, day, 0, 0, 0); - c.set(Calendar.MILLISECOND, 0); - return HSSFDateUtil.getExcelDate(c.getTime()); - } - - private static int getIntCell(HSSFRow row, int colIx) { - double dVal = getDoubleCell(row, colIx); - if (Math.floor(dVal) != dVal) { - throw new RuntimeException("Non integer value (" + dVal - + ") cell found at column " + (char)('A' + colIx)); - } - return (int)dVal; - } - - private static double getDoubleCell(HSSFRow row, int colIx) { - HSSFCell cell = row.getCell(colIx); - if (cell == null) { - throw new RuntimeException("No cell found at column " + colIx); - } - double dVal = cell.getNumericCellValue(); - return dVal; - } - - /** - * Useful to keep output concise when expecting many failures to be reported by this test case - * TODO - refactor duplicates in other Test~FromSpreadsheet classes - */ - private static void printShortStackTrace(PrintStream ps, Throwable e) { - StackTraceElement[] stes = e.getStackTrace(); - - int startIx = 0; - // skip any top frames inside junit.framework.Assert - while(startIx= endIx) { - // something went wrong. just print the whole stack trace - e.printStackTrace(ps); - } - endIx -= 4; // skip 4 frames of reflection invocation - ps.println(e.toString()); - for(int i=startIx; iorg.apache.poi.hssf.record.formula.eval. - * - * @author Josh Micich - */ -public class AllFormulaEvalTests { - - public static Test suite() { - TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName()); - result.addTestSuite(TestAreaEval.class); - result.addTestSuite(TestCircularReferences.class); - result.addTestSuite(TestDivideEval.class); - result.addTestSuite(TestEqualEval.class); - result.addTestSuite(TestExternalFunction.class); - result.addTestSuite(TestFormulaBugs.class); - result.addTestSuite(TestFormulasFromSpreadsheet.class); - result.addTestSuite(TestMinusZeroResult.class); - result.addTestSuite(TestMissingArgEval.class); - result.addTestSuite(TestPercentEval.class); - result.addTestSuite(TestRangeEval.class); - result.addTestSuite(TestUnaryPlusEval.class); - return result; - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/EvalInstances.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/EvalInstances.java deleted file mode 100644 index b6076938b3..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/EvalInstances.java +++ /dev/null @@ -1,53 +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.record.formula.eval; - -import org.apache.poi.hssf.record.formula.functions.Function; - -/** - * Collects eval instances for easy access by tests in this package - * - * @author Josh Micich - */ -final class EvalInstances { - private EvalInstances() { - // no instances of this class - } - - public static final Function Add = TwoOperandNumericOperation.AddEval; - public static final Function Subtract = TwoOperandNumericOperation.SubtractEval; - public static final Function Multiply = TwoOperandNumericOperation.MultiplyEval; - public static final Function Divide = TwoOperandNumericOperation.DivideEval; - - public static final Function Power = TwoOperandNumericOperation.PowerEval; - - public static final Function Percent = PercentEval.instance; - - public static final Function UnaryMinus = UnaryMinusEval.instance; - public static final Function UnaryPlus = UnaryPlusEval.instance; - - public static final Function Equal = RelationalOperationEval.EqualEval; - public static final Function LessThan = RelationalOperationEval.LessThanEval; - public static final Function LessEqual = RelationalOperationEval.LessEqualEval; - public static final Function GreaterThan = RelationalOperationEval.GreaterThanEval; - public static final Function GreaterEqual = RelationalOperationEval.GreaterEqualEval; - public static final Function NotEqual = RelationalOperationEval.NotEqualEval; - - public static final Function Range = RangeEval.instance; - public static final Function Concat = ConcatEval.instance; -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java deleted file mode 100644 index 65e4e7d411..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java +++ /dev/null @@ -1,62 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.AreaPtg; -import org.apache.poi.hssf.record.formula.functions.EvalFactory; - -/** - * Tests for AreaEval - * - * @author Josh Micich - */ -public final class TestAreaEval extends TestCase { - - public void testGetValue_bug44950() { - // TODO - this test probably isn't testing much anymore - AreaPtg ptg = new AreaPtg("B2:D3"); - NumberEval one = new NumberEval(1); - ValueEval[] values = { - one, - new NumberEval(2), - new NumberEval(3), - new NumberEval(4), - new NumberEval(5), - new NumberEval(6), - }; - AreaEval ae = EvalFactory.createAreaEval(ptg, values); - if (one == ae.getAbsoluteValue(1, 2)) { - throw new AssertionFailedError("Identified bug 44950 a"); - } - confirm(1, ae, 1, 1); - confirm(2, ae, 1, 2); - confirm(3, ae, 1, 3); - confirm(4, ae, 2, 1); - confirm(5, ae, 2, 2); - confirm(6, ae, 2, 3); - - } - - private static void confirm(int expectedValue, AreaEval ae, int row, int col) { - NumberEval v = (NumberEval) ae.getAbsoluteValue(row, col); - assertEquals(expectedValue, v.getNumberValue(), 0.0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java deleted file mode 100644 index 878b7bdaec..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java +++ /dev/null @@ -1,169 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellValue; -/** - * Tests HSSFFormulaEvaluator for its handling of cell formula circular references. - * - * @author Josh Micich - */ -public final class TestCircularReferences extends TestCase { - /** - * Translates StackOverflowError into AssertionFailedError - */ - private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFCell testCell) - throws AssertionFailedError { - HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb); - try { - return evaluator.evaluate(testCell); - } catch (StackOverflowError e) { - throw new AssertionFailedError( "circular reference caused stack overflow error"); - } - } - /** - * Makes sure that the specified evaluated cell value represents a circular reference error. - */ - private static void confirmCycleErrorCode(CellValue cellValue) { - assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_ERROR); - assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cellValue.getErrorValue()); - } - - - /** - * ASF Bugzilla Bug 44413 - * "INDEX() formula cannot contain its own location in the data array range" - */ - public void testIndexFormula() { - - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - - int colB = 1; - sheet.createRow(0).createCell(colB).setCellValue(1); - sheet.createRow(1).createCell(colB).setCellValue(2); - sheet.createRow(2).createCell(colB).setCellValue(3); - HSSFRow row4 = sheet.createRow(3); - HSSFCell testCell = row4.createCell(0); - // This formula should evaluate to the contents of B2, - testCell.setCellFormula("INDEX(A1:B4,2,2)"); - // However the range A1:B4 also includes the current cell A4. If the other parameters - // were 4 and 1, this would represent a circular reference. Prior to v3.2 POI would - // 'fully' evaluate ref arguments before invoking operators, which raised the possibility of - // cycles / StackOverflowErrors. - - - CellValue cellValue = evaluateWithCycles(wb, testCell); - - assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_NUMERIC); - assertEquals(2, cellValue.getNumberValue(), 0); - } - - /** - * Cell A1 has formula "=A1" - */ - public void testSimpleCircularReference() { - - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - - HSSFRow row = sheet.createRow(0); - HSSFCell testCell = row.createCell(0); - testCell.setCellFormula("A1"); - - CellValue cellValue = evaluateWithCycles(wb, testCell); - - confirmCycleErrorCode(cellValue); - } - - /** - * A1=B1, B1=C1, C1=D1, D1=A1 - */ - public void testMultiLevelCircularReference() { - - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - - HSSFRow row = sheet.createRow(0); - row.createCell(0).setCellFormula("B1"); - row.createCell(1).setCellFormula("C1"); - row.createCell(2).setCellFormula("D1"); - HSSFCell testCell = row.createCell(3); - testCell.setCellFormula("A1"); - - CellValue cellValue = evaluateWithCycles(wb, testCell); - - confirmCycleErrorCode(cellValue); - } - - public void testIntermediateCircularReferenceResults_bug46898() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - - HSSFRow row = sheet.createRow(0); - - HSSFCell cellA1 = row.createCell(0); - HSSFCell cellB1 = row.createCell(1); - HSSFCell cellC1 = row.createCell(2); - HSSFCell cellD1 = row.createCell(3); - HSSFCell cellE1 = row.createCell(4); - - cellA1.setCellFormula("IF(FALSE, 1+B1, 42)"); - cellB1.setCellFormula("1+C1"); - cellC1.setCellFormula("1+D1"); - cellD1.setCellFormula("1+E1"); - cellE1.setCellFormula("1+A1"); - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv; - - // Happy day flow - evaluate A1 first - cv = fe.evaluate(cellA1); - assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(42.0, cv.getNumberValue(), 0.0); - cv = fe.evaluate(cellB1); // no circ-ref-error because A1 result is cached - assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(46.0, cv.getNumberValue(), 0.0); - - // Show the bug - evaluate another cell from the loop first - fe.clearAllCachedResultValues(); - cv = fe.evaluate(cellB1); - if (cv.getCellType() == ErrorEval.CIRCULAR_REF_ERROR.getErrorCode()) { - throw new AssertionFailedError("Identified bug 46898"); - } - assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(46.0, cv.getNumberValue(), 0.0); - - // start evaluation on another cell - fe.clearAllCachedResultValues(); - cv = fe.evaluate(cellE1); - assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(43.0, cv.getNumberValue(), 0.0); - - - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestDivideEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestDivideEval.java deleted file mode 100644 index eedcbf9761..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestDivideEval.java +++ /dev/null @@ -1,62 +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.record.formula.eval; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.functions.EvalFactory; -import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker; - -/** - * Test for divide operator evaluator. - * - * @author Josh Micich - */ -public final class TestDivideEval extends TestCase { - - private static void confirm(ValueEval arg0, ValueEval arg1, double expectedResult) { - ValueEval[] args = { - arg0, arg1, - }; - - double result = NumericFunctionInvoker.invoke(EvalInstances.Divide, args, 0, 0); - - assertEquals(expectedResult, result, 0); - } - - public void testBasic() { - confirm(new NumberEval(5), new NumberEval(2), 2.5); - confirm(new NumberEval(3), new NumberEval(16), 0.1875); - confirm(new NumberEval(-150), new NumberEval(-15), 10.0); - confirm(new StringEval("0.2"), new NumberEval(0.05), 4.0); - confirm(BoolEval.TRUE, new StringEval("-0.2"), -5.0); - } - - public void test1x1Area() { - AreaEval ae0 = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), }); - AreaEval ae1 = EvalFactory.createAreaEval("C2:C2", new ValueEval[] { new NumberEval(10), }); - confirm(ae0, ae1, 5); - } - public void testDivZero() { - ValueEval[] args = { - new NumberEval(5), NumberEval.ZERO, - }; - ValueEval result = EvalInstances.Divide.evaluate(args, 0, (short) 0); - assertEquals(ErrorEval.DIV_ZERO, result); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestEqualEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestEqualEval.java deleted file mode 100644 index 739b32cc7e..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestEqualEval.java +++ /dev/null @@ -1,169 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.functions.EvalFactory; -import org.apache.poi.hssf.record.formula.functions.Function; - -/** - * Test for {@link EqualEval} - * - * @author Josh Micich - */ -public final class TestEqualEval extends TestCase { - // convenient access to namepace - private static final EvalInstances EI = null; - - /** - * Test for bug observable at svn revision 692218 (Sep 2008)
- * The value from a 1x1 area should be taken immediately, regardless of srcRow and srcCol - */ - public void test1x1AreaOperand() { - - ValueEval[] values = { BoolEval.FALSE, }; - ValueEval[] args = { - EvalFactory.createAreaEval("B1:B1", values), - BoolEval.FALSE, - }; - ValueEval result = evaluate(EI.Equal, args, 10, 10); - if (result instanceof ErrorEval) { - if (result == ErrorEval.VALUE_INVALID) { - throw new AssertionFailedError("Identified bug in evaluation of 1x1 area"); - } - } - assertEquals(BoolEval.class, result.getClass()); - assertTrue(((BoolEval)result).getBooleanValue()); - } - /** - * Empty string is equal to blank - */ - public void testBlankEqualToEmptyString() { - - ValueEval[] args = { - new StringEval(""), - BlankEval.instance, - }; - ValueEval result = evaluate(EI.Equal, args, 10, 10); - assertEquals(BoolEval.class, result.getClass()); - BoolEval be = (BoolEval) result; - if (!be.getBooleanValue()) { - throw new AssertionFailedError("Identified bug blank/empty string equality"); - } - assertTrue(be.getBooleanValue()); - } - - /** - * Test for bug 46613 (observable at svn r737248) - */ - public void testStringInsensitive_bug46613() { - if (!evalStringCmp("abc", "aBc", EI.Equal)) { - throw new AssertionFailedError("Identified bug 46613"); - } - assertTrue(evalStringCmp("abc", "aBc", EI.Equal)); - assertTrue(evalStringCmp("ABC", "azz", EI.LessThan)); - assertTrue(evalStringCmp("abc", "AZZ", EI.LessThan)); - assertTrue(evalStringCmp("ABC", "aaa", EI.GreaterThan)); - assertTrue(evalStringCmp("abc", "AAA", EI.GreaterThan)); - } - - private static boolean evalStringCmp(String a, String b, Function cmpOp) { - ValueEval[] args = { - new StringEval(a), - new StringEval(b), - }; - ValueEval result = evaluate(cmpOp, args, 10, 20); - assertEquals(BoolEval.class, result.getClass()); - BoolEval be = (BoolEval) result; - return be.getBooleanValue(); - } - - public void testBooleanCompares() { - confirmCompares(BoolEval.TRUE, new StringEval("TRUE"), +1); - confirmCompares(BoolEval.TRUE, new NumberEval(1.0), +1); - confirmCompares(BoolEval.TRUE, BoolEval.TRUE, 0); - confirmCompares(BoolEval.TRUE, BoolEval.FALSE, +1); - - confirmCompares(BoolEval.FALSE, new StringEval("TRUE"), +1); - confirmCompares(BoolEval.FALSE, new StringEval("FALSE"), +1); - confirmCompares(BoolEval.FALSE, new NumberEval(0.0), +1); - confirmCompares(BoolEval.FALSE, BoolEval.FALSE, 0); - } - private static void confirmCompares(ValueEval a, ValueEval b, int expRes) { - confirm(a, b, expRes>0, EI.GreaterThan); - confirm(a, b, expRes>=0, EI.GreaterEqual); - confirm(a, b, expRes==0, EI.Equal); - confirm(a, b, expRes<=0, EI.LessEqual); - confirm(a, b, expRes<0, EI.LessThan); - - confirm(b, a, expRes<0, EI.GreaterThan); - confirm(b, a, expRes<=0, EI.GreaterEqual); - confirm(b, a, expRes==0, EI.Equal); - confirm(b, a, expRes>=0, EI.LessEqual); - confirm(b, a, expRes>0, EI.LessThan); - } - private static void confirm(ValueEval a, ValueEval b, boolean expectedResult, Function cmpOp) { - ValueEval[] args = { a, b, }; - ValueEval result = evaluate(cmpOp, args, 10, 20); - assertEquals(BoolEval.class, result.getClass()); - assertEquals(expectedResult, ((BoolEval) result).getBooleanValue()); - } - - /** - * Bug 47198 involved a formula "-A1=0" where cell A1 was 0.0. - * Excel evaluates "-A1=0" to TRUE, not because it thinks -0.0==0.0 - * but because "-A1" evaluated to +0.0 - *

- * Note - the original diagnosis of bug 47198 was that - * "Excel considers -0.0 to be equal to 0.0" which is NQR - * See {@link TestMinusZeroResult} for more specific tests regarding -0.0. - */ - public void testZeroEquality_bug47198() { - NumberEval zero = new NumberEval(0.0); - NumberEval mZero = (NumberEval) evaluate(UnaryMinusEval.instance, new ValueEval[] { zero, }, 0, 0); - if (Double.doubleToLongBits(mZero.getNumberValue()) == 0x8000000000000000L) { - throw new AssertionFailedError("Identified bug 47198: unary minus should convert -0.0 to 0.0"); - } - ValueEval[] args = { zero, mZero, }; - BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0); - if (!result.getBooleanValue()) { - throw new AssertionFailedError("Identified bug 47198: -0.0 != 0.0"); - } - } - - public void testRounding_bug47598() { - double x = 1+1.0028-0.9973; // should be 1.0055, but has IEEE rounding - assertFalse(x == 1.0055); - - NumberEval a = new NumberEval(x); - NumberEval b = new NumberEval(1.0055); - assertEquals("1.0055", b.getStringValue()); - - ValueEval[] args = { a, b, }; - BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0); - if (!result.getBooleanValue()) { - throw new AssertionFailedError("Identified bug 47598: 1+1.0028-0.9973 != 1.0055"); - } - } - - private static ValueEval evaluate(Function oper, ValueEval[] args, int srcRowIx, int srcColIx) { - return oper.evaluate(args, srcRowIx, (short) srcColIx); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java deleted file mode 100644 index 2cfbbfec41..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java +++ /dev/null @@ -1,95 +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.record.formula.eval; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; -import org.apache.poi.hssf.record.formula.udf.DefaultUDFFinder; -import org.apache.poi.hssf.record.formula.udf.AggregatingUDFFinder; -import org.apache.poi.hssf.record.formula.udf.UDFFinder; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.formula.OperationEvaluationContext; - -/** - * @author Josh Micich - * @author Petr Udalau - registering UDFs in workbook and using ToolPacks. - */ -public final class TestExternalFunction extends TestCase { - - private static class MyFunc implements FreeRefFunction { - public MyFunc() { - // - } - - public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { - if (args.length != 1 || !(args[0] instanceof StringEval)) { - return ErrorEval.VALUE_INVALID; - } - StringEval input = (StringEval) args[0]; - return new StringEval(input.getStringValue() + "abc"); - } - } - - private static class MyFunc2 implements FreeRefFunction { - public MyFunc2() { - // - } - - public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { - if (args.length != 1 || !(args[0] instanceof StringEval)) { - return ErrorEval.VALUE_INVALID; - } - StringEval input = (StringEval) args[0]; - return new StringEval(input.getStringValue() + "abc2"); - } - } - - /** - * Checks that an external function can get invoked from the formula - * evaluator. - */ - public void testInvoke() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); - HSSFSheet sheet = wb.getSheetAt(0); - - /** - * register the two test UDFs in a UDF finder, to be passed to the evaluator - */ - UDFFinder udff1 = new DefaultUDFFinder(new String[] { "myFunc", }, - new FreeRefFunction[] { new MyFunc(), }); - UDFFinder udff2 = new DefaultUDFFinder(new String[] { "myFunc2", }, - new FreeRefFunction[] { new MyFunc2(), }); - UDFFinder udff = new AggregatingUDFFinder(udff1, udff2); - - - HSSFRow row = sheet.getRow(0); - HSSFCell myFuncCell = row.getCell(1); // =myFunc("_") - - HSSFCell myFunc2Cell = row.getCell(2); // =myFunc2("_") - - HSSFFormulaEvaluator fe = HSSFFormulaEvaluator.create(wb, null, udff); - assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue()); - assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java deleted file mode 100644 index 1b97905ed2..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java +++ /dev/null @@ -1,176 +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.record.formula.eval; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Miscellaneous tests for bugzilla entries.

The test name contains the - * bugzilla bug id. - * - * - * @author Josh Micich - */ -public final class TestFormulaBugs extends TestCase { - - /** - * Bug 27349 - VLOOKUP with reference to another sheet.

This test was - * added long after the relevant functionality was fixed. - */ - public void test27349() { - // 27349-vlookupAcrossSheets.xls is bugzilla/attachment.cgi?id=10622 - InputStream is = HSSFTestDataSamples.openSampleFileStream("27349-vlookupAcrossSheets.xls"); - HSSFWorkbook wb; - try { - // original bug may have thrown exception here, or output warning to - // stderr - wb = new HSSFWorkbook(is); - } catch (IOException e) { - throw new RuntimeException(e); - } - - HSSFSheet sheet = wb.getSheetAt(0); - HSSFRow row = sheet.getRow(1); - HSSFCell cell = row.getCell(0); - - // this definitely would have failed due to 27349 - assertEquals("VLOOKUP(1,'DATA TABLE'!$A$8:'DATA TABLE'!$B$10,2)", cell - .getCellFormula()); - - // We might as well evaluate the formula - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv = fe.evaluate(cell); - - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(3.0, cv.getNumberValue(), 0.0); - } - - /** - * Bug 27405 - isnumber() formula always evaluates to false in if statement

- * - * seems to be a duplicate of 24925 - */ - public void test27405() { - - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("input"); - // input row 0 - HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell(0); - cell = row.createCell(1); - cell.setCellValue(1); // B1 - // input row 1 - row = sheet.createRow(1); - cell = row.createCell(1); - cell.setCellValue(999); // B2 - - int rno = 4; - row = sheet.createRow(rno); - cell = row.createCell(1); // B5 - cell.setCellFormula("isnumber(b1)"); - cell = row.createCell(3); // D5 - cell.setCellFormula("IF(ISNUMBER(b1),b1,b2)"); - - if (false) { // set true to check excel file manually - // bug report mentions 'Editing the formula in excel "fixes" the problem.' - try { - FileOutputStream fileOut = new FileOutputStream("27405output.xls"); - wb.write(fileOut); - fileOut.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // use POI's evaluator as an extra sanity check - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv; - cv = fe.evaluate(cell); - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(1.0, cv.getNumberValue(), 0.0); - - cv = fe.evaluate(row.getCell(1)); - assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cv.getCellType()); - assertEquals(true, cv.getBooleanValue()); - } - - /** - * Bug 42448 - Can't parse SUMPRODUCT(A!C7:A!C67, B8:B68) / B69

- */ - public void test42448() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet1 = wb.createSheet("Sheet1"); - - HSSFRow row = sheet1.createRow(0); - HSSFCell cell = row.createCell(0); - - // it's important to create the referenced sheet first - HSSFSheet sheet2 = wb.createSheet("A"); // note name 'A' - // TODO - POI crashes if the formula is added before this sheet - // RuntimeException("Zero length string is an invalid sheet name") - // Excel doesn't crash but the formula doesn't work until it is - // re-entered - - String inputFormula = "SUMPRODUCT(A!C7:A!C67, B8:B68) / B69"; // as per bug report - try { - cell.setCellFormula(inputFormula); - } catch (StringIndexOutOfBoundsException e) { - throw new AssertionFailedError("Identified bug 42448"); - } - - assertEquals("SUMPRODUCT(A!C7:A!C67,B8:B68)/B69", cell.getCellFormula()); - - // might as well evaluate the sucker... - - addCell(sheet2, 5, 2, 3.0); // A!C6 - addCell(sheet2, 6, 2, 4.0); // A!C7 - addCell(sheet2, 66, 2, 5.0); // A!C67 - addCell(sheet2, 67, 2, 6.0); // A!C68 - - addCell(sheet1, 6, 1, 7.0); // B7 - addCell(sheet1, 7, 1, 8.0); // B8 - addCell(sheet1, 67, 1, 9.0); // B68 - addCell(sheet1, 68, 1, 10.0); // B69 - - double expectedResult = (4.0 * 8.0 + 5.0 * 9.0) / 10.0; - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv = fe.evaluate(cell); - - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(expectedResult, cv.getNumberValue(), 0.0); - } - - private static void addCell(HSSFSheet sheet, int rowIx, int colIx, - double value) { - sheet.createRow(rowIx).createCell(colIx).setCellValue(value); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java deleted file mode 100644 index 2c7c7c8df4..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java +++ /dev/null @@ -1,310 +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.record.formula.eval; - -import java.io.PrintStream; - -import junit.framework.Assert; -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.functions.TestMathX; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellValue; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; - -/** - * Tests formulas and operators as loaded from a test data spreadsheet.

- * This class does not test implementors of Function and OperationEval in - * isolation. Much of the evaluation engine (i.e. HSSFFormulaEvaluator, ...) gets - * exercised as well. Tests for bug fixes and specific/tricky behaviour can be found in the - * corresponding test class (TestXxxx) of the target (Xxxx) implementor, - * where execution can be observed more easily. - * - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - */ -public final class TestFormulasFromSpreadsheet extends TestCase { - - private static final class Result { - public static final int SOME_EVALUATIONS_FAILED = -1; - public static final int ALL_EVALUATIONS_SUCCEEDED = +1; - public static final int NO_EVALUATIONS_FOUND = 0; - } - - /** - * This class defines constants for navigating around the test data spreadsheet used for these tests. - */ - private static final class SS { - - /** - * Name of the test spreadsheet (found in the standard test data folder) - */ - public final static String FILENAME = "FormulaEvalTestData.xls"; - /** - * Row (zero-based) in the test spreadsheet where the operator examples start. - */ - public static final int START_OPERATORS_ROW_INDEX = 22; // Row '23' - /** - * Row (zero-based) in the test spreadsheet where the function examples start. - */ - public static final int START_FUNCTIONS_ROW_INDEX = 95; // Row '96' - /** - * Index of the column that contains the function names - */ - public static final int COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B' - - /** - * Used to indicate when there are no more functions left - */ - public static final String FUNCTION_NAMES_END_SENTINEL = ""; - - /** - * Index of the column where the test values start (for each function) - */ - public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D' - - /** - * Each function takes 4 rows in the test spreadsheet - */ - public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4; - } - - private HSSFWorkbook workbook; - private Sheet sheet; - // Note - multiple failures are aggregated before ending. - // If one or more functions fail, a single AssertionFailedError is thrown at the end - private int _functionFailureCount; - private int _functionSuccessCount; - private int _evaluationFailureCount; - private int _evaluationSuccessCount; - - private static final Cell getExpectedValueCell(Row row, int columnIndex) { - if (row == null) { - return null; - } - return row.getCell(columnIndex); - } - - - private static void confirmExpectedResult(String msg, Cell expected, CellValue actual) { - if (expected == null) { - throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); - } - if(actual == null) { - throw new AssertionFailedError(msg + " - actual value was null"); - } - - switch (expected.getCellType()) { - case Cell.CELL_TYPE_BLANK: - assertEquals(msg, Cell.CELL_TYPE_BLANK, actual.getCellType()); - break; - case Cell.CELL_TYPE_BOOLEAN: - assertEquals(msg, Cell.CELL_TYPE_BOOLEAN, actual.getCellType()); - assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); - break; - case Cell.CELL_TYPE_ERROR: - assertEquals(msg, Cell.CELL_TYPE_ERROR, actual.getCellType()); - assertEquals(msg, ErrorEval.getText(expected.getErrorCellValue()), ErrorEval.getText(actual.getErrorValue())); - break; - case Cell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation - throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg); - case Cell.CELL_TYPE_NUMERIC: - assertEquals(msg, Cell.CELL_TYPE_NUMERIC, actual.getCellType()); - TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR); - break; - case Cell.CELL_TYPE_STRING: - assertEquals(msg, Cell.CELL_TYPE_STRING, actual.getCellType()); - assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); - break; - } - } - - - protected void setUp() { - if (workbook == null) { - workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); - sheet = workbook.getSheetAt( 0 ); - } - _functionFailureCount = 0; - _functionSuccessCount = 0; - _evaluationFailureCount = 0; - _evaluationSuccessCount = 0; - } - - public void testFunctionsFromTestSpreadsheet() { - - processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null); - processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null); - // example for debugging individual functions/operators: -// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval"); -// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE"); - - // confirm results - String successMsg = "There were " - + _evaluationSuccessCount + " successful evaluation(s) and " - + _functionSuccessCount + " function(s) without error"; - if(_functionFailureCount > 0) { - String msg = _functionFailureCount + " function(s) failed in " - + _evaluationFailureCount + " evaluation(s). " + successMsg; - throw new AssertionFailedError(msg); - } - if(false) { // normally no output for successful tests - System.out.println(getClass().getName() + ": " + successMsg); - } - } - - /** - * @param startRowIndex row index in the spreadsheet where the first function/operator is found - * @param testFocusFunctionName name of a single function/operator to test alone. - * Typically pass null to test all functions - */ - private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) { - HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); - - int rowIndex = startRowIndex; - while (true) { - Row r = sheet.getRow(rowIndex); - String targetFunctionName = getTargetFunctionName(r); - if(targetFunctionName == null) { - throw new AssertionFailedError("Test spreadsheet cell empty on row (" - + (rowIndex+1) + "). Expected function name or '" - + SS.FUNCTION_NAMES_END_SENTINEL + "'"); - } - if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) { - // found end of functions list - break; - } - if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) { - - // expected results are on the row below - Row expectedValuesRow = sheet.getRow(rowIndex + 1); - if(expectedValuesRow == null) { - int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row - throw new AssertionFailedError("Missing expected values row for function '" - + targetFunctionName + " (row " + missingRowNum + ")"); - } - switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) { - case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break; - case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break; - default: - throw new RuntimeException("unexpected result"); - case Result.NO_EVALUATIONS_FOUND: // do nothing - } - } - rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION; - } - } - - /** - * - * @return a constant from the local Result class denoting whether there were any evaluation - * cases, and whether they all succeeded. - */ - private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName, - Row formulasRow, Row expectedValuesRow) { - - int result = Result.NO_EVALUATIONS_FOUND; // so far - short endcolnum = formulasRow.getLastCellNum(); - - // iterate across the row for all the evaluation cases - for (int colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) { - Cell c = formulasRow.getCell(colnum); - if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) { - continue; - } - - CellValue actualValue = evaluator.evaluate(c); - - Cell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum); - try { - confirmExpectedResult("Function '" + targetFunctionName + "': Formula: " + c.getCellFormula() + " @ " + formulasRow.getRowNum() + ":" + colnum, - expectedValueCell, actualValue); - _evaluationSuccessCount ++; - if(result != Result.SOME_EVALUATIONS_FAILED) { - result = Result.ALL_EVALUATIONS_SUCCEEDED; - } - } catch (AssertionFailedError e) { - _evaluationFailureCount ++; - printShortStackTrace(System.err, e); - result = Result.SOME_EVALUATIONS_FAILED; - } - } - return result; - } - - /** - * Useful to keep output concise when expecting many failures to be reported by this test case - */ - private static void printShortStackTrace(PrintStream ps, AssertionFailedError e) { - StackTraceElement[] stes = e.getStackTrace(); - - int startIx = 0; - // skip any top frames inside junit.framework.Assert - while(startIx= endIx) { - // something went wrong. just print the whole stack trace - e.printStackTrace(ps); - } - endIx -= 4; // skip 4 frames of reflection invocation - ps.println(e.toString()); - for(int i=startIx; inull if cell is missing, empty or blank - */ - private static String getTargetFunctionName(Row r) { - if(r == null) { - System.err.println("Warning - given null row, can't figure out function name"); - return null; - } - Cell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME); - if(cell == null) { - System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name"); - return null; - } - if(cell.getCellType() == Cell.CELL_TYPE_BLANK) { - return null; - } - if(cell.getCellType() == Cell.CELL_TYPE_STRING) { - return cell.getRichStringCellValue().getString(); - } - - throw new AssertionFailedError("Bad cell type for 'function name' column: (" - + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")"); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMinusZeroResult.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMinusZeroResult.java deleted file mode 100644 index d2f4cc748d..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMinusZeroResult.java +++ /dev/null @@ -1,151 +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.record.formula.eval; - -import junit.framework.ComparisonFailure; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.functions.Function; -import org.apache.poi.util.HexDump; - -/** - * IEEE 754 defines a quantity '-0.0' which is distinct from '0.0'. - * Negative zero is not easy to observe in Excel, since it is usually converted to 0.0. - * (Note - the results of XLL add-in functions don't seem to be converted, so they are one - * reliable avenue to observe Excel's treatment of '-0.0' as an operand.) - *

- * POI attempts to emulate Excel faithfully, so this class tests - * two aspects of '-0.0' in formula evaluation: - *

    - *
  1. For most operation results '-0.0' is converted to '0.0'.
  2. - *
  3. Comparison operators have slightly different rules regarding '-0.0'.
  4. - *
- * @author Josh Micich - */ -public final class TestMinusZeroResult extends TestCase { - private static final double MINUS_ZERO = -0.0; - - // convenient access to namepace - private static final EvalInstances EI = null; - - public void testSimpleOperators() { - - // unary plus is a no-op - checkEval(MINUS_ZERO, UnaryPlusEval.instance, MINUS_ZERO); - - // most simple operators convert -0.0 to +0.0 - checkEval(0.0, EI.UnaryMinus, 0.0); - checkEval(0.0, EI.Percent, MINUS_ZERO); - checkEval(0.0, EI.Multiply, MINUS_ZERO, 1.0); - checkEval(0.0, EI.Divide, MINUS_ZERO, 1.0); - checkEval(0.0, EI.Power, MINUS_ZERO, 1.0); - - // but SubtractEval does not convert -0.0, so '-' and '+' work like java - checkEval(MINUS_ZERO, EI.Subtract, MINUS_ZERO, 0.0); // this is the main point of bug 47198 - checkEval(0.0, EI.Add, MINUS_ZERO, 0.0); - } - - /** - * These results are hard to see in Excel (since -0.0 is usually converted to +0.0 before it - * gets to the comparison operator) - */ - public void testComparisonOperators() { - checkEval(false, EI.Equal, 0.0, MINUS_ZERO); - checkEval(true, EI.GreaterThan, 0.0, MINUS_ZERO); - checkEval(true, EI.LessThan, MINUS_ZERO, 0.0); - } - - public void testTextRendering() { - confirmTextRendering("-0", MINUS_ZERO); - // sub-normal negative numbers also display as '-0' - confirmTextRendering("-0", Double.longBitsToDouble(0x8000100020003000L)); - } - - /** - * Uses {@link ConcatEval} to force number-to-text conversion - */ - private static void confirmTextRendering(String expRendering, double d) { - ValueEval[] args = { StringEval.EMPTY_INSTANCE, new NumberEval(d), }; - StringEval se = (StringEval) EI.Concat.evaluate(args, -1, (short)-1); - String result = se.getStringValue(); - assertEquals(expRendering, result); - } - - private static void checkEval(double expectedResult, Function instance, double... dArgs) { - NumberEval result = (NumberEval) evaluate(instance, dArgs); - assertDouble(expectedResult, result.getNumberValue()); - } - private static void checkEval(boolean expectedResult, Function instance, double... dArgs) { - BoolEval result = (BoolEval) evaluate(instance, dArgs); - assertEquals(expectedResult, result.getBooleanValue()); - } - private static ValueEval evaluate(Function instance, double... dArgs) { - ValueEval[] evalArgs; - evalArgs = new ValueEval[dArgs.length]; - for (int i = 0; i < evalArgs.length; i++) { - evalArgs[i] = new NumberEval(dArgs[i]); - } - ValueEval r = instance.evaluate(evalArgs, -1, (short)-1); - return r; - } - - /** - * Not really a POI test - just shows similar behaviour of '-0.0' in Java. - */ - public void testJava() { - - assertEquals(0x8000000000000000L, Double.doubleToLongBits(MINUS_ZERO)); - - // The simple operators consider all zeros to be the same - assertTrue(MINUS_ZERO == MINUS_ZERO); - assertTrue(MINUS_ZERO == +0.0); - assertFalse(MINUS_ZERO < +0.0); - - // Double.compare() considers them different - assertTrue(Double.compare(MINUS_ZERO, +0.0) < 0); - - // multiplying zero by any negative quantity yields minus zero - assertDouble(MINUS_ZERO, 0.0*-1); - assertDouble(MINUS_ZERO, 0.0*-1e300); - assertDouble(MINUS_ZERO, 0.0*-1e-300); - - // minus zero can be produced as a result of underflow - assertDouble(MINUS_ZERO, -1e-300 / 1e100); - - // multiplying or dividing minus zero by a positive quantity yields minus zero - assertDouble(MINUS_ZERO, MINUS_ZERO * 1.0); - assertDouble(MINUS_ZERO, MINUS_ZERO / 1.0); - - // subtracting positive zero gives minus zero - assertDouble(MINUS_ZERO, MINUS_ZERO - 0.0); - // BUT adding positive zero gives positive zero - assertDouble(0.0, MINUS_ZERO + 0.0); // <<---- - } - - /** - * Just so there is no ambiguity. The two double values have to be exactly equal - */ - private static void assertDouble(double a, double b) { - long bitsA = Double.doubleToLongBits(a); - long bitsB = Double.doubleToLongBits(b); - if (bitsA != bitsB) { - throw new ComparisonFailure("value different to expected", - new String(HexDump.longToHex(bitsA)), new String(HexDump.longToHex(bitsB))); - } - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMissingArgEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMissingArgEval.java deleted file mode 100644 index 2a830b080b..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestMissingArgEval.java +++ /dev/null @@ -1,74 +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.record.formula.eval; - -import java.util.EmptyStackException; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Tests for {@link MissingArgEval} - * - * @author Josh Micich - */ -public final class TestMissingArgEval extends TestCase { - - public void testEvaluateMissingArgs() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - HSSFSheet sheet = wb.createSheet("Sheet1"); - HSSFCell cell = sheet.createRow(0).createCell(0); - - cell.setCellFormula("if(true,)"); - fe.clearAllCachedResultValues(); - CellValue cv; - try { - cv = fe.evaluate(cell); - } catch (EmptyStackException e) { - throw new AssertionFailedError("Missing args evaluation not implemented (bug 43354"); - } - // MissingArg -> BlankEval -> zero (as formula result) - assertEquals(0.0, cv.getNumberValue(), 0.0); - - // MissingArg -> BlankEval -> empty string (in concatenation) - cell.setCellFormula("\"abc\"&if(true,)"); - fe.clearAllCachedResultValues(); - assertEquals("abc", fe.evaluate(cell).getStringValue()); - } - - public void testCountFuncs() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - HSSFSheet sheet = wb.createSheet("Sheet1"); - HSSFCell cell = sheet.createRow(0).createCell(0); - - cell.setCellFormula("COUNT(C5,,,,)"); // 4 missing args, C5 is blank - assertEquals(4.0, fe.evaluate(cell).getNumberValue(), 0.0); - - cell.setCellFormula("COUNTA(C5,,)"); // 2 missing args, C5 is blank - fe.clearAllCachedResultValues(); - assertEquals(2.0, fe.evaluate(cell).getNumberValue(), 0.0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java deleted file mode 100644 index 98ddadef66..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java +++ /dev/null @@ -1,89 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -/** - * Tests for OperandResolver - * - * @author Brendan Nolan - */ -public final class TestOperandResolver extends TestCase { - - public void testParseDouble_bug48472() { - - String value = "-"; - - Double resolvedValue = null; - - try { - resolvedValue = OperandResolver.parseDouble(value); - } catch (StringIndexOutOfBoundsException e) { - throw new AssertionFailedError("Identified bug 48472"); - } - - assertEquals(null, resolvedValue); - - } - - public void testParseDouble_bug49723() { - - String value = ".1"; - - Double resolvedValue = null; - - resolvedValue = OperandResolver.parseDouble(value); - - assertNotNull("Identified bug 49723", resolvedValue); - - } - - /** - * - * Tests that a list of valid strings all return a non null value from {@link OperandResolver#parseDouble(String)} - * - */ - public void testParseDoubleValidStrings() { - - String[] values = new String[]{".19", "0.19", "1.9", "1E4", "-.19", "-0.19", "8.5","-1E4", ".5E6","+1.5","+1E5", " +1E5 "}; - - for (String value : values) { - assertTrue(OperandResolver.parseDouble(value) != null); - assertEquals(OperandResolver.parseDouble(value), Double.parseDouble(value)); - } - - } - - /** - * - * Tests that a list of invalid strings all return null from {@link OperandResolver#parseDouble(String)} - * - */ - public void testParseDoubleInvalidStrings() { - - String[] values = new String[]{"-", "ABC", "-X", "1E5a", "Infinity", "NaN", ".5F", "1,000"}; - - for (String value : values) { - assertEquals(null, OperandResolver.parseDouble(value)); - } - - } - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java deleted file mode 100644 index ae6524e882..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java +++ /dev/null @@ -1,83 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.functions.EvalFactory; -import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Test for percent operator evaluator. - * - * @author Josh Micich - */ -public final class TestPercentEval extends TestCase { - - private static void confirm(ValueEval arg, double expectedResult) { - ValueEval[] args = { - arg, - }; - - double result = NumericFunctionInvoker.invoke(PercentEval.instance, args, 0, 0); - - assertEquals(expectedResult, result, 0); - } - - public void testBasic() { - confirm(new NumberEval(5), 0.05); - confirm(new NumberEval(3000), 30.0); - confirm(new NumberEval(-150), -1.5); - confirm(new StringEval("0.2"), 0.002); - confirm(BoolEval.TRUE, 0.01); - } - - public void test1x1Area() { - AreaEval ae = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), }); - confirm(ae, 0.5); - } - public void testInSpreadSheet() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell(0); - cell.setCellFormula("B1%"); - row.createCell(1).setCellValue(50.0); - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv; - try { - cv = fe.evaluate(cell); - } catch (RuntimeException e) { - if(e.getCause() instanceof NullPointerException) { - throw new AssertionFailedError("Identified bug 44608"); - } - // else some other unexpected error - throw e; - } - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); - assertEquals(0.5, cv.getNumberValue(), 0.0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestRangeEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestRangeEval.java deleted file mode 100644 index 80af1b924b..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestRangeEval.java +++ /dev/null @@ -1,160 +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.record.formula.eval; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.AreaI; -import org.apache.poi.hssf.record.formula.AreaI.OffsetArea; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.util.AreaReference; -import org.apache.poi.hssf.util.CellReference; -import org.apache.poi.ss.formula.TwoDEval; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Test for unary plus operator evaluator. - * - * @author Josh Micich - */ -public final class TestRangeEval extends TestCase { - - public void testPermutations() { - - confirm("B3", "D7", "B3:D7"); - confirm("B1", "B1", "B1:B1"); - - confirm("B7", "D3", "B3:D7"); - confirm("D3", "B7", "B3:D7"); - confirm("D7", "B3", "B3:D7"); - } - - private static void confirm(String refA, String refB, String expectedAreaRef) { - - ValueEval[] args = { - createRefEval(refA), - createRefEval(refB), - }; - AreaReference ar = new AreaReference(expectedAreaRef); - ValueEval result = EvalInstances.Range.evaluate(args, 0, (short)0); - assertTrue(result instanceof AreaEval); - AreaEval ae = (AreaEval) result; - assertEquals(ar.getFirstCell().getRow(), ae.getFirstRow()); - assertEquals(ar.getLastCell().getRow(), ae.getLastRow()); - assertEquals(ar.getFirstCell().getCol(), ae.getFirstColumn()); - assertEquals(ar.getLastCell().getCol(), ae.getLastColumn()); - } - - private static ValueEval createRefEval(String refStr) { - CellReference cr = new CellReference(refStr); - return new MockRefEval(cr.getRow(), cr.getCol()); - - } - - private static final class MockRefEval extends RefEvalBase { - - public MockRefEval(int rowIndex, int columnIndex) { - super(rowIndex, columnIndex); - } - public ValueEval getInnerValueEval() { - throw new RuntimeException("not expected to be called during this test"); - } - public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, - int relLastColIx) { - AreaI area = new OffsetArea(getRow(), getColumn(), - relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); - return new MockAreaEval(area); - } - } - - private static final class MockAreaEval extends AreaEvalBase { - - public MockAreaEval(AreaI ptg) { - super(ptg); - } - private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn) { - super(firstRow, firstColumn, lastRow, lastColumn); - } - public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { - throw new RuntimeException("not expected to be called during this test"); - } - public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, - int relLastColIx) { - AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(), - relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); - - return new MockAreaEval(area); - } - public TwoDEval getRow(int rowIndex) { - if (rowIndex >= getHeight()) { - throw new IllegalArgumentException("Invalid rowIndex " + rowIndex - + ". Allowable range is (0.." + getHeight() + ")."); - } - return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn()); - } - public TwoDEval getColumn(int columnIndex) { - if (columnIndex >= getWidth()) { - throw new IllegalArgumentException("Invalid columnIndex " + columnIndex - + ". Allowable range is (0.." + getWidth() + ")."); - } - return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex); - } - } - - public void testRangeUsingOffsetFunc_bug46948() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFRow row = wb.createSheet("Sheet1").createRow(0); - HSSFCell cellA1 = row.createCell(0); - HSSFCell cellB1 = row.createCell(1); - row.createCell(2).setCellValue(5.0); // C1 - row.createCell(3).setCellValue(7.0); // D1 - row.createCell(4).setCellValue(9.0); // E1 - - - cellA1.setCellFormula("SUM(C1:OFFSET(C1,0,B1))"); - - cellB1.setCellValue(1.0); // range will be C1:D1 - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue cv; - try { - cv = fe.evaluate(cellA1); - } catch (IllegalArgumentException e) { - if (e.getMessage().equals("Unexpected ref arg class (org.apache.poi.ss.formula.LazyAreaEval)")) { - throw new AssertionFailedError("Identified bug 46948"); - } - throw e; - } - - assertEquals(12.0, cv.getNumberValue(), 0.0); - - cellB1.setCellValue(2.0); // range will be C1:E1 - fe.notifyUpdateCell(cellB1); - cv = fe.evaluate(cellA1); - assertEquals(21.0, cv.getNumberValue(), 0.0); - - cellB1.setCellValue(0.0); // range will be C1:C1 - fe.notifyUpdateCell(cellB1); - cv = fe.evaluate(cellA1); - assertEquals(5.0, cv.getNumberValue(), 0.0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java deleted file mode 100644 index ffa42b3339..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java +++ /dev/null @@ -1,58 +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.record.formula.eval; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.AreaPtg; -import org.apache.poi.hssf.record.formula.functions.EvalFactory; -import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker; - -/** - * Test for unary plus operator evaluator. - * - * @author Josh Micich - */ -public final class TestUnaryPlusEval extends TestCase { - - /** - * Test for bug observable at svn revision 618865 (5-Feb-2008)
- * The code for handling column operands had been copy-pasted from the row handling code. - */ - public void testColumnOperand() { - - short firstRow = (short)8; - short lastRow = (short)12; - short colNum = (short)5; - AreaPtg areaPtg = new AreaPtg(firstRow, lastRow, colNum, colNum, false, false, false, false); - ValueEval[] values = { - new NumberEval(27), - new NumberEval(29), - new NumberEval(35), // value in row 10 - new NumberEval(37), - new NumberEval(38), - }; - ValueEval[] args = { - EvalFactory.createAreaEval(areaPtg, values), - }; - - double result = NumericFunctionInvoker.invoke(EvalInstances.UnaryPlus, args, 10, (short)20); - - assertEquals(35, result, 0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/AllFormulaFunctionTests.java b/src/testcases/org/apache/poi/hssf/record/formula/function/AllFormulaFunctionTests.java deleted file mode 100644 index 01f88bd069..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/AllFormulaFunctionTests.java +++ /dev/null @@ -1,37 +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.record.formula.function; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * Collects all tests for this org.apache.poi.hssf.record.formula.function. - * - * @author Josh Micich - */ -public class AllFormulaFunctionTests { - - public static Test suite() { - TestSuite result = new TestSuite(AllFormulaFunctionTests.class.getName()); - result.addTestSuite(TestFunctionMetadataRegistry.class); - result.addTestSuite(TestParseMissingBuiltInFuncs.class); - result.addTestSuite(TestReadMissingBuiltInFuncs.class); - return result; - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java b/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java deleted file mode 100644 index c3a026c211..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java +++ /dev/null @@ -1,617 +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.record.formula.function; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderFactory; - -/** - * This class is not used during normal POI run-time but is used at development time to generate - * the file 'functionMetadata.txt'. There are more than 300 built-in functions in Excel and the - * intention of this class is to make it easier to maintain the metadata, by extracting it from - * a reliable source. - * - * @author Josh Micich - */ -public final class ExcelFileFormatDocFunctionExtractor { - - private static final String SOURCE_DOC_FILE_NAME = "excelfileformat.odt"; - - /** - * For simplicity, the output file is strictly simple ASCII. - * This method detects any unexpected characters. - */ - /* package */ static boolean isSimpleAscii(char c) { - - if (c>=0x21 && c<=0x7E) { - // everything from '!' to '~' (includes letters, digits, punctuation - return true; - } - // some specific whitespace chars below 0x21: - switch(c) { - case ' ': - case '\t': - case '\r': - case '\n': - return true; - } - return false; - } - - - private static final class FunctionData { - // special characters from the ooo document - private static final int CHAR_ELLIPSIS_8230 = 8230; - private static final int CHAR_NDASH_8211 = 8211; - - private final int _index; - private final boolean _hasFootnote; - private final String _name; - private final int _minParams; - private final int _maxParams; - private final String _returnClass; - private final String _paramClasses; - private final boolean _isVolatile; - - public FunctionData(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams, - String returnClass, String paramClasses, boolean isVolatile) { - _index = funcIx; - _hasFootnote = hasFootnote; - _name = funcName; - _minParams = minParams; - _maxParams = maxParams; - _returnClass = convertSpecialChars(returnClass); - _paramClasses = convertSpecialChars(paramClasses); - _isVolatile = isVolatile; - } - private static String convertSpecialChars(String ss) { - StringBuffer sb = new StringBuffer(ss.length() + 4); - for(int i=0; i 0; - - Integer funcIxKey = Integer.valueOf(funcIx); - if(!_groupFunctionIndexes.add(funcIxKey)) { - throw new RuntimeException("Duplicate function index (" + funcIx + ")"); - } - if(!_groupFunctionNames.add(funcName)) { - throw new RuntimeException("Duplicate function name '" + funcName + "'"); - } - - checkRedefinedFunction(hasFootnote, funcName, funcIxKey); - FunctionData fd = new FunctionData(funcIx, hasFootnote, funcName, - minParams, maxParams, returnClass, paramClasses, isVolatile); - - _allFunctionsByIndex.put(funcIxKey, fd); - _allFunctionsByName.put(funcName, fd); - } - - /** - * Some extra validation here. - * Any function which changes definition will have a footnote in the source document - */ - private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) { - FunctionData fdPrev; - // check by index - fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey); - if(fdPrev != null) { - if(!fdPrev.hasFootnote() || !hasNote) { - throw new RuntimeException("changing function [" - + funcIxKey + "] definition without foot-note"); - } - _allFunctionsByName.remove(fdPrev.getName()); - } - // check by name - fdPrev = (FunctionData) _allFunctionsByName.get(funcName); - if(fdPrev != null) { - if(!fdPrev.hasFootnote() || !hasNote) { - throw new RuntimeException("changing function '" - + funcName + "' definition without foot-note"); - } - _allFunctionsByIndex.remove(Integer.valueOf(fdPrev.getIndex())); - } - } - - public void endTableGroup(String headingText) { - Integer[] keys = new Integer[_groupFunctionIndexes.size()]; - _groupFunctionIndexes.toArray(keys); - _groupFunctionIndexes.clear(); - _groupFunctionNames.clear(); - Arrays.sort(keys); - - _ps.println("# " + headingText); - for (int i = 0; i < keys.length; i++) { - FunctionData fd = (FunctionData) _allFunctionsByIndex.get(keys[i]); - _ps.println(fd.formatAsDataLine()); - } - } - } - - /** - * To avoid drag-in - parse XML using only JDK. - */ - private static class EFFDocHandler implements ContentHandler { - private static final String[] HEADING_PATH_NAMES = { - "office:document-content", "office:body", "office:text", "text:h", - }; - private static final String[] TABLE_BASE_PATH_NAMES = { - "office:document-content", "office:body", "office:text", "table:table", - }; - private static final String[] TABLE_ROW_RELPATH_NAMES = { - "table:table-row", - }; - private static final String[] TABLE_CELL_RELPATH_NAMES = { - "table:table-row", "table:table-cell", "text:p", - }; - // after May 2008 there was one more style applied to the footnotes - private static final String[] NOTE_REF_RELPATH_NAMES_OLD = { - "table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref", - }; - private static final String[] NOTE_REF_RELPATH_NAMES = { - "table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref", - }; - - - private final Stack _elemNameStack; - /** true only when parsing the target tables */ - private boolean _isInsideTable; - - private final List _rowData; - private final StringBuffer _textNodeBuffer; - private final List _rowNoteFlags; - private boolean _cellHasNote; - - private final FunctionDataCollector _fdc; - private String _lastHeadingText; - - public EFFDocHandler(FunctionDataCollector fdc) { - _fdc = fdc; - _elemNameStack = new Stack(); - _isInsideTable = false; - _rowData = new ArrayList(); - _textNodeBuffer = new StringBuffer(); - _rowNoteFlags = new ArrayList(); - } - - private boolean matchesTargetPath() { - return matchesPath(0, TABLE_BASE_PATH_NAMES); - } - private boolean matchesRelPath(String[] pathNames) { - return matchesPath(TABLE_BASE_PATH_NAMES.length, pathNames); - } - private boolean matchesPath(int baseStackIndex, String[] pathNames) { - if(_elemNameStack.size() != baseStackIndex + pathNames.length) { - return false; - } - for (int i = 0; i < pathNames.length; i++) { - if(!_elemNameStack.get(baseStackIndex + i).equals(pathNames[i])) { - return false; - } - } - return true; - } - public void characters(char[] ch, int start, int length) { - // only 2 text nodes where text is collected: - if(matchesRelPath(TABLE_CELL_RELPATH_NAMES) || matchesPath(0, HEADING_PATH_NAMES)) { - _textNodeBuffer.append(ch, start, length); - } - } - - public void endElement(String namespaceURI, String localName, String name) { - String expectedName = (String) _elemNameStack.peek(); - if(expectedName != name) { - throw new RuntimeException("close tag mismatch"); - } - if(matchesPath(0, HEADING_PATH_NAMES)) { - _lastHeadingText = _textNodeBuffer.toString().trim(); - _textNodeBuffer.setLength(0); - } - if(_isInsideTable) { - if(matchesTargetPath()) { - _fdc.endTableGroup(_lastHeadingText); - _isInsideTable = false; - } else if(matchesRelPath(TABLE_ROW_RELPATH_NAMES)) { - String[] cellData = new String[_rowData.size()]; - _rowData.toArray(cellData); - _rowData.clear(); - Boolean[] noteFlags = new Boolean[_rowNoteFlags.size()]; - _rowNoteFlags.toArray(noteFlags); - _rowNoteFlags.clear(); - processTableRow(cellData, noteFlags); - } else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { - _rowData.add(_textNodeBuffer.toString().trim()); - _rowNoteFlags.add(Boolean.valueOf(_cellHasNote)); - _textNodeBuffer.setLength(0); - } - } - _elemNameStack.pop(); - } - - private void processTableRow(String[] cellData, Boolean[] noteFlags) { - // each table row of the document contains data for two functions - if(cellData.length != 15) { - throw new RuntimeException("Bad table row size"); - } - processFunction(cellData, noteFlags, 0); - processFunction(cellData, noteFlags, 8); - } - public void processFunction(String[] cellData, Boolean[] noteFlags, int i) { - String funcIxStr = cellData[i + 0]; - if (funcIxStr.length() < 1) { - // empty (happens on the right hand side when there is an odd number of functions) - return; - } - int funcIx = parseInt(funcIxStr); - - boolean hasFootnote = noteFlags[i + 1].booleanValue(); - String funcName = cellData[i + 1]; - int minParams = parseInt(cellData[i + 2]); - int maxParams = parseInt(cellData[i + 3]); - - String returnClass = cellData[i + 4]; - String paramClasses = cellData[i + 5]; - String volatileFlagStr = cellData[i + 6]; - - _fdc.addFuntion(funcIx, hasFootnote, funcName, minParams, maxParams, returnClass, paramClasses, volatileFlagStr); - } - private static int parseInt(String valStr) { - try { - return Integer.parseInt(valStr); - } catch (NumberFormatException e) { - throw new RuntimeException("Value '" + valStr + "' could not be parsed as an integer"); - } - } - public void startElement(String namespaceURI, String localName, String name, Attributes atts) { - _elemNameStack.add(name); - if(matchesTargetPath()) { - String tableName = atts.getValue("table:name"); - if(tableName.startsWith("tab_fml_func") && !tableName.equals("tab_fml_func0")) { - _isInsideTable = true; - } - return; - } - if(matchesPath(0, HEADING_PATH_NAMES)) { - _textNodeBuffer.setLength(0); - } else if(matchesRelPath(TABLE_ROW_RELPATH_NAMES)) { - _rowData.clear(); - _rowNoteFlags.clear(); - } else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { - _textNodeBuffer.setLength(0); - _cellHasNote = false; - } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) { - _cellHasNote = true; - } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) { - _cellHasNote = true; - } - } - - public void endDocument() { - // do nothing - } - public void endPrefixMapping(String prefix) { - // do nothing - } - public void ignorableWhitespace(char[] ch, int start, int length) { - // do nothing - } - public void processingInstruction(String target, String data) { - // do nothing - } - public void setDocumentLocator(Locator locator) { - // do nothing - } - public void skippedEntity(String name) { - // do nothing - } - public void startDocument() { - // do nothing - } - public void startPrefixMapping(String prefix, String uri) { - // do nothing - } - } - - private static void extractFunctionData(FunctionDataCollector fdc, InputStream is) { - XMLReader xr; - - try { - // First up, try the default one - xr = XMLReaderFactory.createXMLReader(); - } catch (SAXException e) { - // Try one for java 1.4 - System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl"); - try { - xr = XMLReaderFactory.createXMLReader(); - } catch (SAXException e2) { - throw new RuntimeException(e2); - } - } - xr.setContentHandler(new EFFDocHandler(fdc)); - - InputSource inSrc = new InputSource(is); - - try { - xr.parse(inSrc); - is.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (SAXException e) { - throw new RuntimeException(e); - } - } - /** - * To be sure that no tricky unicode chars make it through to the output file. - */ - private static final class SimpleAsciiOutputStream extends OutputStream { - - private final OutputStream _os; - - public SimpleAsciiOutputStream(OutputStream os) { - _os = os; - } - public void write(int b) throws IOException { - checkByte(b); - _os.write(b); - } - private static void checkByte(int b) { - if (!isSimpleAscii((char)b)) { - throw new RuntimeException("Encountered char (" + b + ") which was not simple ascii as expected"); - } - } - public void write(byte[] b, int off, int len) throws IOException { - for (int i = 0; i < len; i++) { - checkByte(b[i + off]); - - } - _os.write(b, off, len); - } - } - - private static void processFile(File effDocFile, File outFile) { - if(!effDocFile.exists()) { - throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist"); - } - OutputStream os; - try { - os = new FileOutputStream(outFile); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - os = new SimpleAsciiOutputStream(os); - PrintStream ps; - try { - ps = new PrintStream(os, true, "UTF-8"); - } catch(UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - - outputLicenseHeader(ps); - Class genClass = ExcelFileFormatDocFunctionExtractor.class; - ps.println("# Created by (" + genClass.getName() + ")"); - // identify the source file - ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'"); - ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")"); - ps.println("#"); - ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )"); - ps.println(""); - try { - ZipFile zf = new ZipFile(effDocFile); - InputStream is = zf.getInputStream(zf.getEntry("content.xml")); - extractFunctionData(new FunctionDataCollector(ps), is); - zf.close(); - } catch (ZipException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - ps.close(); - - String canonicalOutputFileName; - try { - canonicalOutputFileName = outFile.getCanonicalPath(); - } catch (IOException e) { - throw new RuntimeException(e); - } - System.out.println("Successfully output to '" + canonicalOutputFileName + "'"); - } - - private static void outputLicenseHeader(PrintStream ps) { - String[] lines= { - "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.", - }; - for (int i = 0; i < lines.length; i++) { - ps.print("# "); - ps.println(lines[i]); - } - ps.println(); - } - - /** - * Helps identify the source file - */ - private static String getFileMD5(File f) { - MessageDigest m; - try { - m = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - - byte[]buf = new byte[2048]; - try { - InputStream is = new FileInputStream(f); - while(true) { - int bytesRead = is.read(buf); - if(bytesRead<1) { - break; - } - m.update(buf, 0, bytesRead); - } - is.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - - return "0x" + new BigInteger(1, m.digest()).toString(16); - } - - private static File downloadSourceFile() { - URL url; - try { - url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - - File result; - byte[]buf = new byte[2048]; - try { - URLConnection conn = url.openConnection(); - InputStream is = conn.getInputStream(); - System.out.println("downloading " + url.toExternalForm()); - result = File.createTempFile("excelfileformat", ".odt"); - OutputStream os = new FileOutputStream(result); - while(true) { - int bytesRead = is.read(buf); - if(bytesRead<1) { - break; - } - os.write(buf, 0, bytesRead); - } - is.close(); - os.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - System.out.println("file downloaded ok"); - return result; - } - - public static void main(String[] args) { - - File outFile = new File("functionMetadata-asGenerated.txt"); - - if (false) { // set true to use local file - File dir = new File("c:/temp"); - File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME); - processFile(effDocFile, outFile); - return; - } - - File tempEFFDocFile = downloadSourceFile(); - processFile(tempEFFDocFile, outFile); - tempEFFDocFile.delete(); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/TestFunctionMetadataRegistry.java b/src/testcases/org/apache/poi/hssf/record/formula/function/TestFunctionMetadataRegistry.java deleted file mode 100644 index c175c473bf..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/TestFunctionMetadataRegistry.java +++ /dev/null @@ -1,44 +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.record.formula.function; - -import junit.framework.TestCase; - -/** - * - * @author Josh Micich - */ -public final class TestFunctionMetadataRegistry extends TestCase { - - public void testWellKnownFunctions() { - confirmFunction(0, "COUNT"); - confirmFunction(1, "IF"); - - } - - private static void confirmFunction(int index, String funcName) { - FunctionMetadata fm; - fm = FunctionMetadataRegistry.getFunctionByIndex(index); - assertNotNull(fm); - assertEquals(funcName, fm.getName()); - - fm = FunctionMetadataRegistry.getFunctionByName(funcName); - assertNotNull(fm); - assertEquals(index, fm.getIndex()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java deleted file mode 100644 index 95ad2ef535..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java +++ /dev/null @@ -1,90 +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.record.formula.function; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; -import org.apache.poi.hssf.record.formula.FuncPtg; -import org.apache.poi.hssf.record.formula.FuncVarPtg; -import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -/** - * Tests parsing of some built-in functions that were not properly - * registered in POI as of bug #44675, #44733 (March/April 2008). - * - * @author Josh Micich - */ -public final class TestParseMissingBuiltInFuncs extends TestCase { - - private static Ptg[] parse(String formula) { - HSSFWorkbook book = new HSSFWorkbook(); - return HSSFFormulaParser.parse(formula, book); - } - private static void confirmFunc(String formula, int expPtgArraySize, boolean isVarArgFunc, int funcIx) { - Ptg[] ptgs = parse(formula); - Ptg ptgF = ptgs[ptgs.length-1]; // func is last RPN token in all these formulas - - // Check critical things in the Ptg array encoding. - if(!(ptgF instanceof AbstractFunctionPtg)) { - throw new RuntimeException("function token missing"); - } - AbstractFunctionPtg func = (AbstractFunctionPtg) ptgF; - if(func.getFunctionIndex() == 255) { - throw new AssertionFailedError("Failed to recognise built-in function in formula '" - + formula + "'"); - } - assertEquals(expPtgArraySize, ptgs.length); - assertEquals(funcIx, func.getFunctionIndex()); - Class expCls = isVarArgFunc ? FuncVarPtg.class : FuncPtg.class; - assertEquals(expCls, ptgF.getClass()); - - // check that parsed Ptg array converts back to formula text OK - HSSFWorkbook book = new HSSFWorkbook(); - String reRenderedFormula = HSSFFormulaParser.toFormulaString(book, ptgs); - assertEquals(formula, reRenderedFormula); - } - - public void testDatedif() { - int expSize = 4; // NB would be 5 if POI added tAttrVolatile properly - confirmFunc("DATEDIF(NOW(),NOW(),\"d\")", expSize, false, 351); - } - - public void testDdb() { - confirmFunc("DDB(1,1,1,1,1)", 6, true, 144); - } - public void testAtan() { - confirmFunc("ATAN(1)", 2, false, 18); - } - - public void testUsdollar() { - confirmFunc("USDOLLAR(1)", 2, true, 204); - } - - public void testDBCS() { - confirmFunc("DBCS(\"abc\")", 2, false, 215); - } - public void testIsnontext() { - confirmFunc("ISNONTEXT(\"abc\")", 2, false, 190); - } - public void testDproduct() { - confirmFunc("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", 4, false, 189); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java deleted file mode 100644 index 5d8ccc7521..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java +++ /dev/null @@ -1,162 +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.record.formula.function; - -import java.lang.reflect.InvocationTargetException; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.RecordFormatException; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -/** - * Tests reading from a sample spreadsheet some built-in functions that were not properly - * registered in POI as of bug #44675, #44733 (March/April 2008). - * - * @author Josh Micich - */ -public final class TestReadMissingBuiltInFuncs extends TestCase { - - /** - * This spreadsheet has examples of calls to the interesting built-in functions in cells A1:A7 - */ - private static final String SAMPLE_SPREADSHEET_FILE_NAME = "missingFuncs44675.xls"; - private static HSSFSheet _sheet; - - private static HSSFSheet getSheet() { - if (_sheet == null) { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(SAMPLE_SPREADSHEET_FILE_NAME); - _sheet = wb.getSheetAt(0); - } - return _sheet; - } - - public void testDatedif() { - - String formula; - try { - formula = getCellFormula(0); - } catch (IllegalStateException e) { - if(e.getMessage().startsWith("Too few arguments")) { - if(e.getMessage().indexOf("AttrPtg") > 0) { - throw afe("tAttrVolatile not supported in FormulaParser.toFormulaString"); - } - throw afe("NOW() registered with 1 arg instead of 0"); - } - if(e.getMessage().startsWith("too much stuff")) { - throw afe("DATEDIF() not registered"); - } - // some other unexpected error - throw e; - } - assertEquals("DATEDIF(NOW(),NOW(),\"d\")", formula); - } - public void testDdb() { - - String formula = getCellFormula(1); - if("externalflag(1,1,1,1,1)".equals(formula)) { - throw afe("DDB() not registered"); - } - assertEquals("DDB(1,1,1,1,1)", formula); - } - public void testAtan() { - - String formula = getCellFormula(2); - if(formula.equals("ARCTAN(1)")) { - throw afe("func ix 18 registered as ARCTAN() instead of ATAN()"); - } - assertEquals("ATAN(1)", formula); - } - - public void testUsdollar() { - - String formula = getCellFormula(3); - if(formula.equals("YEN(1)")) { - throw afe("func ix 204 registered as YEN() instead of USDOLLAR()"); - } - assertEquals("USDOLLAR(1)", formula); - } - - public void testDBCS() { - - String formula; - try { - formula = getCellFormula(4); - } catch (IllegalStateException e) { - if(e.getMessage().startsWith("too much stuff")) { - throw afe("DBCS() not registered"); - } - // some other unexpected error - throw e; - } catch (NegativeArraySizeException e) { - throw afe("found err- DBCS() registered with -1 args"); - } - if(formula.equals("JIS(\"abc\")")) { - throw afe("func ix 215 registered as JIS() instead of DBCS()"); - } - assertEquals("DBCS(\"abc\")", formula); - } - public void testIsnontext() { - - String formula; - try { - formula = getCellFormula(5); - } catch (IllegalStateException e) { - if(e.getMessage().startsWith("too much stuff")) { - throw afe("ISNONTEXT() registered with wrong index"); - } - // some other unexpected error - throw e; - } - assertEquals("ISNONTEXT(\"abc\")", formula); - } - public void testDproduct() { - - String formula = getCellFormula(6); - assertEquals("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", formula); - } - - private String getCellFormula(int rowIx) { - HSSFSheet sheet; - try { - sheet = getSheet(); - } catch (RecordFormatException e) { - if(e.getCause() instanceof InvocationTargetException) { - InvocationTargetException ite = (InvocationTargetException) e.getCause(); - if(ite.getTargetException() instanceof RuntimeException) { - RuntimeException re = (RuntimeException) ite.getTargetException(); - if(re.getMessage().equals("Invalid built-in function index (189)")) { - throw afe("DPRODUCT() registered with wrong index"); - } - } - } - // some other unexpected error - throw e; - } - String result = sheet.getRow(rowIx).getCell(0).getCellFormula(); - if (false) { - System.err.println(result); - } - return result; - } - private static AssertionFailedError afe(String msg) { - return new AssertionFailedError(msg); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/AbstractNumericTestCase.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/AbstractNumericTestCase.java deleted file mode 100644 index ef5b3add07..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/AbstractNumericTestCase.java +++ /dev/null @@ -1,73 +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. -*/ -/* - * Created on May 29, 2005 - * - */ -package org.apache.poi.hssf.record.formula.functions; - -import junit.framework.TestCase; - -/** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * - */ -public abstract class AbstractNumericTestCase extends TestCase { - - public static final double POS_ZERO = 1E-4; - public static final double DIFF_TOLERANCE_FACTOR = 1E-8; - - public void setUp() { - } - - public void tearDown() { - } - - /** - * Why doesnt JUnit have a method like this for doubles? - * The current impl (3.8.1) of Junit has a retar*** method - * for comparing doubles. DO NOT use that. - * TODO: This class should really be in an abstract super class - * to avoid code duplication across this project. - * @param message - * @param baseval - * @param checkval - */ - public static void assertEquals(String message, double baseval, double checkval, double almostZero, double diffToleranceFactor) { - double posZero = Math.abs(almostZero); - double negZero = -1 * posZero; - if (Double.isNaN(baseval)) { - assertTrue(message+": Expected " + baseval + " but was " + checkval - , Double.isNaN(baseval)); - } - else if (Double.isInfinite(baseval)) { - assertTrue(message+": Expected " + baseval + " but was " + checkval - , Double.isInfinite(baseval) && ((baseval<0) == (checkval<0))); - } - else { - assertTrue(message+": Expected " + baseval + " but was " + checkval - ,baseval != 0 - ? Math.abs(baseval - checkval) <= Math.abs(diffToleranceFactor * baseval) - : checkval < posZero && checkval > negZero); - } - } - - public static void assertEquals(String msg, double baseval, double checkval) { - assertEquals(msg, baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR); - } - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java deleted file mode 100644 index f4b28150d4..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java +++ /dev/null @@ -1,65 +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.record.formula.functions; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * Direct tests for all implementors of Function. - * - * @author Josh Micich - */ -public final class AllIndividualFunctionEvaluationTests { - - public static Test suite() { - TestSuite result = new TestSuite(AllIndividualFunctionEvaluationTests.class.getName()); - result.addTestSuite(TestAverage.class); - result.addTestSuite(TestCountFuncs.class); - result.addTestSuite(TestDate.class); - result.addTestSuite(TestDays360.class); - result.addTestSuite(TestFinanceLib.class); - result.addTestSuite(TestFind.class); - result.addTestSuite(TestIndex.class); - result.addTestSuite(TestIndexFunctionFromSpreadsheet.class); - result.addTestSuite(TestIndirect.class); - result.addTestSuite(TestIsBlank.class); - result.addTestSuite(TestLen.class); - result.addTestSuite(TestLookupFunctionsFromSpreadsheet.class); - result.addTestSuite(TestMatch.class); - result.addTestSuite(TestMathX.class); - result.addTestSuite(TestMid.class); - result.addTestSuite(TestNper.class); - result.addTestSuite(TestOffset.class); - result.addTestSuite(TestPmt.class); - result.addTestSuite(TestRoundFuncs.class); - result.addTestSuite(TestRowCol.class); - result.addTestSuite(TestStatsLib.class); - result.addTestSuite(TestSubtotal.class); - result.addTestSuite(TestSumif.class); - result.addTestSuite(TestSumproduct.class); - result.addTestSuite(TestText.class); - result.addTestSuite(TestTFunc.class); - result.addTestSuite(TestTime.class); - result.addTestSuite(TestTrim.class); - result.addTestSuite(TestTrunc.class); - result.addTestSuite(TestValue.class); - result.addTestSuite(TestXYNumericFunction.class); - return result; - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java deleted file mode 100644 index fb2091911a..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java +++ /dev/null @@ -1,174 +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.record.formula.functions; - -import org.apache.poi.hssf.record.formula.AreaI; -import org.apache.poi.hssf.record.formula.AreaPtg; -import org.apache.poi.hssf.record.formula.Ref3DPtg; -import org.apache.poi.hssf.record.formula.RefPtg; -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.AreaEvalBase; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.RefEval; -import org.apache.poi.hssf.record.formula.eval.RefEvalBase; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.ss.formula.TwoDEval; - -/** - * Test helper class for creating mock Eval objects - * - * @author Josh Micich - */ -public final class EvalFactory { - - private EvalFactory() { - // no instances of this class - } - - /** - * Creates a dummy AreaEval - * @param values empty (null) entries in this array will be converted to NumberEval.ZERO - */ - public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) { - AreaPtg areaPtg = new AreaPtg(areaRefStr); - return createAreaEval(areaPtg, values); - } - - /** - * Creates a dummy AreaEval - * @param values empty (null) entries in this array will be converted to NumberEval.ZERO - */ - public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) { - int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1; - int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1; - int nExpected = nRows * nCols; - if (values.length != nExpected) { - throw new RuntimeException("Expected " + nExpected + " values but got " + values.length); - } - for (int i = 0; i < nExpected; i++) { - if (values[i] == null) { - values[i] = NumberEval.ZERO; - } - } - return new MockAreaEval(areaPtg, values); - } - - /** - * Creates a single RefEval (with value zero) - */ - public static RefEval createRefEval(String refStr) { - return createRefEval(refStr, NumberEval.ZERO); - } - public static RefEval createRefEval(String refStr, ValueEval value) { - return new MockRefEval(new RefPtg(refStr), value); - } - - private static final class MockAreaEval extends AreaEvalBase { - private final ValueEval[] _values; - public MockAreaEval(AreaI areaPtg, ValueEval[] values) { - super(areaPtg); - _values = values; - } - private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn, ValueEval[] values) { - super(firstRow, firstColumn, lastRow, lastColumn); - _values = values; - } - public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { - if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) { - throw new IllegalArgumentException("row index out of range"); - } - int width = getWidth(); - if (relativeColumnIndex < 0 || relativeColumnIndex >=width) { - throw new IllegalArgumentException("column index out of range"); - } - int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex; - return _values[oneDimensionalIndex]; - } - public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { - if (relFirstRowIx < 0 || relFirstColIx < 0 - || relLastRowIx >= getHeight() || relLastColIx >= getWidth()) { - throw new RuntimeException("Operation not implemented on this mock object"); - } - - if (relFirstRowIx == 0 && relFirstColIx == 0 - && relLastRowIx == getHeight()-1 && relLastColIx == getWidth()-1) { - return this; - } - ValueEval[] values = transpose(_values, getWidth(), relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); - return new MockAreaEval(getFirstRow() + relFirstRowIx, getFirstColumn() + relFirstColIx, - getFirstRow() + relLastRowIx, getFirstColumn() + relLastColIx, values); - } - private static ValueEval[] transpose(ValueEval[] srcValues, int srcWidth, - int relFirstRowIx, int relLastRowIx, - int relFirstColIx, int relLastColIx) { - int height = relLastRowIx - relFirstRowIx + 1; - int width = relLastColIx - relFirstColIx + 1; - ValueEval[] result = new ValueEval[height * width]; - for (int r=0; r= getHeight()) { - throw new IllegalArgumentException("Invalid rowIndex " + rowIndex - + ". Allowable range is (0.." + getHeight() + ")."); - } - ValueEval[] values = new ValueEval[getWidth()]; - for (int i = 0; i < values.length; i++) { - values[i] = getRelativeValue(rowIndex, i); - } - return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn(), values); - } - public TwoDEval getColumn(int columnIndex) { - if (columnIndex >= getWidth()) { - throw new IllegalArgumentException("Invalid columnIndex " + columnIndex - + ". Allowable range is (0.." + getWidth() + ")."); - } - ValueEval[] values = new ValueEval[getHeight()]; - for (int i = 0; i < values.length; i++) { - values[i] = getRelativeValue(i, columnIndex); - } - return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex, values); - } - } - - private static final class MockRefEval extends RefEvalBase { - private final ValueEval _value; - public MockRefEval(RefPtg ptg, ValueEval value) { - super(ptg.getRow(), ptg.getColumn()); - _value = value; - } - public MockRefEval(Ref3DPtg ptg, ValueEval value) { - super(ptg.getRow(), ptg.getColumn()); - _value = value; - } - public ValueEval getInnerValueEval() { - return _value; - } - public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { - throw new RuntimeException("Operation not implemented on this mock object"); - } - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java deleted file mode 100644 index 1d43923b2e..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java +++ /dev/null @@ -1,111 +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.record.formula.functions; - -import junit.framework.AssertionFailedError; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.NumericValueEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.ss.formula.eval.NotImplementedException; - -/** - * Test helper class for invoking functions with numeric results. - * - * @author Josh Micich - */ -public final class NumericFunctionInvoker { - - private NumericFunctionInvoker() { - // no instances of this class - } - - private static final class NumericEvalEx extends Exception { - public NumericEvalEx(String msg) { - super(msg); - } - } - - /** - * Invokes the specified function with the arguments. - *

- * Assumes that the cell coordinate parameters of - * Function.evaluate(args, srcCellRow, srcCellCol) - * are not required. - *

- * This method cannot be used for confirming error return codes. Any non-numeric evaluation - * result causes the current junit test to fail. - */ - public static double invoke(Function f, ValueEval[] args) { - return invoke(f, args, -1, -1); - } - /** - * Invokes the specified operator with the arguments. - *

- * This method cannot be used for confirming error return codes. Any non-numeric evaluation - * result causes the current junit test to fail. - */ - public static double invoke(Function f, ValueEval[] args, int srcCellRow, int srcCellCol) { - try { - return invokeInternal(f, args, srcCellRow, srcCellCol); - } catch (NumericEvalEx e) { - throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName() - + ") failed: " + e.getMessage()); - } - } - /** - * Formats nicer error messages for the junit output - */ - private static double invokeInternal(Function target, ValueEval[] args, int srcCellRow, int srcCellCol) - throws NumericEvalEx { - ValueEval evalResult; - try { - evalResult = target.evaluate(args, srcCellRow, (short)srcCellCol); - } catch (NotImplementedException e) { - throw new NumericEvalEx("Not implemented:" + e.getMessage()); - } - - if(evalResult == null) { - throw new NumericEvalEx("Result object was null"); - } - if(evalResult instanceof ErrorEval) { - ErrorEval ee = (ErrorEval) evalResult; - throw new NumericEvalEx(formatErrorMessage(ee)); - } - if(!(evalResult instanceof NumericValueEval)) { - throw new NumericEvalEx("Result object type (" + evalResult.getClass().getName() - + ") is invalid. Expected implementor of (" - + NumericValueEval.class.getName() + ")"); - } - - NumericValueEval result = (NumericValueEval) evalResult; - return result.getNumberValue(); - } - private static String formatErrorMessage(ErrorEval ee) { - if(errorCodesAreEqual(ee, ErrorEval.VALUE_INVALID)) { - return "Error code: #VALUE! (invalid value)"; - } - return "Error code=" + ee.getErrorCode(); - } - private static boolean errorCodesAreEqual(ErrorEval a, ErrorEval b) { - if(a==b) { - return true; - } - return a.getErrorCode() == b.getErrorCode(); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java deleted file mode 100644 index 5a4d52bb9c..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestAverage.java +++ /dev/null @@ -1,98 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -/** - * Tests for Excel function AVERAGE() - * - * @author Josh Micich - */ -public final class TestAverage extends TestCase { - - private static ValueEval invokeAverage(ValueEval[] args) { - return AggregateFunction.AVERAGE.evaluate(args, -1, (short)-1); - } - - private void confirmAverage(ValueEval[] args, double expected) { - ValueEval result = invokeAverage(args); - assertEquals(NumberEval.class, result.getClass()); - assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); - } - - private void confirmAverage(ValueEval[] args, ErrorEval expectedError) { - ValueEval result = invokeAverage(args); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); - } - - public void testBasic() { - - ValueEval[] values = { - new NumberEval(1), - new NumberEval(2), - new NumberEval(3), - new NumberEval(4), - }; - - confirmAverage(values, 2.5); - - values = new ValueEval[] { - new NumberEval(1), - new NumberEval(2), - BlankEval.instance, - new NumberEval(3), - BlankEval.instance, - new NumberEval(4), - BlankEval.instance, - }; - - confirmAverage(values, 2.5); - } - - /** - * Valid cases where values are not pure numbers - */ - public void testUnusualArgs() { - ValueEval[] values = { - new NumberEval(1), - new NumberEval(2), - BoolEval.TRUE, - BoolEval.FALSE, - }; - - confirmAverage(values, 1.0); - - } - - public void testErrors() { - ValueEval[] values = { - new NumberEval(1), - ErrorEval.NAME_INVALID, - new NumberEval(3), - ErrorEval.DIV_ZERO, - }; - confirmAverage(values, ErrorEval.NAME_INVALID); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java deleted file mode 100644 index bb3cfabe1f..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java +++ /dev/null @@ -1,460 +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.record.formula.functions; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.OperandResolver; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK() - * - * @author Josh Micich - */ -public final class TestCountFuncs extends TestCase { - - private static final String NULL = null; - - public void testCountBlank() { - - AreaEval range; - ValueEval[] values; - - values = new ValueEval[] { - new NumberEval(0), - new StringEval(""), // note - does not match blank - BoolEval.TRUE, - BoolEval.FALSE, - ErrorEval.DIV_ZERO, - BlankEval.instance, - }; - range = EvalFactory.createAreaEval("A1:B3", values); - confirmCountBlank(1, range); - - values = new ValueEval[] { - new NumberEval(0), - new StringEval(""), // note - does not match blank - BlankEval.instance, - BoolEval.FALSE, - BoolEval.TRUE, - BlankEval.instance, - }; - range = EvalFactory.createAreaEval("A1:B3", values); - confirmCountBlank(2, range); - } - - public void testCountA() { - - ValueEval[] args; - - args = new ValueEval[] { - new NumberEval(0), - }; - confirmCountA(1, args); - - args = new ValueEval[] { - new NumberEval(0), - new NumberEval(0), - new StringEval(""), - }; - confirmCountA(3, args); - - args = new ValueEval[] { - EvalFactory.createAreaEval("D2:F5", new ValueEval[12]), - }; - confirmCountA(12, args); - - args = new ValueEval[] { - EvalFactory.createAreaEval("D1:F5", new ValueEval[15]), - EvalFactory.createRefEval("A1"), - EvalFactory.createAreaEval("A1:G6", new ValueEval[42]), - new NumberEval(0), - }; - confirmCountA(59, args); - } - - public void testCountIf() { - - AreaEval range; - ValueEval[] values; - - // when criteria is a boolean value - values = new ValueEval[] { - new NumberEval(0), - new StringEval("TRUE"), // note - does not match boolean TRUE - BoolEval.TRUE, - BoolEval.FALSE, - BoolEval.TRUE, - BlankEval.instance, - }; - range = EvalFactory.createAreaEval("A1:B3", values); - confirmCountIf(2, range, BoolEval.TRUE); - - // when criteria is numeric - values = new ValueEval[] { - new NumberEval(0), - new StringEval("2"), - new StringEval("2.001"), - new NumberEval(2), - new NumberEval(2), - BoolEval.TRUE, - }; - range = EvalFactory.createAreaEval("A1:B3", values); - confirmCountIf(3, range, new NumberEval(2)); - // note - same results when criteria is a string that parses as the number with the same value - confirmCountIf(3, range, new StringEval("2.00")); - - // when criteria is an expression (starting with a comparison operator) - confirmCountIf(2, range, new StringEval(">1")); - // when criteria is an expression (starting with a comparison operator) - confirmCountIf(2, range, new StringEval(">0.5")); - } - - public void testCriteriaPredicateNe_Bug46647() { - I_MatchPredicate mp = Countif.createCriteriaPredicate(new StringEval("<>aa"), 0, 0); - StringEval seA = new StringEval("aa"); // this should not match the criteria '<>aa' - StringEval seB = new StringEval("bb"); // this should match - if (mp.matches(seA) && !mp.matches(seB)) { - throw new AssertionFailedError("Identified bug 46647"); - } - assertFalse(mp.matches(seA)); - assertTrue(mp.matches(seB)); - - // general tests for not-equal (<>) operator - AreaEval range; - ValueEval[] values; - - values = new ValueEval[] { - new StringEval("aa"), - new StringEval("def"), - new StringEval("aa"), - new StringEval("ghi"), - new StringEval("aa"), - new StringEval("aa"), - }; - - range = EvalFactory.createAreaEval("A1:A6", values); - confirmCountIf(2, range, new StringEval("<>aa")); - - values = new ValueEval[] { - new StringEval("ab"), - new StringEval("aabb"), - new StringEval("aa"), // match - new StringEval("abb"), - new StringEval("aab"), - new StringEval("ba"), // match - }; - - range = EvalFactory.createAreaEval("A1:A6", values); - confirmCountIf(2, range, new StringEval("<>a*b")); - - - values = new ValueEval[] { - new NumberEval(222), - new NumberEval(222), - new NumberEval(111), - new StringEval("aa"), - new StringEval("111"), - }; - - range = EvalFactory.createAreaEval("A1:A5", values); - confirmCountIf(4, range, new StringEval("<>111")); - } - - /** - * special case where the criteria argument is a cell reference - */ - public void testCountIfWithCriteriaReference() { - - ValueEval[] values = { - new NumberEval(22), - new NumberEval(25), - new NumberEval(21), - new NumberEval(25), - new NumberEval(25), - new NumberEval(25), - }; - AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values); - - ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25)); - ValueEval[] args= { arg0, criteriaArg, }; - - double actual = NumericFunctionInvoker.invoke(new Countif(), args); - assertEquals(4, actual, 0D); - } - - private static void confirmCountA(int expected, ValueEval[] args) { - double result = NumericFunctionInvoker.invoke(new Counta(), args); - assertEquals(expected, result, 0); - } - private static void confirmCountIf(int expected, AreaEval range, ValueEval criteria) { - - ValueEval[] args = { range, criteria, }; - double result = NumericFunctionInvoker.invoke(new Countif(), args); - assertEquals(expected, result, 0); - } - private static void confirmCountBlank(int expected, AreaEval range) { - - ValueEval[] args = { range }; - double result = NumericFunctionInvoker.invoke(new Countblank(), args); - assertEquals(expected, result, 0); - } - - private static I_MatchPredicate createCriteriaPredicate(ValueEval ev) { - return Countif.createCriteriaPredicate(ev, 0, 0); - } - - /** - * the criteria arg is mostly handled by {@link OperandResolver#getSingleValue(org.apache.poi.hssf.record.formula.eval.ValueEval, int, int)}} - */ - public void testCountifAreaCriteria() { - int srcColIx = 2; // anything but column A - - ValueEval v0 = new NumberEval(2.0); - ValueEval v1 = new StringEval("abc"); - ValueEval v2 = ErrorEval.DIV_ZERO; - - AreaEval ev = EvalFactory.createAreaEval("A10:A12", new ValueEval[] { v0, v1, v2, }); - - I_MatchPredicate mp; - mp = Countif.createCriteriaPredicate(ev, 9, srcColIx); - confirmPredicate(true, mp, srcColIx); - confirmPredicate(false, mp, "abc"); - confirmPredicate(false, mp, ErrorEval.DIV_ZERO); - - mp = Countif.createCriteriaPredicate(ev, 10, srcColIx); - confirmPredicate(false, mp, srcColIx); - confirmPredicate(true, mp, "abc"); - confirmPredicate(false, mp, ErrorEval.DIV_ZERO); - - mp = Countif.createCriteriaPredicate(ev, 11, srcColIx); - confirmPredicate(false, mp, srcColIx); - confirmPredicate(false, mp, "abc"); - confirmPredicate(true, mp, ErrorEval.DIV_ZERO); - confirmPredicate(false, mp, ErrorEval.VALUE_INVALID); - - // tricky: indexing outside of A10:A12 - // even this #VALUE! error gets used by COUNTIF as valid criteria - mp = Countif.createCriteriaPredicate(ev, 12, srcColIx); - confirmPredicate(false, mp, srcColIx); - confirmPredicate(false, mp, "abc"); - confirmPredicate(false, mp, ErrorEval.DIV_ZERO); - confirmPredicate(true, mp, ErrorEval.VALUE_INVALID); - } - - public void testCountifEmptyStringCriteria() { - I_MatchPredicate mp; - - // pred '=' matches blank cell but not empty string - mp = createCriteriaPredicate(new StringEval("=")); - confirmPredicate(false, mp, ""); - confirmPredicate(true, mp, NULL); - - // pred '' matches both blank cell but not empty string - mp = createCriteriaPredicate(new StringEval("")); - confirmPredicate(true, mp, ""); - confirmPredicate(true, mp, NULL); - - // pred '<>' matches empty string but not blank cell - mp = createCriteriaPredicate(new StringEval("<>")); - confirmPredicate(false, mp, NULL); - confirmPredicate(true, mp, ""); - } - - public void testCountifComparisons() { - I_MatchPredicate mp; - - mp = createCriteriaPredicate(new StringEval(">5")); - confirmPredicate(false, mp, 4); - confirmPredicate(false, mp, 5); - confirmPredicate(true, mp, 6); - - mp = createCriteriaPredicate(new StringEval("<=5")); - confirmPredicate(true, mp, 4); - confirmPredicate(true, mp, 5); - confirmPredicate(false, mp, 6); - confirmPredicate(false, mp, "4.9"); - confirmPredicate(false, mp, "4.9t"); - confirmPredicate(false, mp, "5.1"); - confirmPredicate(false, mp, NULL); - - mp = createCriteriaPredicate(new StringEval("=abc")); - confirmPredicate(true, mp, "abc"); - - mp = createCriteriaPredicate(new StringEval("=42")); - confirmPredicate(false, mp, 41); - confirmPredicate(true, mp, 42); - confirmPredicate(true, mp, "42"); - - mp = createCriteriaPredicate(new StringEval(">abc")); - confirmPredicate(false, mp, 4); - confirmPredicate(false, mp, "abc"); - confirmPredicate(true, mp, "abd"); - - mp = createCriteriaPredicate(new StringEval(">4t3")); - confirmPredicate(false, mp, 4); - confirmPredicate(false, mp, 500); - confirmPredicate(true, mp, "500"); - confirmPredicate(true, mp, "4t4"); - } - - /** - * the criteria arg value can be an error code (the error does not - * propagate to the COUNTIF result). - */ - public void testCountifErrorCriteria() { - I_MatchPredicate mp; - - mp = createCriteriaPredicate(new StringEval("#REF!")); - confirmPredicate(false, mp, 4); - confirmPredicate(false, mp, "#REF!"); - confirmPredicate(true, mp, ErrorEval.REF_INVALID); - - mp = createCriteriaPredicate(new StringEval("<#VALUE!")); - confirmPredicate(false, mp, 4); - confirmPredicate(false, mp, "#DIV/0!"); - confirmPredicate(false, mp, "#REF!"); - confirmPredicate(true, mp, ErrorEval.DIV_ZERO); - confirmPredicate(false, mp, ErrorEval.REF_INVALID); - - // not quite an error literal, should be treated as plain text - mp = createCriteriaPredicate(new StringEval("<=#REF!a")); - confirmPredicate(false, mp, 4); - confirmPredicate(true, mp, "#DIV/0!"); - confirmPredicate(true, mp, "#REF!"); - confirmPredicate(false, mp, ErrorEval.DIV_ZERO); - confirmPredicate(false, mp, ErrorEval.REF_INVALID); - } - - public void testWildCards() { - I_MatchPredicate mp; - - mp = createCriteriaPredicate(new StringEval("a*b")); - confirmPredicate(false, mp, "abc"); - confirmPredicate(true, mp, "ab"); - confirmPredicate(true, mp, "axxb"); - confirmPredicate(false, mp, "xab"); - - mp = createCriteriaPredicate(new StringEval("a?b")); - confirmPredicate(false, mp, "abc"); - confirmPredicate(false, mp, "ab"); - confirmPredicate(false, mp, "axxb"); - confirmPredicate(false, mp, "xab"); - confirmPredicate(true, mp, "axb"); - - mp = createCriteriaPredicate(new StringEval("a~?")); - confirmPredicate(false, mp, "a~a"); - confirmPredicate(false, mp, "a~?"); - confirmPredicate(true, mp, "a?"); - - mp = createCriteriaPredicate(new StringEval("~*a")); - confirmPredicate(false, mp, "~aa"); - confirmPredicate(false, mp, "~*a"); - confirmPredicate(true, mp, "*a"); - - mp = createCriteriaPredicate(new StringEval("12?12")); - confirmPredicate(false, mp, 12812); - confirmPredicate(true, mp, "12812"); - confirmPredicate(false, mp, "128812"); - } - public void testNotQuiteWildCards() { - I_MatchPredicate mp; - - // make sure special reg-ex chars are treated like normal chars - mp = createCriteriaPredicate(new StringEval("a.b")); - confirmPredicate(false, mp, "aab"); - confirmPredicate(true, mp, "a.b"); - - - mp = createCriteriaPredicate(new StringEval("a~b")); - confirmPredicate(false, mp, "ab"); - confirmPredicate(false, mp, "axb"); - confirmPredicate(false, mp, "a~~b"); - confirmPredicate(true, mp, "a~b"); - - mp = createCriteriaPredicate(new StringEval(">a*b")); - confirmPredicate(false, mp, "a(b"); - confirmPredicate(true, mp, "aab"); - confirmPredicate(false, mp, "a*a"); - confirmPredicate(true, mp, "a*c"); - } - - private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, int value) { - assertEquals(expectedResult, matchPredicate.matches(new NumberEval(value))); - } - private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, String value) { - ValueEval ev = value == null ? BlankEval.instance : new StringEval(value); - assertEquals(expectedResult, matchPredicate.matches(ev)); - } - private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, ErrorEval value) { - assertEquals(expectedResult, matchPredicate.matches(value)); - } - - public void testCountifFromSpreadsheet() { - testCountFunctionFromSpreadsheet("countifExamples.xls", 1, 2, 3, "countif"); - } - - public void testCountBlankFromSpreadsheet() { - testCountFunctionFromSpreadsheet("countblankExamples.xls", 1, 3, 4, "countblank"); - } - - private static void testCountFunctionFromSpreadsheet(String FILE_NAME, int START_ROW_IX, int COL_IX_ACTUAL, int COL_IX_EXPECTED, String functionName) { - - int failureCount = 0; - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME); - HSSFSheet sheet = wb.getSheetAt(0); - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - int maxRow = sheet.getLastRowNum(); - for (int rowIx=START_ROW_IX; rowIx 0) { - throw new AssertionFailedError(failureCount + " " + functionName - + " evaluations failed. See stderr for more details"); - } - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java deleted file mode 100644 index eac8bfd113..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java +++ /dev/null @@ -1,90 +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.record.formula.functions; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * @author Pavel Krupets (pkrupets at palmtreebusiness dot com) - */ -public final class TestDate extends TestCase { - - private HSSFCell cell11; - private HSSFFormulaEvaluator evaluator; - - public void setUp() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("new sheet"); - cell11 = sheet.createRow(0).createCell(0); - cell11.setCellType(HSSFCell.CELL_TYPE_FORMULA); - evaluator = new HSSFFormulaEvaluator(wb); - } - - /** - * Test disabled pending a fix in the formula evaluator - * TODO - create MissingArgEval and modify the formula evaluator to handle this - */ - public void DISABLEDtestSomeArgumentsMissing() { - confirm("DATE(, 1, 0)", 0.0); - confirm("DATE(, 1, 1)", 1.0); - } - - public void testValid() { - - confirm("DATE(1900, 1, 1)", 1); - confirm("DATE(1900, 1, 32)", 32); - confirm("DATE(1900, 222, 1)", 6727); - confirm("DATE(1900, 2, 0)", 31); - confirm("DATE(2000, 1, 222)", 36747.00); - confirm("DATE(2007, 1, 1)", 39083); - } - - public void testBugDate() { - confirm("DATE(1900, 2, 29)", 60); - confirm("DATE(1900, 2, 30)", 61); - confirm("DATE(1900, 1, 222)", 222); - confirm("DATE(1900, 1, 2222)", 2222); - confirm("DATE(1900, 1, 22222)", 22222); - } - - public void testPartYears() { - confirm("DATE(4, 1, 1)", 1462.00); - confirm("DATE(14, 1, 1)", 5115.00); - confirm("DATE(104, 1, 1)", 37987.00); - confirm("DATE(1004, 1, 1)", 366705.00); - } - - private void confirm(String formulaText, double expectedResult) { - cell11.setCellFormula(formulaText); - evaluator.clearAllCachedResultValues(); - CellValue cv = evaluator.evaluate(cell11); - if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) { - throw new AssertionFailedError("Wrong result type: " + cv.formatAsString()); - } - double actualValue = cv.getNumberValue(); - assertEquals(expectedResult, actualValue, 0); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDays360.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDays360.java deleted file mode 100644 index e517ac9b62..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDays360.java +++ /dev/null @@ -1,155 +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.record.formula.functions; - -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.BoolEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; - -/** - * @author Josh Micich - */ -public final class TestDays360 extends TestCase { - - /** - * @param month 1-based - */ - private static Date makeDate(int year, int month, int day) { - - Calendar cal = new GregorianCalendar(year, month-1, day, 0, 0, 0); - cal.set(Calendar.MILLISECOND, 0); - return cal.getTime(); - } - private static Date decrementDay(Date d) { - Calendar c = new GregorianCalendar(); - c.setTimeInMillis(d.getTime()); - c.add(Calendar.DAY_OF_MONTH, -1); - return c.getTime(); - } - private static String fmt(Date d) { - Calendar c = new GregorianCalendar(); - c.setTimeInMillis(d.getTime()); - StringBuilder sb = new StringBuilder(); - sb.append(c.get(Calendar.YEAR)); - sb.append("/"); - sb.append(c.get(Calendar.MONTH)+1); - sb.append("/"); - sb.append(c.get(Calendar.DAY_OF_MONTH)); - return sb.toString(); - } - - - public void testBasic() { - confirm(120, 2009, 1, 15, 2009, 5, 15); - confirm(158, 2009, 1, 26, 2009, 7, 4); - - // same results in leap years - confirm(120, 2008, 1, 15, 2008, 5, 15); - confirm(158, 2008, 1, 26, 2008, 7, 4); - - // longer time spans - confirm(562, 2008, 8, 11, 2010, 3, 3); - confirm(916, 2007, 2, 23, 2009, 9, 9); - } - - private static void confirm(int expResult, int y1, int m1, int d1, int y2, int m2, int d2) { - confirm(expResult, makeDate(y1, m1, d1), makeDate(y2, m2, d2), false); - confirm(-expResult, makeDate(y2, m2, d2), makeDate(y1, m1, d1), false); - - } - /** - * The method parameter only makes a difference when the second parameter - * is the last day of the month that does not have 30 days. - */ - public void DISABLED_testMonthBoundaries() { - // jan - confirmMonthBoundary(false, 1, 0, 0, 2, 3, 4); - confirmMonthBoundary(true, 1, 0, 0, 1, 3, 4); - // feb - confirmMonthBoundary(false, 2,-2, 1, 2, 3, 4); - confirmMonthBoundary(true, 2, 0, 1, 2, 3, 4); - // mar - confirmMonthBoundary(false, 3, 0, 0, 2, 3, 4); - confirmMonthBoundary(true, 3, 0, 0, 1, 3, 4); - // apr - confirmMonthBoundary(false, 4, 0, 1, 2, 3, 4); - confirmMonthBoundary(true, 4, 0, 1, 2, 3, 4); - // may - confirmMonthBoundary(false, 5, 0, 0, 2, 3, 4); - confirmMonthBoundary(true, 5, 0, 0, 1, 3, 4); - // jun - confirmMonthBoundary(false, 6, 0, 1, 2, 3, 4); - confirmMonthBoundary(true, 6, 0, 1, 2, 3, 4); - // etc... - } - - - /** - * @param monthNo 1-based - * @param diffs - */ - private static void confirmMonthBoundary(boolean method, int monthNo, int...diffs) { - Date firstDayOfNextMonth = makeDate(2001, monthNo+1, 1); - Date secondArg = decrementDay(firstDayOfNextMonth); - Date firstArg = secondArg; - - for (int i = 0; i < diffs.length; i++) { - int expResult = diffs[i]; - confirm(expResult, firstArg, secondArg, method); - firstArg = decrementDay(firstArg); - } - - } - private static void confirm(int expResult, Date firstArg, Date secondArg, boolean method) { - - ValueEval ve; - if (method) { - // TODO enable 3rd arg - - ve = invokeDays360(convert(firstArg), convert(secondArg), BoolEval.valueOf(method)); - } else { - ve = invokeDays360(convert(firstArg), convert(secondArg)); - } - if (ve instanceof NumberEval) { - - NumberEval numberEval = (NumberEval) ve; - if (numberEval.getNumberValue() != expResult) { - throw new AssertionFailedError(fmt(firstArg) + " " + fmt(secondArg) + " " + method + - " wrong result got (" + numberEval.getNumberValue() - + ") but expected (" + expResult + ")"); - } - // System.err.println(fmt(firstArg) + " " + fmt(secondArg) + " " + method + " success got (" + expResult + ")"); - return; - } - throw new AssertionFailedError("wrong return type (" + ve.getClass().getName() + ")"); - } - private static ValueEval invokeDays360(ValueEval...args) { - return new Days360().evaluate(args, -1, -1); - } - private static NumberEval convert(Date d) { - return new NumberEval(HSSFDateUtil.getExcelDate(d)); - } -} - diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFinanceLib.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFinanceLib.java deleted file mode 100644 index 4dfe1fbb52..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFinanceLib.java +++ /dev/null @@ -1,202 +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. -*/ -/* - * Created on May 23, 2005 - * - */ -package org.apache.poi.hssf.record.formula.functions; - - -/** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * - */ -public class TestFinanceLib extends AbstractNumericTestCase { - - public void testFv() { - double f, r, y, p, x; - int n; - boolean t = false; - - r = 0; n = 3; y = 2; p = 7; t = true; - f = FinanceLib.fv(r, n, y, p, t); - x = -13; - assertEquals("fv ", x, f); - - r = 1; n = 10; y = 100; p = 10000; t = false; - f = FinanceLib.fv(r, n, y, p, t); - x = -10342300; - assertEquals("fv ", x, f); - - r = 1; n = 10; y = 100; p = 10000; t = true; - f = FinanceLib.fv(r, n, y, p, t); - x = -10444600; - assertEquals("fv ", x, f); - - r = 2; n = 12; y = 120; p = 12000; t = false; - f = FinanceLib.fv(r, n, y, p, t); - x = -6409178400d; - assertEquals("fv ", x, f); - - r = 2; n = 12; y = 120; p = 12000; t = true; - f = FinanceLib.fv(r, n, y, p, t); - x = -6472951200d; - assertEquals("fv ", x, f); - - // cross tests with pv - r = 2.95; n = 13; y = 13000; p = -4406.78544294496; t = false; - f = FinanceLib.fv(r, n, y, p, t); - x = 333891.230010986; // as returned by excel - assertEquals("fv ", x, f); - - r = 2.95; n = 13; y = 13000; p = -17406.7852148156; t = true; - f = FinanceLib.fv(r, n, y, p, t); - x = 333891.230102539; // as returned by excel - assertEquals("fv ", x, f); - - } - public void testNpv() { - double r, v[], npv, x; - - r = 1; v = new double[]{100, 200, 300, 400}; - npv = FinanceLib.npv(r, v); - x = 162.5; - assertEquals("npv ", x, npv); - - r = 2.5; v = new double[]{1000, 666.66666, 333.33, 12.2768416}; - npv = FinanceLib.npv(r, v); - x = 347.99232604144827; - assertEquals("npv ", x, npv); - - r = 12.33333; v = new double[]{1000, 0, -900, -7777.5765}; - npv = FinanceLib.npv(r, v); - x = 74.3742433377061; - assertEquals("npv ", x, npv); - - r = 0.05; v = new double[]{200000, 300000.55, 400000, 1000000, 6000000, 7000000, -300000}; - npv = FinanceLib.npv(r, v); - x = 11342283.4233124; - assertEquals("npv ", x, npv); - } - public void testPmt() { - double f, r, y, p, x; - int n; - boolean t = false; - - r = 0; n = 3; p = 2; f = 7; t = true; - y = FinanceLib.pmt(r, n, p, f, t); - x = -3; - assertEquals("pmt ", x, y); - - // cross check with pv - r = 1; n = 10; p = -109.66796875; f = 10000; t = false; - y = FinanceLib.pmt(r, n, p, f, t); - x = 100; - assertEquals("pmt ", x, y); - - r = 1; n = 10; p = -209.5703125; f = 10000; t = true; - y = FinanceLib.pmt(r, n, p, f, t); - x = 100; - assertEquals("pmt ", x, y); - - // cross check with fv - r = 2; n = 12; f = -6409178400d; p = 12000; t = false; - y = FinanceLib.pmt(r, n, p, f, t); - x = 120; - assertEquals("pmt ", x, y); - - r = 2; n = 12; f = -6472951200d; p = 12000; t = true; - y = FinanceLib.pmt(r, n, p, f, t); - x = 120; - assertEquals("pmt ", x, y); - } - - public void testPv() { - double f, r, y, p, x; - int n; - boolean t = false; - - r = 0; n = 3; y = 2; f = 7; t = true; - f = FinanceLib.pv(r, n, y, f, t); - x = -13; - assertEquals("pv ", x, f); - - r = 1; n = 10; y = 100; f = 10000; t = false; - p = FinanceLib.pv(r, n, y, f, t); - x = -109.66796875; - assertEquals("pv ", x, p); - - r = 1; n = 10; y = 100; f = 10000; t = true; - p = FinanceLib.pv(r, n, y, f, t); - x = -209.5703125; - assertEquals("pv ", x, p); - - r = 2.95; n = 13; y = 13000; f = 333891.23; t = false; - p = FinanceLib.pv(r, n, y, f, t); - x = -4406.78544294496; - assertEquals("pv ", x, p); - - r = 2.95; n = 13; y = 13000; f = 333891.23; t = true; - p = FinanceLib.pv(r, n, y, f, t); - x = -17406.7852148156; - assertEquals("pv ", x, p); - - // cross tests with fv - r = 2; n = 12; y = 120; f = -6409178400d; t = false; - p = FinanceLib.pv(r, n, y, f, t); - x = 12000; - assertEquals("pv ", x, p); - - r = 2; n = 12; y = 120; f = -6472951200d; t = true; - p = FinanceLib.pv(r, n, y, f, t); - x = 12000; - assertEquals("pv ", x, p); - - } - - public void testNper() { - double f, r, y, p, x, n; - boolean t = false; - - r = 0; y = 7; p = 2; f = 3; t = false; - n = FinanceLib.nper(r, y, p, f, t); - x = -0.71428571429; // can you believe it? excel returns nper as a fraction!?? - assertEquals("nper ", x, n); - - // cross check with pv - r = 1; y = 100; p = -109.66796875; f = 10000; t = false; - n = FinanceLib.nper(r, y, p, f, t); - x = 10; - assertEquals("nper ", x, n); - - r = 1; y = 100; p = -209.5703125; f = 10000; t = true; - n = FinanceLib.nper(r, y, p, f, t); - x = 10; - assertEquals("nper ", x, n); - - // cross check with fv - r = 2; y = 120; f = -6409178400d; p = 12000; t = false; - n = FinanceLib.nper(r, y, p, f, t); - x = 12; - assertEquals("nper ", x, n); - - r = 2; y = 120; f = -6472951200d; p = 12000; t = true; - n = FinanceLib.nper(r, y, p, f, t); - x = 12; - assertEquals("nper ", x, n); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java deleted file mode 100644 index 8fb3b2ba95..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java +++ /dev/null @@ -1,76 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFErrorConstants; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Tests for {@link Financed} - * - * @author Torstein Svendsen (torstei@officenet.no) - */ -public final class TestFind extends TestCase { - - public void testFind() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFCell cell = wb.createSheet().createRow(0).createCell(0); - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - - confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1); - confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2); - confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6); - - // number args converted to text - confirmResult(fe, cell, "find(7, 32768)", 3); - confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10); - confirmResult(fe, cell, "find(5, 87654)", 4); - - // Errors - confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE); - confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE); - confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF); - confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE); - confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0); - confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA); - } - - private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, - int expectedResult) { - cell.setCellFormula(formulaText); - fe.notifyUpdateCell(cell); - CellValue result = fe.evaluate(cell); - assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC); - assertEquals(expectedResult, result.getNumberValue(), 0.0); - } - - private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, - int expectedErrorCode) { - cell.setCellFormula(formulaText); - fe.notifyUpdateCell(cell); - CellValue result = fe.evaluate(cell); - assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR); - assertEquals(expectedErrorCode, result.getErrorValue()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java deleted file mode 100644 index a6ae6efafa..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java +++ /dev/null @@ -1,157 +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.record.formula.functions; - -import java.util.Arrays; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.MissingArgEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.ss.formula.WorkbookEvaluator; -import org.apache.poi.ss.util.CellRangeAddress; - -/** - * Tests for the INDEX() function.

- * - * This class contains just a few specific cases that directly invoke {@link Index}, - * with minimum overhead.
- * Another test: {@link TestIndexFunctionFromSpreadsheet} operates from a higher level - * and has far greater coverage of input permutations.
- * - * @author Josh Micich - */ -public final class TestIndex extends TestCase { - - private static final Index FUNC_INST = new Index(); - private static final double[] TEST_VALUES0 = { - 1, 2, - 3, 4, - 5, 6, - 7, 8, - 9, 10, - 11, 12, - }; - - /** - * For the case when the first argument to INDEX() is an area reference - */ - public void testEvaluateAreaReference() { - - double[] values = TEST_VALUES0; - confirmAreaEval("C1:D6", values, 4, 1, 7); - confirmAreaEval("C1:D6", values, 6, 2, 12); - confirmAreaEval("C1:D6", values, 3, 1, 5); - - // now treat same data as 3 columns, 4 rows - confirmAreaEval("C10:E13", values, 2, 2, 5); - confirmAreaEval("C10:E13", values, 4, 1, 10); - } - - /** - * @param areaRefString in Excel notation e.g. 'D2:E97' - * @param dValues array of evaluated values for the area reference - * @param rowNum 1-based - * @param colNum 1-based, pass -1 to signify argument not present - */ - private static void confirmAreaEval(String areaRefString, double[] dValues, - int rowNum, int colNum, double expectedResult) { - ValueEval[] values = new ValueEval[dValues.length]; - for (int i = 0; i < values.length; i++) { - values[i] = new NumberEval(dValues[i]); - } - AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values); - - ValueEval[] args; - if (colNum > 0) { - args = new ValueEval[] { arg0, new NumberEval(rowNum), new NumberEval(colNum), }; - } else { - args = new ValueEval[] { arg0, new NumberEval(rowNum), }; - } - - double actual = invokeAndDereference(args); - assertEquals(expectedResult, actual, 0D); - } - - private static double invokeAndDereference(ValueEval[] args) { - ValueEval ve = FUNC_INST.evaluate(args, -1, -1); - ve = WorkbookEvaluator.dereferenceResult(ve, -1, -1); - assertEquals(NumberEval.class, ve.getClass()); - return ((NumberEval)ve).getNumberValue(); - } - - /** - * Tests expressions like "INDEX(A1:C1,,2)".
- * This problem was found while fixing bug 47048 and is observable up to svn r773441. - */ - public void testMissingArg() { - ValueEval[] values = { - new NumberEval(25.0), - new NumberEval(26.0), - new NumberEval(28.0), - }; - AreaEval arg0 = EvalFactory.createAreaEval("A10:C10", values); - ValueEval[] args = new ValueEval[] { arg0, MissingArgEval.instance, new NumberEval(2), }; - ValueEval actualResult; - try { - actualResult = FUNC_INST.evaluate(args, -1, -1); - } catch (RuntimeException e) { - if (e.getMessage().equals("Unexpected arg eval type (org.apache.poi.hssf.record.formula.eval.MissingArgEval")) { - throw new AssertionFailedError("Identified bug 47048b - INDEX() should support missing-arg"); - } - throw e; - } - // result should be an area eval "B10:B10" - AreaEval ae = confirmAreaEval("B10:B10", actualResult); - actualResult = ae.getValue(0, 0); - assertEquals(NumberEval.class, actualResult.getClass()); - assertEquals(26.0, ((NumberEval)actualResult).getNumberValue(), 0.0); - } - - /** - * When the argument to INDEX is a reference, the result should be a reference - * A formula like "OFFSET(INDEX(A1:B2,2,1),1,1,1,1)" should return the value of cell B3. - * This works because the INDEX() function returns a reference to A2 (not the value of A2) - */ - public void testReferenceResult() { - ValueEval[] values = new ValueEval[4]; - Arrays.fill(values, NumberEval.ZERO); - AreaEval arg0 = EvalFactory.createAreaEval("A1:B2", values); - ValueEval[] args = new ValueEval[] { arg0, new NumberEval(2), new NumberEval(1), }; - ValueEval ve = FUNC_INST.evaluate(args, -1, -1); - confirmAreaEval("A2:A2", ve); - } - - /** - * Confirms that the result is an area ref with the specified coordinates - * @return ve cast to {@link AreaEval} if it is valid - */ - private static AreaEval confirmAreaEval(String refText, ValueEval ve) { - CellRangeAddress cra = CellRangeAddress.valueOf(refText); - assertTrue(ve instanceof AreaEval); - AreaEval ae = (AreaEval) ve; - assertEquals(cra.getFirstRow(), ae.getFirstRow()); - assertEquals(cra.getFirstColumn(), ae.getFirstColumn()); - assertEquals(cra.getLastRow(), ae.getLastRow()); - assertEquals(cra.getLastColumn(), ae.getLastColumn()); - return ae; - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java deleted file mode 100644 index ffd841f823..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndexFunctionFromSpreadsheet.java +++ /dev/null @@ -1,250 +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.record.formula.functions; - -import java.io.PrintStream; - -import junit.framework.Assert; -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.util.CellReference; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Tests INDEX() as loaded from a test data spreadsheet.

- * - * @author Josh Micich - */ -public final class TestIndexFunctionFromSpreadsheet extends TestCase { - - private static final class Result { - public static final int SOME_EVALUATIONS_FAILED = -1; - public static final int ALL_EVALUATIONS_SUCCEEDED = +1; - public static final int NO_EVALUATIONS_FOUND = 0; - } - - /** - * This class defines constants for navigating around the test data spreadsheet used for these tests. - */ - private static final class SS { - - /** Name of the test spreadsheet (found in the standard test data folder) */ - public final static String FILENAME = "IndexFunctionTestCaseData.xls"; - - public static final int COLUMN_INDEX_EVALUATION = 2; // Column 'C' - public static final int COLUMN_INDEX_EXPECTED_RESULT = 3; // Column 'D' - - } - - // Note - multiple failures are aggregated before ending. - // If one or more functions fail, a single AssertionFailedError is thrown at the end - private int _evaluationFailureCount; - private int _evaluationSuccessCount; - - - - private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) { - if (expected == null) { - throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); - } - if(actual == null) { - throw new AssertionFailedError(msg + " - actual value was null"); - } - if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) { - confirmErrorResult(msg, expected.getErrorCellValue(), actual); - return; - } - if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) { - throw unexpectedError(msg, expected, actual.getErrorValue()); - } - if(actual.getCellType() != expected.getCellType()) { - throw wrongTypeError(msg, expected, actual); - } - - - switch (expected.getCellType()) { - case HSSFCell.CELL_TYPE_BOOLEAN: - assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); - break; - case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation - throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg); - case HSSFCell.CELL_TYPE_NUMERIC: - assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), 0.0); - break; - case HSSFCell.CELL_TYPE_STRING: - assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); - break; - } - } - - - private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) { - return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was " - + actualValue.formatAsString() - + " but the expected result was " - + formatValue(expectedCell) - ); - } - private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) { - return new AssertionFailedError(msgPrefix + " Error code (" - + ErrorEval.getText(actualErrorCode) - + ") was evaluated, but the expected result was " - + formatValue(expected) - ); - } - - - private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) { - if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) { - throw new AssertionFailedError(msgPrefix + " Expected cell error (" - + ErrorEval.getText(expectedErrorCode) + ") but actual value was " - + actual.formatAsString()); - } - if(expectedErrorCode != actual.getErrorValue()) { - throw new AssertionFailedError(msgPrefix + " Expected cell error code (" - + ErrorEval.getText(expectedErrorCode) - + ") but actual error code was (" - + ErrorEval.getText(actual.getErrorValue()) - + ")"); - } - } - - - private static String formatValue(HSSFCell expecedCell) { - switch (expecedCell.getCellType()) { - case HSSFCell.CELL_TYPE_BLANK: return ""; - case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue()); - case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue()); - case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString(); - } - throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")"); - } - - - protected void setUp() { - _evaluationFailureCount = 0; - _evaluationSuccessCount = 0; - } - - public void testFunctionsFromTestSpreadsheet() { - HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); - - processTestSheet(workbook, workbook.getSheetName(0)); - - // confirm results - String successMsg = "There were " - + _evaluationSuccessCount + " function(s) without error"; - if(_evaluationFailureCount > 0) { - String msg = _evaluationFailureCount + " evaluation(s) failed. " + successMsg; - throw new AssertionFailedError(msg); - } - if(false) { // normally no output for successful tests - System.out.println(getClass().getName() + ": " + successMsg); - } - } - - private void processTestSheet(HSSFWorkbook workbook, String sheetName) { - HSSFSheet sheet = workbook.getSheetAt(0); - HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); - int maxRows = sheet.getLastRowNum()+1; - int result = Result.NO_EVALUATIONS_FOUND; // so far - - for(int rowIndex=0; rowIndex= endIx) { - // something went wrong. just print the whole stack trace - e.printStackTrace(ps); - } - endIx -= 4; // skip 4 frames of reflection invocation - ps.println(e.toString()); - for(int i=startIx; i - * - * @author Josh Micich - */ -public final class TestIndirect extends TestCase { - // convenient access to namespace - private static final ErrorEval EE = null; - - private static void createDataRow(HSSFSheet sheet, int rowIndex, double... vals) { - HSSFRow row = sheet.createRow(rowIndex); - for (int i = 0; i < vals.length; i++) { - row.createCell(i).setCellValue(vals[i]); - } - } - - private static HSSFWorkbook createWBA() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet1 = wb.createSheet("Sheet1"); - HSSFSheet sheet2 = wb.createSheet("Sheet2"); - HSSFSheet sheet3 = wb.createSheet("John's sales"); - - createDataRow(sheet1, 0, 11, 12, 13, 14); - createDataRow(sheet1, 1, 21, 22, 23, 24); - createDataRow(sheet1, 2, 31, 32, 33, 34); - - createDataRow(sheet2, 0, 50, 55, 60, 65); - createDataRow(sheet2, 1, 51, 56, 61, 66); - createDataRow(sheet2, 2, 52, 57, 62, 67); - - createDataRow(sheet3, 0, 30, 31, 32); - createDataRow(sheet3, 1, 33, 34, 35); - - HSSFName name1 = wb.createName(); - name1.setNameName("sales1"); - name1.setRefersToFormula("Sheet1!A1:D1"); - - HSSFName name2 = wb.createName(); - name2.setNameName("sales2"); - name2.setRefersToFormula("Sheet2!B1:C3"); - - HSSFRow row = sheet1.createRow(3); - row.createCell(0).setCellValue("sales1"); //A4 - row.createCell(1).setCellValue("sales2"); //B4 - - return wb; - } - - private static HSSFWorkbook createWBB() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet1 = wb.createSheet("Sheet1"); - HSSFSheet sheet2 = wb.createSheet("Sheet2"); - HSSFSheet sheet3 = wb.createSheet("## Look here!"); - - createDataRow(sheet1, 0, 400, 440, 480, 520); - createDataRow(sheet1, 1, 420, 460, 500, 540); - - createDataRow(sheet2, 0, 50, 55, 60, 65); - createDataRow(sheet2, 1, 51, 56, 61, 66); - - createDataRow(sheet3, 0, 42); - - return wb; - } - - public void testBasic() { - - HSSFWorkbook wbA = createWBA(); - HSSFCell c = wbA.getSheetAt(0).createRow(5).createCell(2); - HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA); - - // non-error cases - confirm(feA, c, "INDIRECT(\"C2\")", 23); - confirm(feA, c, "INDIRECT(\"$C2\")", 23); - confirm(feA, c, "INDIRECT(\"C$2\")", 23); - confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref - confirm(feA, c, "SUM(INDIRECT(\"Sheet2! B1 : C3 \"))", 351); // spaces in area ref - confirm(feA, c, "SUM(INDIRECT(\"'John''s sales'!A1:C1\"))", 93); // special chars in sheet name - confirm(feA, c, "INDIRECT(\"'Sheet1'!B3\")", 32); // redundant sheet name quotes - confirm(feA, c, "INDIRECT(\"sHeet1!B3\")", 32); // case-insensitive sheet name - confirm(feA, c, "INDIRECT(\" D3 \")", 34); // spaces around cell ref - confirm(feA, c, "INDIRECT(\"Sheet1! D3 \")", 34); // spaces around cell ref - confirm(feA, c, "INDIRECT(\"A1\", TRUE)", 11); // explicit arg1. only TRUE supported so far - - confirm(feA, c, "INDIRECT(\"A1:G1\")", 13); // de-reference area ref (note formula is in C4) - - confirm(feA, c, "SUM(INDIRECT(A4))", 50); // indirect defined name - confirm(feA, c, "SUM(INDIRECT(B4))", 351); // indirect defined name pointinh to other sheet - - // simple error propagation: - - // arg0 is evaluated to text first - confirm(feA, c, "INDIRECT(#DIV/0!)", EE.DIV_ZERO); - confirm(feA, c, "INDIRECT(#DIV/0!)", EE.DIV_ZERO); - confirm(feA, c, "INDIRECT(#NAME?, \"x\")", EE.NAME_INVALID); - confirm(feA, c, "INDIRECT(#NUM!, #N/A)", EE.NUM_ERROR); - - // arg1 is evaluated to boolean before arg0 is decoded - confirm(feA, c, "INDIRECT(\"garbage\", #N/A)", EE.NA); - confirm(feA, c, "INDIRECT(\"garbage\", \"\")", EE.VALUE_INVALID); // empty string is not valid boolean - confirm(feA, c, "INDIRECT(\"garbage\", \"flase\")", EE.VALUE_INVALID); // must be "TRUE" or "FALSE" - - - // spaces around sheet name (with or without quotes makes no difference) - confirm(feA, c, "INDIRECT(\"'Sheet1 '!D3\")", EE.REF_INVALID); - confirm(feA, c, "INDIRECT(\" Sheet1!D3\")", EE.REF_INVALID); - confirm(feA, c, "INDIRECT(\"'Sheet1' !D3\")", EE.REF_INVALID); - - - confirm(feA, c, "SUM(INDIRECT(\"'John's sales'!A1:C1\"))", EE.REF_INVALID); // bad quote escaping - confirm(feA, c, "INDIRECT(\"[Book1]Sheet1!A1\")", EE.REF_INVALID); // unknown external workbook - confirm(feA, c, "INDIRECT(\"Sheet3!A1\")", EE.REF_INVALID); // unknown sheet - if (false) { // TODO - support evaluation of defined names - confirm(feA, c, "INDIRECT(\"Sheet1!IW1\")", EE.REF_INVALID); // bad column - confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", EE.REF_INVALID); // bad row - } - confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", EE.REF_INVALID); // space in cell ref - } - - public void testMultipleWorkbooks() { - HSSFWorkbook wbA = createWBA(); - HSSFCell cellA = wbA.getSheetAt(0).createRow(10).createCell(0); - HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA); - - HSSFWorkbook wbB = createWBB(); - HSSFCell cellB = wbB.getSheetAt(0).createRow(10).createCell(0); - HSSFFormulaEvaluator feB = new HSSFFormulaEvaluator(wbB); - - String[] workbookNames = { "MyBook", "Figures for January", }; - HSSFFormulaEvaluator[] evaluators = { feA, feB, }; - HSSFFormulaEvaluator.setupEnvironment(workbookNames, evaluators); - - confirm(feB, cellB, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // same wb - confirm(feA, cellA, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // across workbooks - - // 2 level recursion - confirm(feB, cellB, "INDIRECT(\"[MyBook]Sheet2!A1\")", 50); // set up (and check) first level - confirm(feA, cellA, "INDIRECT(\"'[Figures for January]Sheet1'!A11\")", 50); // points to cellB - } - - private static void confirm(FormulaEvaluator fe, Cell cell, String formula, - double expectedResult) { - fe.clearAllCachedResultValues(); - cell.setCellFormula(formula); - CellValue cv = fe.evaluate(cell); - if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) { - throw new AssertionFailedError("expected numeric cell type but got " + cv.formatAsString()); - } - assertEquals(expectedResult, cv.getNumberValue(), 0.0); - } - private static void confirm(FormulaEvaluator fe, Cell cell, String formula, - ErrorEval expectedResult) { - fe.clearAllCachedResultValues(); - cell.setCellFormula(formula); - CellValue cv = fe.evaluate(cell); - if (cv.getCellType() != Cell.CELL_TYPE_ERROR) { - throw new AssertionFailedError("expected error cell type but got " + cv.formatAsString()); - } - int expCode = expectedResult.getErrorCode(); - if (cv.getErrorValue() != expCode) { - throw new AssertionFailedError("Expected error '" + EE.getText(expCode) - + "' but got '" + cv.formatAsString() + "'."); - } - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java deleted file mode 100644 index 5168cd9224..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java +++ /dev/null @@ -1,58 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.CellValue; -/** - * Tests for Excel function ISBLANK() - * - * @author Josh Micich - */ -public final class TestIsBlank extends TestCase { - - public void test3DArea() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet1 = wb.createSheet(); - wb.setSheetName(0, "Sheet1"); - wb.createSheet(); - wb.setSheetName(1, "Sheet2"); - HSSFRow row = sheet1.createRow(0); - HSSFCell cell = row.createCell(0); - - - cell.setCellFormula("isblank(Sheet2!A1:A1)"); - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - CellValue result = fe.evaluate(cell); - assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, result.getCellType()); - assertEquals(true, result.getBooleanValue()); - - cell.setCellFormula("isblank(D7:D7)"); - - result = fe.evaluate(cell); - assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, result.getCellType()); - assertEquals(true, result.getBooleanValue()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLeftRight.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLeftRight.java deleted file mode 100644 index 055e493680..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLeftRight.java +++ /dev/null @@ -1,73 +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.record.formula.functions; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -import junit.framework.TestCase; - -/** - * - * Test cases for {@link TextFunction#LEFT} and {@link TextFunction#RIGHT} - * - * @author Brendan Nolan - * - */ -public class TestLeftRight extends TestCase { - - private static final NumberEval NEGATIVE_OPERAND = new NumberEval(-1.0); - private static final StringEval ANY_STRING_VALUE = new StringEval("ANYSTRINGVALUE"); - - - private static ValueEval invokeLeft(ValueEval text, ValueEval operand) { - ValueEval[] args = new ValueEval[] { text, operand }; - return TextFunction.LEFT.evaluate(args, -1, (short)-1); - } - - private static ValueEval invokeRight(ValueEval text, ValueEval operand) { - ValueEval[] args = new ValueEval[] { text, operand }; - return TextFunction.RIGHT.evaluate(args, -1, (short)-1); - } - - public void testLeftRight_bug49841() { - - try { - invokeLeft(ANY_STRING_VALUE, NEGATIVE_OPERAND); - invokeRight(ANY_STRING_VALUE, NEGATIVE_OPERAND); - } catch (StringIndexOutOfBoundsException e) { - fail("Identified bug 49841"); - } - - } - - public void testLeftRightNegativeOperand() { - - assertEquals(ErrorEval.VALUE_INVALID, invokeRight(ANY_STRING_VALUE, NEGATIVE_OPERAND)); - assertEquals(ErrorEval.VALUE_INVALID, invokeLeft(ANY_STRING_VALUE, NEGATIVE_OPERAND)); - - } - - - - - - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java deleted file mode 100644 index be9c55ac6d..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java +++ /dev/null @@ -1,72 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -/** - * Tests for Excel function LEN() - * - * @author Josh Micich - */ -public final class TestLen extends TestCase { - - private static ValueEval invokeLen(ValueEval text) { - ValueEval[] args = new ValueEval[] { text, }; - return TextFunction.LEN.evaluate(args, -1, (short)-1); - } - - private void confirmLen(ValueEval text, int expected) { - ValueEval result = invokeLen(text); - assertEquals(NumberEval.class, result.getClass()); - assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); - } - - private void confirmLen(ValueEval text, ErrorEval expectedError) { - ValueEval result = invokeLen(text); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); - } - - public void testBasic() { - - confirmLen(new StringEval("galactic"), 8); - } - - /** - * Valid cases where text arg is not exactly a string - */ - public void testUnusualArgs() { - - // text (first) arg type is number, other args are strings with fractional digits - confirmLen(new NumberEval(123456), 6); - confirmLen(BoolEval.FALSE, 5); - confirmLen(BoolEval.TRUE, 4); - confirmLen(BlankEval.instance, 0); - } - - public void testErrors() { - confirmLen(ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java deleted file mode 100644 index b0b6ece7f1..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java +++ /dev/null @@ -1,365 +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.record.formula.functions; - -import java.io.PrintStream; - -import junit.framework.Assert; -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.util.CellReference; -import org.apache.poi.ss.usermodel.CellValue; - -/** - * Tests lookup functions (VLOOKUP, HLOOKUP, LOOKUP, MATCH) as loaded from a test data spreadsheet.

- * These tests have been separated from the common function and operator tests because the lookup - * functions have more complex test cases and test data setup. - * - * Tests for bug fixes and specific/tricky behaviour can be found in the corresponding test class - * (TestXxxx) of the target (Xxxx) implementor, where execution can be observed - * more easily. - * - * @author Josh Micich - */ -public final class TestLookupFunctionsFromSpreadsheet extends TestCase { - - private static final class Result { - public static final int SOME_EVALUATIONS_FAILED = -1; - public static final int ALL_EVALUATIONS_SUCCEEDED = +1; - public static final int NO_EVALUATIONS_FOUND = 0; - } - - /** - * This class defines constants for navigating around the test data spreadsheet used for these tests. - */ - private static final class SS { - - /** Name of the test spreadsheet (found in the standard test data folder) */ - public final static String FILENAME = "LookupFunctionsTestCaseData.xls"; - - /** Name of the first sheet in the spreadsheet (contains comments) */ - public final static String README_SHEET_NAME = "Read Me"; - - - /** Row (zero-based) in each sheet where the evaluation cases start. */ - public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5' - /** Index of the column that contains the function names */ - public static final int COLUMN_INDEX_MARKER = 0; // Column 'A' - public static final int COLUMN_INDEX_EVALUATION = 1; // Column 'B' - public static final int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C' - public static final int COLUMN_ROW_COMMENT = 3; // Column 'D' - - /** Used to indicate when there are no more test cases on the current sheet */ - public static final String TEST_CASES_END_MARKER = ""; - /** Used to indicate that the test on the current row should be ignored */ - public static final String SKIP_CURRENT_TEST_CASE_MARKER = ""; - - } - - // Note - multiple failures are aggregated before ending. - // If one or more functions fail, a single AssertionFailedError is thrown at the end - private int _sheetFailureCount; - private int _sheetSuccessCount; - private int _evaluationFailureCount; - private int _evaluationSuccessCount; - - - - private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) { - if (expected == null) { - throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); - } - if(actual == null) { - throw new AssertionFailedError(msg + " - actual value was null"); - } - if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) { - confirmErrorResult(msg, expected.getErrorCellValue(), actual); - return; - } - if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) { - throw unexpectedError(msg, expected, actual.getErrorValue()); - } - if(actual.getCellType() != expected.getCellType()) { - throw wrongTypeError(msg, expected, actual); - } - - - switch (expected.getCellType()) { - case HSSFCell.CELL_TYPE_BOOLEAN: - assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); - break; - case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation - throw new IllegalStateException("Cannot expect formula as result of formula evaluation: " + msg); - case HSSFCell.CELL_TYPE_NUMERIC: - assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0); - break; - case HSSFCell.CELL_TYPE_STRING: - assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); - break; - } - } - - - private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) { - return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was " - + actualValue.formatAsString() - + " but the expected result was " - + formatValue(expectedCell) - ); - } - private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) { - return new AssertionFailedError(msgPrefix + " Error code (" - + ErrorEval.getText(actualErrorCode) - + ") was evaluated, but the expected result was " - + formatValue(expected) - ); - } - - - private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) { - if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) { - throw new AssertionFailedError(msgPrefix + " Expected cell error (" - + ErrorEval.getText(expectedErrorCode) + ") but actual value was " - + actual.formatAsString()); - } - if(expectedErrorCode != actual.getErrorValue()) { - throw new AssertionFailedError(msgPrefix + " Expected cell error code (" - + ErrorEval.getText(expectedErrorCode) - + ") but actual error code was (" - + ErrorEval.getText(actual.getErrorValue()) - + ")"); - } - } - - - private static String formatValue(HSSFCell expecedCell) { - switch (expecedCell.getCellType()) { - case HSSFCell.CELL_TYPE_BLANK: return ""; - case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue()); - case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue()); - case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString(); - } - throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")"); - } - - - protected void setUp() { - _sheetFailureCount = 0; - _sheetSuccessCount = 0; - _evaluationFailureCount = 0; - _evaluationSuccessCount = 0; - } - - public void testFunctionsFromTestSpreadsheet() { - HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); - - confirmReadMeSheet(workbook); - int nSheets = workbook.getNumberOfSheets(); - for(int i=1; i< nSheets; i++) { - int sheetResult = processTestSheet(workbook, i, workbook.getSheetName(i)); - switch(sheetResult) { - case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break; - case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break; - } - } - - // confirm results - String successMsg = "There were " - + _sheetSuccessCount + " successful sheets(s) and " - + _evaluationSuccessCount + " function(s) without error"; - if(_sheetFailureCount > 0) { - String msg = _sheetFailureCount + " sheets(s) failed with " - + _evaluationFailureCount + " evaluation(s). " + successMsg; - throw new AssertionFailedError(msg); - } - if(false) { // normally no output for successful tests - System.out.println(getClass().getName() + ": " + successMsg); - } - } - - private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) { - HSSFSheet sheet = workbook.getSheetAt(sheetIndex); - HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); - int maxRows = sheet.getLastRowNum()+1; - int result = Result.NO_EVALUATIONS_FOUND; // so far - - String currentGroupComment = null; - for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex= endIx) { - // something went wrong. just print the whole stack trace - e.printStackTrace(ps); - } - endIx -= 4; // skip 4 frames of reflection invocation - ps.println(e.toString()); - for(int i=startIx; inull if cell is missing, empty or blank - */ - private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) { - if(r == null) { - return null; - } - HSSFCell cell = r.getCell(colIndex); - if(cell == null) { - return null; - } - if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) { - return null; - } - if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) { - return cell.getRichStringCellValue().getString(); - } - - throw new RuntimeException("Bad cell type for '" + columnName + "' column: (" - + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")"); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMatch.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMatch.java deleted file mode 100644 index a92dd1fbc1..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMatch.java +++ /dev/null @@ -1,205 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.NumericValueEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Test cases for MATCH() - * - * @author Josh Micich - */ -public final class TestMatch extends TestCase { - /** less than or equal to */ - private static final NumberEval MATCH_LARGEST_LTE = new NumberEval(1); - private static final NumberEval MATCH_EXACT = new NumberEval(0); - /** greater than or equal to */ - private static final NumberEval MATCH_SMALLEST_GTE = new NumberEval(-1); - - - private static ValueEval invokeMatch(ValueEval lookup_value, ValueEval lookup_array, ValueEval match_type) { - ValueEval[] args = { lookup_value, lookup_array, match_type, }; - return new Match().evaluate(args, -1, (short)-1); - } - private static void confirmInt(int expected, ValueEval actualEval) { - if(!(actualEval instanceof NumericValueEval)) { - fail("Expected numeric result"); - } - NumericValueEval nve = (NumericValueEval)actualEval; - assertEquals(expected, nve.getNumberValue(), 0); - } - - public void testSimpleNumber() { - - ValueEval[] values = { - new NumberEval(4), - new NumberEval(5), - new NumberEval(10), - new NumberEval(10), - new NumberEval(25), - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); - - confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE)); - confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT)); - confirmInt(4, invokeMatch(new NumberEval(10), ae, MATCH_LARGEST_LTE)); - confirmInt(3, invokeMatch(new NumberEval(10), ae, MATCH_EXACT)); - confirmInt(4, invokeMatch(new NumberEval(20), ae, MATCH_LARGEST_LTE)); - assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT)); - } - - public void testReversedNumber() { - - ValueEval[] values = { - new NumberEval(25), - new NumberEval(10), - new NumberEval(10), - new NumberEval(10), - new NumberEval(4), - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); - - confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE)); - confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT)); - confirmInt(4, invokeMatch(new NumberEval(9), ae, MATCH_SMALLEST_GTE)); - confirmInt(1, invokeMatch(new NumberEval(20), ae, MATCH_SMALLEST_GTE)); - assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT)); - assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(26), ae, MATCH_SMALLEST_GTE)); - } - - public void testSimpleString() { - - ValueEval[] values = { - new StringEval("Albert"), - new StringEval("Charles"), - new StringEval("Ed"), - new StringEval("Greg"), - new StringEval("Ian"), - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); - - // Note String comparisons are case insensitive - confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE)); - confirmInt(3, invokeMatch(new StringEval("eD"), ae, MATCH_LARGEST_LTE)); - confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_EXACT)); - confirmInt(3, invokeMatch(new StringEval("ed"), ae, MATCH_EXACT)); - confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE)); - assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT)); - } - - public void testSimpleBoolean() { - - ValueEval[] values = { - BoolEval.FALSE, - BoolEval.FALSE, - BoolEval.TRUE, - BoolEval.TRUE, - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A4", values); - - // Note String comparisons are case insensitive - confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE)); - confirmInt(1, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT)); - confirmInt(4, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE)); - confirmInt(3, invokeMatch(BoolEval.TRUE, ae, MATCH_EXACT)); - } - - public void testHeterogeneous() { - - ValueEval[] values = { - new NumberEval(4), - BoolEval.FALSE, - new NumberEval(5), - new StringEval("Albert"), - BoolEval.FALSE, - BoolEval.TRUE, - new NumberEval(10), - new StringEval("Charles"), - new StringEval("Ed"), - new NumberEval(10), - new NumberEval(25), - BoolEval.TRUE, - new StringEval("Ed"), - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A13", values); - - assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE)); - - confirmInt(5, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE)); - confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT)); - confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE)); - confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT)); - - confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT)); - - confirmInt(4, invokeMatch(new StringEval("Ben"), ae, MATCH_LARGEST_LTE)); - - confirmInt(13, invokeMatch(new StringEval("ED"), ae, MATCH_LARGEST_LTE)); - confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT)); - - confirmInt(13, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE)); - assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT)); - - confirmInt(11, invokeMatch(new NumberEval(30), ae, MATCH_LARGEST_LTE)); - confirmInt(12, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE)); - } - - - /** - * Ensures that the match_type argument can be an AreaEval.
- * Bugzilla 44421 - */ - public void testMatchArgTypeArea() { - - ValueEval[] values = { - new NumberEval(4), - new NumberEval(5), - new NumberEval(10), - new NumberEval(10), - new NumberEval(25), - }; - - AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); - - AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, }); - - try { - confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE)); - } catch (RuntimeException e) { - if(e.getMessage().startsWith("Unexpected match_type type")) { - // identified bug 44421 - fail(e.getMessage()); - } - // some other error ?? - throw e; - } - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMathX.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMathX.java deleted file mode 100644 index a88f011e7b..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMathX.java +++ /dev/null @@ -1,877 +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. -*/ -/* - * Created on May 23, 2005 - * - */ -package org.apache.poi.hssf.record.formula.functions; - -import org.apache.poi.hssf.record.formula.functions.XYNumericFunction.Accumulator; - - -/** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * - */ -public class TestMathX extends AbstractNumericTestCase { - - public void testAcosh() { - double d = 0; - - d = MathX.acosh(0); - assertTrue("Acosh 0 is NaN", Double.isNaN(d)); - - d = MathX.acosh(1); - assertEquals("Acosh 1 ", 0, d); - - d = MathX.acosh(-1); - assertTrue("Acosh -1 is NaN", Double.isNaN(d)); - - d = MathX.acosh(100); - assertEquals("Acosh 100 ", 5.298292366d, d); - - d = MathX.acosh(101.001); - assertEquals("Acosh 101.001 ", 5.308253091d, d); - - d = MathX.acosh(200000); - assertEquals("Acosh 200000 ", 12.89921983d, d); - - } - - public void testAsinh() { - double d = 0; - - d = MathX.asinh(0); - assertEquals("asinh 0", d, 0); - - d = MathX.asinh(1); - assertEquals("asinh 1 ", 0.881373587, d); - - d = MathX.asinh(-1); - assertEquals("asinh -1 ", -0.881373587, d); - - d = MathX.asinh(-100); - assertEquals("asinh -100 ", -5.298342366, d); - - d = MathX.asinh(100); - assertEquals("asinh 100 ", 5.298342366, d); - - d = MathX.asinh(200000); - assertEquals("asinh 200000", 12.899219826096400, d); - - d = MathX.asinh(-200000); - assertEquals("asinh -200000 ", -12.899223853137, d); - - } - - public void testAtanh() { - double d = 0; - d = MathX.atanh(0); - assertEquals("atanh 0", d, 0); - - d = MathX.atanh(1); - assertEquals("atanh 1 ", Double.POSITIVE_INFINITY, d); - - d = MathX.atanh(-1); - assertEquals("atanh -1 ", Double.NEGATIVE_INFINITY, d); - - d = MathX.atanh(-100); - assertEquals("atanh -100 ", Double.NaN, d); - - d = MathX.atanh(100); - assertEquals("atanh 100 ", Double.NaN, d); - - d = MathX.atanh(200000); - assertEquals("atanh 200000", Double.NaN, d); - - d = MathX.atanh(-200000); - assertEquals("atanh -200000 ", Double.NaN, d); - - d = MathX.atanh(0.1); - assertEquals("atanh 0.1", 0.100335348, d); - - d = MathX.atanh(-0.1); - assertEquals("atanh -0.1 ", -0.100335348, d); - - } - - public void testCosh() { - double d = 0; - d = MathX.cosh(0); - assertEquals("cosh 0", 1, d); - - d = MathX.cosh(1); - assertEquals("cosh 1 ", 1.543080635, d); - - d = MathX.cosh(-1); - assertEquals("cosh -1 ", 1.543080635, d); - - d = MathX.cosh(-100); - assertEquals("cosh -100 ", 1.344058570908070E+43, d); - - d = MathX.cosh(100); - assertEquals("cosh 100 ", 1.344058570908070E+43, d); - - d = MathX.cosh(15); - assertEquals("cosh 15", 1634508.686, d); - - d = MathX.cosh(-15); - assertEquals("cosh -15 ", 1634508.686, d); - - d = MathX.cosh(0.1); - assertEquals("cosh 0.1", 1.005004168, d); - - d = MathX.cosh(-0.1); - assertEquals("cosh -0.1 ", 1.005004168, d); - - } - - public void testTanh() { - double d = 0; - d = MathX.tanh(0); - assertEquals("tanh 0", 0, d); - - d = MathX.tanh(1); - assertEquals("tanh 1 ", 0.761594156, d); - - d = MathX.tanh(-1); - assertEquals("tanh -1 ", -0.761594156, d); - - d = MathX.tanh(-100); - assertEquals("tanh -100 ", -1, d); - - d = MathX.tanh(100); - assertEquals("tanh 100 ", 1, d); - - d = MathX.tanh(15); - assertEquals("tanh 15", 1, d); - - d = MathX.tanh(-15); - assertEquals("tanh -15 ", -1, d); - - d = MathX.tanh(0.1); - assertEquals("tanh 0.1", 0.099667995, d); - - d = MathX.tanh(-0.1); - assertEquals("tanh -0.1 ", -0.099667995, d); - - } - - public void testMax() { - double[] d = new double[100]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - double m = MathX.max(d); - assertEquals("Max ", 20.1, m); - - d = new double[1000]; - m = MathX.max(d); - assertEquals("Max ", 0, m); - - d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; - d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; - d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; - d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; - d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; - m = MathX.max(d); - assertEquals("Max ", 20.1, m); - - d = new double[20]; - d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; - d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; - d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; - d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; - d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; - m = MathX.max(d); - assertEquals("Max ", -1.1, m); - - } - - public void testMin() { - double[] d = new double[100]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - double m = MathX.min(d); - assertEquals("Min ", 0, m); - - d = new double[20]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - m = MathX.min(d); - assertEquals("Min ", 1.1, m); - - d = new double[1000]; - m = MathX.min(d); - assertEquals("Min ", 0, m); - - d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; - d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; - d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; - d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; - d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; - m = MathX.min(d); - assertEquals("Min ", -19.1, m); - - d = new double[20]; - d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; - d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; - d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; - d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; - d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; - m = MathX.min(d); - assertEquals("Min ", -20.1, m); - } - - public void testProduct() { - double[] d = new double[100]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - double m = MathX.min(d); - assertEquals("Min ", 0, m); - - d = new double[20]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - m = MathX.min(d); - assertEquals("Min ", 1.1, m); - - d = new double[1000]; - m = MathX.min(d); - assertEquals("Min ", 0, m); - - d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; - d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; - d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; - d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; - d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; - m = MathX.min(d); - assertEquals("Min ", -19.1, m); - - d = new double[20]; - d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; - d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; - d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; - d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; - d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; - m = MathX.min(d); - assertEquals("Min ", -20.1, m); - } - - public void testMod() { - - //example from Excel help - assertEquals(1.0, MathX.mod(3, 2)); - assertEquals(1.0, MathX.mod(-3, 2)); - assertEquals(-1.0, MathX.mod(3, -2)); - assertEquals(-1.0, MathX.mod(-3, -2)); - - assertEquals((double) 1.4, MathX.mod(3.4, 2)); - assertEquals((double) -1.4, MathX.mod(-3.4, -2)); - assertEquals((double) 0.6000000000000001, MathX.mod(-3.4, 2.0));// should actually be 0.6 - assertEquals((double) -0.6000000000000001, MathX.mod(3.4, -2.0));// should actually be -0.6 - - // Bugzilla 50033 - assertEquals(1.0, MathX.mod(13, 12)); - } - - public void testNChooseK() { - int n=100; - int k=50; - double d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 1.00891344545564E29, d); - - n = -1; k = 1; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", Double.NaN, d); - - n = 1; k = -1; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", Double.NaN, d); - - n = 0; k = 1; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", Double.NaN, d); - - n = 1; k = 0; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 1, d); - - n = 10; k = 9; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 10, d); - - n = 10; k = 10; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 1, d); - - n = 10; k = 1; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 10, d); - - n = 1000; k = 1; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 1000, d); // awesome ;) - - n = 1000; k = 2; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 499500, d); // awesome ;) - - n = 13; k = 7; - d = MathX.nChooseK(n, k); - assertEquals("NChooseK ", 1716, d); - - } - - public void testSign() { - final short minus = -1; - final short zero = 0; - final short plus = 1; - double d = 0; - - - assertEquals("Sign ", minus, MathX.sign(minus)); - assertEquals("Sign ", plus, MathX.sign(plus)); - assertEquals("Sign ", zero, MathX.sign(zero)); - - d = 0; - assertEquals("Sign ", zero, MathX.sign(d)); - - d = -1.000001; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = -.000001; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = -1E-200; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = Double.NEGATIVE_INFINITY; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = -200.11; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = -2000000000000.11; - assertEquals("Sign ", minus, MathX.sign(d)); - - d = 1.000001; - assertEquals("Sign ", plus, MathX.sign(d)); - - d = .000001; - assertEquals("Sign ", plus, MathX.sign(d)); - - d = 1E-200; - assertEquals("Sign ", plus, MathX.sign(d)); - - d = Double.POSITIVE_INFINITY; - assertEquals("Sign ", plus, MathX.sign(d)); - - d = 200.11; - assertEquals("Sign ", plus, MathX.sign(d)); - - d = 2000000000000.11; - assertEquals("Sign ", plus, MathX.sign(d)); - - } - - public void testSinh() { - double d = 0; - d = MathX.sinh(0); - assertEquals("sinh 0", 0, d); - - d = MathX.sinh(1); - assertEquals("sinh 1 ", 1.175201194, d); - - d = MathX.sinh(-1); - assertEquals("sinh -1 ", -1.175201194, d); - - d = MathX.sinh(-100); - assertEquals("sinh -100 ", -1.344058570908070E+43, d); - - d = MathX.sinh(100); - assertEquals("sinh 100 ", 1.344058570908070E+43, d); - - d = MathX.sinh(15); - assertEquals("sinh 15", 1634508.686, d); - - d = MathX.sinh(-15); - assertEquals("sinh -15 ", -1634508.686, d); - - d = MathX.sinh(0.1); - assertEquals("sinh 0.1", 0.10016675, d); - - d = MathX.sinh(-0.1); - assertEquals("sinh -0.1 ", -0.10016675, d); - - } - - public void testSum() { - double[] d = new double[100]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - double s = MathX.sum(d); - assertEquals("Sum ", 212, s); - - d = new double[1000]; - s = MathX.sum(d); - assertEquals("Sum ", 0, s); - - d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; - d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; - d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; - d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; - d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; - s = MathX.sum(d); - assertEquals("Sum ", 10, s); - - d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; - d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; - d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; - d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; - d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; - s = MathX.sum(d); - assertEquals("Sum ", -212, s); - - } - - public void testSumsq() { - double[] d = new double[100]; - d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; - d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; - d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; - d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; - d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; - - double s = MathX.sumsq(d); - assertEquals("Sumsq ", 2912.2, s); - - d = new double[1000]; - s = MathX.sumsq(d); - assertEquals("Sumsq ", 0, s); - - d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; - d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; - d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; - d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; - d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; - s = MathX.sumsq(d); - assertEquals("Sumsq ", 2912.2, s); - - d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; - d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; - d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; - d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; - d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; - s = MathX.sumsq(d); - assertEquals("Sumsq ", 2912.2, s); - } - - public void testFactorial() { - int n = 0; - double s = 0; - - n = 0; - s = MathX.factorial(n); - assertEquals("Factorial ", 1, s); - - n = 1; - s = MathX.factorial(n); - assertEquals("Factorial ", 1, s); - - n = 10; - s = MathX.factorial(n); - assertEquals("Factorial ", 3628800, s); - - n = 99; - s = MathX.factorial(n); - assertEquals("Factorial ", 9.33262154439E+155, s); - - n = -1; - s = MathX.factorial(n); - assertEquals("Factorial ", Double.NaN, s); - - n = Integer.MAX_VALUE; - s = MathX.factorial(n); - assertEquals("Factorial ", Double.POSITIVE_INFINITY, s); - } - - public void testSumx2my2() { - double[] xarr = null; - double[] yarr = null; - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumx2my2(xarr, yarr, 100); - - xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumx2my2(xarr, yarr, 100); - - xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumx2my2(xarr, yarr, -100); - - xarr = new double[]{10}; - yarr = new double[]{9}; - confirmSumx2my2(xarr, yarr, 19); - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumx2my2(xarr, yarr, 0); - } - - public void testSumx2py2() { - double[] xarr = null; - double[] yarr = null; - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumx2py2(xarr, yarr, 670); - - xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumx2py2(xarr, yarr, 670); - - xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumx2py2(xarr, yarr, 670); - - xarr = new double[]{10}; - yarr = new double[]{9}; - confirmSumx2py2(xarr, yarr, 181); - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumx2py2(xarr, yarr, 770); - } - - public void testSumxmy2() { - double[] xarr = null; - double[] yarr = null; - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumxmy2(xarr, yarr, 10); - - xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; - yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - confirmSumxmy2(xarr, yarr, 1330); - - xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumxmy2(xarr, yarr, 10); - - xarr = new double[]{10}; - yarr = new double[]{9}; - confirmSumxmy2(xarr, yarr, 1); - - xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - confirmSumxmy2(xarr, yarr, 0); - } - - private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) { - confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult); - } - private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) { - confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult); - } - private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) { - confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult); - } - - private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr, - double expectedResult) { - double result = 0.0; - for (int i = 0; i < xarr.length; i++) { - result += acc.accumulate(xarr[i], yarr[i]); - } - assertEquals(expectedResult, result, 0.0); - } - - public void testRound() { - double d = 0; - int p = 0; - - d = 0; p = 0; - assertEquals("round ", 0, MathX.round(d, p)); - - d = 10; p = 0; - assertEquals("round ", 10, MathX.round(d, p)); - - d = 123.23; p = 0; - assertEquals("round ", 123, MathX.round(d, p)); - - d = -123.23; p = 0; - assertEquals("round ", -123, MathX.round(d, p)); - - d = 123.12; p = 2; - assertEquals("round ", 123.12, MathX.round(d, p)); - - d = 88.123459; p = 5; - assertEquals("round ", 88.12346, MathX.round(d, p)); - - d = 0; p = 2; - assertEquals("round ", 0, MathX.round(d, p)); - - d = 0; p = -1; - assertEquals("round ", 0, MathX.round(d, p)); - - d = 0.01; p = -1; - assertEquals("round ", 0, MathX.round(d, p)); - - d = 123.12; p = -2; - assertEquals("round ", 100, MathX.round(d, p)); - - d = 88.123459; p = -3; - assertEquals("round ", 0, MathX.round(d, p)); - - d = 49.00000001; p = -1; - assertEquals("round ", 50, MathX.round(d, p)); - - d = 149.999999; p = -2; - assertEquals("round ", 100, MathX.round(d, p)); - - d = 150.0; p = -2; - assertEquals("round ", 200, MathX.round(d, p)); - } - - public void testRoundDown() { - double d = 0; - int p = 0; - - d = 0; p = 0; - assertEquals("roundDown ", 0, MathX.roundDown(d, p)); - - d = 10; p = 0; - assertEquals("roundDown ", 10, MathX.roundDown(d, p)); - - d = 123.99; p = 0; - assertEquals("roundDown ", 123, MathX.roundDown(d, p)); - - d = -123.99; p = 0; - assertEquals("roundDown ", -123, MathX.roundDown(d, p)); - - d = 123.99; p = 2; - assertEquals("roundDown ", 123.99, MathX.roundDown(d, p)); - - d = 88.123459; p = 5; - assertEquals("roundDown ", 88.12345, MathX.roundDown(d, p)); - - d = 0; p = 2; - assertEquals("roundDown ", 0, MathX.roundDown(d, p)); - - d = 0; p = -1; - assertEquals("roundDown ", 0, MathX.roundDown(d, p)); - - d = 0.01; p = -1; - assertEquals("roundDown ", 0, MathX.roundDown(d, p)); - - d = 199.12; p = -2; - assertEquals("roundDown ", 100, MathX.roundDown(d, p)); - - d = 88.123459; p = -3; - assertEquals("roundDown ", 0, MathX.roundDown(d, p)); - - d = 99.00000001; p = -1; - assertEquals("roundDown ", 90, MathX.roundDown(d, p)); - - d = 100.00001; p = -2; - assertEquals("roundDown ", 100, MathX.roundDown(d, p)); - - d = 150.0; p = -2; - assertEquals("roundDown ", 100, MathX.roundDown(d, p)); - } - - public void testRoundUp() { - double d = 0; - int p = 0; - - d = 0; p = 0; - assertEquals("roundUp ", 0, MathX.roundUp(d, p)); - - d = 10; p = 0; - assertEquals("roundUp ", 10, MathX.roundUp(d, p)); - - d = 123.23; p = 0; - assertEquals("roundUp ", 124, MathX.roundUp(d, p)); - - d = -123.23; p = 0; - assertEquals("roundUp ", -124, MathX.roundUp(d, p)); - - d = 123.12; p = 2; - assertEquals("roundUp ", 123.12, MathX.roundUp(d, p)); - - d = 88.123459; p = 5; - assertEquals("roundUp ", 88.12346, MathX.roundUp(d, p)); - - d = 0; p = 2; - assertEquals("roundUp ", 0, MathX.roundUp(d, p)); - - d = 0; p = -1; - assertEquals("roundUp ", 0, MathX.roundUp(d, p)); - - d = 0.01; p = -1; - assertEquals("roundUp ", 10, MathX.roundUp(d, p)); - - d = 123.12; p = -2; - assertEquals("roundUp ", 200, MathX.roundUp(d, p)); - - d = 88.123459; p = -3; - assertEquals("roundUp ", 1000, MathX.roundUp(d, p)); - - d = 49.00000001; p = -1; - assertEquals("roundUp ", 50, MathX.roundUp(d, p)); - - d = 149.999999; p = -2; - assertEquals("roundUp ", 200, MathX.roundUp(d, p)); - - d = 150.0; p = -2; - assertEquals("roundUp ", 200, MathX.roundUp(d, p)); - } - - public void testCeiling() { - double d = 0; - double s = 0; - - d = 0; s = 0; - assertEquals("ceiling ", 0, MathX.ceiling(d, s)); - - d = 1; s = 0; - assertEquals("ceiling ", 0, MathX.ceiling(d, s)); - - d = 0; s = 1; - assertEquals("ceiling ", 0, MathX.ceiling(d, s)); - - d = -1; s = 0; - assertEquals("ceiling ", 0, MathX.ceiling(d, s)); - - d = 0; s = -1; - assertEquals("ceiling ", 0, MathX.ceiling(d, s)); - - d = 10; s = 1.11; - assertEquals("ceiling ", 11.1, MathX.ceiling(d, s)); - - d = 11.12333; s = 0.03499; - assertEquals("ceiling ", 11.12682, MathX.ceiling(d, s)); - - d = -11.12333; s = 0.03499; - assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s)); - - d = 11.12333; s = -0.03499; - assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s)); - - d = -11.12333; s = -0.03499; - assertEquals("ceiling ", -11.12682, MathX.ceiling(d, s)); - - d = 100; s = 0.001; - assertEquals("ceiling ", 100, MathX.ceiling(d, s)); - - d = -0.001; s = -9.99; - assertEquals("ceiling ", -9.99, MathX.ceiling(d, s)); - - d = 4.42; s = 0.05; - assertEquals("ceiling ", 4.45, MathX.ceiling(d, s)); - - d = 0.05; s = 4.42; - assertEquals("ceiling ", 4.42, MathX.ceiling(d, s)); - - d = 0.6666; s = 3.33; - assertEquals("ceiling ", 3.33, MathX.ceiling(d, s)); - - d = 2d/3; s = 3.33; - assertEquals("ceiling ", 3.33, MathX.ceiling(d, s)); - } - - public void testFloor() { - double d = 0; - double s = 0; - - d = 0; s = 0; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = 1; s = 0; - assertEquals("floor ", Double.NaN, MathX.floor(d, s)); - - d = 0; s = 1; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = -1; s = 0; - assertEquals("floor ", Double.NaN, MathX.floor(d, s)); - - d = 0; s = -1; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = 10; s = 1.11; - assertEquals("floor ", 9.99, MathX.floor(d, s)); - - d = 11.12333; s = 0.03499; - assertEquals("floor ", 11.09183, MathX.floor(d, s)); - - d = -11.12333; s = 0.03499; - assertEquals("floor ", Double.NaN, MathX.floor(d, s)); - - d = 11.12333; s = -0.03499; - assertEquals("floor ", Double.NaN, MathX.floor(d, s)); - - d = -11.12333; s = -0.03499; - assertEquals("floor ", -11.09183, MathX.floor(d, s)); - - d = 100; s = 0.001; - assertEquals("floor ", 100, MathX.floor(d, s)); - - d = -0.001; s = -9.99; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = 4.42; s = 0.05; - assertEquals("floor ", 4.4, MathX.floor(d, s)); - - d = 0.05; s = 4.42; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = 0.6666; s = 3.33; - assertEquals("floor ", 0, MathX.floor(d, s)); - - d = 2d/3; s = 3.33; - assertEquals("floor ", 0, MathX.floor(d, s)); - } - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java deleted file mode 100644 index 72b50daf5b..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java +++ /dev/null @@ -1,110 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.RefEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -/** - * Tests for Excel function MID() - * - * @author Josh Micich - */ -public final class TestMid extends TestCase { - - - private static ValueEval invokeMid(ValueEval text, ValueEval startPos, ValueEval numChars) { - ValueEval[] args = new ValueEval[] { text, startPos, numChars, }; - return TextFunction.MID.evaluate(args, -1, (short)-1); - } - - private void confirmMid(ValueEval text, ValueEval startPos, ValueEval numChars, String expected) { - ValueEval result = invokeMid(text, startPos, numChars); - assertEquals(StringEval.class, result.getClass()); - assertEquals(expected, ((StringEval)result).getStringValue()); - } - - private void confirmMid(ValueEval text, ValueEval startPos, ValueEval numChars, ErrorEval expectedError) { - ValueEval result = invokeMid(text, startPos, numChars); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); - } - - public void testBasic() { - - confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(4), "lact"); - } - - /** - * Valid cases where args are not precisely (string, int, int) but can be resolved OK. - */ - public void testUnusualArgs() { - // startPos with fractional digits - confirmMid(new StringEval("galactic"), new NumberEval(3.1), new NumberEval(4), "lact"); - - // string startPos - confirmMid(new StringEval("galactic"), new StringEval("3"), new NumberEval(4), "lact"); - - // text (first) arg type is number, other args are strings with fractional digits - confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34"); - - // startPos is 1x1 area ref, numChars is cell ref - AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } ); - RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3)); - confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala"); - - confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.instance, ""); - - confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, ""); - confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l"); - confirmMid(BlankEval.instance, new NumberEval(3), BoolEval.TRUE, ""); - - } - - /** - * Extreme values for startPos and numChars - */ - public void testExtremes() { - confirmMid(new StringEval("galactic"), new NumberEval(4), new NumberEval(400), "actic"); - - confirmMid(new StringEval("galactic"), new NumberEval(30), new NumberEval(4), ""); - confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(0), ""); - } - - /** - * All sorts of ways to make MID return defined errors. - */ - public void testErrors() { - confirmMid(ErrorEval.NAME_INVALID, new NumberEval(3), new NumberEval(4), ErrorEval.NAME_INVALID); - confirmMid(new StringEval("galactic"), ErrorEval.NAME_INVALID, new NumberEval(4), ErrorEval.NAME_INVALID); - confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); - confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO); - - confirmMid(new StringEval("galactic"), BlankEval.instance, new NumberEval(3.1), ErrorEval.VALUE_INVALID); - - confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID); - confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestNper.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestNper.java deleted file mode 100644 index 99fb4dea41..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestNper.java +++ /dev/null @@ -1,65 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFErrorConstants; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; - -/** - * Tests for {@link FinanceFunction#NPER} - * - * @author Josh Micich - */ -public final class TestNper extends TestCase { - public void testSimpleEvaluate() { - - ValueEval[] args = { - new NumberEval(0.05), - new NumberEval(250), - new NumberEval(-1000), - }; - ValueEval result = FinanceFunction.NPER.evaluate(args, 0, (short)0); - - assertEquals(NumberEval.class, result.getClass()); - assertEquals(4.57353557, ((NumberEval)result).getNumberValue(), 0.00000001); - } - - public void testEvaluate_bug_45732() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("Sheet1"); - HSSFCell cell = sheet.createRow(0).createCell(0); - - cell.setCellFormula("NPER(12,4500,100000,100000)"); - cell.setCellValue(15.0); - assertEquals("NPER(12,4500,100000,100000)", cell.getCellFormula()); - assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType()); - assertEquals(15.0, cell.getNumericCellValue(), 0.0); - - HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); - fe.evaluateFormulaCell(cell); - assertEquals(HSSFCell.CELL_TYPE_ERROR, cell.getCachedFormulaResultType()); - assertEquals(HSSFErrorConstants.ERROR_NUM, cell.getErrorCellValue()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestOffset.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestOffset.java deleted file mode 100644 index 7002408f2e..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestOffset.java +++ /dev/null @@ -1,99 +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.record.formula.functions; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -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.functions.Offset.LinearOffsetRange; - -/** - * Tests for OFFSET function implementation - * - * @author Josh Micich - */ -public final class TestOffset extends TestCase { - - private static void confirmDoubleConvert(double doubleVal, int expected) { - try { - assertEquals(expected, Offset.evaluateIntArg(new NumberEval(doubleVal), -1, -1)); - } catch (EvaluationException e) { - throw new AssertionFailedError("Unexpected error '" + e.getErrorEval().toString() + "'."); - } - } - /** - * Excel's double to int conversion (for function 'OFFSET()') behaves more like Math.floor(). - * Note - negative values are not symmetrical - * Fractional values are silently truncated. - * Truncation is toward negative infinity. - */ - public void testDoubleConversion() { - - confirmDoubleConvert(100.09, 100); - confirmDoubleConvert(100.01, 100); - confirmDoubleConvert(100.00, 100); - confirmDoubleConvert(99.99, 99); - - confirmDoubleConvert(+2.01, +2); - confirmDoubleConvert(+2.00, +2); - confirmDoubleConvert(+1.99, +1); - confirmDoubleConvert(+1.01, +1); - confirmDoubleConvert(+1.00, +1); - confirmDoubleConvert(+0.99, 0); - confirmDoubleConvert(+0.01, 0); - confirmDoubleConvert( 0.00, 0); - confirmDoubleConvert(-0.01, -1); - confirmDoubleConvert(-0.99, -1); - confirmDoubleConvert(-1.00, -1); - confirmDoubleConvert(-1.01, -2); - confirmDoubleConvert(-1.99, -2); - confirmDoubleConvert(-2.00, -2); - confirmDoubleConvert(-2.01, -3); - } - - public void testLinearOffsetRange() { - LinearOffsetRange lor; - - lor = new LinearOffsetRange(3, 2); - assertEquals(3, lor.getFirstIndex()); - assertEquals(4, lor.getLastIndex()); - lor = lor.normaliseAndTranslate(0); // expected no change - assertEquals(3, lor.getFirstIndex()); - assertEquals(4, lor.getLastIndex()); - - lor = lor.normaliseAndTranslate(5); - assertEquals(8, lor.getFirstIndex()); - assertEquals(9, lor.getLastIndex()); - - // negative length - - lor = new LinearOffsetRange(6, -4).normaliseAndTranslate(0); - assertEquals(3, lor.getFirstIndex()); - assertEquals(6, lor.getLastIndex()); - - - // bounds checking - lor = new LinearOffsetRange(0, 100); - assertFalse(lor.isOutOfBounds(0, 16383)); - lor = lor.normaliseAndTranslate(16300); - assertTrue(lor.isOutOfBounds(0, 16383)); - assertFalse(lor.isOutOfBounds(0, 65535)); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java deleted file mode 100644 index cac4bde13f..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPmt.java +++ /dev/null @@ -1,86 +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.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.ValueEval; -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 ValueEval invoke(ValueEval[] args) { - return FinanceFunction.PMT.evaluate(args, -1, (short)-1); - } - /** - * Invocation when not expecting an error result - */ - private static NumberEval invokeNormal(ValueEval[] args) { - ValueEval 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) { - ValueEval[] 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() { - - ValueEval[] args = { - new NumberEval(0.005), - new NumberEval(24), - new NumberEval(1000), - }; - ValueEval 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/testcases/org/apache/poi/hssf/record/formula/functions/TestPoisson.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPoisson.java deleted file mode 100644 index f09a25fb38..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestPoisson.java +++ /dev/null @@ -1,111 +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.record.formula.functions; - -import junit.framework.TestCase; - -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Tests for Excel function POISSON(x,mean,cumulative) - * @author Kalpesh Parmar - */ -public class TestPoisson extends TestCase { - - private static final double DELTA = 1E-15; - - private static ValueEval invokePoisson(double x, double mean, boolean cumulative) - { - - ValueEval[] valueEvals = new ValueEval[3]; - valueEvals[0] = new NumberEval(x); - valueEvals[1] = new NumberEval(mean); - valueEvals[2] = BoolEval.valueOf(cumulative); - - return NumericFunction.POISSON.evaluate(valueEvals,-1,-1); - } - - public void testCumulativeProbability() - { - double x = 1; - double mean = 0.2; - double result = 0.9824769036935787; // known result - - NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); - - assertEquals(myResult.getNumberValue(), result, DELTA); - } - - public void testNonCumulativeProbability() - { - double x = 0; - double mean = 0.2; - double result = 0.8187307530779818; // known result - - NumberEval myResult = (NumberEval)invokePoisson(x,mean,false); - - assertEquals(myResult.getNumberValue(), result, DELTA); - } - - public void testNegativeMean() - { - double x = 0; - double mean = -0.2; - - ErrorEval myResult = (ErrorEval)invokePoisson(x,mean,false); - - assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), myResult.getErrorCode()); - } - - public void testNegativeX() - { - double x = -1; - double mean = 0.2; - - ErrorEval myResult = (ErrorEval)invokePoisson(x,mean,false); - - assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), myResult.getErrorCode()); - } - - - - public void testXAsDecimalNumber() - { - double x = 1.1; - double mean = 0.2; - double result = 0.9824769036935787; // known result - - NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); - - assertEquals(myResult.getNumberValue(), result, DELTA); - } - - public void testXZeroMeanZero() - { - double x = 0; - double mean = 0; - double result = 1; // known result in excel - - NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); - - assertEquals(myResult.getNumberValue(), result, DELTA); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java deleted file mode 100644 index d3fa564391..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRoundFuncs.java +++ /dev/null @@ -1,50 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; - -/** - * Test cases for ROUND(), ROUNDUP(), ROUNDDOWN() - * - * @author Josh Micich - */ -public final class TestRoundFuncs extends TestCase { - private static final NumericFunction F = null; - public void testRounddownWithStringArg() { - - ValueEval strArg = new StringEval("abc"); - ValueEval[] args = { strArg, new NumberEval(2), }; - ValueEval result = F.ROUNDDOWN.evaluate(args, -1, (short)-1); - assertEquals(ErrorEval.VALUE_INVALID, result); - } - - public void testRoundupWithStringArg() { - - ValueEval strArg = new StringEval("abc"); - ValueEval[] args = { strArg, new NumberEval(2), }; - ValueEval result = F.ROUNDUP.evaluate(args, -1, (short)-1); - assertEquals(ErrorEval.VALUE_INVALID, result); - } - -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java deleted file mode 100644 index 532e768eb1..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java +++ /dev/null @@ -1,97 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Tests for ROW(), ROWS(), COLUMN(), COLUMNS() - * - * @author Josh Micich - */ -public final class TestRowCol extends TestCase { - - public void testCol() { - Function target = new Column(); - { - ValueEval[] args = { EvalFactory.createRefEval("C5"), }; - double actual = NumericFunctionInvoker.invoke(target, args); - assertEquals(3, actual, 0D); - } - { - ValueEval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), }; - double actual = NumericFunctionInvoker.invoke(target, args); - assertEquals(5, actual, 0D); - } - } - - public void testRow() { - Function target = new RowFunc(); - { - ValueEval[] args = { EvalFactory.createRefEval("C5"), }; - double actual = NumericFunctionInvoker.invoke(target, args); - assertEquals(5, actual, 0D); - } - { - ValueEval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), }; - double actual = NumericFunctionInvoker.invoke(target, args); - assertEquals(2, actual, 0D); - } - } - - public void testColumns() { - - confirmColumnsFunc("A1:F1", 6, 1); - confirmColumnsFunc("A1:C2", 3, 2); - confirmColumnsFunc("A1:B3", 2, 3); - confirmColumnsFunc("A1:A6", 1, 6); - - ValueEval[] args = { EvalFactory.createRefEval("C5"), }; - double actual = NumericFunctionInvoker.invoke(new Columns(), args); - assertEquals(1, actual, 0D); - } - - public void testRows() { - - confirmRowsFunc("A1:F1", 6, 1); - confirmRowsFunc("A1:C2", 3, 2); - confirmRowsFunc("A1:B3", 2, 3); - confirmRowsFunc("A1:A6", 1, 6); - - ValueEval[] args = { EvalFactory.createRefEval("C5"), }; - double actual = NumericFunctionInvoker.invoke(new Rows(), args); - assertEquals(1, actual, 0D); - } - - private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) { - ValueEval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), }; - - double actual = NumericFunctionInvoker.invoke(new Rows(), args); - assertEquals(nRows, actual, 0D); - } - - - private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) { - ValueEval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), }; - - double actual = NumericFunctionInvoker.invoke(new Columns(), args); - assertEquals(nCols, actual, 0D); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java deleted file mode 100644 index 3562a67789..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestStatsLib.java +++ /dev/null @@ -1,271 +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. -*/ -/* - * Created on May 30, 2005 - * - */ -package org.apache.poi.hssf.record.formula.functions; - -import junit.framework.AssertionFailedError; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.EvaluationException; - - -/** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * - */ -public class TestStatsLib extends AbstractNumericTestCase { - - public void testDevsq() { - double[] v = null; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - d = StatsLib.devsq(v); - x = 82.5; - assertEquals("devsq ", x, d); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - d = StatsLib.devsq(v); - x = 0; - assertEquals("devsq ", x, d); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - d = StatsLib.devsq(v); - x = 0; - assertEquals("devsq ", x, d); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - d = StatsLib.devsq(v); - x = 2.5; - assertEquals("devsq ", x, d); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - d = StatsLib.devsq(v); - x = 10953.7416965767; - assertEquals("devsq ", x, d); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.devsq(v); - x = 82.5; - assertEquals("devsq ", x, d); - } - - public void testKthLargest() { - double[] v = null; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - d = StatsLib.kthLargest(v, 3); - x = 8; - assertEquals("kthLargest ", x, d); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - d = StatsLib.kthLargest(v, 3); - x = 1; - assertEquals("kthLargest ", x, d); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - d = StatsLib.kthLargest(v, 3); - x = 0; - assertEquals("kthLargest ", x, d); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - d = StatsLib.kthLargest(v, 3); - x = 2; - assertEquals("kthLargest ", x, d); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - d = StatsLib.kthLargest(v, 3); - x = 5.37828; - assertEquals("kthLargest ", x, d); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.kthLargest(v, 3); - x = -3; - assertEquals("kthLargest ", x, d); - } - - public void testKthSmallest() { - } - - public void testAvedev() { - double[] v = null; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - d = StatsLib.avedev(v); - x = 2.5; - assertEquals("avedev ", x, d); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - d = StatsLib.avedev(v); - x = 0; - assertEquals("avedev ", x, d); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - d = StatsLib.avedev(v); - x = 0; - assertEquals("avedev ", x, d); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - d = StatsLib.avedev(v); - x = 0.5; - assertEquals("avedev ", x, d); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - d = StatsLib.avedev(v); - x = 36.42176053333; - assertEquals("avedev ", x, d); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.avedev(v); - x = 2.5; - assertEquals("avedev ", x, d); - } - - public void testMedian() { - double[] v = null; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - d = StatsLib.median(v); - x = 5.5; - assertEquals("median ", x, d); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - d = StatsLib.median(v); - x = 1; - assertEquals("median ", x, d); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - d = StatsLib.median(v); - x = 0; - assertEquals("median ", x, d); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - d = StatsLib.median(v); - x = 1.5; - assertEquals("median ", x, d); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - d = StatsLib.median(v); - x = 5.37828; - assertEquals("median ", x, d); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.median(v); - x = -5.5; - assertEquals("median ", x, d); - - v = new double[] {-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.median(v); - x = -6; - assertEquals("median ", x, d); - - v = new double[] {1,2,3,4,5,6,7,8,9}; - d = StatsLib.median(v); - x = 5; - assertEquals("median ", x, d); - } - - public void testMode() { - double[] v; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - confirmMode(v, null); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - confirmMode(v, 1.0); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - confirmMode(v, 0.0); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - confirmMode(v, 1.0); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - confirmMode(v, null); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - confirmMode(v, null); - - v = new double[] {1,2,3,4,1,1,1,1,0,0,0,0,0}; - confirmMode(v, 1.0); - - v = new double[] {0,1,2,3,4,1,1,1,0,0,0,0,1}; - confirmMode(v, 0.0); - } - private static void confirmMode(double[] v, double expectedResult) { - confirmMode(v, new Double(expectedResult)); - } - private static void confirmMode(double[] v, Double expectedResult) { - double actual; - try { - actual = Mode.evaluate(v); - if (expectedResult == null) { - throw new AssertionFailedError("Expected N/A exception was not thrown"); - } - } catch (EvaluationException e) { - if (expectedResult == null) { - assertEquals(ErrorEval.NA, e.getErrorEval()); - return; - } - throw new RuntimeException(e); - } - assertEquals("mode", expectedResult.doubleValue(), actual); - } - - - public void testStddev() { - double[] v = null; - double d, x = 0; - - v = new double[] {1,2,3,4,5,6,7,8,9,10}; - d = StatsLib.stdev(v); - x = 3.02765035410; - assertEquals("stdev ", x, d); - - v = new double[] {1,1,1,1,1,1,1,1,1,1}; - d = StatsLib.stdev(v); - x = 0; - assertEquals("stdev ", x, d); - - v = new double[] {0,0,0,0,0,0,0,0,0,0}; - d = StatsLib.stdev(v); - x = 0; - assertEquals("stdev ", x, d); - - v = new double[] {1,2,1,2,1,2,1,2,1,2}; - d = StatsLib.stdev(v); - x = 0.52704627669; - assertEquals("stdev ", x, d); - - v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; - d = StatsLib.stdev(v); - x = 52.33006233652; - assertEquals("stdev ", x, d); - - v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; - d = StatsLib.stdev(v); - x = 3.02765035410; - assertEquals("stdev ", x, d); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSubtotal.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSubtotal.java deleted file mode 100644 index 974f897fbc..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSubtotal.java +++ /dev/null @@ -1,72 +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.record.formula.functions; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -import junit.framework.TestCase; - -/** - * Tests for {@link Subtotal} - * - * @author Paul Tomlin - */ -public final class TestSubtotal extends TestCase { - private static final int FUNCTION_AVERAGE = 1; - private static final int FUNCTION_COUNT = 2; - private static final int FUNCTION_MAX = 4; - private static final int FUNCTION_MIN = 5; - private static final int FUNCTION_PRODUCT = 6; - private static final int FUNCTION_STDEV = 7; - private static final int FUNCTION_SUM = 9; - - private static final double[] TEST_VALUES0 = { - 1, 2, - 3, 4, - 5, 6, - 7, 8, - 9, 10 - }; - - private static void confirmSubtotal(int function, double expected) { - ValueEval[] values = new ValueEval[TEST_VALUES0.length]; - for (int i = 0; i < TEST_VALUES0.length; i++) { - values[i] = new NumberEval(TEST_VALUES0[i]); - } - - AreaEval arg1 = EvalFactory.createAreaEval("C1:D5", values); - ValueEval args[] = { new NumberEval(function), arg1 }; - - ValueEval result = new Subtotal().evaluate(args, 0, 0); - - assertEquals(NumberEval.class, result.getClass()); - assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0); - } - - public void testBasics() { - confirmSubtotal(FUNCTION_SUM, 55.0); - confirmSubtotal(FUNCTION_AVERAGE, 5.5); - confirmSubtotal(FUNCTION_COUNT, 10.0); - confirmSubtotal(FUNCTION_MAX, 10.0); - confirmSubtotal(FUNCTION_MIN, 1.0); - confirmSubtotal(FUNCTION_PRODUCT, 3628800.0); - confirmSubtotal(FUNCTION_STDEV, 3.0276503540974917); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumif.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumif.java deleted file mode 100644 index ff611ec31e..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumif.java +++ /dev/null @@ -1,102 +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.record.formula.functions; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -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.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Test cases for SUMPRODUCT() - * - * @author Josh Micich - */ -public final class TestSumif extends TestCase { - private static final NumberEval _30 = new NumberEval(30); - private static final NumberEval _40 = new NumberEval(40); - private static final NumberEval _50 = new NumberEval(50); - private static final NumberEval _60 = new NumberEval(60); - - private static ValueEval invokeSumif(int rowIx, int colIx, ValueEval...args) { - return new Sumif().evaluate(args, rowIx, colIx); - } - private static void confirmDouble(double expected, ValueEval actualEval) { - if(!(actualEval instanceof NumericValueEval)) { - throw new AssertionFailedError("Expected numeric result"); - } - NumericValueEval nve = (NumericValueEval)actualEval; - assertEquals(expected, nve.getNumberValue(), 0); - } - - public void testBasic() { - ValueEval[] arg0values = new ValueEval[] { _30, _30, _40, _40, _50, _50 }; - ValueEval[] arg2values = new ValueEval[] { _30, _40, _50, _60, _60, _60 }; - - AreaEval arg0; - AreaEval arg2; - - arg0 = EvalFactory.createAreaEval("A3:B5", arg0values); - arg2 = EvalFactory.createAreaEval("D1:E3", arg2values); - - confirm(60.0, arg0, new NumberEval(30.0)); - confirm(70.0, arg0, new NumberEval(30.0), arg2); - confirm(100.0, arg0, new StringEval(">45")); - - } - private static void confirm(double expectedResult, ValueEval...args) { - confirmDouble(expectedResult, invokeSumif(-1, -1, args)); - } - - - /** - * test for bug observed near svn r882931 - */ - public void testCriteriaArgRange() { - ValueEval[] arg0values = new ValueEval[] { _50, _60, _50, _50, _50, _30, }; - ValueEval[] arg1values = new ValueEval[] { _30, _40, _50, _60, }; - - AreaEval arg0; - AreaEval arg1; - ValueEval ve; - - arg0 = EvalFactory.createAreaEval("A3:B5", arg0values); - arg1 = EvalFactory.createAreaEval("A2:D2", arg1values); // single row range - - ve = invokeSumif(0, 2, arg0, arg1); // invoking from cell C1 - if (ve instanceof NumberEval) { - NumberEval ne = (NumberEval) ve; - if (ne.getNumberValue() == 30.0) { - throw new AssertionFailedError("identified error in SUMIF - criteria arg not evaluated properly"); - } - } - - confirmDouble(200, ve); - - arg0 = EvalFactory.createAreaEval("C1:D3", arg0values); - arg1 = EvalFactory.createAreaEval("B1:B4", arg1values); // single column range - - ve = invokeSumif(3, 0, arg0, arg1); // invoking from cell A4 - - confirmDouble(60, ve); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumproduct.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumproduct.java deleted file mode 100644 index 63d1088e8c..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumproduct.java +++ /dev/null @@ -1,117 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -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.RefEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Test cases for SUMPRODUCT() - * - * @author Josh Micich - */ -public final class TestSumproduct extends TestCase { - - private static ValueEval invokeSumproduct(ValueEval[] args) { - // srcCellRow and srcCellColumn are ignored by SUMPRODUCT - return new Sumproduct().evaluate(args, -1, (short)-1); - } - private static void confirmDouble(double expected, ValueEval actualEval) { - if(!(actualEval instanceof NumericValueEval)) { - fail("Expected numeric result"); - } - NumericValueEval nve = (NumericValueEval)actualEval; - assertEquals(expected, nve.getNumberValue(), 0); - } - - public void testScalarSimple() { - - RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3)); - ValueEval[] args = { - refEval, - new NumberEval(2), - }; - ValueEval result = invokeSumproduct(args); - confirmDouble(6D, result); - } - - public void testAreaSimple() { - ValueEval[] aValues = { - new NumberEval(2), - new NumberEval(4), - new NumberEval(5), - }; - ValueEval[] bValues = { - new NumberEval(3), - new NumberEval(6), - new NumberEval(7), - }; - AreaEval aeA = EvalFactory.createAreaEval("A1:A3", aValues); - AreaEval aeB = EvalFactory.createAreaEval("B1:B3", bValues); - - ValueEval[] args = { aeA, aeB, }; - ValueEval result = invokeSumproduct(args); - confirmDouble(65D, result); - } - - /** - * For scalar products, the terms may be 1x1 area refs - */ - public void testOneByOneArea() { - - AreaEval ae = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(7), }); - - ValueEval[] args = { - ae, - new NumberEval(2), - }; - ValueEval result = invokeSumproduct(args); - confirmDouble(14D, result); - } - - public void testMismatchAreaDimensions() { - - AreaEval aeA = EvalFactory.createAreaEval("A1:A3", new ValueEval[3]); - AreaEval aeB = EvalFactory.createAreaEval("B1:D1", new ValueEval[3]); - - ValueEval[] args; - args = new ValueEval[] { aeA, aeB, }; - assertEquals(ErrorEval.VALUE_INVALID, invokeSumproduct(args)); - - args = new ValueEval[] { aeA, new NumberEval(5), }; - assertEquals(ErrorEval.VALUE_INVALID, invokeSumproduct(args)); - } - - public void testAreaWithErrorCell() { - ValueEval[] aValues = { - ErrorEval.REF_INVALID, - null, - }; - AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues); - AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]); - - ValueEval[] args = { aeA, aeB, }; - assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args)); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTFunc.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTFunc.java deleted file mode 100644 index 9d77b3dd1f..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTFunc.java +++ /dev/null @@ -1,132 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Test cases for Excel function T() - * - * @author Josh Micich - */ -public final class TestTFunc extends TestCase { - - /** - * @return the result of calling function T() with the specified argument - */ - private static ValueEval invokeT(ValueEval arg) { - ValueEval[] args = { arg, }; - ValueEval result = new T().evaluate(args, -1, (short)-1); - assertNotNull("result may never be null", result); - return result; - } - /** - * Simulates call: T(A1) - * where cell A1 has the specified innerValue - */ - private ValueEval invokeTWithReference(ValueEval innerValue) { - ValueEval arg = EvalFactory.createRefEval("$B$2", innerValue); - return invokeT(arg); - } - - private static void confirmText(String text) { - ValueEval arg = new StringEval(text); - ValueEval eval = invokeT(arg); - StringEval se = (StringEval) eval; - assertEquals(text, se.getStringValue()); - } - - public void testTextValues() { - - confirmText("abc"); - confirmText(""); - confirmText(" "); - confirmText("~"); - confirmText("123"); - confirmText("TRUE"); - } - - private static void confirmError(ValueEval arg) { - ValueEval eval = invokeT(arg); - assertTrue(arg == eval); - } - - public void testErrorValues() { - - confirmError(ErrorEval.VALUE_INVALID); - confirmError(ErrorEval.NA); - confirmError(ErrorEval.REF_INVALID); - } - - private static void confirmString(ValueEval eval, String expected) { - assertTrue(eval instanceof StringEval); - assertEquals(expected, ((StringEval)eval).getStringValue()); - } - - private static void confirmOther(ValueEval arg) { - ValueEval eval = invokeT(arg); - confirmString(eval, ""); - } - - public void testOtherValues() { - confirmOther(new NumberEval(2)); - confirmOther(BoolEval.FALSE); - confirmOther(BlankEval.instance); // can this particular case be verified? - } - - public void testRefValues() { - ValueEval eval; - - eval = invokeTWithReference(new StringEval("def")); - confirmString(eval, "def"); - eval = invokeTWithReference(new StringEval(" ")); - confirmString(eval, " "); - - eval = invokeTWithReference(new NumberEval(2)); - confirmString(eval, ""); - eval = invokeTWithReference(BoolEval.TRUE); - confirmString(eval, ""); - - eval = invokeTWithReference(ErrorEval.NAME_INVALID); - assertTrue(eval == ErrorEval.NAME_INVALID); - } - - public void testAreaArg() { - ValueEval[] areaValues = new ValueEval[] { - new StringEval("abc"), new StringEval("def"), - new StringEval("ghi"), new StringEval("jkl"), - }; - AreaEval ae = EvalFactory.createAreaEval("C10:D11", areaValues); - - ValueEval ve; - ve = invokeT(ae); - confirmString(ve, "abc"); - - areaValues[0] = new NumberEval(5.0); - ve = invokeT(ae); - confirmString(ve, ""); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java deleted file mode 100644 index f56132cd54..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java +++ /dev/null @@ -1,113 +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.record.formula.functions; - -import java.text.DecimalFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.GregorianCalendar; -import java.util.Locale; - -import junit.framework.TestCase; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; - -/** - * Test case for TEXT() - * - * @author Stephen Wolke (smwolke at geistig.com) - */ -public final class TestText extends TestCase { - private static final TextFunction T = null; - - public void testTextWithStringFirstArg() { - - ValueEval strArg = new StringEval("abc"); - ValueEval formatArg = new StringEval("abc"); - ValueEval[] args = { strArg, formatArg }; - ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); - assertEquals(ErrorEval.VALUE_INVALID, result); - } - - public void testTextWithDeciamlFormatSecondArg() { - - ValueEval numArg = new NumberEval(321321.321); - ValueEval formatArg = new StringEval("#,###.00000"); - ValueEval[] args = { numArg, formatArg }; - ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); - char groupSeparator = new DecimalFormatSymbols(Locale.getDefault()).getGroupingSeparator(); - char decimalSeparator = new DecimalFormatSymbols(Locale.getDefault()).getDecimalSeparator(); - ValueEval testResult = new StringEval("321" + groupSeparator + "321" + decimalSeparator + "32100"); - assertEquals(testResult.toString(), result.toString()); - numArg = new NumberEval(321.321); - formatArg = new StringEval("00000.00000"); - args[0] = numArg; - args[1] = formatArg; - result = T.TEXT.evaluate(args, -1, (short)-1); - testResult = new StringEval("00321" + decimalSeparator + "32100"); - assertEquals(testResult.toString(), result.toString()); - - formatArg = new StringEval("$#.#"); - args[1] = formatArg; - result = T.TEXT.evaluate(args, -1, (short)-1); - testResult = new StringEval("$321" + decimalSeparator + "3"); - assertEquals(testResult.toString(), result.toString()); - } - - public void testTextWithFractionFormatSecondArg() { - - ValueEval numArg = new NumberEval(321.321); - ValueEval formatArg = new StringEval("# #/#"); - ValueEval[] args = { numArg, formatArg }; - ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); - ValueEval testResult = new StringEval("321 1/3"); - assertEquals(testResult.toString(), result.toString()); - - formatArg = new StringEval("# #/##"); - args[1] = formatArg; - result = T.TEXT.evaluate(args, -1, (short)-1); - testResult = new StringEval("321 26/81"); - assertEquals(testResult.toString(), result.toString()); - - formatArg = new StringEval("#/##"); - args[1] = formatArg; - result = T.TEXT.evaluate(args, -1, (short)-1); - testResult = new StringEval("26027/81"); - assertEquals(testResult.toString(), result.toString()); - } - - public void testTextWithDateFormatSecondArg() { - - ValueEval numArg = new NumberEval(321.321); - ValueEval formatArg = new StringEval("dd:MM:yyyy hh:mm:ss"); - ValueEval[] args = { numArg, formatArg }; - ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); - ValueEval testResult = new StringEval("16:11:1900 07:42:14"); - assertEquals(testResult.toString(), result.toString()); - - // this line is intended to compute how "November" would look like in the current locale - String november = new SimpleDateFormat("MMMM").format(new GregorianCalendar(2010,10,15).getTime()); - - formatArg = new StringEval("MMMM dd, yyyy"); - args[1] = formatArg; - result = T.TEXT.evaluate(args, -1, (short)-1); - testResult = new StringEval(november + " 16, 1900"); - assertEquals(testResult.toString(), result.toString()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTime.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTime.java deleted file mode 100644 index bfd1747393..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTime.java +++ /dev/null @@ -1,122 +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.record.formula.functions; - -import java.util.regex.Pattern; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFCellStyle; -import org.apache.poi.hssf.usermodel.HSSFDataFormat; -import org.apache.poi.hssf.usermodel.HSSFDataFormatter; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; - -/** - * Tests for {@link TimeFunc} - * - * @author @author Steven Butler (sebutler @ gmail dot com) - */ -public final class TestTime extends TestCase { - - private static final int SECONDS_PER_MINUTE = 60; - private static final int SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE; - private static final double SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR; - private HSSFCell cell11; - private HSSFFormulaEvaluator evaluator; - private HSSFWorkbook wb; - private HSSFDataFormatter form; - private HSSFCellStyle style; - - public void setUp() { - wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet("new sheet"); - style = wb.createCellStyle(); - HSSFDataFormat fmt = wb.createDataFormat(); - style.setDataFormat(fmt.getFormat("hh:mm:ss")); - - cell11 = sheet.createRow(0).createCell(0); - form = new HSSFDataFormatter(); - - evaluator = new HSSFFormulaEvaluator(wb); - } - - public void testSomeArgumentsMissing() { - confirm("00:00:00", "TIME(, 0, 0)"); - confirm("12:00:00", "TIME(12, , )"); - } - - public void testValid() { - confirm("00:00:01", 0, 0, 1); - confirm("00:01:00", 0, 1, 0); - - confirm("00:00:00", 0, 0, 0); - - confirm("01:00:00", 1, 0, 0); - confirm("12:00:00", 12, 0, 0); - confirm("23:00:00", 23, 0, 0); - confirm("00:00:00", 24, 0, 0); - confirm("01:00:00", 25, 0, 0); - confirm("00:00:00", 48, 0, 0); - confirm("06:00:00", 6, 0, 0); - confirm("06:01:00", 6, 1, 0); - confirm("06:30:00", 6, 30, 0); - - confirm("06:59:00", 6, 59, 0); - confirm("07:00:00", 6, 60, 0); - confirm("07:01:00", 6, 61, 0); - confirm("08:00:00", 6, 120, 0); - confirm("06:00:00", 6, 1440, 0); - confirm("18:49:00", 18, 49, 0); - confirm("18:49:01", 18, 49, 1); - confirm("18:49:30", 18, 49, 30); - confirm("18:49:59", 18, 49, 59); - confirm("18:50:00", 18, 49, 60); - confirm("18:50:01", 18, 49, 61); - confirm("18:50:59", 18, 49, 119); - confirm("18:51:00", 18, 49, 120); - confirm("03:55:07", 18, 49, 32767); - confirm("12:08:01", 18, 32767, 61); - confirm("07:50:01", 32767, 49, 61); - } - private void confirm(String expectedTimeStr, int inH, int inM, int inS) { - confirm(expectedTimeStr, "TIME(" + inH + "," + inM + "," + inS + ")"); - } - - private void confirm(String expectedTimeStr, String formulaText) { -// System.out.println("=" + formulaText); - String[] parts = Pattern.compile(":").split(expectedTimeStr); - int expH = Integer.parseInt(parts[0]); - int expM = Integer.parseInt(parts[1]); - int expS = Integer.parseInt(parts[2]); - - double expectedValue = (expH*SECONDS_PER_HOUR + expM*SECONDS_PER_MINUTE + expS)/SECONDS_PER_DAY; - - cell11.setCellFormula(formulaText); - cell11.setCellStyle(style); - evaluator.clearAllCachedResultValues(); - - double actualValue = evaluator.evaluate(cell11).getNumberValue(); - assertEquals(expectedValue, actualValue, 0.0); - - String actualText = form.formatCellValue(cell11, evaluator); - assertEquals(expectedTimeStr, actualText); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java deleted file mode 100644 index 5fd7173729..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java +++ /dev/null @@ -1,78 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -/** - * Tests for Excel function TRIM() - * - * @author Josh Micich - */ -public final class TestTrim extends TestCase { - - - private static ValueEval invokeTrim(ValueEval text) { - ValueEval[] args = new ValueEval[] { text, }; - return TextFunction.TRIM.evaluate(args, -1, (short)-1); - } - - private void confirmTrim(ValueEval text, String expected) { - ValueEval result = invokeTrim(text); - assertEquals(StringEval.class, result.getClass()); - assertEquals(expected, ((StringEval)result).getStringValue()); - } - - private void confirmTrim(ValueEval text, ErrorEval expectedError) { - ValueEval result = invokeTrim(text); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); - } - - public void testBasic() { - - confirmTrim(new StringEval(" hi "), "hi"); - confirmTrim(new StringEval("hi "), "hi"); - confirmTrim(new StringEval(" hi"), "hi"); - confirmTrim(new StringEval(" hi there "), "hi there"); - confirmTrim(new StringEval(""), ""); - confirmTrim(new StringEval(" "), ""); - } - - /** - * Valid cases where text arg is not exactly a string - */ - public void testUnusualArgs() { - - // text (first) arg type is number, other args are strings with fractional digits - confirmTrim(new NumberEval(123456), "123456"); - confirmTrim(BoolEval.FALSE, "FALSE"); - confirmTrim(BoolEval.TRUE, "TRUE"); - confirmTrim(BlankEval.instance, ""); - } - - public void testErrors() { - confirmTrim(ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java deleted file mode 100644 index ef42d1ce0f..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java +++ /dev/null @@ -1,59 +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.record.formula.functions; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; - -/** - * Test case for TRUNC() - * - * @author Stephen Wolke (smwolke at geistig.com) - */ -public final class TestTrunc extends AbstractNumericTestCase { - private static final NumericFunction F = null; - public void testTruncWithStringArg() { - - ValueEval strArg = new StringEval("abc"); - ValueEval[] args = { strArg, new NumberEval(2) }; - ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); - assertEquals(ErrorEval.VALUE_INVALID, result); - } - - public void testTruncWithWholeNumber() { - ValueEval[] args = { new NumberEval(200), new NumberEval(2) }; - @SuppressWarnings("static-access") - ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); - assertEquals("TRUNC", (new NumberEval(200d)).getNumberValue(), ((NumberEval)result).getNumberValue()); - } - - public void testTruncWithDecimalNumber() { - ValueEval[] args = { new NumberEval(2.612777), new NumberEval(3) }; - @SuppressWarnings("static-access") - ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); - assertEquals("TRUNC", (new NumberEval(2.612d)).getNumberValue(), ((NumberEval)result).getNumberValue()); - } - - public void testTruncWithDecimalNumberOneArg() { - ValueEval[] args = { new NumberEval(2.612777) }; - ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); - assertEquals("TRUNC", (new NumberEval(2d)).getNumberValue(), ((NumberEval)result).getNumberValue()); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java deleted file mode 100644 index 19a6d68927..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java +++ /dev/null @@ -1,94 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; - -/** - * Tests for {@link Value} - * - * @author Josh Micich - */ -public final class TestValue extends TestCase { - - private static ValueEval invokeValue(String strText) { - ValueEval[] args = new ValueEval[] { new StringEval(strText), }; - return new Value().evaluate(args, -1, (short) -1); - } - - private static void confirmValue(String strText, double expected) { - ValueEval result = invokeValue(strText); - assertEquals(NumberEval.class, result.getClass()); - assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0); - } - - private static void confirmValueError(String strText) { - ValueEval result = invokeValue(strText); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(ErrorEval.VALUE_INVALID, result); - } - - public void testBasic() { - - confirmValue("100", 100); - confirmValue("-2.3", -2.3); - confirmValue(".5", 0.5); - confirmValue(".5e2", 50); - confirmValue(".5e-2", 0.005); - confirmValue(".5e+2", 50); - confirmValue("+5", 5); - confirmValue("$1,000", 1000); - confirmValue("100.5e1", 1005); - confirmValue("1,0000", 10000); - confirmValue("1,000,0000", 10000000); - confirmValue("1,000,0000,00000", 1000000000000.0); - confirmValue(" 100 ", 100); - confirmValue(" + 100", 100); - confirmValue("10000", 10000); - confirmValue("$-5", -5); - confirmValue("$.5", 0.5); - confirmValue("123e+5", 12300000); - confirmValue("1,000e2", 100000); - confirmValue("$10e2", 1000); - confirmValue("$1,000e2", 100000); - } - - public void testErrors() { - confirmValueError("1+1"); - confirmValueError("1 1"); - confirmValueError("1,00.0"); - confirmValueError("1,00"); - confirmValueError("$1,00.5e1"); - confirmValueError("1,00.5e1"); - confirmValueError("1,0,000"); - confirmValueError("1,00,000"); - confirmValueError("++100"); - confirmValueError("$$5"); - confirmValueError("-"); - confirmValueError("+"); - confirmValueError("$"); - confirmValueError(",300"); - confirmValueError("0.233,4"); - confirmValueError("1e2.5"); - } -} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestXYNumericFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestXYNumericFunction.java deleted file mode 100644 index 818409cae7..0000000000 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestXYNumericFunction.java +++ /dev/null @@ -1,135 +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.record.formula.functions; - -import junit.framework.TestCase; - -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; -/** - * Tests for Excel functions SUMX2MY2(), SUMX2PY2(), SUMXMY2() - * - * @author Josh Micich - */ -public final class TestXYNumericFunction extends TestCase { - private static final Function SUM_SQUARES = new Sumx2py2(); - private static final Function DIFF_SQUARES = new Sumx2my2(); - private static final Function SUM_SQUARES_OF_DIFFS = new Sumxmy2(); - - private static ValueEval invoke(Function function, ValueEval xArray, ValueEval yArray) { - ValueEval[] args = new ValueEval[] { xArray, yArray, }; - return function.evaluate(args, -1, (short)-1); - } - - private void confirm(Function function, ValueEval xArray, ValueEval yArray, double expected) { - ValueEval result = invoke(function, xArray, yArray); - assertEquals(NumberEval.class, result.getClass()); - assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); - } - private void confirmError(Function function, ValueEval xArray, ValueEval yArray, ErrorEval expectedError) { - ValueEval result = invoke(function, xArray, yArray); - assertEquals(ErrorEval.class, result.getClass()); - assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); - } - - private void confirmError(ValueEval xArray, ValueEval yArray, ErrorEval expectedError) { - confirmError(SUM_SQUARES, xArray, yArray, expectedError); - confirmError(DIFF_SQUARES, xArray, yArray, expectedError); - confirmError(SUM_SQUARES_OF_DIFFS, xArray, yArray, expectedError); - } - - public void testBasic() { - ValueEval[] xValues = { - new NumberEval(1), - new NumberEval(2), - }; - ValueEval areaEvalX = createAreaEval(xValues); - confirm(SUM_SQUARES, areaEvalX, areaEvalX, 10.0); - confirm(DIFF_SQUARES, areaEvalX, areaEvalX, 0.0); - confirm(SUM_SQUARES_OF_DIFFS, areaEvalX, areaEvalX, 0.0); - - ValueEval[] yValues = { - new NumberEval(3), - new NumberEval(4), - }; - ValueEval areaEvalY = createAreaEval(yValues); - confirm(SUM_SQUARES, areaEvalX, areaEvalY, 30.0); - confirm(DIFF_SQUARES, areaEvalX, areaEvalY, -20.0); - confirm(SUM_SQUARES_OF_DIFFS, areaEvalX, areaEvalY, 8.0); - } - - /** - * number of items in array is not limited to 30 - */ - public void testLargeArrays() { - ValueEval[] xValues = createMockNumberArray(100, 3); - ValueEval[] yValues = createMockNumberArray(100, 2); - - confirm(SUM_SQUARES, createAreaEval(xValues), createAreaEval(yValues), 1300.0); - confirm(DIFF_SQUARES, createAreaEval(xValues), createAreaEval(yValues), 500.0); - confirm(SUM_SQUARES_OF_DIFFS, createAreaEval(xValues), createAreaEval(yValues), 100.0); - } - - - private ValueEval[] createMockNumberArray(int size, double value) { - ValueEval[] result = new ValueEval[size]; - for (int i = 0; i < result.length; i++) { - result[i] = new NumberEval(value); - } - return result; - } - - private static ValueEval createAreaEval(ValueEval[] values) { - String refStr = "A1:A" + values.length; - return EvalFactory.createAreaEval(refStr, values); - } - - public void testErrors() { - ValueEval[] xValues = { - ErrorEval.REF_INVALID, - new NumberEval(2), - }; - ValueEval areaEvalX = createAreaEval(xValues); - ValueEval[] yValues = { - new NumberEval(2), - ErrorEval.NULL_INTERSECTION, - }; - ValueEval areaEvalY = createAreaEval(yValues); - ValueEval[] zValues = { // wrong size - new NumberEval(2), - }; - ValueEval areaEvalZ = createAreaEval(zValues); - - // if either arg is an error, that error propagates - confirmError(ErrorEval.REF_INVALID, ErrorEval.NAME_INVALID, ErrorEval.REF_INVALID); - confirmError(areaEvalX, ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); - confirmError(ErrorEval.NAME_INVALID, areaEvalX, ErrorEval.NAME_INVALID); - - // array sizes must match - confirmError(areaEvalX, areaEvalZ, ErrorEval.NA); - confirmError(areaEvalZ, areaEvalY, ErrorEval.NA); - - // any error in an array item propagates up - confirmError(areaEvalX, areaEvalX, ErrorEval.REF_INVALID); - - // search for errors array by array, not pair by pair - confirmError(areaEvalX, areaEvalY, ErrorEval.REF_INVALID); - confirmError(areaEvalY, areaEvalX, ErrorEval.NULL_INTERSECTION); - } -} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java index 811eef0913..6de40073dc 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java @@ -31,8 +31,8 @@ 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 org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.EvaluationListener; import org.apache.poi.ss.formula.WorkbookEvaluator; diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java index 2d97c1be05..f28725669c 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java @@ -18,13 +18,12 @@ package org.apache.poi.hssf.usermodel; import junit.framework.AssertionFailedError; -import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.record.NameRecord; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.EvaluationCell; import org.apache.poi.ss.formula.EvaluationListener; import org.apache.poi.ss.formula.WorkbookEvaluator; diff --git a/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java b/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java index a9a259175b..128a767f56 100644 --- a/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java +++ b/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java @@ -19,8 +19,8 @@ package org.apache.poi.ss.formula; import junit.framework.TestCase; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; /** * Tests {@link org.apache.poi.ss.formula.CellCacheEntry}. diff --git a/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java b/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java index c1d9523e73..87788ef8e4 100644 --- a/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java +++ b/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java @@ -30,12 +30,12 @@ import junit.framework.TestCase; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -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.NumberEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.hssf.usermodel.FormulaExtractor; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFEvaluationTestHelper; diff --git a/src/testcases/org/apache/poi/ss/formula/TestFormulaShifter.java b/src/testcases/org/apache/poi/ss/formula/TestFormulaShifter.java new file mode 100644 index 0000000000..9f840e12a2 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/TestFormulaShifter.java @@ -0,0 +1,119 @@ +/* ==================================================================== + 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.ss.formula; + +import junit.framework.TestCase; +import org.apache.poi.hssf.record.formula.AreaErrPtg; +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.ss.formula.FormulaShifter; + +/** + * Tests for {@link FormulaShifter}. + * + * @author Josh Micich + */ +public final class TestFormulaShifter extends TestCase { + // Note - the expected result row coordinates here were determined/verified + // in Excel 2007 by manually testing. + + /** + * Tests what happens to area refs when a range of rows from inside, or overlapping are + * moved + */ + public void testShiftAreasSourceRows() { + + // all these operations are on an area ref spanning rows 10 to 20 + AreaPtg aptg = createAreaPtg(10, 20); + + confirmAreaShift(aptg, 9, 21, 20, 30, 40); + confirmAreaShift(aptg, 10, 21, 20, 30, 40); + confirmAreaShift(aptg, 9, 20, 20, 30, 40); + + confirmAreaShift(aptg, 8, 11, -3, 7, 20); // simple expansion of top + // rows containing area top being shifted down: + confirmAreaShift(aptg, 8, 11, 3, 13, 20); + confirmAreaShift(aptg, 8, 11, 7, 17, 20); + confirmAreaShift(aptg, 8, 11, 8, 18, 20); + confirmAreaShift(aptg, 8, 11, 9, 12, 20); // note behaviour changes here + confirmAreaShift(aptg, 8, 11, 10, 12, 21); + confirmAreaShift(aptg, 8, 11, 12, 12, 23); + confirmAreaShift(aptg, 8, 11, 13, 10, 20); // ignored + + // rows from within being moved: + confirmAreaShift(aptg, 12, 16, 3, 10, 20); // stay within - no change + confirmAreaShift(aptg, 11, 19, 20, 10, 20); // move completely out - no change + confirmAreaShift(aptg, 16, 17, -6, 10, 20); // moved exactly to top - no change + confirmAreaShift(aptg, 16, 17, -7, 11, 20); // truncation at top + confirmAreaShift(aptg, 12, 16, 4, 10, 20); // moved exactly to bottom - no change + confirmAreaShift(aptg, 12, 16, 6, 10, 17); // truncation at bottom + + // rows containing area bottom being shifted up: + confirmAreaShift(aptg, 18, 22, -1, 10, 19); // simple contraction at bottom + confirmAreaShift(aptg, 18, 22, -7, 10, 13); // simple contraction at bottom + confirmAreaShift(aptg, 18, 22, -8, 10, 17); // top calculated differently here + confirmAreaShift(aptg, 18, 22, -9, 9, 17); + confirmAreaShift(aptg, 18, 22,-15, 10, 20); // no change because range would be turned inside out + confirmAreaShift(aptg, 15, 19, -7, 13, 20); // dest truncates top (even though src is from inside range) + confirmAreaShift(aptg, 19, 23,-12, 7, 18); // complex: src encloses bottom, dest encloses top + + confirmAreaShift(aptg, 18, 22, 5, 10, 25); // simple expansion at bottom + } + /** + * Tests what happens to an area ref when some outside rows are moved to overlap + * that area ref + */ + public void testShiftAreasDestRows() { + // all these operations are on an area ref spanning rows 20 to 25 + AreaPtg aptg = createAreaPtg(20, 25); + + // no change because no overlap: + confirmAreaShift(aptg, 5, 10, 9, 20, 25); + confirmAreaShift(aptg, 5, 10, 21, 20, 25); + + confirmAreaShift(aptg, 11, 14, 10, 20, 25); + + confirmAreaShift(aptg, 7, 17, 10, -1, -1); // converted to DeletedAreaRef + confirmAreaShift(aptg, 5, 15, 7, 23, 25); // truncation at top + confirmAreaShift(aptg, 13, 16, 10, 20, 22); // truncation at bottom + } + + private static void confirmAreaShift(AreaPtg aptg, + int firstRowMoved, int lastRowMoved, int numberRowsMoved, + int expectedAreaFirstRow, int expectedAreaLastRow) { + + FormulaShifter fs = FormulaShifter.createForRowShift(0, firstRowMoved, lastRowMoved, numberRowsMoved); + boolean expectedChanged = aptg.getFirstRow() != expectedAreaFirstRow || aptg.getLastRow() != expectedAreaLastRow; + + AreaPtg copyPtg = (AreaPtg) aptg.copy(); // clone so we can re-use aptg in calling method + Ptg[] ptgs = { copyPtg, }; + boolean actualChanged = fs.adjustFormula(ptgs, 0); + if (expectedAreaFirstRow < 0) { + assertEquals(AreaErrPtg.class, ptgs[0].getClass()); + return; + } + assertEquals(expectedChanged, actualChanged); + assertEquals(copyPtg, ptgs[0]); // expected to change in place (although this is not a strict requirement) + assertEquals(expectedAreaFirstRow, copyPtg.getFirstRow()); + assertEquals(expectedAreaLastRow, copyPtg.getLastRow()); + + } + private static AreaPtg createAreaPtg(int initialAreaFirstRow, int initialAreaLastRow) { + return new AreaPtg(initialAreaFirstRow, initialAreaLastRow, 2, 5, false, false, false, false); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/TestSheetNameFormatter.java b/src/testcases/org/apache/poi/ss/formula/TestSheetNameFormatter.java new file mode 100644 index 0000000000..69b0c9b4ff --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/TestSheetNameFormatter.java @@ -0,0 +1,108 @@ +/* ==================================================================== + 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.ss.formula; + +import junit.framework.TestCase; +import org.apache.poi.ss.formula.SheetNameFormatter; + +/** + * Tests for {@link SheetNameFormatter} + * + * @author Josh Micich + */ +public final class TestSheetNameFormatter extends TestCase { + + private static void confirmFormat(String rawSheetName, String expectedSheetNameEncoding) { + assertEquals(expectedSheetNameEncoding, SheetNameFormatter.format(rawSheetName)); + } + + /** + * Tests main public method 'format' + */ + public void testFormat() { + + confirmFormat("abc", "abc"); + confirmFormat("123", "'123'"); + + confirmFormat("my sheet", "'my sheet'"); // space + confirmFormat("A:MEM", "'A:MEM'"); // colon + + confirmFormat("O'Brian", "'O''Brian'"); // single quote gets doubled + + + confirmFormat("3rdTimeLucky", "'3rdTimeLucky'"); // digit in first pos + confirmFormat("_", "_"); // plain underscore OK + confirmFormat("my_3rd_sheet", "my_3rd_sheet"); // underscores and digits OK + confirmFormat("A12220", "'A12220'"); + confirmFormat("TAXRETURN19980415", "TAXRETURN19980415"); + } + + public void testBooleanLiterals() { + confirmFormat("TRUE", "'TRUE'"); + confirmFormat("FALSE", "'FALSE'"); + confirmFormat("True", "'True'"); + confirmFormat("fAlse", "'fAlse'"); + + confirmFormat("Yes", "Yes"); + confirmFormat("No", "No"); + } + + private static void confirmCellNameMatch(String rawSheetName, boolean expected) { + assertEquals(expected, SheetNameFormatter.nameLooksLikePlainCellReference(rawSheetName)); + } + + /** + * Tests functionality to determine whether a sheet name containing only letters and digits + * would look (to Excel) like a cell name. + */ + public void testLooksLikePlainCellReference() { + + confirmCellNameMatch("A1", true); + confirmCellNameMatch("a111", true); + confirmCellNameMatch("AA", false); + confirmCellNameMatch("aa1", true); + confirmCellNameMatch("A1A", false); + confirmCellNameMatch("A1A1", false); + confirmCellNameMatch("Sh3", false); + confirmCellNameMatch("SALES20080101", false); // out of range + } + + private static void confirmCellRange(String text, int numberOfPrefixLetters, boolean expected) { + String prefix = text.substring(0, numberOfPrefixLetters); + String suffix = text.substring(numberOfPrefixLetters); + assertEquals(expected, SheetNameFormatter.cellReferenceIsWithinRange(prefix, suffix)); + } + + /** + * Tests exact boundaries for names that look very close to cell names (i.e. contain 1 or more + * letters followed by one or more digits). + */ + public void testCellRange() { + confirmCellRange("A1", 1, true); + confirmCellRange("a111", 1, true); + confirmCellRange("A65536", 1, true); + confirmCellRange("A65537", 1, false); + confirmCellRange("iv1", 2, true); + confirmCellRange("IW1", 2, false); + confirmCellRange("AAA1", 3, false); + confirmCellRange("a111", 1, true); + confirmCellRange("Sheet1", 6, false); + confirmCellRange("iV65536", 2, true); // max cell in Excel 97-2003 + confirmCellRange("IW65537", 2, false); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java index 5e59933cf6..8dac906ecb 100644 --- a/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java +++ b/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java @@ -28,11 +28,11 @@ import org.apache.poi.hssf.record.formula.DeletedRef3DPtg; import org.apache.poi.hssf.record.formula.IntPtg; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.RefErrorPtg; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.MissingArgEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.MissingArgEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; diff --git a/src/testcases/org/apache/poi/ss/formula/atp/TestRandBetween.java b/src/testcases/org/apache/poi/ss/formula/atp/TestRandBetween.java new file mode 100644 index 0000000000..6b8d50322e --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/atp/TestRandBetween.java @@ -0,0 +1,193 @@ +/* ==================================================================== + 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.ss.formula.atp; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * Testcase for 'Analysis Toolpak' function RANDBETWEEN() + * + * @author Brendan Nolan + */ +public class TestRandBetween extends TestCase { + + private Workbook wb; + private FormulaEvaluator evaluator; + private Cell bottomValueCell; + private Cell topValueCell; + private Cell formulaCell; + + @Override + protected void setUp() throws Exception { + super.setUp(); + wb = HSSFTestDataSamples.openSampleWorkbook("TestRandBetween.xls"); + evaluator = wb.getCreationHelper().createFormulaEvaluator(); + + Sheet sheet = wb.createSheet("RandBetweenSheet"); + Row row = sheet.createRow(0); + bottomValueCell = row.createCell(0); + topValueCell = row.createCell(1); + formulaCell = row.createCell(2, Cell.CELL_TYPE_FORMULA); + } + + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + } + + /** + * Check where values are the same + */ + public void testRandBetweenSameValues() { + + evaluator.clearAllCachedResultValues(); + formulaCell.setCellFormula("RANDBETWEEN(1,1)"); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(1, formulaCell.getNumericCellValue(), 0); + evaluator.clearAllCachedResultValues(); + formulaCell.setCellFormula("RANDBETWEEN(-1,-1)"); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(-1, formulaCell.getNumericCellValue(), 0); + + } + + /** + * Check special case where rounded up bottom value is greater than + * top value. + */ + public void testRandBetweenSpecialCase() { + + + bottomValueCell.setCellValue(0.05); + topValueCell.setCellValue(0.1); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(1, formulaCell.getNumericCellValue(), 0); + bottomValueCell.setCellValue(-0.1); + topValueCell.setCellValue(-0.05); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(0, formulaCell.getNumericCellValue(), 0); + bottomValueCell.setCellValue(-1.1); + topValueCell.setCellValue(-1.05); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(-1, formulaCell.getNumericCellValue(), 0); + bottomValueCell.setCellValue(-1.1); + topValueCell.setCellValue(-1.1); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(-1, formulaCell.getNumericCellValue(), 0); + } + + /** + * Check top value of BLANK which Excel will evaluate as 0 + */ + public void testRandBetweenTopBlank() { + + bottomValueCell.setCellValue(-1); + topValueCell.setCellType(Cell.CELL_TYPE_BLANK); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertTrue(formulaCell.getNumericCellValue() == 0 || formulaCell.getNumericCellValue() == -1); + + } + /** + * Check where input values are of wrong type + */ + public void testRandBetweenWrongInputTypes() { + // Check case where bottom input is of the wrong type + bottomValueCell.setCellValue("STRING"); + topValueCell.setCellValue(1); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); + assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); + + + // Check case where top input is of the wrong type + bottomValueCell.setCellValue(1); + topValueCell.setCellValue("STRING"); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); + assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); + + // Check case where both inputs are of wrong type + bottomValueCell.setCellValue("STRING"); + topValueCell.setCellValue("STRING"); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); + assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), formulaCell.getErrorCellValue()); + + } + + /** + * Check case where bottom is greater than top + */ + public void testRandBetweenBottomGreaterThanTop() { + + // Check case where bottom is greater than top + bottomValueCell.setCellValue(1); + topValueCell.setCellValue(0); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); + assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), formulaCell.getErrorCellValue()); + bottomValueCell.setCellValue(1); + topValueCell.setCellType(Cell.CELL_TYPE_BLANK); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertEquals(Cell.CELL_TYPE_ERROR, formulaCell.getCachedFormulaResultType()); + assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), formulaCell.getErrorCellValue()); + } + + /** + * Boundary check of Double MIN and MAX values + */ + public void testRandBetweenBoundaryCheck() { + + bottomValueCell.setCellValue(Double.MIN_VALUE); + topValueCell.setCellValue(Double.MAX_VALUE); + formulaCell.setCellFormula("RANDBETWEEN($A$1,$B$1)"); + evaluator.clearAllCachedResultValues(); + evaluator.evaluateFormulaCell(formulaCell); + assertTrue(formulaCell.getNumericCellValue() >= Double.MIN_VALUE && formulaCell.getNumericCellValue() <= Double.MAX_VALUE); + + } + +} diff --git a/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculator.java b/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculator.java new file mode 100644 index 0000000000..22d3ba3492 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculator.java @@ -0,0 +1,67 @@ +/* ==================================================================== + 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.ss.formula.atp; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.EvaluationException; +import org.apache.poi.ss.usermodel.DateUtil; + +/** + * Specific test cases for YearFracCalculator + */ +public final class TestYearFracCalculator extends TestCase { + + public void testBasis1() { + confirm(md(1999, 1, 1), md(1999, 4, 5), 1, 0.257534247); + confirm(md(1999, 4, 1), md(1999, 4, 5), 1, 0.010958904); + confirm(md(1999, 4, 1), md(1999, 4, 4), 1, 0.008219178); + confirm(md(1999, 4, 2), md(1999, 4, 5), 1, 0.008219178); + confirm(md(1999, 3, 31), md(1999, 4, 3), 1, 0.008219178); + confirm(md(1999, 4, 5), md(1999, 4, 8), 1, 0.008219178); + confirm(md(1999, 4, 4), md(1999, 4, 7), 1, 0.008219178); + confirm(md(2000, 2, 5), md(2000, 6, 1), 0, 0.322222222); + } + + private void confirm(double startDate, double endDate, int basis, double expectedValue) { + double actualValue; + try { + actualValue = YearFracCalculator.calculate(startDate, endDate, basis); + } catch (EvaluationException e) { + throw new RuntimeException(e); + } + double diff = actualValue - expectedValue; + if (Math.abs(diff) > 0.000000001) { + double hours = diff * 365 * 24; + System.out.println(startDate + " " + endDate + " off by " + hours + " hours"); + assertEquals(expectedValue, actualValue, 0.000000001); + } + + } + + private static double md(int year, int month, int day) { + Calendar c = new GregorianCalendar(); + + c.set(year, month-1, day, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + return DateUtil.getExcelDate(c.getTime()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculatorFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculatorFromSpreadsheet.java new file mode 100644 index 0000000000..d735fe8c2c --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/atp/TestYearFracCalculatorFromSpreadsheet.java @@ -0,0 +1,178 @@ +/* ==================================================================== + 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.ss.formula.atp; + +import java.io.PrintStream; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Iterator; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.ComparisonFailure; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.eval.EvaluationException; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * Tests YearFracCalculator using test-cases listed in a sample spreadsheet + * + * @author Josh Micich + */ +public final class TestYearFracCalculatorFromSpreadsheet extends TestCase { + + private static final class SS { + + public static final int BASIS_COLUMN = 1; // "B" + public static final int START_YEAR_COLUMN = 2; // "C" + public static final int END_YEAR_COLUMN = 5; // "F" + public static final int YEARFRAC_FORMULA_COLUMN = 11; // "L" + public static final int EXPECTED_RESULT_COLUMN = 13; // "N" + } + + public void testAll() { + + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("yearfracExamples.xls"); + HSSFSheet sheet = wb.getSheetAt(0); + HSSFFormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator(wb); + int nSuccess = 0; + int nFailures = 0; + int nUnexpectedErrors = 0; + Iterator rowIterator = sheet.rowIterator(); + while(rowIterator.hasNext()) { + HSSFRow row = (HSSFRow) rowIterator.next(); + + HSSFCell cell = row.getCell(SS.YEARFRAC_FORMULA_COLUMN); + if (cell == null || cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) { + continue; + } + try { + processRow(row, cell, formulaEvaluator); + nSuccess++; + } catch (RuntimeException e) { + nUnexpectedErrors ++; + printShortStackTrace(System.err, e); + } catch (AssertionFailedError e) { + nFailures ++; + printShortStackTrace(System.err, e); + } + } + if (nUnexpectedErrors + nFailures > 0) { + String msg = nFailures + " failures(s) and " + nUnexpectedErrors + + " unexpected errors(s) occurred. See stderr for details"; + throw new AssertionFailedError(msg); + } + if (nSuccess < 1) { + throw new RuntimeException("No test sample cases found"); + } + } + + private static void processRow(HSSFRow row, HSSFCell cell, HSSFFormulaEvaluator formulaEvaluator) { + + double startDate = makeDate(row, SS.START_YEAR_COLUMN); + double endDate = makeDate(row, SS.END_YEAR_COLUMN); + + int basis = getIntCell(row, SS.BASIS_COLUMN); + + double expectedValue = getDoubleCell(row, SS.EXPECTED_RESULT_COLUMN); + + double actualValue; + try { + actualValue = YearFracCalculator.calculate(startDate, endDate, basis); + } catch (EvaluationException e) { + throw new RuntimeException(e); + } + if (expectedValue != actualValue) { + throw new ComparisonFailure("Direct calculate failed - row " + (row.getRowNum()+1), + String.valueOf(expectedValue), String.valueOf(actualValue)); + } + actualValue = formulaEvaluator.evaluate(cell).getNumberValue(); + if (expectedValue != actualValue) { + throw new ComparisonFailure("Formula evaluate failed - row " + (row.getRowNum()+1), + String.valueOf(expectedValue), String.valueOf(actualValue)); + } + } + + private static double makeDate(HSSFRow row, int yearColumn) { + int year = getIntCell(row, yearColumn + 0); + int month = getIntCell(row, yearColumn + 1); + int day = getIntCell(row, yearColumn + 2); + Calendar c = new GregorianCalendar(year, month-1, day, 0, 0, 0); + c.set(Calendar.MILLISECOND, 0); + return HSSFDateUtil.getExcelDate(c.getTime()); + } + + private static int getIntCell(HSSFRow row, int colIx) { + double dVal = getDoubleCell(row, colIx); + if (Math.floor(dVal) != dVal) { + throw new RuntimeException("Non integer value (" + dVal + + ") cell found at column " + (char)('A' + colIx)); + } + return (int)dVal; + } + + private static double getDoubleCell(HSSFRow row, int colIx) { + HSSFCell cell = row.getCell(colIx); + if (cell == null) { + throw new RuntimeException("No cell found at column " + colIx); + } + double dVal = cell.getNumericCellValue(); + return dVal; + } + + /** + * Useful to keep output concise when expecting many failures to be reported by this test case + * TODO - refactor duplicates in other Test~FromSpreadsheet classes + */ + private static void printShortStackTrace(PrintStream ps, Throwable e) { + StackTraceElement[] stes = e.getStackTrace(); + + int startIx = 0; + // skip any top frames inside junit.framework.Assert + while(startIx= endIx) { + // something went wrong. just print the whole stack trace + e.printStackTrace(ps); + } + endIx -= 4; // skip 4 frames of reflection invocation + ps.println(e.toString()); + for(int i=startIx; iorg.apache.poi.hssf.record.formula.eval. + * + * @author Josh Micich + */ +public class AllFormulaEvalTests { + + public static Test suite() { + TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName()); + result.addTestSuite(TestAreaEval.class); + result.addTestSuite(TestCircularReferences.class); + result.addTestSuite(TestDivideEval.class); + result.addTestSuite(TestEqualEval.class); + result.addTestSuite(TestExternalFunction.class); + result.addTestSuite(TestFormulaBugs.class); + result.addTestSuite(TestFormulasFromSpreadsheet.class); + result.addTestSuite(TestMinusZeroResult.class); + result.addTestSuite(TestMissingArgEval.class); + result.addTestSuite(TestPercentEval.class); + result.addTestSuite(TestRangeEval.class); + result.addTestSuite(TestUnaryPlusEval.class); + return result; + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/EvalInstances.java b/src/testcases/org/apache/poi/ss/formula/eval/EvalInstances.java new file mode 100644 index 0000000000..4a15444773 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/EvalInstances.java @@ -0,0 +1,53 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import org.apache.poi.ss.formula.functions.Function; + +/** + * Collects eval instances for easy access by tests in this package + * + * @author Josh Micich + */ +final class EvalInstances { + private EvalInstances() { + // no instances of this class + } + + public static final Function Add = TwoOperandNumericOperation.AddEval; + public static final Function Subtract = TwoOperandNumericOperation.SubtractEval; + public static final Function Multiply = TwoOperandNumericOperation.MultiplyEval; + public static final Function Divide = TwoOperandNumericOperation.DivideEval; + + public static final Function Power = TwoOperandNumericOperation.PowerEval; + + public static final Function Percent = PercentEval.instance; + + public static final Function UnaryMinus = UnaryMinusEval.instance; + public static final Function UnaryPlus = UnaryPlusEval.instance; + + public static final Function Equal = RelationalOperationEval.EqualEval; + public static final Function LessThan = RelationalOperationEval.LessThanEval; + public static final Function LessEqual = RelationalOperationEval.LessEqualEval; + public static final Function GreaterThan = RelationalOperationEval.GreaterThanEval; + public static final Function GreaterEqual = RelationalOperationEval.GreaterEqualEval; + public static final Function NotEqual = RelationalOperationEval.NotEqualEval; + + public static final Function Range = RangeEval.instance; + public static final Function Concat = ConcatEval.instance; +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestAreaEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestAreaEval.java new file mode 100644 index 0000000000..3965766cd6 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestAreaEval.java @@ -0,0 +1,62 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.ss.formula.functions.EvalFactory; + +/** + * Tests for AreaEval + * + * @author Josh Micich + */ +public final class TestAreaEval extends TestCase { + + public void testGetValue_bug44950() { + // TODO - this test probably isn't testing much anymore + AreaPtg ptg = new AreaPtg("B2:D3"); + NumberEval one = new NumberEval(1); + ValueEval[] values = { + one, + new NumberEval(2), + new NumberEval(3), + new NumberEval(4), + new NumberEval(5), + new NumberEval(6), + }; + AreaEval ae = EvalFactory.createAreaEval(ptg, values); + if (one == ae.getAbsoluteValue(1, 2)) { + throw new AssertionFailedError("Identified bug 44950 a"); + } + confirm(1, ae, 1, 1); + confirm(2, ae, 1, 2); + confirm(3, ae, 1, 3); + confirm(4, ae, 2, 1); + confirm(5, ae, 2, 2); + confirm(6, ae, 2, 3); + + } + + private static void confirm(int expectedValue, AreaEval ae, int row, int col) { + NumberEval v = (NumberEval) ae.getAbsoluteValue(row, col); + assertEquals(expectedValue, v.getNumberValue(), 0.0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestCircularReferences.java b/src/testcases/org/apache/poi/ss/formula/eval/TestCircularReferences.java new file mode 100644 index 0000000000..ca3b7b56ae --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestCircularReferences.java @@ -0,0 +1,169 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellValue; +/** + * Tests HSSFFormulaEvaluator for its handling of cell formula circular references. + * + * @author Josh Micich + */ +public final class TestCircularReferences extends TestCase { + /** + * Translates StackOverflowError into AssertionFailedError + */ + private static CellValue evaluateWithCycles(HSSFWorkbook wb, HSSFCell testCell) + throws AssertionFailedError { + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb); + try { + return evaluator.evaluate(testCell); + } catch (StackOverflowError e) { + throw new AssertionFailedError( "circular reference caused stack overflow error"); + } + } + /** + * Makes sure that the specified evaluated cell value represents a circular reference error. + */ + private static void confirmCycleErrorCode(CellValue cellValue) { + assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_ERROR); + assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cellValue.getErrorValue()); + } + + + /** + * ASF Bugzilla Bug 44413 + * "INDEX() formula cannot contain its own location in the data array range" + */ + public void testIndexFormula() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + + int colB = 1; + sheet.createRow(0).createCell(colB).setCellValue(1); + sheet.createRow(1).createCell(colB).setCellValue(2); + sheet.createRow(2).createCell(colB).setCellValue(3); + HSSFRow row4 = sheet.createRow(3); + HSSFCell testCell = row4.createCell(0); + // This formula should evaluate to the contents of B2, + testCell.setCellFormula("INDEX(A1:B4,2,2)"); + // However the range A1:B4 also includes the current cell A4. If the other parameters + // were 4 and 1, this would represent a circular reference. Prior to v3.2 POI would + // 'fully' evaluate ref arguments before invoking operators, which raised the possibility of + // cycles / StackOverflowErrors. + + + CellValue cellValue = evaluateWithCycles(wb, testCell); + + assertTrue(cellValue.getCellType() == HSSFCell.CELL_TYPE_NUMERIC); + assertEquals(2, cellValue.getNumberValue(), 0); + } + + /** + * Cell A1 has formula "=A1" + */ + public void testSimpleCircularReference() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + + HSSFRow row = sheet.createRow(0); + HSSFCell testCell = row.createCell(0); + testCell.setCellFormula("A1"); + + CellValue cellValue = evaluateWithCycles(wb, testCell); + + confirmCycleErrorCode(cellValue); + } + + /** + * A1=B1, B1=C1, C1=D1, D1=A1 + */ + public void testMultiLevelCircularReference() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + + HSSFRow row = sheet.createRow(0); + row.createCell(0).setCellFormula("B1"); + row.createCell(1).setCellFormula("C1"); + row.createCell(2).setCellFormula("D1"); + HSSFCell testCell = row.createCell(3); + testCell.setCellFormula("A1"); + + CellValue cellValue = evaluateWithCycles(wb, testCell); + + confirmCycleErrorCode(cellValue); + } + + public void testIntermediateCircularReferenceResults_bug46898() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + + HSSFRow row = sheet.createRow(0); + + HSSFCell cellA1 = row.createCell(0); + HSSFCell cellB1 = row.createCell(1); + HSSFCell cellC1 = row.createCell(2); + HSSFCell cellD1 = row.createCell(3); + HSSFCell cellE1 = row.createCell(4); + + cellA1.setCellFormula("IF(FALSE, 1+B1, 42)"); + cellB1.setCellFormula("1+C1"); + cellC1.setCellFormula("1+D1"); + cellD1.setCellFormula("1+E1"); + cellE1.setCellFormula("1+A1"); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv; + + // Happy day flow - evaluate A1 first + cv = fe.evaluate(cellA1); + assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(42.0, cv.getNumberValue(), 0.0); + cv = fe.evaluate(cellB1); // no circ-ref-error because A1 result is cached + assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(46.0, cv.getNumberValue(), 0.0); + + // Show the bug - evaluate another cell from the loop first + fe.clearAllCachedResultValues(); + cv = fe.evaluate(cellB1); + if (cv.getCellType() == ErrorEval.CIRCULAR_REF_ERROR.getErrorCode()) { + throw new AssertionFailedError("Identified bug 46898"); + } + assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(46.0, cv.getNumberValue(), 0.0); + + // start evaluation on another cell + fe.clearAllCachedResultValues(); + cv = fe.evaluate(cellE1); + assertEquals(Cell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(43.0, cv.getNumberValue(), 0.0); + + + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestDivideEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestDivideEval.java new file mode 100644 index 0000000000..11c661d9fa --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestDivideEval.java @@ -0,0 +1,62 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.functions.EvalFactory; +import org.apache.poi.ss.formula.functions.NumericFunctionInvoker; + +/** + * Test for divide operator evaluator. + * + * @author Josh Micich + */ +public final class TestDivideEval extends TestCase { + + private static void confirm(ValueEval arg0, ValueEval arg1, double expectedResult) { + ValueEval[] args = { + arg0, arg1, + }; + + double result = NumericFunctionInvoker.invoke(EvalInstances.Divide, args, 0, 0); + + assertEquals(expectedResult, result, 0); + } + + public void testBasic() { + confirm(new NumberEval(5), new NumberEval(2), 2.5); + confirm(new NumberEval(3), new NumberEval(16), 0.1875); + confirm(new NumberEval(-150), new NumberEval(-15), 10.0); + confirm(new StringEval("0.2"), new NumberEval(0.05), 4.0); + confirm(BoolEval.TRUE, new StringEval("-0.2"), -5.0); + } + + public void test1x1Area() { + AreaEval ae0 = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), }); + AreaEval ae1 = EvalFactory.createAreaEval("C2:C2", new ValueEval[] { new NumberEval(10), }); + confirm(ae0, ae1, 5); + } + public void testDivZero() { + ValueEval[] args = { + new NumberEval(5), NumberEval.ZERO, + }; + ValueEval result = EvalInstances.Divide.evaluate(args, 0, (short) 0); + assertEquals(ErrorEval.DIV_ZERO, result); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestEqualEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestEqualEval.java new file mode 100644 index 0000000000..7eaa3e9132 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestEqualEval.java @@ -0,0 +1,169 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.functions.EvalFactory; +import org.apache.poi.ss.formula.functions.Function; + +/** + * Test for {@link EqualEval} + * + * @author Josh Micich + */ +public final class TestEqualEval extends TestCase { + // convenient access to namepace + private static final EvalInstances EI = null; + + /** + * Test for bug observable at svn revision 692218 (Sep 2008)
+ * The value from a 1x1 area should be taken immediately, regardless of srcRow and srcCol + */ + public void test1x1AreaOperand() { + + ValueEval[] values = { BoolEval.FALSE, }; + ValueEval[] args = { + EvalFactory.createAreaEval("B1:B1", values), + BoolEval.FALSE, + }; + ValueEval result = evaluate(EI.Equal, args, 10, 10); + if (result instanceof ErrorEval) { + if (result == ErrorEval.VALUE_INVALID) { + throw new AssertionFailedError("Identified bug in evaluation of 1x1 area"); + } + } + assertEquals(BoolEval.class, result.getClass()); + assertTrue(((BoolEval)result).getBooleanValue()); + } + /** + * Empty string is equal to blank + */ + public void testBlankEqualToEmptyString() { + + ValueEval[] args = { + new StringEval(""), + BlankEval.instance, + }; + ValueEval result = evaluate(EI.Equal, args, 10, 10); + assertEquals(BoolEval.class, result.getClass()); + BoolEval be = (BoolEval) result; + if (!be.getBooleanValue()) { + throw new AssertionFailedError("Identified bug blank/empty string equality"); + } + assertTrue(be.getBooleanValue()); + } + + /** + * Test for bug 46613 (observable at svn r737248) + */ + public void testStringInsensitive_bug46613() { + if (!evalStringCmp("abc", "aBc", EI.Equal)) { + throw new AssertionFailedError("Identified bug 46613"); + } + assertTrue(evalStringCmp("abc", "aBc", EI.Equal)); + assertTrue(evalStringCmp("ABC", "azz", EI.LessThan)); + assertTrue(evalStringCmp("abc", "AZZ", EI.LessThan)); + assertTrue(evalStringCmp("ABC", "aaa", EI.GreaterThan)); + assertTrue(evalStringCmp("abc", "AAA", EI.GreaterThan)); + } + + private static boolean evalStringCmp(String a, String b, Function cmpOp) { + ValueEval[] args = { + new StringEval(a), + new StringEval(b), + }; + ValueEval result = evaluate(cmpOp, args, 10, 20); + assertEquals(BoolEval.class, result.getClass()); + BoolEval be = (BoolEval) result; + return be.getBooleanValue(); + } + + public void testBooleanCompares() { + confirmCompares(BoolEval.TRUE, new StringEval("TRUE"), +1); + confirmCompares(BoolEval.TRUE, new NumberEval(1.0), +1); + confirmCompares(BoolEval.TRUE, BoolEval.TRUE, 0); + confirmCompares(BoolEval.TRUE, BoolEval.FALSE, +1); + + confirmCompares(BoolEval.FALSE, new StringEval("TRUE"), +1); + confirmCompares(BoolEval.FALSE, new StringEval("FALSE"), +1); + confirmCompares(BoolEval.FALSE, new NumberEval(0.0), +1); + confirmCompares(BoolEval.FALSE, BoolEval.FALSE, 0); + } + private static void confirmCompares(ValueEval a, ValueEval b, int expRes) { + confirm(a, b, expRes>0, EI.GreaterThan); + confirm(a, b, expRes>=0, EI.GreaterEqual); + confirm(a, b, expRes==0, EI.Equal); + confirm(a, b, expRes<=0, EI.LessEqual); + confirm(a, b, expRes<0, EI.LessThan); + + confirm(b, a, expRes<0, EI.GreaterThan); + confirm(b, a, expRes<=0, EI.GreaterEqual); + confirm(b, a, expRes==0, EI.Equal); + confirm(b, a, expRes>=0, EI.LessEqual); + confirm(b, a, expRes>0, EI.LessThan); + } + private static void confirm(ValueEval a, ValueEval b, boolean expectedResult, Function cmpOp) { + ValueEval[] args = { a, b, }; + ValueEval result = evaluate(cmpOp, args, 10, 20); + assertEquals(BoolEval.class, result.getClass()); + assertEquals(expectedResult, ((BoolEval) result).getBooleanValue()); + } + + /** + * Bug 47198 involved a formula "-A1=0" where cell A1 was 0.0. + * Excel evaluates "-A1=0" to TRUE, not because it thinks -0.0==0.0 + * but because "-A1" evaluated to +0.0 + *

+ * Note - the original diagnosis of bug 47198 was that + * "Excel considers -0.0 to be equal to 0.0" which is NQR + * See {@link TestMinusZeroResult} for more specific tests regarding -0.0. + */ + public void testZeroEquality_bug47198() { + NumberEval zero = new NumberEval(0.0); + NumberEval mZero = (NumberEval) evaluate(UnaryMinusEval.instance, new ValueEval[] { zero, }, 0, 0); + if (Double.doubleToLongBits(mZero.getNumberValue()) == 0x8000000000000000L) { + throw new AssertionFailedError("Identified bug 47198: unary minus should convert -0.0 to 0.0"); + } + ValueEval[] args = { zero, mZero, }; + BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0); + if (!result.getBooleanValue()) { + throw new AssertionFailedError("Identified bug 47198: -0.0 != 0.0"); + } + } + + public void testRounding_bug47598() { + double x = 1+1.0028-0.9973; // should be 1.0055, but has IEEE rounding + assertFalse(x == 1.0055); + + NumberEval a = new NumberEval(x); + NumberEval b = new NumberEval(1.0055); + assertEquals("1.0055", b.getStringValue()); + + ValueEval[] args = { a, b, }; + BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0); + if (!result.getBooleanValue()) { + throw new AssertionFailedError("Identified bug 47598: 1+1.0028-0.9973 != 1.0055"); + } + } + + private static ValueEval evaluate(Function oper, ValueEval[] args, int srcRowIx, int srcColIx) { + return oper.evaluate(args, srcRowIx, (short) srcColIx); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/ss/formula/eval/TestExternalFunction.java new file mode 100644 index 0000000000..30500b19a9 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestExternalFunction.java @@ -0,0 +1,95 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.functions.FreeRefFunction; +import org.apache.poi.ss.formula.udf.DefaultUDFFinder; +import org.apache.poi.ss.formula.udf.AggregatingUDFFinder; +import org.apache.poi.ss.formula.udf.UDFFinder; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.formula.OperationEvaluationContext; + +/** + * @author Josh Micich + * @author Petr Udalau - registering UDFs in workbook and using ToolPacks. + */ +public final class TestExternalFunction extends TestCase { + + private static class MyFunc implements FreeRefFunction { + public MyFunc() { + // + } + + public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { + if (args.length != 1 || !(args[0] instanceof StringEval)) { + return ErrorEval.VALUE_INVALID; + } + StringEval input = (StringEval) args[0]; + return new StringEval(input.getStringValue() + "abc"); + } + } + + private static class MyFunc2 implements FreeRefFunction { + public MyFunc2() { + // + } + + public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { + if (args.length != 1 || !(args[0] instanceof StringEval)) { + return ErrorEval.VALUE_INVALID; + } + StringEval input = (StringEval) args[0]; + return new StringEval(input.getStringValue() + "abc2"); + } + } + + /** + * Checks that an external function can get invoked from the formula + * evaluator. + */ + public void testInvoke() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); + HSSFSheet sheet = wb.getSheetAt(0); + + /** + * register the two test UDFs in a UDF finder, to be passed to the evaluator + */ + UDFFinder udff1 = new DefaultUDFFinder(new String[] { "myFunc", }, + new FreeRefFunction[] { new MyFunc(), }); + UDFFinder udff2 = new DefaultUDFFinder(new String[] { "myFunc2", }, + new FreeRefFunction[] { new MyFunc2(), }); + UDFFinder udff = new AggregatingUDFFinder(udff1, udff2); + + + HSSFRow row = sheet.getRow(0); + HSSFCell myFuncCell = row.getCell(1); // =myFunc("_") + + HSSFCell myFunc2Cell = row.getCell(2); // =myFunc2("_") + + HSSFFormulaEvaluator fe = HSSFFormulaEvaluator.create(wb, null, udff); + assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue()); + assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java b/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java new file mode 100644 index 0000000000..824c8aba5d --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestFormulaBugs.java @@ -0,0 +1,176 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Miscellaneous tests for bugzilla entries.

The test name contains the + * bugzilla bug id. + * + * + * @author Josh Micich + */ +public final class TestFormulaBugs extends TestCase { + + /** + * Bug 27349 - VLOOKUP with reference to another sheet.

This test was + * added long after the relevant functionality was fixed. + */ + public void test27349() { + // 27349-vlookupAcrossSheets.xls is bugzilla/attachment.cgi?id=10622 + InputStream is = HSSFTestDataSamples.openSampleFileStream("27349-vlookupAcrossSheets.xls"); + HSSFWorkbook wb; + try { + // original bug may have thrown exception here, or output warning to + // stderr + wb = new HSSFWorkbook(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + + HSSFSheet sheet = wb.getSheetAt(0); + HSSFRow row = sheet.getRow(1); + HSSFCell cell = row.getCell(0); + + // this definitely would have failed due to 27349 + assertEquals("VLOOKUP(1,'DATA TABLE'!$A$8:'DATA TABLE'!$B$10,2)", cell + .getCellFormula()); + + // We might as well evaluate the formula + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv = fe.evaluate(cell); + + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(3.0, cv.getNumberValue(), 0.0); + } + + /** + * Bug 27405 - isnumber() formula always evaluates to false in if statement

+ * + * seems to be a duplicate of 24925 + */ + public void test27405() { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("input"); + // input row 0 + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); + cell = row.createCell(1); + cell.setCellValue(1); // B1 + // input row 1 + row = sheet.createRow(1); + cell = row.createCell(1); + cell.setCellValue(999); // B2 + + int rno = 4; + row = sheet.createRow(rno); + cell = row.createCell(1); // B5 + cell.setCellFormula("isnumber(b1)"); + cell = row.createCell(3); // D5 + cell.setCellFormula("IF(ISNUMBER(b1),b1,b2)"); + + if (false) { // set true to check excel file manually + // bug report mentions 'Editing the formula in excel "fixes" the problem.' + try { + FileOutputStream fileOut = new FileOutputStream("27405output.xls"); + wb.write(fileOut); + fileOut.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // use POI's evaluator as an extra sanity check + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv; + cv = fe.evaluate(cell); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(1.0, cv.getNumberValue(), 0.0); + + cv = fe.evaluate(row.getCell(1)); + assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cv.getCellType()); + assertEquals(true, cv.getBooleanValue()); + } + + /** + * Bug 42448 - Can't parse SUMPRODUCT(A!C7:A!C67, B8:B68) / B69

+ */ + public void test42448() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet1 = wb.createSheet("Sheet1"); + + HSSFRow row = sheet1.createRow(0); + HSSFCell cell = row.createCell(0); + + // it's important to create the referenced sheet first + HSSFSheet sheet2 = wb.createSheet("A"); // note name 'A' + // TODO - POI crashes if the formula is added before this sheet + // RuntimeException("Zero length string is an invalid sheet name") + // Excel doesn't crash but the formula doesn't work until it is + // re-entered + + String inputFormula = "SUMPRODUCT(A!C7:A!C67, B8:B68) / B69"; // as per bug report + try { + cell.setCellFormula(inputFormula); + } catch (StringIndexOutOfBoundsException e) { + throw new AssertionFailedError("Identified bug 42448"); + } + + assertEquals("SUMPRODUCT(A!C7:A!C67,B8:B68)/B69", cell.getCellFormula()); + + // might as well evaluate the sucker... + + addCell(sheet2, 5, 2, 3.0); // A!C6 + addCell(sheet2, 6, 2, 4.0); // A!C7 + addCell(sheet2, 66, 2, 5.0); // A!C67 + addCell(sheet2, 67, 2, 6.0); // A!C68 + + addCell(sheet1, 6, 1, 7.0); // B7 + addCell(sheet1, 7, 1, 8.0); // B8 + addCell(sheet1, 67, 1, 9.0); // B68 + addCell(sheet1, 68, 1, 10.0); // B69 + + double expectedResult = (4.0 * 8.0 + 5.0 * 9.0) / 10.0; + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv = fe.evaluate(cell); + + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(expectedResult, cv.getNumberValue(), 0.0); + } + + private static void addCell(HSSFSheet sheet, int rowIx, int colIx, + double value) { + sheet.createRow(rowIx).createCell(colIx).setCellValue(value); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestFormulasFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/eval/TestFormulasFromSpreadsheet.java new file mode 100644 index 0000000000..fd0771fdc8 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestFormulasFromSpreadsheet.java @@ -0,0 +1,310 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import java.io.PrintStream; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.functions.TestMathX; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; + +/** + * Tests formulas and operators as loaded from a test data spreadsheet.

+ * This class does not test implementors of Function and OperationEval in + * isolation. Much of the evaluation engine (i.e. HSSFFormulaEvaluator, ...) gets + * exercised as well. Tests for bug fixes and specific/tricky behaviour can be found in the + * corresponding test class (TestXxxx) of the target (Xxxx) implementor, + * where execution can be observed more easily. + * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + */ +public final class TestFormulasFromSpreadsheet extends TestCase { + + private static final class Result { + public static final int SOME_EVALUATIONS_FAILED = -1; + public static final int ALL_EVALUATIONS_SUCCEEDED = +1; + public static final int NO_EVALUATIONS_FOUND = 0; + } + + /** + * This class defines constants for navigating around the test data spreadsheet used for these tests. + */ + private static final class SS { + + /** + * Name of the test spreadsheet (found in the standard test data folder) + */ + public final static String FILENAME = "FormulaEvalTestData.xls"; + /** + * Row (zero-based) in the test spreadsheet where the operator examples start. + */ + public static final int START_OPERATORS_ROW_INDEX = 22; // Row '23' + /** + * Row (zero-based) in the test spreadsheet where the function examples start. + */ + public static final int START_FUNCTIONS_ROW_INDEX = 95; // Row '96' + /** + * Index of the column that contains the function names + */ + public static final int COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B' + + /** + * Used to indicate when there are no more functions left + */ + public static final String FUNCTION_NAMES_END_SENTINEL = ""; + + /** + * Index of the column where the test values start (for each function) + */ + public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D' + + /** + * Each function takes 4 rows in the test spreadsheet + */ + public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4; + } + + private HSSFWorkbook workbook; + private Sheet sheet; + // Note - multiple failures are aggregated before ending. + // If one or more functions fail, a single AssertionFailedError is thrown at the end + private int _functionFailureCount; + private int _functionSuccessCount; + private int _evaluationFailureCount; + private int _evaluationSuccessCount; + + private static final Cell getExpectedValueCell(Row row, int columnIndex) { + if (row == null) { + return null; + } + return row.getCell(columnIndex); + } + + + private static void confirmExpectedResult(String msg, Cell expected, CellValue actual) { + if (expected == null) { + throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); + } + if(actual == null) { + throw new AssertionFailedError(msg + " - actual value was null"); + } + + switch (expected.getCellType()) { + case Cell.CELL_TYPE_BLANK: + assertEquals(msg, Cell.CELL_TYPE_BLANK, actual.getCellType()); + break; + case Cell.CELL_TYPE_BOOLEAN: + assertEquals(msg, Cell.CELL_TYPE_BOOLEAN, actual.getCellType()); + assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); + break; + case Cell.CELL_TYPE_ERROR: + assertEquals(msg, Cell.CELL_TYPE_ERROR, actual.getCellType()); + assertEquals(msg, ErrorEval.getText(expected.getErrorCellValue()), ErrorEval.getText(actual.getErrorValue())); + break; + case Cell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation + throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg); + case Cell.CELL_TYPE_NUMERIC: + assertEquals(msg, Cell.CELL_TYPE_NUMERIC, actual.getCellType()); + TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR); + break; + case Cell.CELL_TYPE_STRING: + assertEquals(msg, Cell.CELL_TYPE_STRING, actual.getCellType()); + assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); + break; + } + } + + + protected void setUp() { + if (workbook == null) { + workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); + sheet = workbook.getSheetAt( 0 ); + } + _functionFailureCount = 0; + _functionSuccessCount = 0; + _evaluationFailureCount = 0; + _evaluationSuccessCount = 0; + } + + public void testFunctionsFromTestSpreadsheet() { + + processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null); + processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null); + // example for debugging individual functions/operators: +// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval"); +// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE"); + + // confirm results + String successMsg = "There were " + + _evaluationSuccessCount + " successful evaluation(s) and " + + _functionSuccessCount + " function(s) without error"; + if(_functionFailureCount > 0) { + String msg = _functionFailureCount + " function(s) failed in " + + _evaluationFailureCount + " evaluation(s). " + successMsg; + throw new AssertionFailedError(msg); + } + if(false) { // normally no output for successful tests + System.out.println(getClass().getName() + ": " + successMsg); + } + } + + /** + * @param startRowIndex row index in the spreadsheet where the first function/operator is found + * @param testFocusFunctionName name of a single function/operator to test alone. + * Typically pass null to test all functions + */ + private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) { + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); + + int rowIndex = startRowIndex; + while (true) { + Row r = sheet.getRow(rowIndex); + String targetFunctionName = getTargetFunctionName(r); + if(targetFunctionName == null) { + throw new AssertionFailedError("Test spreadsheet cell empty on row (" + + (rowIndex+1) + "). Expected function name or '" + + SS.FUNCTION_NAMES_END_SENTINEL + "'"); + } + if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) { + // found end of functions list + break; + } + if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) { + + // expected results are on the row below + Row expectedValuesRow = sheet.getRow(rowIndex + 1); + if(expectedValuesRow == null) { + int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row + throw new AssertionFailedError("Missing expected values row for function '" + + targetFunctionName + " (row " + missingRowNum + ")"); + } + switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) { + case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break; + case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break; + default: + throw new RuntimeException("unexpected result"); + case Result.NO_EVALUATIONS_FOUND: // do nothing + } + } + rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION; + } + } + + /** + * + * @return a constant from the local Result class denoting whether there were any evaluation + * cases, and whether they all succeeded. + */ + private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName, + Row formulasRow, Row expectedValuesRow) { + + int result = Result.NO_EVALUATIONS_FOUND; // so far + short endcolnum = formulasRow.getLastCellNum(); + + // iterate across the row for all the evaluation cases + for (int colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) { + Cell c = formulasRow.getCell(colnum); + if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) { + continue; + } + + CellValue actualValue = evaluator.evaluate(c); + + Cell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum); + try { + confirmExpectedResult("Function '" + targetFunctionName + "': Formula: " + c.getCellFormula() + " @ " + formulasRow.getRowNum() + ":" + colnum, + expectedValueCell, actualValue); + _evaluationSuccessCount ++; + if(result != Result.SOME_EVALUATIONS_FAILED) { + result = Result.ALL_EVALUATIONS_SUCCEEDED; + } + } catch (AssertionFailedError e) { + _evaluationFailureCount ++; + printShortStackTrace(System.err, e); + result = Result.SOME_EVALUATIONS_FAILED; + } + } + return result; + } + + /** + * Useful to keep output concise when expecting many failures to be reported by this test case + */ + private static void printShortStackTrace(PrintStream ps, AssertionFailedError e) { + StackTraceElement[] stes = e.getStackTrace(); + + int startIx = 0; + // skip any top frames inside junit.framework.Assert + while(startIx= endIx) { + // something went wrong. just print the whole stack trace + e.printStackTrace(ps); + } + endIx -= 4; // skip 4 frames of reflection invocation + ps.println(e.toString()); + for(int i=startIx; inull if cell is missing, empty or blank + */ + private static String getTargetFunctionName(Row r) { + if(r == null) { + System.err.println("Warning - given null row, can't figure out function name"); + return null; + } + Cell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME); + if(cell == null) { + System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name"); + return null; + } + if(cell.getCellType() == Cell.CELL_TYPE_BLANK) { + return null; + } + if(cell.getCellType() == Cell.CELL_TYPE_STRING) { + return cell.getRichStringCellValue().getString(); + } + + throw new AssertionFailedError("Bad cell type for 'function name' column: (" + + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")"); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestMinusZeroResult.java b/src/testcases/org/apache/poi/ss/formula/eval/TestMinusZeroResult.java new file mode 100644 index 0000000000..656c47dfd6 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestMinusZeroResult.java @@ -0,0 +1,151 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.ComparisonFailure; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.functions.Function; +import org.apache.poi.util.HexDump; + +/** + * IEEE 754 defines a quantity '-0.0' which is distinct from '0.0'. + * Negative zero is not easy to observe in Excel, since it is usually converted to 0.0. + * (Note - the results of XLL add-in functions don't seem to be converted, so they are one + * reliable avenue to observe Excel's treatment of '-0.0' as an operand.) + *

+ * POI attempts to emulate Excel faithfully, so this class tests + * two aspects of '-0.0' in formula evaluation: + *

    + *
  1. For most operation results '-0.0' is converted to '0.0'.
  2. + *
  3. Comparison operators have slightly different rules regarding '-0.0'.
  4. + *
+ * @author Josh Micich + */ +public final class TestMinusZeroResult extends TestCase { + private static final double MINUS_ZERO = -0.0; + + // convenient access to namepace + private static final EvalInstances EI = null; + + public void testSimpleOperators() { + + // unary plus is a no-op + checkEval(MINUS_ZERO, UnaryPlusEval.instance, MINUS_ZERO); + + // most simple operators convert -0.0 to +0.0 + checkEval(0.0, EI.UnaryMinus, 0.0); + checkEval(0.0, EI.Percent, MINUS_ZERO); + checkEval(0.0, EI.Multiply, MINUS_ZERO, 1.0); + checkEval(0.0, EI.Divide, MINUS_ZERO, 1.0); + checkEval(0.0, EI.Power, MINUS_ZERO, 1.0); + + // but SubtractEval does not convert -0.0, so '-' and '+' work like java + checkEval(MINUS_ZERO, EI.Subtract, MINUS_ZERO, 0.0); // this is the main point of bug 47198 + checkEval(0.0, EI.Add, MINUS_ZERO, 0.0); + } + + /** + * These results are hard to see in Excel (since -0.0 is usually converted to +0.0 before it + * gets to the comparison operator) + */ + public void testComparisonOperators() { + checkEval(false, EI.Equal, 0.0, MINUS_ZERO); + checkEval(true, EI.GreaterThan, 0.0, MINUS_ZERO); + checkEval(true, EI.LessThan, MINUS_ZERO, 0.0); + } + + public void testTextRendering() { + confirmTextRendering("-0", MINUS_ZERO); + // sub-normal negative numbers also display as '-0' + confirmTextRendering("-0", Double.longBitsToDouble(0x8000100020003000L)); + } + + /** + * Uses {@link ConcatEval} to force number-to-text conversion + */ + private static void confirmTextRendering(String expRendering, double d) { + ValueEval[] args = { StringEval.EMPTY_INSTANCE, new NumberEval(d), }; + StringEval se = (StringEval) EI.Concat.evaluate(args, -1, (short)-1); + String result = se.getStringValue(); + assertEquals(expRendering, result); + } + + private static void checkEval(double expectedResult, Function instance, double... dArgs) { + NumberEval result = (NumberEval) evaluate(instance, dArgs); + assertDouble(expectedResult, result.getNumberValue()); + } + private static void checkEval(boolean expectedResult, Function instance, double... dArgs) { + BoolEval result = (BoolEval) evaluate(instance, dArgs); + assertEquals(expectedResult, result.getBooleanValue()); + } + private static ValueEval evaluate(Function instance, double... dArgs) { + ValueEval[] evalArgs; + evalArgs = new ValueEval[dArgs.length]; + for (int i = 0; i < evalArgs.length; i++) { + evalArgs[i] = new NumberEval(dArgs[i]); + } + ValueEval r = instance.evaluate(evalArgs, -1, (short)-1); + return r; + } + + /** + * Not really a POI test - just shows similar behaviour of '-0.0' in Java. + */ + public void testJava() { + + assertEquals(0x8000000000000000L, Double.doubleToLongBits(MINUS_ZERO)); + + // The simple operators consider all zeros to be the same + assertTrue(MINUS_ZERO == MINUS_ZERO); + assertTrue(MINUS_ZERO == +0.0); + assertFalse(MINUS_ZERO < +0.0); + + // Double.compare() considers them different + assertTrue(Double.compare(MINUS_ZERO, +0.0) < 0); + + // multiplying zero by any negative quantity yields minus zero + assertDouble(MINUS_ZERO, 0.0*-1); + assertDouble(MINUS_ZERO, 0.0*-1e300); + assertDouble(MINUS_ZERO, 0.0*-1e-300); + + // minus zero can be produced as a result of underflow + assertDouble(MINUS_ZERO, -1e-300 / 1e100); + + // multiplying or dividing minus zero by a positive quantity yields minus zero + assertDouble(MINUS_ZERO, MINUS_ZERO * 1.0); + assertDouble(MINUS_ZERO, MINUS_ZERO / 1.0); + + // subtracting positive zero gives minus zero + assertDouble(MINUS_ZERO, MINUS_ZERO - 0.0); + // BUT adding positive zero gives positive zero + assertDouble(0.0, MINUS_ZERO + 0.0); // <<---- + } + + /** + * Just so there is no ambiguity. The two double values have to be exactly equal + */ + private static void assertDouble(double a, double b) { + long bitsA = Double.doubleToLongBits(a); + long bitsB = Double.doubleToLongBits(b); + if (bitsA != bitsB) { + throw new ComparisonFailure("value different to expected", + new String(HexDump.longToHex(bitsA)), new String(HexDump.longToHex(bitsB))); + } + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestMissingArgEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestMissingArgEval.java new file mode 100644 index 0000000000..2bef73c810 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestMissingArgEval.java @@ -0,0 +1,74 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import java.util.EmptyStackException; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Tests for {@link MissingArgEval} + * + * @author Josh Micich + */ +public final class TestMissingArgEval extends TestCase { + + public void testEvaluateMissingArgs() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + HSSFSheet sheet = wb.createSheet("Sheet1"); + HSSFCell cell = sheet.createRow(0).createCell(0); + + cell.setCellFormula("if(true,)"); + fe.clearAllCachedResultValues(); + CellValue cv; + try { + cv = fe.evaluate(cell); + } catch (EmptyStackException e) { + throw new AssertionFailedError("Missing args evaluation not implemented (bug 43354"); + } + // MissingArg -> BlankEval -> zero (as formula result) + assertEquals(0.0, cv.getNumberValue(), 0.0); + + // MissingArg -> BlankEval -> empty string (in concatenation) + cell.setCellFormula("\"abc\"&if(true,)"); + fe.clearAllCachedResultValues(); + assertEquals("abc", fe.evaluate(cell).getStringValue()); + } + + public void testCountFuncs() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + HSSFSheet sheet = wb.createSheet("Sheet1"); + HSSFCell cell = sheet.createRow(0).createCell(0); + + cell.setCellFormula("COUNT(C5,,,,)"); // 4 missing args, C5 is blank + assertEquals(4.0, fe.evaluate(cell).getNumberValue(), 0.0); + + cell.setCellFormula("COUNTA(C5,,)"); // 2 missing args, C5 is blank + fe.clearAllCachedResultValues(); + assertEquals(2.0, fe.evaluate(cell).getNumberValue(), 0.0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestOperandResolver.java b/src/testcases/org/apache/poi/ss/formula/eval/TestOperandResolver.java new file mode 100644 index 0000000000..4e24f84e70 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestOperandResolver.java @@ -0,0 +1,89 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * Tests for OperandResolver + * + * @author Brendan Nolan + */ +public final class TestOperandResolver extends TestCase { + + public void testParseDouble_bug48472() { + + String value = "-"; + + Double resolvedValue = null; + + try { + resolvedValue = OperandResolver.parseDouble(value); + } catch (StringIndexOutOfBoundsException e) { + throw new AssertionFailedError("Identified bug 48472"); + } + + assertEquals(null, resolvedValue); + + } + + public void testParseDouble_bug49723() { + + String value = ".1"; + + Double resolvedValue = null; + + resolvedValue = OperandResolver.parseDouble(value); + + assertNotNull("Identified bug 49723", resolvedValue); + + } + + /** + * + * Tests that a list of valid strings all return a non null value from {@link OperandResolver#parseDouble(String)} + * + */ + public void testParseDoubleValidStrings() { + + String[] values = new String[]{".19", "0.19", "1.9", "1E4", "-.19", "-0.19", "8.5","-1E4", ".5E6","+1.5","+1E5", " +1E5 "}; + + for (String value : values) { + assertTrue(OperandResolver.parseDouble(value) != null); + assertEquals(OperandResolver.parseDouble(value), Double.parseDouble(value)); + } + + } + + /** + * + * Tests that a list of invalid strings all return null from {@link OperandResolver#parseDouble(String)} + * + */ + public void testParseDoubleInvalidStrings() { + + String[] values = new String[]{"-", "ABC", "-X", "1E5a", "Infinity", "NaN", ".5F", "1,000"}; + + for (String value : values) { + assertEquals(null, OperandResolver.parseDouble(value)); + } + + } + +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestPercentEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestPercentEval.java new file mode 100644 index 0000000000..faeee6af3e --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestPercentEval.java @@ -0,0 +1,83 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.functions.EvalFactory; +import org.apache.poi.ss.formula.functions.NumericFunctionInvoker; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Test for percent operator evaluator. + * + * @author Josh Micich + */ +public final class TestPercentEval extends TestCase { + + private static void confirm(ValueEval arg, double expectedResult) { + ValueEval[] args = { + arg, + }; + + double result = NumericFunctionInvoker.invoke(PercentEval.instance, args, 0, 0); + + assertEquals(expectedResult, result, 0); + } + + public void testBasic() { + confirm(new NumberEval(5), 0.05); + confirm(new NumberEval(3000), 30.0); + confirm(new NumberEval(-150), -1.5); + confirm(new StringEval("0.2"), 0.002); + confirm(BoolEval.TRUE, 0.01); + } + + public void test1x1Area() { + AreaEval ae = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), }); + confirm(ae, 0.5); + } + public void testInSpreadSheet() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + HSSFRow row = sheet.createRow(0); + HSSFCell cell = row.createCell(0); + cell.setCellFormula("B1%"); + row.createCell(1).setCellValue(50.0); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv; + try { + cv = fe.evaluate(cell); + } catch (RuntimeException e) { + if(e.getCause() instanceof NullPointerException) { + throw new AssertionFailedError("Identified bug 44608"); + } + // else some other unexpected error + throw e; + } + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType()); + assertEquals(0.5, cv.getNumberValue(), 0.0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestRangeEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestRangeEval.java new file mode 100644 index 0000000000..439d642dc5 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestRangeEval.java @@ -0,0 +1,160 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.formula.AreaI; +import org.apache.poi.hssf.record.formula.AreaI.OffsetArea; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.AreaReference; +import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.formula.TwoDEval; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Test for unary plus operator evaluator. + * + * @author Josh Micich + */ +public final class TestRangeEval extends TestCase { + + public void testPermutations() { + + confirm("B3", "D7", "B3:D7"); + confirm("B1", "B1", "B1:B1"); + + confirm("B7", "D3", "B3:D7"); + confirm("D3", "B7", "B3:D7"); + confirm("D7", "B3", "B3:D7"); + } + + private static void confirm(String refA, String refB, String expectedAreaRef) { + + ValueEval[] args = { + createRefEval(refA), + createRefEval(refB), + }; + AreaReference ar = new AreaReference(expectedAreaRef); + ValueEval result = EvalInstances.Range.evaluate(args, 0, (short)0); + assertTrue(result instanceof AreaEval); + AreaEval ae = (AreaEval) result; + assertEquals(ar.getFirstCell().getRow(), ae.getFirstRow()); + assertEquals(ar.getLastCell().getRow(), ae.getLastRow()); + assertEquals(ar.getFirstCell().getCol(), ae.getFirstColumn()); + assertEquals(ar.getLastCell().getCol(), ae.getLastColumn()); + } + + private static ValueEval createRefEval(String refStr) { + CellReference cr = new CellReference(refStr); + return new MockRefEval(cr.getRow(), cr.getCol()); + + } + + private static final class MockRefEval extends RefEvalBase { + + public MockRefEval(int rowIndex, int columnIndex) { + super(rowIndex, columnIndex); + } + public ValueEval getInnerValueEval() { + throw new RuntimeException("not expected to be called during this test"); + } + public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, + int relLastColIx) { + AreaI area = new OffsetArea(getRow(), getColumn(), + relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); + return new MockAreaEval(area); + } + } + + private static final class MockAreaEval extends AreaEvalBase { + + public MockAreaEval(AreaI ptg) { + super(ptg); + } + private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn) { + super(firstRow, firstColumn, lastRow, lastColumn); + } + public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { + throw new RuntimeException("not expected to be called during this test"); + } + public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, + int relLastColIx) { + AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(), + relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); + + return new MockAreaEval(area); + } + public TwoDEval getRow(int rowIndex) { + if (rowIndex >= getHeight()) { + throw new IllegalArgumentException("Invalid rowIndex " + rowIndex + + ". Allowable range is (0.." + getHeight() + ")."); + } + return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn()); + } + public TwoDEval getColumn(int columnIndex) { + if (columnIndex >= getWidth()) { + throw new IllegalArgumentException("Invalid columnIndex " + columnIndex + + ". Allowable range is (0.." + getWidth() + ")."); + } + return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex); + } + } + + public void testRangeUsingOffsetFunc_bug46948() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFRow row = wb.createSheet("Sheet1").createRow(0); + HSSFCell cellA1 = row.createCell(0); + HSSFCell cellB1 = row.createCell(1); + row.createCell(2).setCellValue(5.0); // C1 + row.createCell(3).setCellValue(7.0); // D1 + row.createCell(4).setCellValue(9.0); // E1 + + + cellA1.setCellFormula("SUM(C1:OFFSET(C1,0,B1))"); + + cellB1.setCellValue(1.0); // range will be C1:D1 + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue cv; + try { + cv = fe.evaluate(cellA1); + } catch (IllegalArgumentException e) { + if (e.getMessage().equals("Unexpected ref arg class (org.apache.poi.ss.formula.LazyAreaEval)")) { + throw new AssertionFailedError("Identified bug 46948"); + } + throw e; + } + + assertEquals(12.0, cv.getNumberValue(), 0.0); + + cellB1.setCellValue(2.0); // range will be C1:E1 + fe.notifyUpdateCell(cellB1); + cv = fe.evaluate(cellA1); + assertEquals(21.0, cv.getNumberValue(), 0.0); + + cellB1.setCellValue(0.0); // range will be C1:C1 + fe.notifyUpdateCell(cellB1); + cv = fe.evaluate(cellA1); + assertEquals(5.0, cv.getNumberValue(), 0.0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/TestUnaryPlusEval.java b/src/testcases/org/apache/poi/ss/formula/eval/TestUnaryPlusEval.java new file mode 100644 index 0000000000..33022ad44b --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/eval/TestUnaryPlusEval.java @@ -0,0 +1,58 @@ +/* ==================================================================== + 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.ss.formula.eval; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.ss.formula.functions.EvalFactory; +import org.apache.poi.ss.formula.functions.NumericFunctionInvoker; + +/** + * Test for unary plus operator evaluator. + * + * @author Josh Micich + */ +public final class TestUnaryPlusEval extends TestCase { + + /** + * Test for bug observable at svn revision 618865 (5-Feb-2008)
+ * The code for handling column operands had been copy-pasted from the row handling code. + */ + public void testColumnOperand() { + + short firstRow = (short)8; + short lastRow = (short)12; + short colNum = (short)5; + AreaPtg areaPtg = new AreaPtg(firstRow, lastRow, colNum, colNum, false, false, false, false); + ValueEval[] values = { + new NumberEval(27), + new NumberEval(29), + new NumberEval(35), // value in row 10 + new NumberEval(37), + new NumberEval(38), + }; + ValueEval[] args = { + EvalFactory.createAreaEval(areaPtg, values), + }; + + double result = NumericFunctionInvoker.invoke(EvalInstances.UnaryPlus, args, 10, (short)20); + + assertEquals(35, result, 0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java b/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java index 1e48069828..505ea127b7 100644 --- a/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java +++ b/src/testcases/org/apache/poi/ss/formula/eval/forked/TestForkedEvaluator.java @@ -20,7 +20,7 @@ package org.apache.poi.ss.formula.eval.forked; import junit.framework.AssertionFailedError; import junit.framework.TestCase; -import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; diff --git a/src/testcases/org/apache/poi/ss/formula/function/AllFormulaFunctionTests.java b/src/testcases/org/apache/poi/ss/formula/function/AllFormulaFunctionTests.java new file mode 100644 index 0000000000..5bbf8f0131 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/function/AllFormulaFunctionTests.java @@ -0,0 +1,37 @@ +/* ==================================================================== + 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.ss.formula.function; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Collects all tests for this org.apache.poi.hssf.record.formula.function. + * + * @author Josh Micich + */ +public class AllFormulaFunctionTests { + + public static Test suite() { + TestSuite result = new TestSuite(AllFormulaFunctionTests.class.getName()); + result.addTestSuite(TestFunctionMetadataRegistry.class); + result.addTestSuite(TestParseMissingBuiltInFuncs.class); + result.addTestSuite(TestReadMissingBuiltInFuncs.class); + return result; + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/function/ExcelFileFormatDocFunctionExtractor.java b/src/testcases/org/apache/poi/ss/formula/function/ExcelFileFormatDocFunctionExtractor.java new file mode 100644 index 0000000000..4d6877f0f9 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/function/ExcelFileFormatDocFunctionExtractor.java @@ -0,0 +1,617 @@ +/* ==================================================================== + 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.ss.formula.function; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * This class is not used during normal POI run-time but is used at development time to generate + * the file 'functionMetadata.txt'. There are more than 300 built-in functions in Excel and the + * intention of this class is to make it easier to maintain the metadata, by extracting it from + * a reliable source. + * + * @author Josh Micich + */ +public final class ExcelFileFormatDocFunctionExtractor { + + private static final String SOURCE_DOC_FILE_NAME = "excelfileformat.odt"; + + /** + * For simplicity, the output file is strictly simple ASCII. + * This method detects any unexpected characters. + */ + /* package */ static boolean isSimpleAscii(char c) { + + if (c>=0x21 && c<=0x7E) { + // everything from '!' to '~' (includes letters, digits, punctuation + return true; + } + // some specific whitespace chars below 0x21: + switch(c) { + case ' ': + case '\t': + case '\r': + case '\n': + return true; + } + return false; + } + + + private static final class FunctionData { + // special characters from the ooo document + private static final int CHAR_ELLIPSIS_8230 = 8230; + private static final int CHAR_NDASH_8211 = 8211; + + private final int _index; + private final boolean _hasFootnote; + private final String _name; + private final int _minParams; + private final int _maxParams; + private final String _returnClass; + private final String _paramClasses; + private final boolean _isVolatile; + + public FunctionData(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams, + String returnClass, String paramClasses, boolean isVolatile) { + _index = funcIx; + _hasFootnote = hasFootnote; + _name = funcName; + _minParams = minParams; + _maxParams = maxParams; + _returnClass = convertSpecialChars(returnClass); + _paramClasses = convertSpecialChars(paramClasses); + _isVolatile = isVolatile; + } + private static String convertSpecialChars(String ss) { + StringBuffer sb = new StringBuffer(ss.length() + 4); + for(int i=0; i 0; + + Integer funcIxKey = Integer.valueOf(funcIx); + if(!_groupFunctionIndexes.add(funcIxKey)) { + throw new RuntimeException("Duplicate function index (" + funcIx + ")"); + } + if(!_groupFunctionNames.add(funcName)) { + throw new RuntimeException("Duplicate function name '" + funcName + "'"); + } + + checkRedefinedFunction(hasFootnote, funcName, funcIxKey); + FunctionData fd = new FunctionData(funcIx, hasFootnote, funcName, + minParams, maxParams, returnClass, paramClasses, isVolatile); + + _allFunctionsByIndex.put(funcIxKey, fd); + _allFunctionsByName.put(funcName, fd); + } + + /** + * Some extra validation here. + * Any function which changes definition will have a footnote in the source document + */ + private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) { + FunctionData fdPrev; + // check by index + fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey); + if(fdPrev != null) { + if(!fdPrev.hasFootnote() || !hasNote) { + throw new RuntimeException("changing function [" + + funcIxKey + "] definition without foot-note"); + } + _allFunctionsByName.remove(fdPrev.getName()); + } + // check by name + fdPrev = (FunctionData) _allFunctionsByName.get(funcName); + if(fdPrev != null) { + if(!fdPrev.hasFootnote() || !hasNote) { + throw new RuntimeException("changing function '" + + funcName + "' definition without foot-note"); + } + _allFunctionsByIndex.remove(Integer.valueOf(fdPrev.getIndex())); + } + } + + public void endTableGroup(String headingText) { + Integer[] keys = new Integer[_groupFunctionIndexes.size()]; + _groupFunctionIndexes.toArray(keys); + _groupFunctionIndexes.clear(); + _groupFunctionNames.clear(); + Arrays.sort(keys); + + _ps.println("# " + headingText); + for (int i = 0; i < keys.length; i++) { + FunctionData fd = (FunctionData) _allFunctionsByIndex.get(keys[i]); + _ps.println(fd.formatAsDataLine()); + } + } + } + + /** + * To avoid drag-in - parse XML using only JDK. + */ + private static class EFFDocHandler implements ContentHandler { + private static final String[] HEADING_PATH_NAMES = { + "office:document-content", "office:body", "office:text", "text:h", + }; + private static final String[] TABLE_BASE_PATH_NAMES = { + "office:document-content", "office:body", "office:text", "table:table", + }; + private static final String[] TABLE_ROW_RELPATH_NAMES = { + "table:table-row", + }; + private static final String[] TABLE_CELL_RELPATH_NAMES = { + "table:table-row", "table:table-cell", "text:p", + }; + // after May 2008 there was one more style applied to the footnotes + private static final String[] NOTE_REF_RELPATH_NAMES_OLD = { + "table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref", + }; + private static final String[] NOTE_REF_RELPATH_NAMES = { + "table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref", + }; + + + private final Stack _elemNameStack; + /** true only when parsing the target tables */ + private boolean _isInsideTable; + + private final List _rowData; + private final StringBuffer _textNodeBuffer; + private final List _rowNoteFlags; + private boolean _cellHasNote; + + private final FunctionDataCollector _fdc; + private String _lastHeadingText; + + public EFFDocHandler(FunctionDataCollector fdc) { + _fdc = fdc; + _elemNameStack = new Stack(); + _isInsideTable = false; + _rowData = new ArrayList(); + _textNodeBuffer = new StringBuffer(); + _rowNoteFlags = new ArrayList(); + } + + private boolean matchesTargetPath() { + return matchesPath(0, TABLE_BASE_PATH_NAMES); + } + private boolean matchesRelPath(String[] pathNames) { + return matchesPath(TABLE_BASE_PATH_NAMES.length, pathNames); + } + private boolean matchesPath(int baseStackIndex, String[] pathNames) { + if(_elemNameStack.size() != baseStackIndex + pathNames.length) { + return false; + } + for (int i = 0; i < pathNames.length; i++) { + if(!_elemNameStack.get(baseStackIndex + i).equals(pathNames[i])) { + return false; + } + } + return true; + } + public void characters(char[] ch, int start, int length) { + // only 2 text nodes where text is collected: + if(matchesRelPath(TABLE_CELL_RELPATH_NAMES) || matchesPath(0, HEADING_PATH_NAMES)) { + _textNodeBuffer.append(ch, start, length); + } + } + + public void endElement(String namespaceURI, String localName, String name) { + String expectedName = (String) _elemNameStack.peek(); + if(expectedName != name) { + throw new RuntimeException("close tag mismatch"); + } + if(matchesPath(0, HEADING_PATH_NAMES)) { + _lastHeadingText = _textNodeBuffer.toString().trim(); + _textNodeBuffer.setLength(0); + } + if(_isInsideTable) { + if(matchesTargetPath()) { + _fdc.endTableGroup(_lastHeadingText); + _isInsideTable = false; + } else if(matchesRelPath(TABLE_ROW_RELPATH_NAMES)) { + String[] cellData = new String[_rowData.size()]; + _rowData.toArray(cellData); + _rowData.clear(); + Boolean[] noteFlags = new Boolean[_rowNoteFlags.size()]; + _rowNoteFlags.toArray(noteFlags); + _rowNoteFlags.clear(); + processTableRow(cellData, noteFlags); + } else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { + _rowData.add(_textNodeBuffer.toString().trim()); + _rowNoteFlags.add(Boolean.valueOf(_cellHasNote)); + _textNodeBuffer.setLength(0); + } + } + _elemNameStack.pop(); + } + + private void processTableRow(String[] cellData, Boolean[] noteFlags) { + // each table row of the document contains data for two functions + if(cellData.length != 15) { + throw new RuntimeException("Bad table row size"); + } + processFunction(cellData, noteFlags, 0); + processFunction(cellData, noteFlags, 8); + } + public void processFunction(String[] cellData, Boolean[] noteFlags, int i) { + String funcIxStr = cellData[i + 0]; + if (funcIxStr.length() < 1) { + // empty (happens on the right hand side when there is an odd number of functions) + return; + } + int funcIx = parseInt(funcIxStr); + + boolean hasFootnote = noteFlags[i + 1].booleanValue(); + String funcName = cellData[i + 1]; + int minParams = parseInt(cellData[i + 2]); + int maxParams = parseInt(cellData[i + 3]); + + String returnClass = cellData[i + 4]; + String paramClasses = cellData[i + 5]; + String volatileFlagStr = cellData[i + 6]; + + _fdc.addFuntion(funcIx, hasFootnote, funcName, minParams, maxParams, returnClass, paramClasses, volatileFlagStr); + } + private static int parseInt(String valStr) { + try { + return Integer.parseInt(valStr); + } catch (NumberFormatException e) { + throw new RuntimeException("Value '" + valStr + "' could not be parsed as an integer"); + } + } + public void startElement(String namespaceURI, String localName, String name, Attributes atts) { + _elemNameStack.add(name); + if(matchesTargetPath()) { + String tableName = atts.getValue("table:name"); + if(tableName.startsWith("tab_fml_func") && !tableName.equals("tab_fml_func0")) { + _isInsideTable = true; + } + return; + } + if(matchesPath(0, HEADING_PATH_NAMES)) { + _textNodeBuffer.setLength(0); + } else if(matchesRelPath(TABLE_ROW_RELPATH_NAMES)) { + _rowData.clear(); + _rowNoteFlags.clear(); + } else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { + _textNodeBuffer.setLength(0); + _cellHasNote = false; + } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) { + _cellHasNote = true; + } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) { + _cellHasNote = true; + } + } + + public void endDocument() { + // do nothing + } + public void endPrefixMapping(String prefix) { + // do nothing + } + public void ignorableWhitespace(char[] ch, int start, int length) { + // do nothing + } + public void processingInstruction(String target, String data) { + // do nothing + } + public void setDocumentLocator(Locator locator) { + // do nothing + } + public void skippedEntity(String name) { + // do nothing + } + public void startDocument() { + // do nothing + } + public void startPrefixMapping(String prefix, String uri) { + // do nothing + } + } + + private static void extractFunctionData(FunctionDataCollector fdc, InputStream is) { + XMLReader xr; + + try { + // First up, try the default one + xr = XMLReaderFactory.createXMLReader(); + } catch (SAXException e) { + // Try one for java 1.4 + System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl"); + try { + xr = XMLReaderFactory.createXMLReader(); + } catch (SAXException e2) { + throw new RuntimeException(e2); + } + } + xr.setContentHandler(new EFFDocHandler(fdc)); + + InputSource inSrc = new InputSource(is); + + try { + xr.parse(inSrc); + is.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (SAXException e) { + throw new RuntimeException(e); + } + } + /** + * To be sure that no tricky unicode chars make it through to the output file. + */ + private static final class SimpleAsciiOutputStream extends OutputStream { + + private final OutputStream _os; + + public SimpleAsciiOutputStream(OutputStream os) { + _os = os; + } + public void write(int b) throws IOException { + checkByte(b); + _os.write(b); + } + private static void checkByte(int b) { + if (!isSimpleAscii((char)b)) { + throw new RuntimeException("Encountered char (" + b + ") which was not simple ascii as expected"); + } + } + public void write(byte[] b, int off, int len) throws IOException { + for (int i = 0; i < len; i++) { + checkByte(b[i + off]); + + } + _os.write(b, off, len); + } + } + + private static void processFile(File effDocFile, File outFile) { + if(!effDocFile.exists()) { + throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist"); + } + OutputStream os; + try { + os = new FileOutputStream(outFile); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + os = new SimpleAsciiOutputStream(os); + PrintStream ps; + try { + ps = new PrintStream(os, true, "UTF-8"); + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + outputLicenseHeader(ps); + Class genClass = ExcelFileFormatDocFunctionExtractor.class; + ps.println("# Created by (" + genClass.getName() + ")"); + // identify the source file + ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'"); + ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")"); + ps.println("#"); + ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )"); + ps.println(""); + try { + ZipFile zf = new ZipFile(effDocFile); + InputStream is = zf.getInputStream(zf.getEntry("content.xml")); + extractFunctionData(new FunctionDataCollector(ps), is); + zf.close(); + } catch (ZipException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + ps.close(); + + String canonicalOutputFileName; + try { + canonicalOutputFileName = outFile.getCanonicalPath(); + } catch (IOException e) { + throw new RuntimeException(e); + } + System.out.println("Successfully output to '" + canonicalOutputFileName + "'"); + } + + private static void outputLicenseHeader(PrintStream ps) { + String[] lines= { + "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.", + }; + for (int i = 0; i < lines.length; i++) { + ps.print("# "); + ps.println(lines[i]); + } + ps.println(); + } + + /** + * Helps identify the source file + */ + private static String getFileMD5(File f) { + MessageDigest m; + try { + m = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + byte[]buf = new byte[2048]; + try { + InputStream is = new FileInputStream(f); + while(true) { + int bytesRead = is.read(buf); + if(bytesRead<1) { + break; + } + m.update(buf, 0, bytesRead); + } + is.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return "0x" + new BigInteger(1, m.digest()).toString(16); + } + + private static File downloadSourceFile() { + URL url; + try { + url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + File result; + byte[]buf = new byte[2048]; + try { + URLConnection conn = url.openConnection(); + InputStream is = conn.getInputStream(); + System.out.println("downloading " + url.toExternalForm()); + result = File.createTempFile("excelfileformat", ".odt"); + OutputStream os = new FileOutputStream(result); + while(true) { + int bytesRead = is.read(buf); + if(bytesRead<1) { + break; + } + os.write(buf, 0, bytesRead); + } + is.close(); + os.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + System.out.println("file downloaded ok"); + return result; + } + + public static void main(String[] args) { + + File outFile = new File("functionMetadata-asGenerated.txt"); + + if (false) { // set true to use local file + File dir = new File("c:/temp"); + File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME); + processFile(effDocFile, outFile); + return; + } + + File tempEFFDocFile = downloadSourceFile(); + processFile(tempEFFDocFile, outFile); + tempEFFDocFile.delete(); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/function/TestFunctionMetadataRegistry.java b/src/testcases/org/apache/poi/ss/formula/function/TestFunctionMetadataRegistry.java new file mode 100644 index 0000000000..b050401d99 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/function/TestFunctionMetadataRegistry.java @@ -0,0 +1,44 @@ +/* ==================================================================== + 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.ss.formula.function; + +import junit.framework.TestCase; + +/** + * + * @author Josh Micich + */ +public final class TestFunctionMetadataRegistry extends TestCase { + + public void testWellKnownFunctions() { + confirmFunction(0, "COUNT"); + confirmFunction(1, "IF"); + + } + + private static void confirmFunction(int index, String funcName) { + FunctionMetadata fm; + fm = FunctionMetadataRegistry.getFunctionByIndex(index); + assertNotNull(fm); + assertEquals(funcName, fm.getName()); + + fm = FunctionMetadataRegistry.getFunctionByName(funcName); + assertNotNull(fm); + assertEquals(index, fm.getIndex()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/function/TestParseMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/ss/formula/function/TestParseMissingBuiltInFuncs.java new file mode 100644 index 0000000000..a6872e5f2c --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/function/TestParseMissingBuiltInFuncs.java @@ -0,0 +1,90 @@ +/* ==================================================================== + 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.ss.formula.function; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; +import org.apache.poi.hssf.record.formula.FuncPtg; +import org.apache.poi.hssf.record.formula.FuncVarPtg; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +/** + * Tests parsing of some built-in functions that were not properly + * registered in POI as of bug #44675, #44733 (March/April 2008). + * + * @author Josh Micich + */ +public final class TestParseMissingBuiltInFuncs extends TestCase { + + private static Ptg[] parse(String formula) { + HSSFWorkbook book = new HSSFWorkbook(); + return HSSFFormulaParser.parse(formula, book); + } + private static void confirmFunc(String formula, int expPtgArraySize, boolean isVarArgFunc, int funcIx) { + Ptg[] ptgs = parse(formula); + Ptg ptgF = ptgs[ptgs.length-1]; // func is last RPN token in all these formulas + + // Check critical things in the Ptg array encoding. + if(!(ptgF instanceof AbstractFunctionPtg)) { + throw new RuntimeException("function token missing"); + } + AbstractFunctionPtg func = (AbstractFunctionPtg) ptgF; + if(func.getFunctionIndex() == 255) { + throw new AssertionFailedError("Failed to recognise built-in function in formula '" + + formula + "'"); + } + assertEquals(expPtgArraySize, ptgs.length); + assertEquals(funcIx, func.getFunctionIndex()); + Class expCls = isVarArgFunc ? FuncVarPtg.class : FuncPtg.class; + assertEquals(expCls, ptgF.getClass()); + + // check that parsed Ptg array converts back to formula text OK + HSSFWorkbook book = new HSSFWorkbook(); + String reRenderedFormula = HSSFFormulaParser.toFormulaString(book, ptgs); + assertEquals(formula, reRenderedFormula); + } + + public void testDatedif() { + int expSize = 4; // NB would be 5 if POI added tAttrVolatile properly + confirmFunc("DATEDIF(NOW(),NOW(),\"d\")", expSize, false, 351); + } + + public void testDdb() { + confirmFunc("DDB(1,1,1,1,1)", 6, true, 144); + } + public void testAtan() { + confirmFunc("ATAN(1)", 2, false, 18); + } + + public void testUsdollar() { + confirmFunc("USDOLLAR(1)", 2, true, 204); + } + + public void testDBCS() { + confirmFunc("DBCS(\"abc\")", 2, false, 215); + } + public void testIsnontext() { + confirmFunc("ISNONTEXT(\"abc\")", 2, false, 190); + } + public void testDproduct() { + confirmFunc("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", 4, false, 189); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/function/TestReadMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/ss/formula/function/TestReadMissingBuiltInFuncs.java new file mode 100644 index 0000000000..9de7e764e7 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/function/TestReadMissingBuiltInFuncs.java @@ -0,0 +1,162 @@ +/* ==================================================================== + 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.ss.formula.function; + +import java.lang.reflect.InvocationTargetException; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.record.RecordFormatException; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +/** + * Tests reading from a sample spreadsheet some built-in functions that were not properly + * registered in POI as of bug #44675, #44733 (March/April 2008). + * + * @author Josh Micich + */ +public final class TestReadMissingBuiltInFuncs extends TestCase { + + /** + * This spreadsheet has examples of calls to the interesting built-in functions in cells A1:A7 + */ + private static final String SAMPLE_SPREADSHEET_FILE_NAME = "missingFuncs44675.xls"; + private static HSSFSheet _sheet; + + private static HSSFSheet getSheet() { + if (_sheet == null) { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(SAMPLE_SPREADSHEET_FILE_NAME); + _sheet = wb.getSheetAt(0); + } + return _sheet; + } + + public void testDatedif() { + + String formula; + try { + formula = getCellFormula(0); + } catch (IllegalStateException e) { + if(e.getMessage().startsWith("Too few arguments")) { + if(e.getMessage().indexOf("AttrPtg") > 0) { + throw afe("tAttrVolatile not supported in FormulaParser.toFormulaString"); + } + throw afe("NOW() registered with 1 arg instead of 0"); + } + if(e.getMessage().startsWith("too much stuff")) { + throw afe("DATEDIF() not registered"); + } + // some other unexpected error + throw e; + } + assertEquals("DATEDIF(NOW(),NOW(),\"d\")", formula); + } + public void testDdb() { + + String formula = getCellFormula(1); + if("externalflag(1,1,1,1,1)".equals(formula)) { + throw afe("DDB() not registered"); + } + assertEquals("DDB(1,1,1,1,1)", formula); + } + public void testAtan() { + + String formula = getCellFormula(2); + if(formula.equals("ARCTAN(1)")) { + throw afe("func ix 18 registered as ARCTAN() instead of ATAN()"); + } + assertEquals("ATAN(1)", formula); + } + + public void testUsdollar() { + + String formula = getCellFormula(3); + if(formula.equals("YEN(1)")) { + throw afe("func ix 204 registered as YEN() instead of USDOLLAR()"); + } + assertEquals("USDOLLAR(1)", formula); + } + + public void testDBCS() { + + String formula; + try { + formula = getCellFormula(4); + } catch (IllegalStateException e) { + if(e.getMessage().startsWith("too much stuff")) { + throw afe("DBCS() not registered"); + } + // some other unexpected error + throw e; + } catch (NegativeArraySizeException e) { + throw afe("found err- DBCS() registered with -1 args"); + } + if(formula.equals("JIS(\"abc\")")) { + throw afe("func ix 215 registered as JIS() instead of DBCS()"); + } + assertEquals("DBCS(\"abc\")", formula); + } + public void testIsnontext() { + + String formula; + try { + formula = getCellFormula(5); + } catch (IllegalStateException e) { + if(e.getMessage().startsWith("too much stuff")) { + throw afe("ISNONTEXT() registered with wrong index"); + } + // some other unexpected error + throw e; + } + assertEquals("ISNONTEXT(\"abc\")", formula); + } + public void testDproduct() { + + String formula = getCellFormula(6); + assertEquals("DPRODUCT(C1:E5,\"HarvestYield\",G1:H2)", formula); + } + + private String getCellFormula(int rowIx) { + HSSFSheet sheet; + try { + sheet = getSheet(); + } catch (RecordFormatException e) { + if(e.getCause() instanceof InvocationTargetException) { + InvocationTargetException ite = (InvocationTargetException) e.getCause(); + if(ite.getTargetException() instanceof RuntimeException) { + RuntimeException re = (RuntimeException) ite.getTargetException(); + if(re.getMessage().equals("Invalid built-in function index (189)")) { + throw afe("DPRODUCT() registered with wrong index"); + } + } + } + // some other unexpected error + throw e; + } + String result = sheet.getRow(rowIx).getCell(0).getCellFormula(); + if (false) { + System.err.println(result); + } + return result; + } + private static AssertionFailedError afe(String msg) { + return new AssertionFailedError(msg); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java b/src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java new file mode 100644 index 0000000000..c5453ea39a --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/AbstractNumericTestCase.java @@ -0,0 +1,73 @@ +/* +* 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. +*/ +/* + * Created on May 29, 2005 + * + */ +package org.apache.poi.ss.formula.functions; + +import junit.framework.TestCase; + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public abstract class AbstractNumericTestCase extends TestCase { + + public static final double POS_ZERO = 1E-4; + public static final double DIFF_TOLERANCE_FACTOR = 1E-8; + + public void setUp() { + } + + public void tearDown() { + } + + /** + * Why doesnt JUnit have a method like this for doubles? + * The current impl (3.8.1) of Junit has a retar*** method + * for comparing doubles. DO NOT use that. + * TODO: This class should really be in an abstract super class + * to avoid code duplication across this project. + * @param message + * @param baseval + * @param checkval + */ + public static void assertEquals(String message, double baseval, double checkval, double almostZero, double diffToleranceFactor) { + double posZero = Math.abs(almostZero); + double negZero = -1 * posZero; + if (Double.isNaN(baseval)) { + assertTrue(message+": Expected " + baseval + " but was " + checkval + , Double.isNaN(baseval)); + } + else if (Double.isInfinite(baseval)) { + assertTrue(message+": Expected " + baseval + " but was " + checkval + , Double.isInfinite(baseval) && ((baseval<0) == (checkval<0))); + } + else { + assertTrue(message+": Expected " + baseval + " but was " + checkval + ,baseval != 0 + ? Math.abs(baseval - checkval) <= Math.abs(diffToleranceFactor * baseval) + : checkval < posZero && checkval > negZero); + } + } + + public static void assertEquals(String msg, double baseval, double checkval) { + assertEquals(msg, baseval, checkval, POS_ZERO, DIFF_TOLERANCE_FACTOR); + } + +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/AllIndividualFunctionEvaluationTests.java b/src/testcases/org/apache/poi/ss/formula/functions/AllIndividualFunctionEvaluationTests.java new file mode 100644 index 0000000000..4e42389ec1 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/AllIndividualFunctionEvaluationTests.java @@ -0,0 +1,65 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Direct tests for all implementors of Function. + * + * @author Josh Micich + */ +public final class AllIndividualFunctionEvaluationTests { + + public static Test suite() { + TestSuite result = new TestSuite(AllIndividualFunctionEvaluationTests.class.getName()); + result.addTestSuite(TestAverage.class); + result.addTestSuite(TestCountFuncs.class); + result.addTestSuite(TestDate.class); + result.addTestSuite(TestDays360.class); + result.addTestSuite(TestFinanceLib.class); + result.addTestSuite(TestFind.class); + result.addTestSuite(TestIndex.class); + result.addTestSuite(TestIndexFunctionFromSpreadsheet.class); + result.addTestSuite(TestIndirect.class); + result.addTestSuite(TestIsBlank.class); + result.addTestSuite(TestLen.class); + result.addTestSuite(TestLookupFunctionsFromSpreadsheet.class); + result.addTestSuite(TestMatch.class); + result.addTestSuite(TestMathX.class); + result.addTestSuite(TestMid.class); + result.addTestSuite(TestNper.class); + result.addTestSuite(TestOffset.class); + result.addTestSuite(TestPmt.class); + result.addTestSuite(TestRoundFuncs.class); + result.addTestSuite(TestRowCol.class); + result.addTestSuite(TestStatsLib.class); + result.addTestSuite(TestSubtotal.class); + result.addTestSuite(TestSumif.class); + result.addTestSuite(TestSumproduct.class); + result.addTestSuite(TestText.class); + result.addTestSuite(TestTFunc.class); + result.addTestSuite(TestTime.class); + result.addTestSuite(TestTrim.class); + result.addTestSuite(TestTrunc.class); + result.addTestSuite(TestValue.class); + result.addTestSuite(TestXYNumericFunction.class); + return result; + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/EvalFactory.java b/src/testcases/org/apache/poi/ss/formula/functions/EvalFactory.java new file mode 100644 index 0000000000..7eee5627b8 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/EvalFactory.java @@ -0,0 +1,174 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import org.apache.poi.hssf.record.formula.AreaI; +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.hssf.record.formula.Ref3DPtg; +import org.apache.poi.hssf.record.formula.RefPtg; +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.AreaEvalBase; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.RefEval; +import org.apache.poi.ss.formula.eval.RefEvalBase; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.TwoDEval; + +/** + * Test helper class for creating mock Eval objects + * + * @author Josh Micich + */ +public final class EvalFactory { + + private EvalFactory() { + // no instances of this class + } + + /** + * Creates a dummy AreaEval + * @param values empty (null) entries in this array will be converted to NumberEval.ZERO + */ + public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) { + AreaPtg areaPtg = new AreaPtg(areaRefStr); + return createAreaEval(areaPtg, values); + } + + /** + * Creates a dummy AreaEval + * @param values empty (null) entries in this array will be converted to NumberEval.ZERO + */ + public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) { + int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1; + int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1; + int nExpected = nRows * nCols; + if (values.length != nExpected) { + throw new RuntimeException("Expected " + nExpected + " values but got " + values.length); + } + for (int i = 0; i < nExpected; i++) { + if (values[i] == null) { + values[i] = NumberEval.ZERO; + } + } + return new MockAreaEval(areaPtg, values); + } + + /** + * Creates a single RefEval (with value zero) + */ + public static RefEval createRefEval(String refStr) { + return createRefEval(refStr, NumberEval.ZERO); + } + public static RefEval createRefEval(String refStr, ValueEval value) { + return new MockRefEval(new RefPtg(refStr), value); + } + + private static final class MockAreaEval extends AreaEvalBase { + private final ValueEval[] _values; + public MockAreaEval(AreaI areaPtg, ValueEval[] values) { + super(areaPtg); + _values = values; + } + private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn, ValueEval[] values) { + super(firstRow, firstColumn, lastRow, lastColumn); + _values = values; + } + public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { + if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) { + throw new IllegalArgumentException("row index out of range"); + } + int width = getWidth(); + if (relativeColumnIndex < 0 || relativeColumnIndex >=width) { + throw new IllegalArgumentException("column index out of range"); + } + int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex; + return _values[oneDimensionalIndex]; + } + public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { + if (relFirstRowIx < 0 || relFirstColIx < 0 + || relLastRowIx >= getHeight() || relLastColIx >= getWidth()) { + throw new RuntimeException("Operation not implemented on this mock object"); + } + + if (relFirstRowIx == 0 && relFirstColIx == 0 + && relLastRowIx == getHeight()-1 && relLastColIx == getWidth()-1) { + return this; + } + ValueEval[] values = transpose(_values, getWidth(), relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); + return new MockAreaEval(getFirstRow() + relFirstRowIx, getFirstColumn() + relFirstColIx, + getFirstRow() + relLastRowIx, getFirstColumn() + relLastColIx, values); + } + private static ValueEval[] transpose(ValueEval[] srcValues, int srcWidth, + int relFirstRowIx, int relLastRowIx, + int relFirstColIx, int relLastColIx) { + int height = relLastRowIx - relFirstRowIx + 1; + int width = relLastColIx - relFirstColIx + 1; + ValueEval[] result = new ValueEval[height * width]; + for (int r=0; r= getHeight()) { + throw new IllegalArgumentException("Invalid rowIndex " + rowIndex + + ". Allowable range is (0.." + getHeight() + ")."); + } + ValueEval[] values = new ValueEval[getWidth()]; + for (int i = 0; i < values.length; i++) { + values[i] = getRelativeValue(rowIndex, i); + } + return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn(), values); + } + public TwoDEval getColumn(int columnIndex) { + if (columnIndex >= getWidth()) { + throw new IllegalArgumentException("Invalid columnIndex " + columnIndex + + ". Allowable range is (0.." + getWidth() + ")."); + } + ValueEval[] values = new ValueEval[getHeight()]; + for (int i = 0; i < values.length; i++) { + values[i] = getRelativeValue(i, columnIndex); + } + return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex, values); + } + } + + private static final class MockRefEval extends RefEvalBase { + private final ValueEval _value; + public MockRefEval(RefPtg ptg, ValueEval value) { + super(ptg.getRow(), ptg.getColumn()); + _value = value; + } + public MockRefEval(Ref3DPtg ptg, ValueEval value) { + super(ptg.getRow(), ptg.getColumn()); + _value = value; + } + public ValueEval getInnerValueEval() { + return _value; + } + public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { + throw new RuntimeException("Operation not implemented on this mock object"); + } + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/NumericFunctionInvoker.java b/src/testcases/org/apache/poi/ss/formula/functions/NumericFunctionInvoker.java new file mode 100644 index 0000000000..f51e8a22f1 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/NumericFunctionInvoker.java @@ -0,0 +1,111 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NotImplementedException; + +/** + * Test helper class for invoking functions with numeric results. + * + * @author Josh Micich + */ +public final class NumericFunctionInvoker { + + private NumericFunctionInvoker() { + // no instances of this class + } + + private static final class NumericEvalEx extends Exception { + public NumericEvalEx(String msg) { + super(msg); + } + } + + /** + * Invokes the specified function with the arguments. + *

+ * Assumes that the cell coordinate parameters of + * Function.evaluate(args, srcCellRow, srcCellCol) + * are not required. + *

+ * This method cannot be used for confirming error return codes. Any non-numeric evaluation + * result causes the current junit test to fail. + */ + public static double invoke(Function f, ValueEval[] args) { + return invoke(f, args, -1, -1); + } + /** + * Invokes the specified operator with the arguments. + *

+ * This method cannot be used for confirming error return codes. Any non-numeric evaluation + * result causes the current junit test to fail. + */ + public static double invoke(Function f, ValueEval[] args, int srcCellRow, int srcCellCol) { + try { + return invokeInternal(f, args, srcCellRow, srcCellCol); + } catch (NumericEvalEx e) { + throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName() + + ") failed: " + e.getMessage()); + } + } + /** + * Formats nicer error messages for the junit output + */ + private static double invokeInternal(Function target, ValueEval[] args, int srcCellRow, int srcCellCol) + throws NumericEvalEx { + ValueEval evalResult; + try { + evalResult = target.evaluate(args, srcCellRow, (short)srcCellCol); + } catch (NotImplementedException e) { + throw new NumericEvalEx("Not implemented:" + e.getMessage()); + } + + if(evalResult == null) { + throw new NumericEvalEx("Result object was null"); + } + if(evalResult instanceof ErrorEval) { + ErrorEval ee = (ErrorEval) evalResult; + throw new NumericEvalEx(formatErrorMessage(ee)); + } + if(!(evalResult instanceof NumericValueEval)) { + throw new NumericEvalEx("Result object type (" + evalResult.getClass().getName() + + ") is invalid. Expected implementor of (" + + NumericValueEval.class.getName() + ")"); + } + + NumericValueEval result = (NumericValueEval) evalResult; + return result.getNumberValue(); + } + private static String formatErrorMessage(ErrorEval ee) { + if(errorCodesAreEqual(ee, ErrorEval.VALUE_INVALID)) { + return "Error code: #VALUE! (invalid value)"; + } + return "Error code=" + ee.getErrorCode(); + } + private static boolean errorCodesAreEqual(ErrorEval a, ErrorEval b) { + if(a==b) { + return true; + } + return a.getErrorCode() == b.getErrorCode(); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestAverage.java b/src/testcases/org/apache/poi/ss/formula/functions/TestAverage.java new file mode 100644 index 0000000000..1dcba00c51 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestAverage.java @@ -0,0 +1,98 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +/** + * Tests for Excel function AVERAGE() + * + * @author Josh Micich + */ +public final class TestAverage extends TestCase { + + private static ValueEval invokeAverage(ValueEval[] args) { + return AggregateFunction.AVERAGE.evaluate(args, -1, (short)-1); + } + + private void confirmAverage(ValueEval[] args, double expected) { + ValueEval result = invokeAverage(args); + assertEquals(NumberEval.class, result.getClass()); + assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); + } + + private void confirmAverage(ValueEval[] args, ErrorEval expectedError) { + ValueEval result = invokeAverage(args); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); + } + + public void testBasic() { + + ValueEval[] values = { + new NumberEval(1), + new NumberEval(2), + new NumberEval(3), + new NumberEval(4), + }; + + confirmAverage(values, 2.5); + + values = new ValueEval[] { + new NumberEval(1), + new NumberEval(2), + BlankEval.instance, + new NumberEval(3), + BlankEval.instance, + new NumberEval(4), + BlankEval.instance, + }; + + confirmAverage(values, 2.5); + } + + /** + * Valid cases where values are not pure numbers + */ + public void testUnusualArgs() { + ValueEval[] values = { + new NumberEval(1), + new NumberEval(2), + BoolEval.TRUE, + BoolEval.FALSE, + }; + + confirmAverage(values, 1.0); + + } + + public void testErrors() { + ValueEval[] values = { + new NumberEval(1), + ErrorEval.NAME_INVALID, + new NumberEval(3), + ErrorEval.DIV_ZERO, + }; + confirmAverage(values, ErrorEval.NAME_INVALID); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java b/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java new file mode 100644 index 0000000000..8897feb60e --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java @@ -0,0 +1,460 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.OperandResolver; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.functions.CountUtils.I_MatchPredicate; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK() + * + * @author Josh Micich + */ +public final class TestCountFuncs extends TestCase { + + private static final String NULL = null; + + public void testCountBlank() { + + AreaEval range; + ValueEval[] values; + + values = new ValueEval[] { + new NumberEval(0), + new StringEval(""), // note - does not match blank + BoolEval.TRUE, + BoolEval.FALSE, + ErrorEval.DIV_ZERO, + BlankEval.instance, + }; + range = EvalFactory.createAreaEval("A1:B3", values); + confirmCountBlank(1, range); + + values = new ValueEval[] { + new NumberEval(0), + new StringEval(""), // note - does not match blank + BlankEval.instance, + BoolEval.FALSE, + BoolEval.TRUE, + BlankEval.instance, + }; + range = EvalFactory.createAreaEval("A1:B3", values); + confirmCountBlank(2, range); + } + + public void testCountA() { + + ValueEval[] args; + + args = new ValueEval[] { + new NumberEval(0), + }; + confirmCountA(1, args); + + args = new ValueEval[] { + new NumberEval(0), + new NumberEval(0), + new StringEval(""), + }; + confirmCountA(3, args); + + args = new ValueEval[] { + EvalFactory.createAreaEval("D2:F5", new ValueEval[12]), + }; + confirmCountA(12, args); + + args = new ValueEval[] { + EvalFactory.createAreaEval("D1:F5", new ValueEval[15]), + EvalFactory.createRefEval("A1"), + EvalFactory.createAreaEval("A1:G6", new ValueEval[42]), + new NumberEval(0), + }; + confirmCountA(59, args); + } + + public void testCountIf() { + + AreaEval range; + ValueEval[] values; + + // when criteria is a boolean value + values = new ValueEval[] { + new NumberEval(0), + new StringEval("TRUE"), // note - does not match boolean TRUE + BoolEval.TRUE, + BoolEval.FALSE, + BoolEval.TRUE, + BlankEval.instance, + }; + range = EvalFactory.createAreaEval("A1:B3", values); + confirmCountIf(2, range, BoolEval.TRUE); + + // when criteria is numeric + values = new ValueEval[] { + new NumberEval(0), + new StringEval("2"), + new StringEval("2.001"), + new NumberEval(2), + new NumberEval(2), + BoolEval.TRUE, + }; + range = EvalFactory.createAreaEval("A1:B3", values); + confirmCountIf(3, range, new NumberEval(2)); + // note - same results when criteria is a string that parses as the number with the same value + confirmCountIf(3, range, new StringEval("2.00")); + + // when criteria is an expression (starting with a comparison operator) + confirmCountIf(2, range, new StringEval(">1")); + // when criteria is an expression (starting with a comparison operator) + confirmCountIf(2, range, new StringEval(">0.5")); + } + + public void testCriteriaPredicateNe_Bug46647() { + I_MatchPredicate mp = Countif.createCriteriaPredicate(new StringEval("<>aa"), 0, 0); + StringEval seA = new StringEval("aa"); // this should not match the criteria '<>aa' + StringEval seB = new StringEval("bb"); // this should match + if (mp.matches(seA) && !mp.matches(seB)) { + throw new AssertionFailedError("Identified bug 46647"); + } + assertFalse(mp.matches(seA)); + assertTrue(mp.matches(seB)); + + // general tests for not-equal (<>) operator + AreaEval range; + ValueEval[] values; + + values = new ValueEval[] { + new StringEval("aa"), + new StringEval("def"), + new StringEval("aa"), + new StringEval("ghi"), + new StringEval("aa"), + new StringEval("aa"), + }; + + range = EvalFactory.createAreaEval("A1:A6", values); + confirmCountIf(2, range, new StringEval("<>aa")); + + values = new ValueEval[] { + new StringEval("ab"), + new StringEval("aabb"), + new StringEval("aa"), // match + new StringEval("abb"), + new StringEval("aab"), + new StringEval("ba"), // match + }; + + range = EvalFactory.createAreaEval("A1:A6", values); + confirmCountIf(2, range, new StringEval("<>a*b")); + + + values = new ValueEval[] { + new NumberEval(222), + new NumberEval(222), + new NumberEval(111), + new StringEval("aa"), + new StringEval("111"), + }; + + range = EvalFactory.createAreaEval("A1:A5", values); + confirmCountIf(4, range, new StringEval("<>111")); + } + + /** + * special case where the criteria argument is a cell reference + */ + public void testCountIfWithCriteriaReference() { + + ValueEval[] values = { + new NumberEval(22), + new NumberEval(25), + new NumberEval(21), + new NumberEval(25), + new NumberEval(25), + new NumberEval(25), + }; + AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values); + + ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25)); + ValueEval[] args= { arg0, criteriaArg, }; + + double actual = NumericFunctionInvoker.invoke(new Countif(), args); + assertEquals(4, actual, 0D); + } + + private static void confirmCountA(int expected, ValueEval[] args) { + double result = NumericFunctionInvoker.invoke(new Counta(), args); + assertEquals(expected, result, 0); + } + private static void confirmCountIf(int expected, AreaEval range, ValueEval criteria) { + + ValueEval[] args = { range, criteria, }; + double result = NumericFunctionInvoker.invoke(new Countif(), args); + assertEquals(expected, result, 0); + } + private static void confirmCountBlank(int expected, AreaEval range) { + + ValueEval[] args = { range }; + double result = NumericFunctionInvoker.invoke(new Countblank(), args); + assertEquals(expected, result, 0); + } + + private static I_MatchPredicate createCriteriaPredicate(ValueEval ev) { + return Countif.createCriteriaPredicate(ev, 0, 0); + } + + /** + * the criteria arg is mostly handled by {@link OperandResolver#getSingleValue(org.apache.poi.ss.formula.eval.ValueEval, int, int)}} + */ + public void testCountifAreaCriteria() { + int srcColIx = 2; // anything but column A + + ValueEval v0 = new NumberEval(2.0); + ValueEval v1 = new StringEval("abc"); + ValueEval v2 = ErrorEval.DIV_ZERO; + + AreaEval ev = EvalFactory.createAreaEval("A10:A12", new ValueEval[] { v0, v1, v2, }); + + I_MatchPredicate mp; + mp = Countif.createCriteriaPredicate(ev, 9, srcColIx); + confirmPredicate(true, mp, srcColIx); + confirmPredicate(false, mp, "abc"); + confirmPredicate(false, mp, ErrorEval.DIV_ZERO); + + mp = Countif.createCriteriaPredicate(ev, 10, srcColIx); + confirmPredicate(false, mp, srcColIx); + confirmPredicate(true, mp, "abc"); + confirmPredicate(false, mp, ErrorEval.DIV_ZERO); + + mp = Countif.createCriteriaPredicate(ev, 11, srcColIx); + confirmPredicate(false, mp, srcColIx); + confirmPredicate(false, mp, "abc"); + confirmPredicate(true, mp, ErrorEval.DIV_ZERO); + confirmPredicate(false, mp, ErrorEval.VALUE_INVALID); + + // tricky: indexing outside of A10:A12 + // even this #VALUE! error gets used by COUNTIF as valid criteria + mp = Countif.createCriteriaPredicate(ev, 12, srcColIx); + confirmPredicate(false, mp, srcColIx); + confirmPredicate(false, mp, "abc"); + confirmPredicate(false, mp, ErrorEval.DIV_ZERO); + confirmPredicate(true, mp, ErrorEval.VALUE_INVALID); + } + + public void testCountifEmptyStringCriteria() { + I_MatchPredicate mp; + + // pred '=' matches blank cell but not empty string + mp = createCriteriaPredicate(new StringEval("=")); + confirmPredicate(false, mp, ""); + confirmPredicate(true, mp, NULL); + + // pred '' matches both blank cell but not empty string + mp = createCriteriaPredicate(new StringEval("")); + confirmPredicate(true, mp, ""); + confirmPredicate(true, mp, NULL); + + // pred '<>' matches empty string but not blank cell + mp = createCriteriaPredicate(new StringEval("<>")); + confirmPredicate(false, mp, NULL); + confirmPredicate(true, mp, ""); + } + + public void testCountifComparisons() { + I_MatchPredicate mp; + + mp = createCriteriaPredicate(new StringEval(">5")); + confirmPredicate(false, mp, 4); + confirmPredicate(false, mp, 5); + confirmPredicate(true, mp, 6); + + mp = createCriteriaPredicate(new StringEval("<=5")); + confirmPredicate(true, mp, 4); + confirmPredicate(true, mp, 5); + confirmPredicate(false, mp, 6); + confirmPredicate(false, mp, "4.9"); + confirmPredicate(false, mp, "4.9t"); + confirmPredicate(false, mp, "5.1"); + confirmPredicate(false, mp, NULL); + + mp = createCriteriaPredicate(new StringEval("=abc")); + confirmPredicate(true, mp, "abc"); + + mp = createCriteriaPredicate(new StringEval("=42")); + confirmPredicate(false, mp, 41); + confirmPredicate(true, mp, 42); + confirmPredicate(true, mp, "42"); + + mp = createCriteriaPredicate(new StringEval(">abc")); + confirmPredicate(false, mp, 4); + confirmPredicate(false, mp, "abc"); + confirmPredicate(true, mp, "abd"); + + mp = createCriteriaPredicate(new StringEval(">4t3")); + confirmPredicate(false, mp, 4); + confirmPredicate(false, mp, 500); + confirmPredicate(true, mp, "500"); + confirmPredicate(true, mp, "4t4"); + } + + /** + * the criteria arg value can be an error code (the error does not + * propagate to the COUNTIF result). + */ + public void testCountifErrorCriteria() { + I_MatchPredicate mp; + + mp = createCriteriaPredicate(new StringEval("#REF!")); + confirmPredicate(false, mp, 4); + confirmPredicate(false, mp, "#REF!"); + confirmPredicate(true, mp, ErrorEval.REF_INVALID); + + mp = createCriteriaPredicate(new StringEval("<#VALUE!")); + confirmPredicate(false, mp, 4); + confirmPredicate(false, mp, "#DIV/0!"); + confirmPredicate(false, mp, "#REF!"); + confirmPredicate(true, mp, ErrorEval.DIV_ZERO); + confirmPredicate(false, mp, ErrorEval.REF_INVALID); + + // not quite an error literal, should be treated as plain text + mp = createCriteriaPredicate(new StringEval("<=#REF!a")); + confirmPredicate(false, mp, 4); + confirmPredicate(true, mp, "#DIV/0!"); + confirmPredicate(true, mp, "#REF!"); + confirmPredicate(false, mp, ErrorEval.DIV_ZERO); + confirmPredicate(false, mp, ErrorEval.REF_INVALID); + } + + public void testWildCards() { + I_MatchPredicate mp; + + mp = createCriteriaPredicate(new StringEval("a*b")); + confirmPredicate(false, mp, "abc"); + confirmPredicate(true, mp, "ab"); + confirmPredicate(true, mp, "axxb"); + confirmPredicate(false, mp, "xab"); + + mp = createCriteriaPredicate(new StringEval("a?b")); + confirmPredicate(false, mp, "abc"); + confirmPredicate(false, mp, "ab"); + confirmPredicate(false, mp, "axxb"); + confirmPredicate(false, mp, "xab"); + confirmPredicate(true, mp, "axb"); + + mp = createCriteriaPredicate(new StringEval("a~?")); + confirmPredicate(false, mp, "a~a"); + confirmPredicate(false, mp, "a~?"); + confirmPredicate(true, mp, "a?"); + + mp = createCriteriaPredicate(new StringEval("~*a")); + confirmPredicate(false, mp, "~aa"); + confirmPredicate(false, mp, "~*a"); + confirmPredicate(true, mp, "*a"); + + mp = createCriteriaPredicate(new StringEval("12?12")); + confirmPredicate(false, mp, 12812); + confirmPredicate(true, mp, "12812"); + confirmPredicate(false, mp, "128812"); + } + public void testNotQuiteWildCards() { + I_MatchPredicate mp; + + // make sure special reg-ex chars are treated like normal chars + mp = createCriteriaPredicate(new StringEval("a.b")); + confirmPredicate(false, mp, "aab"); + confirmPredicate(true, mp, "a.b"); + + + mp = createCriteriaPredicate(new StringEval("a~b")); + confirmPredicate(false, mp, "ab"); + confirmPredicate(false, mp, "axb"); + confirmPredicate(false, mp, "a~~b"); + confirmPredicate(true, mp, "a~b"); + + mp = createCriteriaPredicate(new StringEval(">a*b")); + confirmPredicate(false, mp, "a(b"); + confirmPredicate(true, mp, "aab"); + confirmPredicate(false, mp, "a*a"); + confirmPredicate(true, mp, "a*c"); + } + + private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, int value) { + assertEquals(expectedResult, matchPredicate.matches(new NumberEval(value))); + } + private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, String value) { + ValueEval ev = value == null ? BlankEval.instance : new StringEval(value); + assertEquals(expectedResult, matchPredicate.matches(ev)); + } + private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, ErrorEval value) { + assertEquals(expectedResult, matchPredicate.matches(value)); + } + + public void testCountifFromSpreadsheet() { + testCountFunctionFromSpreadsheet("countifExamples.xls", 1, 2, 3, "countif"); + } + + public void testCountBlankFromSpreadsheet() { + testCountFunctionFromSpreadsheet("countblankExamples.xls", 1, 3, 4, "countblank"); + } + + private static void testCountFunctionFromSpreadsheet(String FILE_NAME, int START_ROW_IX, int COL_IX_ACTUAL, int COL_IX_EXPECTED, String functionName) { + + int failureCount = 0; + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME); + HSSFSheet sheet = wb.getSheetAt(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + int maxRow = sheet.getLastRowNum(); + for (int rowIx=START_ROW_IX; rowIx 0) { + throw new AssertionFailedError(failureCount + " " + functionName + + " evaluations failed. See stderr for more details"); + } + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestDate.java b/src/testcases/org/apache/poi/ss/formula/functions/TestDate.java new file mode 100644 index 0000000000..64e1c45542 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestDate.java @@ -0,0 +1,90 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * @author Pavel Krupets (pkrupets at palmtreebusiness dot com) + */ +public final class TestDate extends TestCase { + + private HSSFCell cell11; + private HSSFFormulaEvaluator evaluator; + + public void setUp() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("new sheet"); + cell11 = sheet.createRow(0).createCell(0); + cell11.setCellType(HSSFCell.CELL_TYPE_FORMULA); + evaluator = new HSSFFormulaEvaluator(wb); + } + + /** + * Test disabled pending a fix in the formula evaluator + * TODO - create MissingArgEval and modify the formula evaluator to handle this + */ + public void DISABLEDtestSomeArgumentsMissing() { + confirm("DATE(, 1, 0)", 0.0); + confirm("DATE(, 1, 1)", 1.0); + } + + public void testValid() { + + confirm("DATE(1900, 1, 1)", 1); + confirm("DATE(1900, 1, 32)", 32); + confirm("DATE(1900, 222, 1)", 6727); + confirm("DATE(1900, 2, 0)", 31); + confirm("DATE(2000, 1, 222)", 36747.00); + confirm("DATE(2007, 1, 1)", 39083); + } + + public void testBugDate() { + confirm("DATE(1900, 2, 29)", 60); + confirm("DATE(1900, 2, 30)", 61); + confirm("DATE(1900, 1, 222)", 222); + confirm("DATE(1900, 1, 2222)", 2222); + confirm("DATE(1900, 1, 22222)", 22222); + } + + public void testPartYears() { + confirm("DATE(4, 1, 1)", 1462.00); + confirm("DATE(14, 1, 1)", 5115.00); + confirm("DATE(104, 1, 1)", 37987.00); + confirm("DATE(1004, 1, 1)", 366705.00); + } + + private void confirm(String formulaText, double expectedResult) { + cell11.setCellFormula(formulaText); + evaluator.clearAllCachedResultValues(); + CellValue cv = evaluator.evaluate(cell11); + if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) { + throw new AssertionFailedError("Wrong result type: " + cv.formatAsString()); + } + double actualValue = cv.getNumberValue(); + assertEquals(expectedResult, actualValue, 0); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestDays360.java b/src/testcases/org/apache/poi/ss/formula/functions/TestDays360.java new file mode 100644 index 0000000000..15dd1246b1 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestDays360.java @@ -0,0 +1,155 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; + +/** + * @author Josh Micich + */ +public final class TestDays360 extends TestCase { + + /** + * @param month 1-based + */ + private static Date makeDate(int year, int month, int day) { + + Calendar cal = new GregorianCalendar(year, month-1, day, 0, 0, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + private static Date decrementDay(Date d) { + Calendar c = new GregorianCalendar(); + c.setTimeInMillis(d.getTime()); + c.add(Calendar.DAY_OF_MONTH, -1); + return c.getTime(); + } + private static String fmt(Date d) { + Calendar c = new GregorianCalendar(); + c.setTimeInMillis(d.getTime()); + StringBuilder sb = new StringBuilder(); + sb.append(c.get(Calendar.YEAR)); + sb.append("/"); + sb.append(c.get(Calendar.MONTH)+1); + sb.append("/"); + sb.append(c.get(Calendar.DAY_OF_MONTH)); + return sb.toString(); + } + + + public void testBasic() { + confirm(120, 2009, 1, 15, 2009, 5, 15); + confirm(158, 2009, 1, 26, 2009, 7, 4); + + // same results in leap years + confirm(120, 2008, 1, 15, 2008, 5, 15); + confirm(158, 2008, 1, 26, 2008, 7, 4); + + // longer time spans + confirm(562, 2008, 8, 11, 2010, 3, 3); + confirm(916, 2007, 2, 23, 2009, 9, 9); + } + + private static void confirm(int expResult, int y1, int m1, int d1, int y2, int m2, int d2) { + confirm(expResult, makeDate(y1, m1, d1), makeDate(y2, m2, d2), false); + confirm(-expResult, makeDate(y2, m2, d2), makeDate(y1, m1, d1), false); + + } + /** + * The method parameter only makes a difference when the second parameter + * is the last day of the month that does not have 30 days. + */ + public void DISABLED_testMonthBoundaries() { + // jan + confirmMonthBoundary(false, 1, 0, 0, 2, 3, 4); + confirmMonthBoundary(true, 1, 0, 0, 1, 3, 4); + // feb + confirmMonthBoundary(false, 2,-2, 1, 2, 3, 4); + confirmMonthBoundary(true, 2, 0, 1, 2, 3, 4); + // mar + confirmMonthBoundary(false, 3, 0, 0, 2, 3, 4); + confirmMonthBoundary(true, 3, 0, 0, 1, 3, 4); + // apr + confirmMonthBoundary(false, 4, 0, 1, 2, 3, 4); + confirmMonthBoundary(true, 4, 0, 1, 2, 3, 4); + // may + confirmMonthBoundary(false, 5, 0, 0, 2, 3, 4); + confirmMonthBoundary(true, 5, 0, 0, 1, 3, 4); + // jun + confirmMonthBoundary(false, 6, 0, 1, 2, 3, 4); + confirmMonthBoundary(true, 6, 0, 1, 2, 3, 4); + // etc... + } + + + /** + * @param monthNo 1-based + * @param diffs + */ + private static void confirmMonthBoundary(boolean method, int monthNo, int...diffs) { + Date firstDayOfNextMonth = makeDate(2001, monthNo+1, 1); + Date secondArg = decrementDay(firstDayOfNextMonth); + Date firstArg = secondArg; + + for (int i = 0; i < diffs.length; i++) { + int expResult = diffs[i]; + confirm(expResult, firstArg, secondArg, method); + firstArg = decrementDay(firstArg); + } + + } + private static void confirm(int expResult, Date firstArg, Date secondArg, boolean method) { + + ValueEval ve; + if (method) { + // TODO enable 3rd arg - + ve = invokeDays360(convert(firstArg), convert(secondArg), BoolEval.valueOf(method)); + } else { + ve = invokeDays360(convert(firstArg), convert(secondArg)); + } + if (ve instanceof NumberEval) { + + NumberEval numberEval = (NumberEval) ve; + if (numberEval.getNumberValue() != expResult) { + throw new AssertionFailedError(fmt(firstArg) + " " + fmt(secondArg) + " " + method + + " wrong result got (" + numberEval.getNumberValue() + + ") but expected (" + expResult + ")"); + } + // System.err.println(fmt(firstArg) + " " + fmt(secondArg) + " " + method + " success got (" + expResult + ")"); + return; + } + throw new AssertionFailedError("wrong return type (" + ve.getClass().getName() + ")"); + } + private static ValueEval invokeDays360(ValueEval...args) { + return new Days360().evaluate(args, -1, -1); + } + private static NumberEval convert(Date d) { + return new NumberEval(HSSFDateUtil.getExcelDate(d)); + } +} + diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestFinanceLib.java b/src/testcases/org/apache/poi/ss/formula/functions/TestFinanceLib.java new file mode 100644 index 0000000000..90300bf240 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestFinanceLib.java @@ -0,0 +1,202 @@ +/* +* 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. +*/ +/* + * Created on May 23, 2005 + * + */ +package org.apache.poi.ss.formula.functions; + + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public class TestFinanceLib extends AbstractNumericTestCase { + + public void testFv() { + double f, r, y, p, x; + int n; + boolean t = false; + + r = 0; n = 3; y = 2; p = 7; t = true; + f = FinanceLib.fv(r, n, y, p, t); + x = -13; + assertEquals("fv ", x, f); + + r = 1; n = 10; y = 100; p = 10000; t = false; + f = FinanceLib.fv(r, n, y, p, t); + x = -10342300; + assertEquals("fv ", x, f); + + r = 1; n = 10; y = 100; p = 10000; t = true; + f = FinanceLib.fv(r, n, y, p, t); + x = -10444600; + assertEquals("fv ", x, f); + + r = 2; n = 12; y = 120; p = 12000; t = false; + f = FinanceLib.fv(r, n, y, p, t); + x = -6409178400d; + assertEquals("fv ", x, f); + + r = 2; n = 12; y = 120; p = 12000; t = true; + f = FinanceLib.fv(r, n, y, p, t); + x = -6472951200d; + assertEquals("fv ", x, f); + + // cross tests with pv + r = 2.95; n = 13; y = 13000; p = -4406.78544294496; t = false; + f = FinanceLib.fv(r, n, y, p, t); + x = 333891.230010986; // as returned by excel + assertEquals("fv ", x, f); + + r = 2.95; n = 13; y = 13000; p = -17406.7852148156; t = true; + f = FinanceLib.fv(r, n, y, p, t); + x = 333891.230102539; // as returned by excel + assertEquals("fv ", x, f); + + } + public void testNpv() { + double r, v[], npv, x; + + r = 1; v = new double[]{100, 200, 300, 400}; + npv = FinanceLib.npv(r, v); + x = 162.5; + assertEquals("npv ", x, npv); + + r = 2.5; v = new double[]{1000, 666.66666, 333.33, 12.2768416}; + npv = FinanceLib.npv(r, v); + x = 347.99232604144827; + assertEquals("npv ", x, npv); + + r = 12.33333; v = new double[]{1000, 0, -900, -7777.5765}; + npv = FinanceLib.npv(r, v); + x = 74.3742433377061; + assertEquals("npv ", x, npv); + + r = 0.05; v = new double[]{200000, 300000.55, 400000, 1000000, 6000000, 7000000, -300000}; + npv = FinanceLib.npv(r, v); + x = 11342283.4233124; + assertEquals("npv ", x, npv); + } + public void testPmt() { + double f, r, y, p, x; + int n; + boolean t = false; + + r = 0; n = 3; p = 2; f = 7; t = true; + y = FinanceLib.pmt(r, n, p, f, t); + x = -3; + assertEquals("pmt ", x, y); + + // cross check with pv + r = 1; n = 10; p = -109.66796875; f = 10000; t = false; + y = FinanceLib.pmt(r, n, p, f, t); + x = 100; + assertEquals("pmt ", x, y); + + r = 1; n = 10; p = -209.5703125; f = 10000; t = true; + y = FinanceLib.pmt(r, n, p, f, t); + x = 100; + assertEquals("pmt ", x, y); + + // cross check with fv + r = 2; n = 12; f = -6409178400d; p = 12000; t = false; + y = FinanceLib.pmt(r, n, p, f, t); + x = 120; + assertEquals("pmt ", x, y); + + r = 2; n = 12; f = -6472951200d; p = 12000; t = true; + y = FinanceLib.pmt(r, n, p, f, t); + x = 120; + assertEquals("pmt ", x, y); + } + + public void testPv() { + double f, r, y, p, x; + int n; + boolean t = false; + + r = 0; n = 3; y = 2; f = 7; t = true; + f = FinanceLib.pv(r, n, y, f, t); + x = -13; + assertEquals("pv ", x, f); + + r = 1; n = 10; y = 100; f = 10000; t = false; + p = FinanceLib.pv(r, n, y, f, t); + x = -109.66796875; + assertEquals("pv ", x, p); + + r = 1; n = 10; y = 100; f = 10000; t = true; + p = FinanceLib.pv(r, n, y, f, t); + x = -209.5703125; + assertEquals("pv ", x, p); + + r = 2.95; n = 13; y = 13000; f = 333891.23; t = false; + p = FinanceLib.pv(r, n, y, f, t); + x = -4406.78544294496; + assertEquals("pv ", x, p); + + r = 2.95; n = 13; y = 13000; f = 333891.23; t = true; + p = FinanceLib.pv(r, n, y, f, t); + x = -17406.7852148156; + assertEquals("pv ", x, p); + + // cross tests with fv + r = 2; n = 12; y = 120; f = -6409178400d; t = false; + p = FinanceLib.pv(r, n, y, f, t); + x = 12000; + assertEquals("pv ", x, p); + + r = 2; n = 12; y = 120; f = -6472951200d; t = true; + p = FinanceLib.pv(r, n, y, f, t); + x = 12000; + assertEquals("pv ", x, p); + + } + + public void testNper() { + double f, r, y, p, x, n; + boolean t = false; + + r = 0; y = 7; p = 2; f = 3; t = false; + n = FinanceLib.nper(r, y, p, f, t); + x = -0.71428571429; // can you believe it? excel returns nper as a fraction!?? + assertEquals("nper ", x, n); + + // cross check with pv + r = 1; y = 100; p = -109.66796875; f = 10000; t = false; + n = FinanceLib.nper(r, y, p, f, t); + x = 10; + assertEquals("nper ", x, n); + + r = 1; y = 100; p = -209.5703125; f = 10000; t = true; + n = FinanceLib.nper(r, y, p, f, t); + x = 10; + assertEquals("nper ", x, n); + + // cross check with fv + r = 2; y = 120; f = -6409178400d; p = 12000; t = false; + n = FinanceLib.nper(r, y, p, f, t); + x = 12; + assertEquals("nper ", x, n); + + r = 2; y = 120; f = -6472951200d; p = 12000; t = true; + n = FinanceLib.nper(r, y, p, f, t); + x = 12; + assertEquals("nper ", x, n); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestFind.java b/src/testcases/org/apache/poi/ss/formula/functions/TestFind.java new file mode 100644 index 0000000000..a78e89ddeb --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestFind.java @@ -0,0 +1,76 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFErrorConstants; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Tests for {@link Financed} + * + * @author Torstein Svendsen (torstei@officenet.no) + */ +public final class TestFind extends TestCase { + + public void testFind() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFCell cell = wb.createSheet().createRow(0).createCell(0); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + + confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1); + confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2); + confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6); + + // number args converted to text + confirmResult(fe, cell, "find(7, 32768)", 3); + confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10); + confirmResult(fe, cell, "find(5, 87654)", 4); + + // Errors + confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF); + confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0); + confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA); + } + + private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, + int expectedResult) { + cell.setCellFormula(formulaText); + fe.notifyUpdateCell(cell); + CellValue result = fe.evaluate(cell); + assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC); + assertEquals(expectedResult, result.getNumberValue(), 0.0); + } + + private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, + int expectedErrorCode) { + cell.setCellFormula(formulaText); + fe.notifyUpdateCell(cell); + CellValue result = fe.evaluate(cell); + assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR); + assertEquals(expectedErrorCode, result.getErrorValue()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestIndex.java b/src/testcases/org/apache/poi/ss/formula/functions/TestIndex.java new file mode 100644 index 0000000000..ce0325285f --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestIndex.java @@ -0,0 +1,157 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.util.Arrays; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.MissingArgEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.WorkbookEvaluator; +import org.apache.poi.ss.util.CellRangeAddress; + +/** + * Tests for the INDEX() function.

+ * + * This class contains just a few specific cases that directly invoke {@link Index}, + * with minimum overhead.
+ * Another test: {@link TestIndexFunctionFromSpreadsheet} operates from a higher level + * and has far greater coverage of input permutations.
+ * + * @author Josh Micich + */ +public final class TestIndex extends TestCase { + + private static final Index FUNC_INST = new Index(); + private static final double[] TEST_VALUES0 = { + 1, 2, + 3, 4, + 5, 6, + 7, 8, + 9, 10, + 11, 12, + }; + + /** + * For the case when the first argument to INDEX() is an area reference + */ + public void testEvaluateAreaReference() { + + double[] values = TEST_VALUES0; + confirmAreaEval("C1:D6", values, 4, 1, 7); + confirmAreaEval("C1:D6", values, 6, 2, 12); + confirmAreaEval("C1:D6", values, 3, 1, 5); + + // now treat same data as 3 columns, 4 rows + confirmAreaEval("C10:E13", values, 2, 2, 5); + confirmAreaEval("C10:E13", values, 4, 1, 10); + } + + /** + * @param areaRefString in Excel notation e.g. 'D2:E97' + * @param dValues array of evaluated values for the area reference + * @param rowNum 1-based + * @param colNum 1-based, pass -1 to signify argument not present + */ + private static void confirmAreaEval(String areaRefString, double[] dValues, + int rowNum, int colNum, double expectedResult) { + ValueEval[] values = new ValueEval[dValues.length]; + for (int i = 0; i < values.length; i++) { + values[i] = new NumberEval(dValues[i]); + } + AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values); + + ValueEval[] args; + if (colNum > 0) { + args = new ValueEval[] { arg0, new NumberEval(rowNum), new NumberEval(colNum), }; + } else { + args = new ValueEval[] { arg0, new NumberEval(rowNum), }; + } + + double actual = invokeAndDereference(args); + assertEquals(expectedResult, actual, 0D); + } + + private static double invokeAndDereference(ValueEval[] args) { + ValueEval ve = FUNC_INST.evaluate(args, -1, -1); + ve = WorkbookEvaluator.dereferenceResult(ve, -1, -1); + assertEquals(NumberEval.class, ve.getClass()); + return ((NumberEval)ve).getNumberValue(); + } + + /** + * Tests expressions like "INDEX(A1:C1,,2)".
+ * This problem was found while fixing bug 47048 and is observable up to svn r773441. + */ + public void testMissingArg() { + ValueEval[] values = { + new NumberEval(25.0), + new NumberEval(26.0), + new NumberEval(28.0), + }; + AreaEval arg0 = EvalFactory.createAreaEval("A10:C10", values); + ValueEval[] args = new ValueEval[] { arg0, MissingArgEval.instance, new NumberEval(2), }; + ValueEval actualResult; + try { + actualResult = FUNC_INST.evaluate(args, -1, -1); + } catch (RuntimeException e) { + if (e.getMessage().equals("Unexpected arg eval type (org.apache.poi.hssf.record.formula.eval.MissingArgEval")) { + throw new AssertionFailedError("Identified bug 47048b - INDEX() should support missing-arg"); + } + throw e; + } + // result should be an area eval "B10:B10" + AreaEval ae = confirmAreaEval("B10:B10", actualResult); + actualResult = ae.getValue(0, 0); + assertEquals(NumberEval.class, actualResult.getClass()); + assertEquals(26.0, ((NumberEval)actualResult).getNumberValue(), 0.0); + } + + /** + * When the argument to INDEX is a reference, the result should be a reference + * A formula like "OFFSET(INDEX(A1:B2,2,1),1,1,1,1)" should return the value of cell B3. + * This works because the INDEX() function returns a reference to A2 (not the value of A2) + */ + public void testReferenceResult() { + ValueEval[] values = new ValueEval[4]; + Arrays.fill(values, NumberEval.ZERO); + AreaEval arg0 = EvalFactory.createAreaEval("A1:B2", values); + ValueEval[] args = new ValueEval[] { arg0, new NumberEval(2), new NumberEval(1), }; + ValueEval ve = FUNC_INST.evaluate(args, -1, -1); + confirmAreaEval("A2:A2", ve); + } + + /** + * Confirms that the result is an area ref with the specified coordinates + * @return ve cast to {@link AreaEval} if it is valid + */ + private static AreaEval confirmAreaEval(String refText, ValueEval ve) { + CellRangeAddress cra = CellRangeAddress.valueOf(refText); + assertTrue(ve instanceof AreaEval); + AreaEval ae = (AreaEval) ve; + assertEquals(cra.getFirstRow(), ae.getFirstRow()); + assertEquals(cra.getFirstColumn(), ae.getFirstColumn()); + assertEquals(cra.getLastRow(), ae.getLastRow()); + assertEquals(cra.getLastColumn(), ae.getLastColumn()); + return ae; + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java new file mode 100644 index 0000000000..c2978435a1 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java @@ -0,0 +1,250 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.io.PrintStream; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Tests INDEX() as loaded from a test data spreadsheet.

+ * + * @author Josh Micich + */ +public final class TestIndexFunctionFromSpreadsheet extends TestCase { + + private static final class Result { + public static final int SOME_EVALUATIONS_FAILED = -1; + public static final int ALL_EVALUATIONS_SUCCEEDED = +1; + public static final int NO_EVALUATIONS_FOUND = 0; + } + + /** + * This class defines constants for navigating around the test data spreadsheet used for these tests. + */ + private static final class SS { + + /** Name of the test spreadsheet (found in the standard test data folder) */ + public final static String FILENAME = "IndexFunctionTestCaseData.xls"; + + public static final int COLUMN_INDEX_EVALUATION = 2; // Column 'C' + public static final int COLUMN_INDEX_EXPECTED_RESULT = 3; // Column 'D' + + } + + // Note - multiple failures are aggregated before ending. + // If one or more functions fail, a single AssertionFailedError is thrown at the end + private int _evaluationFailureCount; + private int _evaluationSuccessCount; + + + + private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) { + if (expected == null) { + throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); + } + if(actual == null) { + throw new AssertionFailedError(msg + " - actual value was null"); + } + if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) { + confirmErrorResult(msg, expected.getErrorCellValue(), actual); + return; + } + if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) { + throw unexpectedError(msg, expected, actual.getErrorValue()); + } + if(actual.getCellType() != expected.getCellType()) { + throw wrongTypeError(msg, expected, actual); + } + + + switch (expected.getCellType()) { + case HSSFCell.CELL_TYPE_BOOLEAN: + assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); + break; + case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation + throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg); + case HSSFCell.CELL_TYPE_NUMERIC: + assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), 0.0); + break; + case HSSFCell.CELL_TYPE_STRING: + assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); + break; + } + } + + + private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) { + return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was " + + actualValue.formatAsString() + + " but the expected result was " + + formatValue(expectedCell) + ); + } + private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) { + return new AssertionFailedError(msgPrefix + " Error code (" + + ErrorEval.getText(actualErrorCode) + + ") was evaluated, but the expected result was " + + formatValue(expected) + ); + } + + + private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) { + if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) { + throw new AssertionFailedError(msgPrefix + " Expected cell error (" + + ErrorEval.getText(expectedErrorCode) + ") but actual value was " + + actual.formatAsString()); + } + if(expectedErrorCode != actual.getErrorValue()) { + throw new AssertionFailedError(msgPrefix + " Expected cell error code (" + + ErrorEval.getText(expectedErrorCode) + + ") but actual error code was (" + + ErrorEval.getText(actual.getErrorValue()) + + ")"); + } + } + + + private static String formatValue(HSSFCell expecedCell) { + switch (expecedCell.getCellType()) { + case HSSFCell.CELL_TYPE_BLANK: return ""; + case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue()); + case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue()); + case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString(); + } + throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")"); + } + + + protected void setUp() { + _evaluationFailureCount = 0; + _evaluationSuccessCount = 0; + } + + public void testFunctionsFromTestSpreadsheet() { + HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); + + processTestSheet(workbook, workbook.getSheetName(0)); + + // confirm results + String successMsg = "There were " + + _evaluationSuccessCount + " function(s) without error"; + if(_evaluationFailureCount > 0) { + String msg = _evaluationFailureCount + " evaluation(s) failed. " + successMsg; + throw new AssertionFailedError(msg); + } + if(false) { // normally no output for successful tests + System.out.println(getClass().getName() + ": " + successMsg); + } + } + + private void processTestSheet(HSSFWorkbook workbook, String sheetName) { + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); + int maxRows = sheet.getLastRowNum()+1; + int result = Result.NO_EVALUATIONS_FOUND; // so far + + for(int rowIndex=0; rowIndex= endIx) { + // something went wrong. just print the whole stack trace + e.printStackTrace(ps); + } + endIx -= 4; // skip 4 frames of reflection invocation + ps.println(e.toString()); + for(int i=startIx; i + * + * @author Josh Micich + */ +public final class TestIndirect extends TestCase { + // convenient access to namespace + private static final ErrorEval EE = null; + + private static void createDataRow(HSSFSheet sheet, int rowIndex, double... vals) { + HSSFRow row = sheet.createRow(rowIndex); + for (int i = 0; i < vals.length; i++) { + row.createCell(i).setCellValue(vals[i]); + } + } + + private static HSSFWorkbook createWBA() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet1 = wb.createSheet("Sheet1"); + HSSFSheet sheet2 = wb.createSheet("Sheet2"); + HSSFSheet sheet3 = wb.createSheet("John's sales"); + + createDataRow(sheet1, 0, 11, 12, 13, 14); + createDataRow(sheet1, 1, 21, 22, 23, 24); + createDataRow(sheet1, 2, 31, 32, 33, 34); + + createDataRow(sheet2, 0, 50, 55, 60, 65); + createDataRow(sheet2, 1, 51, 56, 61, 66); + createDataRow(sheet2, 2, 52, 57, 62, 67); + + createDataRow(sheet3, 0, 30, 31, 32); + createDataRow(sheet3, 1, 33, 34, 35); + + HSSFName name1 = wb.createName(); + name1.setNameName("sales1"); + name1.setRefersToFormula("Sheet1!A1:D1"); + + HSSFName name2 = wb.createName(); + name2.setNameName("sales2"); + name2.setRefersToFormula("Sheet2!B1:C3"); + + HSSFRow row = sheet1.createRow(3); + row.createCell(0).setCellValue("sales1"); //A4 + row.createCell(1).setCellValue("sales2"); //B4 + + return wb; + } + + private static HSSFWorkbook createWBB() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet1 = wb.createSheet("Sheet1"); + HSSFSheet sheet2 = wb.createSheet("Sheet2"); + HSSFSheet sheet3 = wb.createSheet("## Look here!"); + + createDataRow(sheet1, 0, 400, 440, 480, 520); + createDataRow(sheet1, 1, 420, 460, 500, 540); + + createDataRow(sheet2, 0, 50, 55, 60, 65); + createDataRow(sheet2, 1, 51, 56, 61, 66); + + createDataRow(sheet3, 0, 42); + + return wb; + } + + public void testBasic() { + + HSSFWorkbook wbA = createWBA(); + HSSFCell c = wbA.getSheetAt(0).createRow(5).createCell(2); + HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA); + + // non-error cases + confirm(feA, c, "INDIRECT(\"C2\")", 23); + confirm(feA, c, "INDIRECT(\"$C2\")", 23); + confirm(feA, c, "INDIRECT(\"C$2\")", 23); + confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref + confirm(feA, c, "SUM(INDIRECT(\"Sheet2! B1 : C3 \"))", 351); // spaces in area ref + confirm(feA, c, "SUM(INDIRECT(\"'John''s sales'!A1:C1\"))", 93); // special chars in sheet name + confirm(feA, c, "INDIRECT(\"'Sheet1'!B3\")", 32); // redundant sheet name quotes + confirm(feA, c, "INDIRECT(\"sHeet1!B3\")", 32); // case-insensitive sheet name + confirm(feA, c, "INDIRECT(\" D3 \")", 34); // spaces around cell ref + confirm(feA, c, "INDIRECT(\"Sheet1! D3 \")", 34); // spaces around cell ref + confirm(feA, c, "INDIRECT(\"A1\", TRUE)", 11); // explicit arg1. only TRUE supported so far + + confirm(feA, c, "INDIRECT(\"A1:G1\")", 13); // de-reference area ref (note formula is in C4) + + confirm(feA, c, "SUM(INDIRECT(A4))", 50); // indirect defined name + confirm(feA, c, "SUM(INDIRECT(B4))", 351); // indirect defined name pointinh to other sheet + + // simple error propagation: + + // arg0 is evaluated to text first + confirm(feA, c, "INDIRECT(#DIV/0!)", EE.DIV_ZERO); + confirm(feA, c, "INDIRECT(#DIV/0!)", EE.DIV_ZERO); + confirm(feA, c, "INDIRECT(#NAME?, \"x\")", EE.NAME_INVALID); + confirm(feA, c, "INDIRECT(#NUM!, #N/A)", EE.NUM_ERROR); + + // arg1 is evaluated to boolean before arg0 is decoded + confirm(feA, c, "INDIRECT(\"garbage\", #N/A)", EE.NA); + confirm(feA, c, "INDIRECT(\"garbage\", \"\")", EE.VALUE_INVALID); // empty string is not valid boolean + confirm(feA, c, "INDIRECT(\"garbage\", \"flase\")", EE.VALUE_INVALID); // must be "TRUE" or "FALSE" + + + // spaces around sheet name (with or without quotes makes no difference) + confirm(feA, c, "INDIRECT(\"'Sheet1 '!D3\")", EE.REF_INVALID); + confirm(feA, c, "INDIRECT(\" Sheet1!D3\")", EE.REF_INVALID); + confirm(feA, c, "INDIRECT(\"'Sheet1' !D3\")", EE.REF_INVALID); + + + confirm(feA, c, "SUM(INDIRECT(\"'John's sales'!A1:C1\"))", EE.REF_INVALID); // bad quote escaping + confirm(feA, c, "INDIRECT(\"[Book1]Sheet1!A1\")", EE.REF_INVALID); // unknown external workbook + confirm(feA, c, "INDIRECT(\"Sheet3!A1\")", EE.REF_INVALID); // unknown sheet + if (false) { // TODO - support evaluation of defined names + confirm(feA, c, "INDIRECT(\"Sheet1!IW1\")", EE.REF_INVALID); // bad column + confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", EE.REF_INVALID); // bad row + } + confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", EE.REF_INVALID); // space in cell ref + } + + public void testMultipleWorkbooks() { + HSSFWorkbook wbA = createWBA(); + HSSFCell cellA = wbA.getSheetAt(0).createRow(10).createCell(0); + HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA); + + HSSFWorkbook wbB = createWBB(); + HSSFCell cellB = wbB.getSheetAt(0).createRow(10).createCell(0); + HSSFFormulaEvaluator feB = new HSSFFormulaEvaluator(wbB); + + String[] workbookNames = { "MyBook", "Figures for January", }; + HSSFFormulaEvaluator[] evaluators = { feA, feB, }; + HSSFFormulaEvaluator.setupEnvironment(workbookNames, evaluators); + + confirm(feB, cellB, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // same wb + confirm(feA, cellA, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // across workbooks + + // 2 level recursion + confirm(feB, cellB, "INDIRECT(\"[MyBook]Sheet2!A1\")", 50); // set up (and check) first level + confirm(feA, cellA, "INDIRECT(\"'[Figures for January]Sheet1'!A11\")", 50); // points to cellB + } + + private static void confirm(FormulaEvaluator fe, Cell cell, String formula, + double expectedResult) { + fe.clearAllCachedResultValues(); + cell.setCellFormula(formula); + CellValue cv = fe.evaluate(cell); + if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) { + throw new AssertionFailedError("expected numeric cell type but got " + cv.formatAsString()); + } + assertEquals(expectedResult, cv.getNumberValue(), 0.0); + } + private static void confirm(FormulaEvaluator fe, Cell cell, String formula, + ErrorEval expectedResult) { + fe.clearAllCachedResultValues(); + cell.setCellFormula(formula); + CellValue cv = fe.evaluate(cell); + if (cv.getCellType() != Cell.CELL_TYPE_ERROR) { + throw new AssertionFailedError("expected error cell type but got " + cv.formatAsString()); + } + int expCode = expectedResult.getErrorCode(); + if (cv.getErrorValue() != expCode) { + throw new AssertionFailedError("Expected error '" + EE.getText(expCode) + + "' but got '" + cv.formatAsString() + "'."); + } + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestIsBlank.java b/src/testcases/org/apache/poi/ss/formula/functions/TestIsBlank.java new file mode 100644 index 0000000000..6b40f9c173 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestIsBlank.java @@ -0,0 +1,58 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellValue; +/** + * Tests for Excel function ISBLANK() + * + * @author Josh Micich + */ +public final class TestIsBlank extends TestCase { + + public void test3DArea() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet1 = wb.createSheet(); + wb.setSheetName(0, "Sheet1"); + wb.createSheet(); + wb.setSheetName(1, "Sheet2"); + HSSFRow row = sheet1.createRow(0); + HSSFCell cell = row.createCell(0); + + + cell.setCellFormula("isblank(Sheet2!A1:A1)"); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + CellValue result = fe.evaluate(cell); + assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, result.getCellType()); + assertEquals(true, result.getBooleanValue()); + + cell.setCellFormula("isblank(D7:D7)"); + + result = fe.evaluate(cell); + assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, result.getCellType()); + assertEquals(true, result.getBooleanValue()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestLeftRight.java b/src/testcases/org/apache/poi/ss/formula/functions/TestLeftRight.java new file mode 100644 index 0000000000..58160bdfeb --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestLeftRight.java @@ -0,0 +1,73 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +import junit.framework.TestCase; + +/** + * + * Test cases for {@link TextFunction#LEFT} and {@link TextFunction#RIGHT} + * + * @author Brendan Nolan + * + */ +public class TestLeftRight extends TestCase { + + private static final NumberEval NEGATIVE_OPERAND = new NumberEval(-1.0); + private static final StringEval ANY_STRING_VALUE = new StringEval("ANYSTRINGVALUE"); + + + private static ValueEval invokeLeft(ValueEval text, ValueEval operand) { + ValueEval[] args = new ValueEval[] { text, operand }; + return TextFunction.LEFT.evaluate(args, -1, (short)-1); + } + + private static ValueEval invokeRight(ValueEval text, ValueEval operand) { + ValueEval[] args = new ValueEval[] { text, operand }; + return TextFunction.RIGHT.evaluate(args, -1, (short)-1); + } + + public void testLeftRight_bug49841() { + + try { + invokeLeft(ANY_STRING_VALUE, NEGATIVE_OPERAND); + invokeRight(ANY_STRING_VALUE, NEGATIVE_OPERAND); + } catch (StringIndexOutOfBoundsException e) { + fail("Identified bug 49841"); + } + + } + + public void testLeftRightNegativeOperand() { + + assertEquals(ErrorEval.VALUE_INVALID, invokeRight(ANY_STRING_VALUE, NEGATIVE_OPERAND)); + assertEquals(ErrorEval.VALUE_INVALID, invokeLeft(ANY_STRING_VALUE, NEGATIVE_OPERAND)); + + } + + + + + + +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestLen.java b/src/testcases/org/apache/poi/ss/formula/functions/TestLen.java new file mode 100644 index 0000000000..a9a3d4cff2 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestLen.java @@ -0,0 +1,72 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; +/** + * Tests for Excel function LEN() + * + * @author Josh Micich + */ +public final class TestLen extends TestCase { + + private static ValueEval invokeLen(ValueEval text) { + ValueEval[] args = new ValueEval[] { text, }; + return TextFunction.LEN.evaluate(args, -1, (short)-1); + } + + private void confirmLen(ValueEval text, int expected) { + ValueEval result = invokeLen(text); + assertEquals(NumberEval.class, result.getClass()); + assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); + } + + private void confirmLen(ValueEval text, ErrorEval expectedError) { + ValueEval result = invokeLen(text); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); + } + + public void testBasic() { + + confirmLen(new StringEval("galactic"), 8); + } + + /** + * Valid cases where text arg is not exactly a string + */ + public void testUnusualArgs() { + + // text (first) arg type is number, other args are strings with fractional digits + confirmLen(new NumberEval(123456), 6); + confirmLen(BoolEval.FALSE, 5); + confirmLen(BoolEval.TRUE, 4); + confirmLen(BlankEval.instance, 0); + } + + public void testErrors() { + confirmLen(ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestLookupFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestLookupFunctionsFromSpreadsheet.java new file mode 100644 index 0000000000..6054d08208 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestLookupFunctionsFromSpreadsheet.java @@ -0,0 +1,365 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.io.PrintStream; + +import junit.framework.Assert; +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.usermodel.CellValue; + +/** + * Tests lookup functions (VLOOKUP, HLOOKUP, LOOKUP, MATCH) as loaded from a test data spreadsheet.

+ * These tests have been separated from the common function and operator tests because the lookup + * functions have more complex test cases and test data setup. + * + * Tests for bug fixes and specific/tricky behaviour can be found in the corresponding test class + * (TestXxxx) of the target (Xxxx) implementor, where execution can be observed + * more easily. + * + * @author Josh Micich + */ +public final class TestLookupFunctionsFromSpreadsheet extends TestCase { + + private static final class Result { + public static final int SOME_EVALUATIONS_FAILED = -1; + public static final int ALL_EVALUATIONS_SUCCEEDED = +1; + public static final int NO_EVALUATIONS_FOUND = 0; + } + + /** + * This class defines constants for navigating around the test data spreadsheet used for these tests. + */ + private static final class SS { + + /** Name of the test spreadsheet (found in the standard test data folder) */ + public final static String FILENAME = "LookupFunctionsTestCaseData.xls"; + + /** Name of the first sheet in the spreadsheet (contains comments) */ + public final static String README_SHEET_NAME = "Read Me"; + + + /** Row (zero-based) in each sheet where the evaluation cases start. */ + public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5' + /** Index of the column that contains the function names */ + public static final int COLUMN_INDEX_MARKER = 0; // Column 'A' + public static final int COLUMN_INDEX_EVALUATION = 1; // Column 'B' + public static final int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C' + public static final int COLUMN_ROW_COMMENT = 3; // Column 'D' + + /** Used to indicate when there are no more test cases on the current sheet */ + public static final String TEST_CASES_END_MARKER = ""; + /** Used to indicate that the test on the current row should be ignored */ + public static final String SKIP_CURRENT_TEST_CASE_MARKER = ""; + + } + + // Note - multiple failures are aggregated before ending. + // If one or more functions fail, a single AssertionFailedError is thrown at the end + private int _sheetFailureCount; + private int _sheetSuccessCount; + private int _evaluationFailureCount; + private int _evaluationSuccessCount; + + + + private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) { + if (expected == null) { + throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); + } + if(actual == null) { + throw new AssertionFailedError(msg + " - actual value was null"); + } + if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) { + confirmErrorResult(msg, expected.getErrorCellValue(), actual); + return; + } + if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) { + throw unexpectedError(msg, expected, actual.getErrorValue()); + } + if(actual.getCellType() != expected.getCellType()) { + throw wrongTypeError(msg, expected, actual); + } + + + switch (expected.getCellType()) { + case HSSFCell.CELL_TYPE_BOOLEAN: + assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue()); + break; + case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation + throw new IllegalStateException("Cannot expect formula as result of formula evaluation: " + msg); + case HSSFCell.CELL_TYPE_NUMERIC: + assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0); + break; + case HSSFCell.CELL_TYPE_STRING: + assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue()); + break; + } + } + + + private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) { + return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was " + + actualValue.formatAsString() + + " but the expected result was " + + formatValue(expectedCell) + ); + } + private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) { + return new AssertionFailedError(msgPrefix + " Error code (" + + ErrorEval.getText(actualErrorCode) + + ") was evaluated, but the expected result was " + + formatValue(expected) + ); + } + + + private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) { + if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) { + throw new AssertionFailedError(msgPrefix + " Expected cell error (" + + ErrorEval.getText(expectedErrorCode) + ") but actual value was " + + actual.formatAsString()); + } + if(expectedErrorCode != actual.getErrorValue()) { + throw new AssertionFailedError(msgPrefix + " Expected cell error code (" + + ErrorEval.getText(expectedErrorCode) + + ") but actual error code was (" + + ErrorEval.getText(actual.getErrorValue()) + + ")"); + } + } + + + private static String formatValue(HSSFCell expecedCell) { + switch (expecedCell.getCellType()) { + case HSSFCell.CELL_TYPE_BLANK: return ""; + case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue()); + case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue()); + case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString(); + } + throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")"); + } + + + protected void setUp() { + _sheetFailureCount = 0; + _sheetSuccessCount = 0; + _evaluationFailureCount = 0; + _evaluationSuccessCount = 0; + } + + public void testFunctionsFromTestSpreadsheet() { + HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME); + + confirmReadMeSheet(workbook); + int nSheets = workbook.getNumberOfSheets(); + for(int i=1; i< nSheets; i++) { + int sheetResult = processTestSheet(workbook, i, workbook.getSheetName(i)); + switch(sheetResult) { + case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break; + case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break; + } + } + + // confirm results + String successMsg = "There were " + + _sheetSuccessCount + " successful sheets(s) and " + + _evaluationSuccessCount + " function(s) without error"; + if(_sheetFailureCount > 0) { + String msg = _sheetFailureCount + " sheets(s) failed with " + + _evaluationFailureCount + " evaluation(s). " + successMsg; + throw new AssertionFailedError(msg); + } + if(false) { // normally no output for successful tests + System.out.println(getClass().getName() + ": " + successMsg); + } + } + + private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) { + HSSFSheet sheet = workbook.getSheetAt(sheetIndex); + HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook); + int maxRows = sheet.getLastRowNum()+1; + int result = Result.NO_EVALUATIONS_FOUND; // so far + + String currentGroupComment = null; + for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex= endIx) { + // something went wrong. just print the whole stack trace + e.printStackTrace(ps); + } + endIx -= 4; // skip 4 frames of reflection invocation + ps.println(e.toString()); + for(int i=startIx; inull if cell is missing, empty or blank + */ + private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) { + if(r == null) { + return null; + } + HSSFCell cell = r.getCell(colIndex); + if(cell == null) { + return null; + } + if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) { + return null; + } + if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) { + return cell.getRichStringCellValue().getString(); + } + + throw new RuntimeException("Bad cell type for '" + columnName + "' column: (" + + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")"); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java new file mode 100644 index 0000000000..f9fdab6a79 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java @@ -0,0 +1,205 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Test cases for MATCH() + * + * @author Josh Micich + */ +public final class TestMatch extends TestCase { + /** less than or equal to */ + private static final NumberEval MATCH_LARGEST_LTE = new NumberEval(1); + private static final NumberEval MATCH_EXACT = new NumberEval(0); + /** greater than or equal to */ + private static final NumberEval MATCH_SMALLEST_GTE = new NumberEval(-1); + + + private static ValueEval invokeMatch(ValueEval lookup_value, ValueEval lookup_array, ValueEval match_type) { + ValueEval[] args = { lookup_value, lookup_array, match_type, }; + return new Match().evaluate(args, -1, (short)-1); + } + private static void confirmInt(int expected, ValueEval actualEval) { + if(!(actualEval instanceof NumericValueEval)) { + fail("Expected numeric result"); + } + NumericValueEval nve = (NumericValueEval)actualEval; + assertEquals(expected, nve.getNumberValue(), 0); + } + + public void testSimpleNumber() { + + ValueEval[] values = { + new NumberEval(4), + new NumberEval(5), + new NumberEval(10), + new NumberEval(10), + new NumberEval(25), + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); + + confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE)); + confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT)); + confirmInt(4, invokeMatch(new NumberEval(10), ae, MATCH_LARGEST_LTE)); + confirmInt(3, invokeMatch(new NumberEval(10), ae, MATCH_EXACT)); + confirmInt(4, invokeMatch(new NumberEval(20), ae, MATCH_LARGEST_LTE)); + assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT)); + } + + public void testReversedNumber() { + + ValueEval[] values = { + new NumberEval(25), + new NumberEval(10), + new NumberEval(10), + new NumberEval(10), + new NumberEval(4), + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); + + confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE)); + confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT)); + confirmInt(4, invokeMatch(new NumberEval(9), ae, MATCH_SMALLEST_GTE)); + confirmInt(1, invokeMatch(new NumberEval(20), ae, MATCH_SMALLEST_GTE)); + assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT)); + assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(26), ae, MATCH_SMALLEST_GTE)); + } + + public void testSimpleString() { + + ValueEval[] values = { + new StringEval("Albert"), + new StringEval("Charles"), + new StringEval("Ed"), + new StringEval("Greg"), + new StringEval("Ian"), + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); + + // Note String comparisons are case insensitive + confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE)); + confirmInt(3, invokeMatch(new StringEval("eD"), ae, MATCH_LARGEST_LTE)); + confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_EXACT)); + confirmInt(3, invokeMatch(new StringEval("ed"), ae, MATCH_EXACT)); + confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE)); + assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT)); + } + + public void testSimpleBoolean() { + + ValueEval[] values = { + BoolEval.FALSE, + BoolEval.FALSE, + BoolEval.TRUE, + BoolEval.TRUE, + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A4", values); + + // Note String comparisons are case insensitive + confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE)); + confirmInt(1, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT)); + confirmInt(4, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE)); + confirmInt(3, invokeMatch(BoolEval.TRUE, ae, MATCH_EXACT)); + } + + public void testHeterogeneous() { + + ValueEval[] values = { + new NumberEval(4), + BoolEval.FALSE, + new NumberEval(5), + new StringEval("Albert"), + BoolEval.FALSE, + BoolEval.TRUE, + new NumberEval(10), + new StringEval("Charles"), + new StringEval("Ed"), + new NumberEval(10), + new NumberEval(25), + BoolEval.TRUE, + new StringEval("Ed"), + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A13", values); + + assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE)); + + confirmInt(5, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE)); + confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT)); + confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE)); + confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT)); + + confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT)); + + confirmInt(4, invokeMatch(new StringEval("Ben"), ae, MATCH_LARGEST_LTE)); + + confirmInt(13, invokeMatch(new StringEval("ED"), ae, MATCH_LARGEST_LTE)); + confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT)); + + confirmInt(13, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE)); + assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT)); + + confirmInt(11, invokeMatch(new NumberEval(30), ae, MATCH_LARGEST_LTE)); + confirmInt(12, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE)); + } + + + /** + * Ensures that the match_type argument can be an AreaEval.
+ * Bugzilla 44421 + */ + public void testMatchArgTypeArea() { + + ValueEval[] values = { + new NumberEval(4), + new NumberEval(5), + new NumberEval(10), + new NumberEval(10), + new NumberEval(25), + }; + + AreaEval ae = EvalFactory.createAreaEval("A1:A5", values); + + AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, }); + + try { + confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE)); + } catch (RuntimeException e) { + if(e.getMessage().startsWith("Unexpected match_type type")) { + // identified bug 44421 + fail(e.getMessage()); + } + // some other error ?? + throw e; + } + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMathX.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMathX.java new file mode 100644 index 0000000000..dd6974b35d --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMathX.java @@ -0,0 +1,877 @@ +/* +* 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. +*/ +/* + * Created on May 23, 2005 + * + */ +package org.apache.poi.ss.formula.functions; + +import org.apache.poi.ss.formula.functions.XYNumericFunction.Accumulator; + + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public class TestMathX extends AbstractNumericTestCase { + + public void testAcosh() { + double d = 0; + + d = MathX.acosh(0); + assertTrue("Acosh 0 is NaN", Double.isNaN(d)); + + d = MathX.acosh(1); + assertEquals("Acosh 1 ", 0, d); + + d = MathX.acosh(-1); + assertTrue("Acosh -1 is NaN", Double.isNaN(d)); + + d = MathX.acosh(100); + assertEquals("Acosh 100 ", 5.298292366d, d); + + d = MathX.acosh(101.001); + assertEquals("Acosh 101.001 ", 5.308253091d, d); + + d = MathX.acosh(200000); + assertEquals("Acosh 200000 ", 12.89921983d, d); + + } + + public void testAsinh() { + double d = 0; + + d = MathX.asinh(0); + assertEquals("asinh 0", d, 0); + + d = MathX.asinh(1); + assertEquals("asinh 1 ", 0.881373587, d); + + d = MathX.asinh(-1); + assertEquals("asinh -1 ", -0.881373587, d); + + d = MathX.asinh(-100); + assertEquals("asinh -100 ", -5.298342366, d); + + d = MathX.asinh(100); + assertEquals("asinh 100 ", 5.298342366, d); + + d = MathX.asinh(200000); + assertEquals("asinh 200000", 12.899219826096400, d); + + d = MathX.asinh(-200000); + assertEquals("asinh -200000 ", -12.899223853137, d); + + } + + public void testAtanh() { + double d = 0; + d = MathX.atanh(0); + assertEquals("atanh 0", d, 0); + + d = MathX.atanh(1); + assertEquals("atanh 1 ", Double.POSITIVE_INFINITY, d); + + d = MathX.atanh(-1); + assertEquals("atanh -1 ", Double.NEGATIVE_INFINITY, d); + + d = MathX.atanh(-100); + assertEquals("atanh -100 ", Double.NaN, d); + + d = MathX.atanh(100); + assertEquals("atanh 100 ", Double.NaN, d); + + d = MathX.atanh(200000); + assertEquals("atanh 200000", Double.NaN, d); + + d = MathX.atanh(-200000); + assertEquals("atanh -200000 ", Double.NaN, d); + + d = MathX.atanh(0.1); + assertEquals("atanh 0.1", 0.100335348, d); + + d = MathX.atanh(-0.1); + assertEquals("atanh -0.1 ", -0.100335348, d); + + } + + public void testCosh() { + double d = 0; + d = MathX.cosh(0); + assertEquals("cosh 0", 1, d); + + d = MathX.cosh(1); + assertEquals("cosh 1 ", 1.543080635, d); + + d = MathX.cosh(-1); + assertEquals("cosh -1 ", 1.543080635, d); + + d = MathX.cosh(-100); + assertEquals("cosh -100 ", 1.344058570908070E+43, d); + + d = MathX.cosh(100); + assertEquals("cosh 100 ", 1.344058570908070E+43, d); + + d = MathX.cosh(15); + assertEquals("cosh 15", 1634508.686, d); + + d = MathX.cosh(-15); + assertEquals("cosh -15 ", 1634508.686, d); + + d = MathX.cosh(0.1); + assertEquals("cosh 0.1", 1.005004168, d); + + d = MathX.cosh(-0.1); + assertEquals("cosh -0.1 ", 1.005004168, d); + + } + + public void testTanh() { + double d = 0; + d = MathX.tanh(0); + assertEquals("tanh 0", 0, d); + + d = MathX.tanh(1); + assertEquals("tanh 1 ", 0.761594156, d); + + d = MathX.tanh(-1); + assertEquals("tanh -1 ", -0.761594156, d); + + d = MathX.tanh(-100); + assertEquals("tanh -100 ", -1, d); + + d = MathX.tanh(100); + assertEquals("tanh 100 ", 1, d); + + d = MathX.tanh(15); + assertEquals("tanh 15", 1, d); + + d = MathX.tanh(-15); + assertEquals("tanh -15 ", -1, d); + + d = MathX.tanh(0.1); + assertEquals("tanh 0.1", 0.099667995, d); + + d = MathX.tanh(-0.1); + assertEquals("tanh -0.1 ", -0.099667995, d); + + } + + public void testMax() { + double[] d = new double[100]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + double m = MathX.max(d); + assertEquals("Max ", 20.1, m); + + d = new double[1000]; + m = MathX.max(d); + assertEquals("Max ", 0, m); + + d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; + d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; + d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; + d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; + d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; + m = MathX.max(d); + assertEquals("Max ", 20.1, m); + + d = new double[20]; + d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; + d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; + d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; + d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; + d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; + m = MathX.max(d); + assertEquals("Max ", -1.1, m); + + } + + public void testMin() { + double[] d = new double[100]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + double m = MathX.min(d); + assertEquals("Min ", 0, m); + + d = new double[20]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + m = MathX.min(d); + assertEquals("Min ", 1.1, m); + + d = new double[1000]; + m = MathX.min(d); + assertEquals("Min ", 0, m); + + d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; + d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; + d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; + d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; + d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; + m = MathX.min(d); + assertEquals("Min ", -19.1, m); + + d = new double[20]; + d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; + d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; + d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; + d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; + d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; + m = MathX.min(d); + assertEquals("Min ", -20.1, m); + } + + public void testProduct() { + double[] d = new double[100]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + double m = MathX.min(d); + assertEquals("Min ", 0, m); + + d = new double[20]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + m = MathX.min(d); + assertEquals("Min ", 1.1, m); + + d = new double[1000]; + m = MathX.min(d); + assertEquals("Min ", 0, m); + + d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; + d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; + d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; + d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; + d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; + m = MathX.min(d); + assertEquals("Min ", -19.1, m); + + d = new double[20]; + d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; + d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; + d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; + d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; + d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; + m = MathX.min(d); + assertEquals("Min ", -20.1, m); + } + + public void testMod() { + + //example from Excel help + assertEquals(1.0, MathX.mod(3, 2)); + assertEquals(1.0, MathX.mod(-3, 2)); + assertEquals(-1.0, MathX.mod(3, -2)); + assertEquals(-1.0, MathX.mod(-3, -2)); + + assertEquals((double) 1.4, MathX.mod(3.4, 2)); + assertEquals((double) -1.4, MathX.mod(-3.4, -2)); + assertEquals((double) 0.6000000000000001, MathX.mod(-3.4, 2.0));// should actually be 0.6 + assertEquals((double) -0.6000000000000001, MathX.mod(3.4, -2.0));// should actually be -0.6 + + // Bugzilla 50033 + assertEquals(1.0, MathX.mod(13, 12)); + } + + public void testNChooseK() { + int n=100; + int k=50; + double d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 1.00891344545564E29, d); + + n = -1; k = 1; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", Double.NaN, d); + + n = 1; k = -1; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", Double.NaN, d); + + n = 0; k = 1; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", Double.NaN, d); + + n = 1; k = 0; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 1, d); + + n = 10; k = 9; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 10, d); + + n = 10; k = 10; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 1, d); + + n = 10; k = 1; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 10, d); + + n = 1000; k = 1; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 1000, d); // awesome ;) + + n = 1000; k = 2; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 499500, d); // awesome ;) + + n = 13; k = 7; + d = MathX.nChooseK(n, k); + assertEquals("NChooseK ", 1716, d); + + } + + public void testSign() { + final short minus = -1; + final short zero = 0; + final short plus = 1; + double d = 0; + + + assertEquals("Sign ", minus, MathX.sign(minus)); + assertEquals("Sign ", plus, MathX.sign(plus)); + assertEquals("Sign ", zero, MathX.sign(zero)); + + d = 0; + assertEquals("Sign ", zero, MathX.sign(d)); + + d = -1.000001; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = -.000001; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = -1E-200; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = Double.NEGATIVE_INFINITY; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = -200.11; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = -2000000000000.11; + assertEquals("Sign ", minus, MathX.sign(d)); + + d = 1.000001; + assertEquals("Sign ", plus, MathX.sign(d)); + + d = .000001; + assertEquals("Sign ", plus, MathX.sign(d)); + + d = 1E-200; + assertEquals("Sign ", plus, MathX.sign(d)); + + d = Double.POSITIVE_INFINITY; + assertEquals("Sign ", plus, MathX.sign(d)); + + d = 200.11; + assertEquals("Sign ", plus, MathX.sign(d)); + + d = 2000000000000.11; + assertEquals("Sign ", plus, MathX.sign(d)); + + } + + public void testSinh() { + double d = 0; + d = MathX.sinh(0); + assertEquals("sinh 0", 0, d); + + d = MathX.sinh(1); + assertEquals("sinh 1 ", 1.175201194, d); + + d = MathX.sinh(-1); + assertEquals("sinh -1 ", -1.175201194, d); + + d = MathX.sinh(-100); + assertEquals("sinh -100 ", -1.344058570908070E+43, d); + + d = MathX.sinh(100); + assertEquals("sinh 100 ", 1.344058570908070E+43, d); + + d = MathX.sinh(15); + assertEquals("sinh 15", 1634508.686, d); + + d = MathX.sinh(-15); + assertEquals("sinh -15 ", -1634508.686, d); + + d = MathX.sinh(0.1); + assertEquals("sinh 0.1", 0.10016675, d); + + d = MathX.sinh(-0.1); + assertEquals("sinh -0.1 ", -0.10016675, d); + + } + + public void testSum() { + double[] d = new double[100]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + double s = MathX.sum(d); + assertEquals("Sum ", 212, s); + + d = new double[1000]; + s = MathX.sum(d); + assertEquals("Sum ", 0, s); + + d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; + d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; + d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; + d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; + d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; + s = MathX.sum(d); + assertEquals("Sum ", 10, s); + + d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; + d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; + d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; + d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; + d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; + s = MathX.sum(d); + assertEquals("Sum ", -212, s); + + } + + public void testSumsq() { + double[] d = new double[100]; + d[0] = 1.1; d[1] = 2.1; d[2] = 3.1; d[3] = 4.1; + d[4] = 5.1; d[5] = 6.1; d[6] = 7.1; d[7] = 8.1; + d[8] = 9.1; d[9] = 10.1; d[10] = 11.1; d[11] = 12.1; + d[12] = 13.1; d[13] = 14.1; d[14] = 15.1; d[15] = 16.1; + d[16] = 17.1; d[17] = 18.1; d[18] = 19.1; d[19] = 20.1; + + double s = MathX.sumsq(d); + assertEquals("Sumsq ", 2912.2, s); + + d = new double[1000]; + s = MathX.sumsq(d); + assertEquals("Sumsq ", 0, s); + + d[0] = -1.1; d[1] = 2.1; d[2] = -3.1; d[3] = 4.1; + d[4] = -5.1; d[5] = 6.1; d[6] = -7.1; d[7] = 8.1; + d[8] = -9.1; d[9] = 10.1; d[10] = -11.1; d[11] = 12.1; + d[12] = -13.1; d[13] = 14.1; d[14] = -15.1; d[15] = 16.1; + d[16] = -17.1; d[17] = 18.1; d[18] = -19.1; d[19] = 20.1; + s = MathX.sumsq(d); + assertEquals("Sumsq ", 2912.2, s); + + d[0] = -1.1; d[1] = -2.1; d[2] = -3.1; d[3] = -4.1; + d[4] = -5.1; d[5] = -6.1; d[6] = -7.1; d[7] = -8.1; + d[8] = -9.1; d[9] = -10.1; d[10] = -11.1; d[11] = -12.1; + d[12] = -13.1; d[13] = -14.1; d[14] = -15.1; d[15] = -16.1; + d[16] = -17.1; d[17] = -18.1; d[18] = -19.1; d[19] = -20.1; + s = MathX.sumsq(d); + assertEquals("Sumsq ", 2912.2, s); + } + + public void testFactorial() { + int n = 0; + double s = 0; + + n = 0; + s = MathX.factorial(n); + assertEquals("Factorial ", 1, s); + + n = 1; + s = MathX.factorial(n); + assertEquals("Factorial ", 1, s); + + n = 10; + s = MathX.factorial(n); + assertEquals("Factorial ", 3628800, s); + + n = 99; + s = MathX.factorial(n); + assertEquals("Factorial ", 9.33262154439E+155, s); + + n = -1; + s = MathX.factorial(n); + assertEquals("Factorial ", Double.NaN, s); + + n = Integer.MAX_VALUE; + s = MathX.factorial(n); + assertEquals("Factorial ", Double.POSITIVE_INFINITY, s); + } + + public void testSumx2my2() { + double[] xarr = null; + double[] yarr = null; + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumx2my2(xarr, yarr, 100); + + xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumx2my2(xarr, yarr, 100); + + xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumx2my2(xarr, yarr, -100); + + xarr = new double[]{10}; + yarr = new double[]{9}; + confirmSumx2my2(xarr, yarr, 19); + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumx2my2(xarr, yarr, 0); + } + + public void testSumx2py2() { + double[] xarr = null; + double[] yarr = null; + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumx2py2(xarr, yarr, 670); + + xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumx2py2(xarr, yarr, 670); + + xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumx2py2(xarr, yarr, 670); + + xarr = new double[]{10}; + yarr = new double[]{9}; + confirmSumx2py2(xarr, yarr, 181); + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumx2py2(xarr, yarr, 770); + } + + public void testSumxmy2() { + double[] xarr = null; + double[] yarr = null; + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumxmy2(xarr, yarr, 10); + + xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; + yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + confirmSumxmy2(xarr, yarr, 1330); + + xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumxmy2(xarr, yarr, 10); + + xarr = new double[]{10}; + yarr = new double[]{9}; + confirmSumxmy2(xarr, yarr, 1); + + xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + confirmSumxmy2(xarr, yarr, 0); + } + + private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) { + confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult); + } + private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) { + confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult); + } + private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) { + confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult); + } + + private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr, + double expectedResult) { + double result = 0.0; + for (int i = 0; i < xarr.length; i++) { + result += acc.accumulate(xarr[i], yarr[i]); + } + assertEquals(expectedResult, result, 0.0); + } + + public void testRound() { + double d = 0; + int p = 0; + + d = 0; p = 0; + assertEquals("round ", 0, MathX.round(d, p)); + + d = 10; p = 0; + assertEquals("round ", 10, MathX.round(d, p)); + + d = 123.23; p = 0; + assertEquals("round ", 123, MathX.round(d, p)); + + d = -123.23; p = 0; + assertEquals("round ", -123, MathX.round(d, p)); + + d = 123.12; p = 2; + assertEquals("round ", 123.12, MathX.round(d, p)); + + d = 88.123459; p = 5; + assertEquals("round ", 88.12346, MathX.round(d, p)); + + d = 0; p = 2; + assertEquals("round ", 0, MathX.round(d, p)); + + d = 0; p = -1; + assertEquals("round ", 0, MathX.round(d, p)); + + d = 0.01; p = -1; + assertEquals("round ", 0, MathX.round(d, p)); + + d = 123.12; p = -2; + assertEquals("round ", 100, MathX.round(d, p)); + + d = 88.123459; p = -3; + assertEquals("round ", 0, MathX.round(d, p)); + + d = 49.00000001; p = -1; + assertEquals("round ", 50, MathX.round(d, p)); + + d = 149.999999; p = -2; + assertEquals("round ", 100, MathX.round(d, p)); + + d = 150.0; p = -2; + assertEquals("round ", 200, MathX.round(d, p)); + } + + public void testRoundDown() { + double d = 0; + int p = 0; + + d = 0; p = 0; + assertEquals("roundDown ", 0, MathX.roundDown(d, p)); + + d = 10; p = 0; + assertEquals("roundDown ", 10, MathX.roundDown(d, p)); + + d = 123.99; p = 0; + assertEquals("roundDown ", 123, MathX.roundDown(d, p)); + + d = -123.99; p = 0; + assertEquals("roundDown ", -123, MathX.roundDown(d, p)); + + d = 123.99; p = 2; + assertEquals("roundDown ", 123.99, MathX.roundDown(d, p)); + + d = 88.123459; p = 5; + assertEquals("roundDown ", 88.12345, MathX.roundDown(d, p)); + + d = 0; p = 2; + assertEquals("roundDown ", 0, MathX.roundDown(d, p)); + + d = 0; p = -1; + assertEquals("roundDown ", 0, MathX.roundDown(d, p)); + + d = 0.01; p = -1; + assertEquals("roundDown ", 0, MathX.roundDown(d, p)); + + d = 199.12; p = -2; + assertEquals("roundDown ", 100, MathX.roundDown(d, p)); + + d = 88.123459; p = -3; + assertEquals("roundDown ", 0, MathX.roundDown(d, p)); + + d = 99.00000001; p = -1; + assertEquals("roundDown ", 90, MathX.roundDown(d, p)); + + d = 100.00001; p = -2; + assertEquals("roundDown ", 100, MathX.roundDown(d, p)); + + d = 150.0; p = -2; + assertEquals("roundDown ", 100, MathX.roundDown(d, p)); + } + + public void testRoundUp() { + double d = 0; + int p = 0; + + d = 0; p = 0; + assertEquals("roundUp ", 0, MathX.roundUp(d, p)); + + d = 10; p = 0; + assertEquals("roundUp ", 10, MathX.roundUp(d, p)); + + d = 123.23; p = 0; + assertEquals("roundUp ", 124, MathX.roundUp(d, p)); + + d = -123.23; p = 0; + assertEquals("roundUp ", -124, MathX.roundUp(d, p)); + + d = 123.12; p = 2; + assertEquals("roundUp ", 123.12, MathX.roundUp(d, p)); + + d = 88.123459; p = 5; + assertEquals("roundUp ", 88.12346, MathX.roundUp(d, p)); + + d = 0; p = 2; + assertEquals("roundUp ", 0, MathX.roundUp(d, p)); + + d = 0; p = -1; + assertEquals("roundUp ", 0, MathX.roundUp(d, p)); + + d = 0.01; p = -1; + assertEquals("roundUp ", 10, MathX.roundUp(d, p)); + + d = 123.12; p = -2; + assertEquals("roundUp ", 200, MathX.roundUp(d, p)); + + d = 88.123459; p = -3; + assertEquals("roundUp ", 1000, MathX.roundUp(d, p)); + + d = 49.00000001; p = -1; + assertEquals("roundUp ", 50, MathX.roundUp(d, p)); + + d = 149.999999; p = -2; + assertEquals("roundUp ", 200, MathX.roundUp(d, p)); + + d = 150.0; p = -2; + assertEquals("roundUp ", 200, MathX.roundUp(d, p)); + } + + public void testCeiling() { + double d = 0; + double s = 0; + + d = 0; s = 0; + assertEquals("ceiling ", 0, MathX.ceiling(d, s)); + + d = 1; s = 0; + assertEquals("ceiling ", 0, MathX.ceiling(d, s)); + + d = 0; s = 1; + assertEquals("ceiling ", 0, MathX.ceiling(d, s)); + + d = -1; s = 0; + assertEquals("ceiling ", 0, MathX.ceiling(d, s)); + + d = 0; s = -1; + assertEquals("ceiling ", 0, MathX.ceiling(d, s)); + + d = 10; s = 1.11; + assertEquals("ceiling ", 11.1, MathX.ceiling(d, s)); + + d = 11.12333; s = 0.03499; + assertEquals("ceiling ", 11.12682, MathX.ceiling(d, s)); + + d = -11.12333; s = 0.03499; + assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s)); + + d = 11.12333; s = -0.03499; + assertEquals("ceiling ", Double.NaN, MathX.ceiling(d, s)); + + d = -11.12333; s = -0.03499; + assertEquals("ceiling ", -11.12682, MathX.ceiling(d, s)); + + d = 100; s = 0.001; + assertEquals("ceiling ", 100, MathX.ceiling(d, s)); + + d = -0.001; s = -9.99; + assertEquals("ceiling ", -9.99, MathX.ceiling(d, s)); + + d = 4.42; s = 0.05; + assertEquals("ceiling ", 4.45, MathX.ceiling(d, s)); + + d = 0.05; s = 4.42; + assertEquals("ceiling ", 4.42, MathX.ceiling(d, s)); + + d = 0.6666; s = 3.33; + assertEquals("ceiling ", 3.33, MathX.ceiling(d, s)); + + d = 2d/3; s = 3.33; + assertEquals("ceiling ", 3.33, MathX.ceiling(d, s)); + } + + public void testFloor() { + double d = 0; + double s = 0; + + d = 0; s = 0; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = 1; s = 0; + assertEquals("floor ", Double.NaN, MathX.floor(d, s)); + + d = 0; s = 1; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = -1; s = 0; + assertEquals("floor ", Double.NaN, MathX.floor(d, s)); + + d = 0; s = -1; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = 10; s = 1.11; + assertEquals("floor ", 9.99, MathX.floor(d, s)); + + d = 11.12333; s = 0.03499; + assertEquals("floor ", 11.09183, MathX.floor(d, s)); + + d = -11.12333; s = 0.03499; + assertEquals("floor ", Double.NaN, MathX.floor(d, s)); + + d = 11.12333; s = -0.03499; + assertEquals("floor ", Double.NaN, MathX.floor(d, s)); + + d = -11.12333; s = -0.03499; + assertEquals("floor ", -11.09183, MathX.floor(d, s)); + + d = 100; s = 0.001; + assertEquals("floor ", 100, MathX.floor(d, s)); + + d = -0.001; s = -9.99; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = 4.42; s = 0.05; + assertEquals("floor ", 4.4, MathX.floor(d, s)); + + d = 0.05; s = 4.42; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = 0.6666; s = 3.33; + assertEquals("floor ", 0, MathX.floor(d, s)); + + d = 2d/3; s = 3.33; + assertEquals("floor ", 0, MathX.floor(d, s)); + } + +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMid.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMid.java new file mode 100644 index 0000000000..7c19d44a61 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMid.java @@ -0,0 +1,110 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.RefEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; +/** + * Tests for Excel function MID() + * + * @author Josh Micich + */ +public final class TestMid extends TestCase { + + + private static ValueEval invokeMid(ValueEval text, ValueEval startPos, ValueEval numChars) { + ValueEval[] args = new ValueEval[] { text, startPos, numChars, }; + return TextFunction.MID.evaluate(args, -1, (short)-1); + } + + private void confirmMid(ValueEval text, ValueEval startPos, ValueEval numChars, String expected) { + ValueEval result = invokeMid(text, startPos, numChars); + assertEquals(StringEval.class, result.getClass()); + assertEquals(expected, ((StringEval)result).getStringValue()); + } + + private void confirmMid(ValueEval text, ValueEval startPos, ValueEval numChars, ErrorEval expectedError) { + ValueEval result = invokeMid(text, startPos, numChars); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); + } + + public void testBasic() { + + confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(4), "lact"); + } + + /** + * Valid cases where args are not precisely (string, int, int) but can be resolved OK. + */ + public void testUnusualArgs() { + // startPos with fractional digits + confirmMid(new StringEval("galactic"), new NumberEval(3.1), new NumberEval(4), "lact"); + + // string startPos + confirmMid(new StringEval("galactic"), new StringEval("3"), new NumberEval(4), "lact"); + + // text (first) arg type is number, other args are strings with fractional digits + confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34"); + + // startPos is 1x1 area ref, numChars is cell ref + AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } ); + RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3)); + confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala"); + + confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.instance, ""); + + confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, ""); + confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l"); + confirmMid(BlankEval.instance, new NumberEval(3), BoolEval.TRUE, ""); + + } + + /** + * Extreme values for startPos and numChars + */ + public void testExtremes() { + confirmMid(new StringEval("galactic"), new NumberEval(4), new NumberEval(400), "actic"); + + confirmMid(new StringEval("galactic"), new NumberEval(30), new NumberEval(4), ""); + confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(0), ""); + } + + /** + * All sorts of ways to make MID return defined errors. + */ + public void testErrors() { + confirmMid(ErrorEval.NAME_INVALID, new NumberEval(3), new NumberEval(4), ErrorEval.NAME_INVALID); + confirmMid(new StringEval("galactic"), ErrorEval.NAME_INVALID, new NumberEval(4), ErrorEval.NAME_INVALID); + confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); + confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO); + + confirmMid(new StringEval("galactic"), BlankEval.instance, new NumberEval(3.1), ErrorEval.VALUE_INVALID); + + confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID); + confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestNper.java b/src/testcases/org/apache/poi/ss/formula/functions/TestNper.java new file mode 100644 index 0000000000..4754ec02af --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestNper.java @@ -0,0 +1,65 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFErrorConstants; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * Tests for {@link FinanceFunction#NPER} + * + * @author Josh Micich + */ +public final class TestNper extends TestCase { + public void testSimpleEvaluate() { + + ValueEval[] args = { + new NumberEval(0.05), + new NumberEval(250), + new NumberEval(-1000), + }; + ValueEval result = FinanceFunction.NPER.evaluate(args, 0, (short)0); + + assertEquals(NumberEval.class, result.getClass()); + assertEquals(4.57353557, ((NumberEval)result).getNumberValue(), 0.00000001); + } + + public void testEvaluate_bug_45732() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("Sheet1"); + HSSFCell cell = sheet.createRow(0).createCell(0); + + cell.setCellFormula("NPER(12,4500,100000,100000)"); + cell.setCellValue(15.0); + assertEquals("NPER(12,4500,100000,100000)", cell.getCellFormula()); + assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType()); + assertEquals(15.0, cell.getNumericCellValue(), 0.0); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + fe.evaluateFormulaCell(cell); + assertEquals(HSSFCell.CELL_TYPE_ERROR, cell.getCachedFormulaResultType()); + assertEquals(HSSFErrorConstants.ERROR_NUM, cell.getErrorCellValue()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestOffset.java b/src/testcases/org/apache/poi/ss/formula/functions/TestOffset.java new file mode 100644 index 0000000000..24d347270a --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestOffset.java @@ -0,0 +1,99 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.EvaluationException; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.functions.Offset.LinearOffsetRange; + +/** + * Tests for OFFSET function implementation + * + * @author Josh Micich + */ +public final class TestOffset extends TestCase { + + private static void confirmDoubleConvert(double doubleVal, int expected) { + try { + assertEquals(expected, Offset.evaluateIntArg(new NumberEval(doubleVal), -1, -1)); + } catch (EvaluationException e) { + throw new AssertionFailedError("Unexpected error '" + e.getErrorEval().toString() + "'."); + } + } + /** + * Excel's double to int conversion (for function 'OFFSET()') behaves more like Math.floor(). + * Note - negative values are not symmetrical + * Fractional values are silently truncated. + * Truncation is toward negative infinity. + */ + public void testDoubleConversion() { + + confirmDoubleConvert(100.09, 100); + confirmDoubleConvert(100.01, 100); + confirmDoubleConvert(100.00, 100); + confirmDoubleConvert(99.99, 99); + + confirmDoubleConvert(+2.01, +2); + confirmDoubleConvert(+2.00, +2); + confirmDoubleConvert(+1.99, +1); + confirmDoubleConvert(+1.01, +1); + confirmDoubleConvert(+1.00, +1); + confirmDoubleConvert(+0.99, 0); + confirmDoubleConvert(+0.01, 0); + confirmDoubleConvert( 0.00, 0); + confirmDoubleConvert(-0.01, -1); + confirmDoubleConvert(-0.99, -1); + confirmDoubleConvert(-1.00, -1); + confirmDoubleConvert(-1.01, -2); + confirmDoubleConvert(-1.99, -2); + confirmDoubleConvert(-2.00, -2); + confirmDoubleConvert(-2.01, -3); + } + + public void testLinearOffsetRange() { + LinearOffsetRange lor; + + lor = new LinearOffsetRange(3, 2); + assertEquals(3, lor.getFirstIndex()); + assertEquals(4, lor.getLastIndex()); + lor = lor.normaliseAndTranslate(0); // expected no change + assertEquals(3, lor.getFirstIndex()); + assertEquals(4, lor.getLastIndex()); + + lor = lor.normaliseAndTranslate(5); + assertEquals(8, lor.getFirstIndex()); + assertEquals(9, lor.getLastIndex()); + + // negative length + + lor = new LinearOffsetRange(6, -4).normaliseAndTranslate(0); + assertEquals(3, lor.getFirstIndex()); + assertEquals(6, lor.getLastIndex()); + + + // bounds checking + lor = new LinearOffsetRange(0, 100); + assertFalse(lor.isOutOfBounds(0, 16383)); + lor = lor.normaliseAndTranslate(16300); + assertTrue(lor.isOutOfBounds(0, 16383)); + assertFalse(lor.isOutOfBounds(0, 65535)); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestPmt.java b/src/testcases/org/apache/poi/ss/formula/functions/TestPmt.java new file mode 100644 index 0000000000..77618805aa --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestPmt.java @@ -0,0 +1,86 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.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 ValueEval invoke(ValueEval[] args) { + return FinanceFunction.PMT.evaluate(args, -1, (short)-1); + } + /** + * Invocation when not expecting an error result + */ + private static NumberEval invokeNormal(ValueEval[] args) { + ValueEval 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) { + ValueEval[] 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() { + + ValueEval[] args = { + new NumberEval(0.005), + new NumberEval(24), + new NumberEval(1000), + }; + ValueEval 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/testcases/org/apache/poi/ss/formula/functions/TestPoisson.java b/src/testcases/org/apache/poi/ss/formula/functions/TestPoisson.java new file mode 100644 index 0000000000..e18d66ec6b --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestPoisson.java @@ -0,0 +1,111 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Tests for Excel function POISSON(x,mean,cumulative) + * @author Kalpesh Parmar + */ +public class TestPoisson extends TestCase { + + private static final double DELTA = 1E-15; + + private static ValueEval invokePoisson(double x, double mean, boolean cumulative) + { + + ValueEval[] valueEvals = new ValueEval[3]; + valueEvals[0] = new NumberEval(x); + valueEvals[1] = new NumberEval(mean); + valueEvals[2] = BoolEval.valueOf(cumulative); + + return NumericFunction.POISSON.evaluate(valueEvals,-1,-1); + } + + public void testCumulativeProbability() + { + double x = 1; + double mean = 0.2; + double result = 0.9824769036935787; // known result + + NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); + + assertEquals(myResult.getNumberValue(), result, DELTA); + } + + public void testNonCumulativeProbability() + { + double x = 0; + double mean = 0.2; + double result = 0.8187307530779818; // known result + + NumberEval myResult = (NumberEval)invokePoisson(x,mean,false); + + assertEquals(myResult.getNumberValue(), result, DELTA); + } + + public void testNegativeMean() + { + double x = 0; + double mean = -0.2; + + ErrorEval myResult = (ErrorEval)invokePoisson(x,mean,false); + + assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), myResult.getErrorCode()); + } + + public void testNegativeX() + { + double x = -1; + double mean = 0.2; + + ErrorEval myResult = (ErrorEval)invokePoisson(x,mean,false); + + assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), myResult.getErrorCode()); + } + + + + public void testXAsDecimalNumber() + { + double x = 1.1; + double mean = 0.2; + double result = 0.9824769036935787; // known result + + NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); + + assertEquals(myResult.getNumberValue(), result, DELTA); + } + + public void testXZeroMeanZero() + { + double x = 0; + double mean = 0; + double result = 1; // known result in excel + + NumberEval myResult = (NumberEval)invokePoisson(x,mean,true); + + assertEquals(myResult.getNumberValue(), result, DELTA); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestRoundFuncs.java b/src/testcases/org/apache/poi/ss/formula/functions/TestRoundFuncs.java new file mode 100644 index 0000000000..10166eee0d --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestRoundFuncs.java @@ -0,0 +1,50 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; + +/** + * Test cases for ROUND(), ROUNDUP(), ROUNDDOWN() + * + * @author Josh Micich + */ +public final class TestRoundFuncs extends TestCase { + private static final NumericFunction F = null; + public void testRounddownWithStringArg() { + + ValueEval strArg = new StringEval("abc"); + ValueEval[] args = { strArg, new NumberEval(2), }; + ValueEval result = F.ROUNDDOWN.evaluate(args, -1, (short)-1); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + + public void testRoundupWithStringArg() { + + ValueEval strArg = new StringEval("abc"); + ValueEval[] args = { strArg, new NumberEval(2), }; + ValueEval result = F.ROUNDUP.evaluate(args, -1, (short)-1); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestRowCol.java b/src/testcases/org/apache/poi/ss/formula/functions/TestRowCol.java new file mode 100644 index 0000000000..a27a63ee92 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestRowCol.java @@ -0,0 +1,97 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Tests for ROW(), ROWS(), COLUMN(), COLUMNS() + * + * @author Josh Micich + */ +public final class TestRowCol extends TestCase { + + public void testCol() { + Function target = new Column(); + { + ValueEval[] args = { EvalFactory.createRefEval("C5"), }; + double actual = NumericFunctionInvoker.invoke(target, args); + assertEquals(3, actual, 0D); + } + { + ValueEval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), }; + double actual = NumericFunctionInvoker.invoke(target, args); + assertEquals(5, actual, 0D); + } + } + + public void testRow() { + Function target = new RowFunc(); + { + ValueEval[] args = { EvalFactory.createRefEval("C5"), }; + double actual = NumericFunctionInvoker.invoke(target, args); + assertEquals(5, actual, 0D); + } + { + ValueEval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), }; + double actual = NumericFunctionInvoker.invoke(target, args); + assertEquals(2, actual, 0D); + } + } + + public void testColumns() { + + confirmColumnsFunc("A1:F1", 6, 1); + confirmColumnsFunc("A1:C2", 3, 2); + confirmColumnsFunc("A1:B3", 2, 3); + confirmColumnsFunc("A1:A6", 1, 6); + + ValueEval[] args = { EvalFactory.createRefEval("C5"), }; + double actual = NumericFunctionInvoker.invoke(new Columns(), args); + assertEquals(1, actual, 0D); + } + + public void testRows() { + + confirmRowsFunc("A1:F1", 6, 1); + confirmRowsFunc("A1:C2", 3, 2); + confirmRowsFunc("A1:B3", 2, 3); + confirmRowsFunc("A1:A6", 1, 6); + + ValueEval[] args = { EvalFactory.createRefEval("C5"), }; + double actual = NumericFunctionInvoker.invoke(new Rows(), args); + assertEquals(1, actual, 0D); + } + + private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) { + ValueEval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), }; + + double actual = NumericFunctionInvoker.invoke(new Rows(), args); + assertEquals(nRows, actual, 0D); + } + + + private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) { + ValueEval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), }; + + double actual = NumericFunctionInvoker.invoke(new Columns(), args); + assertEquals(nCols, actual, 0D); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestStatsLib.java b/src/testcases/org/apache/poi/ss/formula/functions/TestStatsLib.java new file mode 100644 index 0000000000..47ce2d5a91 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestStatsLib.java @@ -0,0 +1,271 @@ +/* +* 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. +*/ +/* + * Created on May 30, 2005 + * + */ +package org.apache.poi.ss.formula.functions; + +import junit.framework.AssertionFailedError; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.EvaluationException; + + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public class TestStatsLib extends AbstractNumericTestCase { + + public void testDevsq() { + double[] v = null; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + d = StatsLib.devsq(v); + x = 82.5; + assertEquals("devsq ", x, d); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + d = StatsLib.devsq(v); + x = 0; + assertEquals("devsq ", x, d); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + d = StatsLib.devsq(v); + x = 0; + assertEquals("devsq ", x, d); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + d = StatsLib.devsq(v); + x = 2.5; + assertEquals("devsq ", x, d); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + d = StatsLib.devsq(v); + x = 10953.7416965767; + assertEquals("devsq ", x, d); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.devsq(v); + x = 82.5; + assertEquals("devsq ", x, d); + } + + public void testKthLargest() { + double[] v = null; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + d = StatsLib.kthLargest(v, 3); + x = 8; + assertEquals("kthLargest ", x, d); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + d = StatsLib.kthLargest(v, 3); + x = 1; + assertEquals("kthLargest ", x, d); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + d = StatsLib.kthLargest(v, 3); + x = 0; + assertEquals("kthLargest ", x, d); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + d = StatsLib.kthLargest(v, 3); + x = 2; + assertEquals("kthLargest ", x, d); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + d = StatsLib.kthLargest(v, 3); + x = 5.37828; + assertEquals("kthLargest ", x, d); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.kthLargest(v, 3); + x = -3; + assertEquals("kthLargest ", x, d); + } + + public void testKthSmallest() { + } + + public void testAvedev() { + double[] v = null; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + d = StatsLib.avedev(v); + x = 2.5; + assertEquals("avedev ", x, d); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + d = StatsLib.avedev(v); + x = 0; + assertEquals("avedev ", x, d); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + d = StatsLib.avedev(v); + x = 0; + assertEquals("avedev ", x, d); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + d = StatsLib.avedev(v); + x = 0.5; + assertEquals("avedev ", x, d); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + d = StatsLib.avedev(v); + x = 36.42176053333; + assertEquals("avedev ", x, d); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.avedev(v); + x = 2.5; + assertEquals("avedev ", x, d); + } + + public void testMedian() { + double[] v = null; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + d = StatsLib.median(v); + x = 5.5; + assertEquals("median ", x, d); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + d = StatsLib.median(v); + x = 1; + assertEquals("median ", x, d); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + d = StatsLib.median(v); + x = 0; + assertEquals("median ", x, d); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + d = StatsLib.median(v); + x = 1.5; + assertEquals("median ", x, d); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + d = StatsLib.median(v); + x = 5.37828; + assertEquals("median ", x, d); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.median(v); + x = -5.5; + assertEquals("median ", x, d); + + v = new double[] {-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.median(v); + x = -6; + assertEquals("median ", x, d); + + v = new double[] {1,2,3,4,5,6,7,8,9}; + d = StatsLib.median(v); + x = 5; + assertEquals("median ", x, d); + } + + public void testMode() { + double[] v; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + confirmMode(v, null); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + confirmMode(v, 1.0); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + confirmMode(v, 0.0); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + confirmMode(v, 1.0); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + confirmMode(v, null); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + confirmMode(v, null); + + v = new double[] {1,2,3,4,1,1,1,1,0,0,0,0,0}; + confirmMode(v, 1.0); + + v = new double[] {0,1,2,3,4,1,1,1,0,0,0,0,1}; + confirmMode(v, 0.0); + } + private static void confirmMode(double[] v, double expectedResult) { + confirmMode(v, new Double(expectedResult)); + } + private static void confirmMode(double[] v, Double expectedResult) { + double actual; + try { + actual = Mode.evaluate(v); + if (expectedResult == null) { + throw new AssertionFailedError("Expected N/A exception was not thrown"); + } + } catch (EvaluationException e) { + if (expectedResult == null) { + assertEquals(ErrorEval.NA, e.getErrorEval()); + return; + } + throw new RuntimeException(e); + } + assertEquals("mode", expectedResult.doubleValue(), actual); + } + + + public void testStddev() { + double[] v = null; + double d, x = 0; + + v = new double[] {1,2,3,4,5,6,7,8,9,10}; + d = StatsLib.stdev(v); + x = 3.02765035410; + assertEquals("stdev ", x, d); + + v = new double[] {1,1,1,1,1,1,1,1,1,1}; + d = StatsLib.stdev(v); + x = 0; + assertEquals("stdev ", x, d); + + v = new double[] {0,0,0,0,0,0,0,0,0,0}; + d = StatsLib.stdev(v); + x = 0; + assertEquals("stdev ", x, d); + + v = new double[] {1,2,1,2,1,2,1,2,1,2}; + d = StatsLib.stdev(v); + x = 0.52704627669; + assertEquals("stdev ", x, d); + + v = new double[] {123.12,33.3333,2d/3d,5.37828,0.999}; + d = StatsLib.stdev(v); + x = 52.33006233652; + assertEquals("stdev ", x, d); + + v = new double[] {-1,-2,-3,-4,-5,-6,-7,-8,-9,-10}; + d = StatsLib.stdev(v); + x = 3.02765035410; + assertEquals("stdev ", x, d); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java b/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java new file mode 100644 index 0000000000..54cf5b774a --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestSubtotal.java @@ -0,0 +1,72 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +import junit.framework.TestCase; + +/** + * Tests for {@link Subtotal} + * + * @author Paul Tomlin + */ +public final class TestSubtotal extends TestCase { + private static final int FUNCTION_AVERAGE = 1; + private static final int FUNCTION_COUNT = 2; + private static final int FUNCTION_MAX = 4; + private static final int FUNCTION_MIN = 5; + private static final int FUNCTION_PRODUCT = 6; + private static final int FUNCTION_STDEV = 7; + private static final int FUNCTION_SUM = 9; + + private static final double[] TEST_VALUES0 = { + 1, 2, + 3, 4, + 5, 6, + 7, 8, + 9, 10 + }; + + private static void confirmSubtotal(int function, double expected) { + ValueEval[] values = new ValueEval[TEST_VALUES0.length]; + for (int i = 0; i < TEST_VALUES0.length; i++) { + values[i] = new NumberEval(TEST_VALUES0[i]); + } + + AreaEval arg1 = EvalFactory.createAreaEval("C1:D5", values); + ValueEval args[] = { new NumberEval(function), arg1 }; + + ValueEval result = new Subtotal().evaluate(args, 0, 0); + + assertEquals(NumberEval.class, result.getClass()); + assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0); + } + + public void testBasics() { + confirmSubtotal(FUNCTION_SUM, 55.0); + confirmSubtotal(FUNCTION_AVERAGE, 5.5); + confirmSubtotal(FUNCTION_COUNT, 10.0); + confirmSubtotal(FUNCTION_MAX, 10.0); + confirmSubtotal(FUNCTION_MIN, 1.0); + confirmSubtotal(FUNCTION_PRODUCT, 3628800.0); + confirmSubtotal(FUNCTION_STDEV, 3.0276503540974917); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestSumif.java b/src/testcases/org/apache/poi/ss/formula/functions/TestSumif.java new file mode 100644 index 0000000000..1ef090ea4f --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestSumif.java @@ -0,0 +1,102 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Test cases for SUMPRODUCT() + * + * @author Josh Micich + */ +public final class TestSumif extends TestCase { + private static final NumberEval _30 = new NumberEval(30); + private static final NumberEval _40 = new NumberEval(40); + private static final NumberEval _50 = new NumberEval(50); + private static final NumberEval _60 = new NumberEval(60); + + private static ValueEval invokeSumif(int rowIx, int colIx, ValueEval...args) { + return new Sumif().evaluate(args, rowIx, colIx); + } + private static void confirmDouble(double expected, ValueEval actualEval) { + if(!(actualEval instanceof NumericValueEval)) { + throw new AssertionFailedError("Expected numeric result"); + } + NumericValueEval nve = (NumericValueEval)actualEval; + assertEquals(expected, nve.getNumberValue(), 0); + } + + public void testBasic() { + ValueEval[] arg0values = new ValueEval[] { _30, _30, _40, _40, _50, _50 }; + ValueEval[] arg2values = new ValueEval[] { _30, _40, _50, _60, _60, _60 }; + + AreaEval arg0; + AreaEval arg2; + + arg0 = EvalFactory.createAreaEval("A3:B5", arg0values); + arg2 = EvalFactory.createAreaEval("D1:E3", arg2values); + + confirm(60.0, arg0, new NumberEval(30.0)); + confirm(70.0, arg0, new NumberEval(30.0), arg2); + confirm(100.0, arg0, new StringEval(">45")); + + } + private static void confirm(double expectedResult, ValueEval...args) { + confirmDouble(expectedResult, invokeSumif(-1, -1, args)); + } + + + /** + * test for bug observed near svn r882931 + */ + public void testCriteriaArgRange() { + ValueEval[] arg0values = new ValueEval[] { _50, _60, _50, _50, _50, _30, }; + ValueEval[] arg1values = new ValueEval[] { _30, _40, _50, _60, }; + + AreaEval arg0; + AreaEval arg1; + ValueEval ve; + + arg0 = EvalFactory.createAreaEval("A3:B5", arg0values); + arg1 = EvalFactory.createAreaEval("A2:D2", arg1values); // single row range + + ve = invokeSumif(0, 2, arg0, arg1); // invoking from cell C1 + if (ve instanceof NumberEval) { + NumberEval ne = (NumberEval) ve; + if (ne.getNumberValue() == 30.0) { + throw new AssertionFailedError("identified error in SUMIF - criteria arg not evaluated properly"); + } + } + + confirmDouble(200, ve); + + arg0 = EvalFactory.createAreaEval("C1:D3", arg0values); + arg1 = EvalFactory.createAreaEval("B1:B4", arg1values); // single column range + + ve = invokeSumif(3, 0, arg0, arg1); // invoking from cell A4 + + confirmDouble(60, ve); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestSumproduct.java b/src/testcases/org/apache/poi/ss/formula/functions/TestSumproduct.java new file mode 100644 index 0000000000..a8ccf47898 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestSumproduct.java @@ -0,0 +1,117 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.NumericValueEval; +import org.apache.poi.ss.formula.eval.RefEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Test cases for SUMPRODUCT() + * + * @author Josh Micich + */ +public final class TestSumproduct extends TestCase { + + private static ValueEval invokeSumproduct(ValueEval[] args) { + // srcCellRow and srcCellColumn are ignored by SUMPRODUCT + return new Sumproduct().evaluate(args, -1, (short)-1); + } + private static void confirmDouble(double expected, ValueEval actualEval) { + if(!(actualEval instanceof NumericValueEval)) { + fail("Expected numeric result"); + } + NumericValueEval nve = (NumericValueEval)actualEval; + assertEquals(expected, nve.getNumberValue(), 0); + } + + public void testScalarSimple() { + + RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3)); + ValueEval[] args = { + refEval, + new NumberEval(2), + }; + ValueEval result = invokeSumproduct(args); + confirmDouble(6D, result); + } + + public void testAreaSimple() { + ValueEval[] aValues = { + new NumberEval(2), + new NumberEval(4), + new NumberEval(5), + }; + ValueEval[] bValues = { + new NumberEval(3), + new NumberEval(6), + new NumberEval(7), + }; + AreaEval aeA = EvalFactory.createAreaEval("A1:A3", aValues); + AreaEval aeB = EvalFactory.createAreaEval("B1:B3", bValues); + + ValueEval[] args = { aeA, aeB, }; + ValueEval result = invokeSumproduct(args); + confirmDouble(65D, result); + } + + /** + * For scalar products, the terms may be 1x1 area refs + */ + public void testOneByOneArea() { + + AreaEval ae = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(7), }); + + ValueEval[] args = { + ae, + new NumberEval(2), + }; + ValueEval result = invokeSumproduct(args); + confirmDouble(14D, result); + } + + public void testMismatchAreaDimensions() { + + AreaEval aeA = EvalFactory.createAreaEval("A1:A3", new ValueEval[3]); + AreaEval aeB = EvalFactory.createAreaEval("B1:D1", new ValueEval[3]); + + ValueEval[] args; + args = new ValueEval[] { aeA, aeB, }; + assertEquals(ErrorEval.VALUE_INVALID, invokeSumproduct(args)); + + args = new ValueEval[] { aeA, new NumberEval(5), }; + assertEquals(ErrorEval.VALUE_INVALID, invokeSumproduct(args)); + } + + public void testAreaWithErrorCell() { + ValueEval[] aValues = { + ErrorEval.REF_INVALID, + null, + }; + AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues); + AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]); + + ValueEval[] args = { aeA, aeB, }; + assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args)); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestTFunc.java b/src/testcases/org/apache/poi/ss/formula/functions/TestTFunc.java new file mode 100644 index 0000000000..4e1209bfa6 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestTFunc.java @@ -0,0 +1,132 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Test cases for Excel function T() + * + * @author Josh Micich + */ +public final class TestTFunc extends TestCase { + + /** + * @return the result of calling function T() with the specified argument + */ + private static ValueEval invokeT(ValueEval arg) { + ValueEval[] args = { arg, }; + ValueEval result = new T().evaluate(args, -1, (short)-1); + assertNotNull("result may never be null", result); + return result; + } + /** + * Simulates call: T(A1) + * where cell A1 has the specified innerValue + */ + private ValueEval invokeTWithReference(ValueEval innerValue) { + ValueEval arg = EvalFactory.createRefEval("$B$2", innerValue); + return invokeT(arg); + } + + private static void confirmText(String text) { + ValueEval arg = new StringEval(text); + ValueEval eval = invokeT(arg); + StringEval se = (StringEval) eval; + assertEquals(text, se.getStringValue()); + } + + public void testTextValues() { + + confirmText("abc"); + confirmText(""); + confirmText(" "); + confirmText("~"); + confirmText("123"); + confirmText("TRUE"); + } + + private static void confirmError(ValueEval arg) { + ValueEval eval = invokeT(arg); + assertTrue(arg == eval); + } + + public void testErrorValues() { + + confirmError(ErrorEval.VALUE_INVALID); + confirmError(ErrorEval.NA); + confirmError(ErrorEval.REF_INVALID); + } + + private static void confirmString(ValueEval eval, String expected) { + assertTrue(eval instanceof StringEval); + assertEquals(expected, ((StringEval)eval).getStringValue()); + } + + private static void confirmOther(ValueEval arg) { + ValueEval eval = invokeT(arg); + confirmString(eval, ""); + } + + public void testOtherValues() { + confirmOther(new NumberEval(2)); + confirmOther(BoolEval.FALSE); + confirmOther(BlankEval.instance); // can this particular case be verified? + } + + public void testRefValues() { + ValueEval eval; + + eval = invokeTWithReference(new StringEval("def")); + confirmString(eval, "def"); + eval = invokeTWithReference(new StringEval(" ")); + confirmString(eval, " "); + + eval = invokeTWithReference(new NumberEval(2)); + confirmString(eval, ""); + eval = invokeTWithReference(BoolEval.TRUE); + confirmString(eval, ""); + + eval = invokeTWithReference(ErrorEval.NAME_INVALID); + assertTrue(eval == ErrorEval.NAME_INVALID); + } + + public void testAreaArg() { + ValueEval[] areaValues = new ValueEval[] { + new StringEval("abc"), new StringEval("def"), + new StringEval("ghi"), new StringEval("jkl"), + }; + AreaEval ae = EvalFactory.createAreaEval("C10:D11", areaValues); + + ValueEval ve; + ve = invokeT(ae); + confirmString(ve, "abc"); + + areaValues[0] = new NumberEval(5.0); + ve = invokeT(ae); + confirmString(ve, ""); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestText.java b/src/testcases/org/apache/poi/ss/formula/functions/TestText.java new file mode 100644 index 0000000000..8ff0bbfa92 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestText.java @@ -0,0 +1,113 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.text.DecimalFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.Locale; + +import junit.framework.TestCase; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.StringEval; + +/** + * Test case for TEXT() + * + * @author Stephen Wolke (smwolke at geistig.com) + */ +public final class TestText extends TestCase { + private static final TextFunction T = null; + + public void testTextWithStringFirstArg() { + + ValueEval strArg = new StringEval("abc"); + ValueEval formatArg = new StringEval("abc"); + ValueEval[] args = { strArg, formatArg }; + ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + + public void testTextWithDeciamlFormatSecondArg() { + + ValueEval numArg = new NumberEval(321321.321); + ValueEval formatArg = new StringEval("#,###.00000"); + ValueEval[] args = { numArg, formatArg }; + ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); + char groupSeparator = new DecimalFormatSymbols(Locale.getDefault()).getGroupingSeparator(); + char decimalSeparator = new DecimalFormatSymbols(Locale.getDefault()).getDecimalSeparator(); + ValueEval testResult = new StringEval("321" + groupSeparator + "321" + decimalSeparator + "32100"); + assertEquals(testResult.toString(), result.toString()); + numArg = new NumberEval(321.321); + formatArg = new StringEval("00000.00000"); + args[0] = numArg; + args[1] = formatArg; + result = T.TEXT.evaluate(args, -1, (short)-1); + testResult = new StringEval("00321" + decimalSeparator + "32100"); + assertEquals(testResult.toString(), result.toString()); + + formatArg = new StringEval("$#.#"); + args[1] = formatArg; + result = T.TEXT.evaluate(args, -1, (short)-1); + testResult = new StringEval("$321" + decimalSeparator + "3"); + assertEquals(testResult.toString(), result.toString()); + } + + public void testTextWithFractionFormatSecondArg() { + + ValueEval numArg = new NumberEval(321.321); + ValueEval formatArg = new StringEval("# #/#"); + ValueEval[] args = { numArg, formatArg }; + ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); + ValueEval testResult = new StringEval("321 1/3"); + assertEquals(testResult.toString(), result.toString()); + + formatArg = new StringEval("# #/##"); + args[1] = formatArg; + result = T.TEXT.evaluate(args, -1, (short)-1); + testResult = new StringEval("321 26/81"); + assertEquals(testResult.toString(), result.toString()); + + formatArg = new StringEval("#/##"); + args[1] = formatArg; + result = T.TEXT.evaluate(args, -1, (short)-1); + testResult = new StringEval("26027/81"); + assertEquals(testResult.toString(), result.toString()); + } + + public void testTextWithDateFormatSecondArg() { + + ValueEval numArg = new NumberEval(321.321); + ValueEval formatArg = new StringEval("dd:MM:yyyy hh:mm:ss"); + ValueEval[] args = { numArg, formatArg }; + ValueEval result = T.TEXT.evaluate(args, -1, (short)-1); + ValueEval testResult = new StringEval("16:11:1900 07:42:14"); + assertEquals(testResult.toString(), result.toString()); + + // this line is intended to compute how "November" would look like in the current locale + String november = new SimpleDateFormat("MMMM").format(new GregorianCalendar(2010,10,15).getTime()); + + formatArg = new StringEval("MMMM dd, yyyy"); + args[1] = formatArg; + result = T.TEXT.evaluate(args, -1, (short)-1); + testResult = new StringEval(november + " 16, 1900"); + assertEquals(testResult.toString(), result.toString()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestTime.java b/src/testcases/org/apache/poi/ss/formula/functions/TestTime.java new file mode 100644 index 0000000000..a1f89ff79b --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestTime.java @@ -0,0 +1,122 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import java.util.regex.Pattern; + +import junit.framework.TestCase; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFDataFormat; +import org.apache.poi.hssf.usermodel.HSSFDataFormatter; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * Tests for {@link TimeFunc} + * + * @author @author Steven Butler (sebutler @ gmail dot com) + */ +public final class TestTime extends TestCase { + + private static final int SECONDS_PER_MINUTE = 60; + private static final int SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE; + private static final double SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR; + private HSSFCell cell11; + private HSSFFormulaEvaluator evaluator; + private HSSFWorkbook wb; + private HSSFDataFormatter form; + private HSSFCellStyle style; + + public void setUp() { + wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet("new sheet"); + style = wb.createCellStyle(); + HSSFDataFormat fmt = wb.createDataFormat(); + style.setDataFormat(fmt.getFormat("hh:mm:ss")); + + cell11 = sheet.createRow(0).createCell(0); + form = new HSSFDataFormatter(); + + evaluator = new HSSFFormulaEvaluator(wb); + } + + public void testSomeArgumentsMissing() { + confirm("00:00:00", "TIME(, 0, 0)"); + confirm("12:00:00", "TIME(12, , )"); + } + + public void testValid() { + confirm("00:00:01", 0, 0, 1); + confirm("00:01:00", 0, 1, 0); + + confirm("00:00:00", 0, 0, 0); + + confirm("01:00:00", 1, 0, 0); + confirm("12:00:00", 12, 0, 0); + confirm("23:00:00", 23, 0, 0); + confirm("00:00:00", 24, 0, 0); + confirm("01:00:00", 25, 0, 0); + confirm("00:00:00", 48, 0, 0); + confirm("06:00:00", 6, 0, 0); + confirm("06:01:00", 6, 1, 0); + confirm("06:30:00", 6, 30, 0); + + confirm("06:59:00", 6, 59, 0); + confirm("07:00:00", 6, 60, 0); + confirm("07:01:00", 6, 61, 0); + confirm("08:00:00", 6, 120, 0); + confirm("06:00:00", 6, 1440, 0); + confirm("18:49:00", 18, 49, 0); + confirm("18:49:01", 18, 49, 1); + confirm("18:49:30", 18, 49, 30); + confirm("18:49:59", 18, 49, 59); + confirm("18:50:00", 18, 49, 60); + confirm("18:50:01", 18, 49, 61); + confirm("18:50:59", 18, 49, 119); + confirm("18:51:00", 18, 49, 120); + confirm("03:55:07", 18, 49, 32767); + confirm("12:08:01", 18, 32767, 61); + confirm("07:50:01", 32767, 49, 61); + } + private void confirm(String expectedTimeStr, int inH, int inM, int inS) { + confirm(expectedTimeStr, "TIME(" + inH + "," + inM + "," + inS + ")"); + } + + private void confirm(String expectedTimeStr, String formulaText) { +// System.out.println("=" + formulaText); + String[] parts = Pattern.compile(":").split(expectedTimeStr); + int expH = Integer.parseInt(parts[0]); + int expM = Integer.parseInt(parts[1]); + int expS = Integer.parseInt(parts[2]); + + double expectedValue = (expH*SECONDS_PER_HOUR + expM*SECONDS_PER_MINUTE + expS)/SECONDS_PER_DAY; + + cell11.setCellFormula(formulaText); + cell11.setCellStyle(style); + evaluator.clearAllCachedResultValues(); + + double actualValue = evaluator.evaluate(cell11).getNumberValue(); + assertEquals(expectedValue, actualValue, 0.0); + + String actualText = form.formatCellValue(cell11, evaluator); + assertEquals(expectedTimeStr, actualText); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestTrim.java b/src/testcases/org/apache/poi/ss/formula/functions/TestTrim.java new file mode 100644 index 0000000000..bb5efa7280 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestTrim.java @@ -0,0 +1,78 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.BlankEval; +import org.apache.poi.ss.formula.eval.BoolEval; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; +/** + * Tests for Excel function TRIM() + * + * @author Josh Micich + */ +public final class TestTrim extends TestCase { + + + private static ValueEval invokeTrim(ValueEval text) { + ValueEval[] args = new ValueEval[] { text, }; + return TextFunction.TRIM.evaluate(args, -1, (short)-1); + } + + private void confirmTrim(ValueEval text, String expected) { + ValueEval result = invokeTrim(text); + assertEquals(StringEval.class, result.getClass()); + assertEquals(expected, ((StringEval)result).getStringValue()); + } + + private void confirmTrim(ValueEval text, ErrorEval expectedError) { + ValueEval result = invokeTrim(text); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); + } + + public void testBasic() { + + confirmTrim(new StringEval(" hi "), "hi"); + confirmTrim(new StringEval("hi "), "hi"); + confirmTrim(new StringEval(" hi"), "hi"); + confirmTrim(new StringEval(" hi there "), "hi there"); + confirmTrim(new StringEval(""), ""); + confirmTrim(new StringEval(" "), ""); + } + + /** + * Valid cases where text arg is not exactly a string + */ + public void testUnusualArgs() { + + // text (first) arg type is number, other args are strings with fractional digits + confirmTrim(new NumberEval(123456), "123456"); + confirmTrim(BoolEval.FALSE, "FALSE"); + confirmTrim(BoolEval.TRUE, "TRUE"); + confirmTrim(BlankEval.instance, ""); + } + + public void testErrors() { + confirmTrim(ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestTrunc.java b/src/testcases/org/apache/poi/ss/formula/functions/TestTrunc.java new file mode 100644 index 0000000000..c3ed459745 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestTrunc.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.ss.formula.functions; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.ValueEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; + +/** + * Test case for TRUNC() + * + * @author Stephen Wolke (smwolke at geistig.com) + */ +public final class TestTrunc extends AbstractNumericTestCase { + private static final NumericFunction F = null; + public void testTruncWithStringArg() { + + ValueEval strArg = new StringEval("abc"); + ValueEval[] args = { strArg, new NumberEval(2) }; + ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + + public void testTruncWithWholeNumber() { + ValueEval[] args = { new NumberEval(200), new NumberEval(2) }; + @SuppressWarnings("static-access") + ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); + assertEquals("TRUNC", (new NumberEval(200d)).getNumberValue(), ((NumberEval)result).getNumberValue()); + } + + public void testTruncWithDecimalNumber() { + ValueEval[] args = { new NumberEval(2.612777), new NumberEval(3) }; + @SuppressWarnings("static-access") + ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); + assertEquals("TRUNC", (new NumberEval(2.612d)).getNumberValue(), ((NumberEval)result).getNumberValue()); + } + + public void testTruncWithDecimalNumberOneArg() { + ValueEval[] args = { new NumberEval(2.612777) }; + ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1); + assertEquals("TRUNC", (new NumberEval(2d)).getNumberValue(), ((NumberEval)result).getNumberValue()); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestValue.java b/src/testcases/org/apache/poi/ss/formula/functions/TestValue.java new file mode 100644 index 0000000000..f85db0cfff --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestValue.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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.StringEval; +import org.apache.poi.ss.formula.eval.ValueEval; + +/** + * Tests for {@link Value} + * + * @author Josh Micich + */ +public final class TestValue extends TestCase { + + private static ValueEval invokeValue(String strText) { + ValueEval[] args = new ValueEval[] { new StringEval(strText), }; + return new Value().evaluate(args, -1, (short) -1); + } + + private static void confirmValue(String strText, double expected) { + ValueEval result = invokeValue(strText); + assertEquals(NumberEval.class, result.getClass()); + assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0); + } + + private static void confirmValueError(String strText) { + ValueEval result = invokeValue(strText); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(ErrorEval.VALUE_INVALID, result); + } + + public void testBasic() { + + confirmValue("100", 100); + confirmValue("-2.3", -2.3); + confirmValue(".5", 0.5); + confirmValue(".5e2", 50); + confirmValue(".5e-2", 0.005); + confirmValue(".5e+2", 50); + confirmValue("+5", 5); + confirmValue("$1,000", 1000); + confirmValue("100.5e1", 1005); + confirmValue("1,0000", 10000); + confirmValue("1,000,0000", 10000000); + confirmValue("1,000,0000,00000", 1000000000000.0); + confirmValue(" 100 ", 100); + confirmValue(" + 100", 100); + confirmValue("10000", 10000); + confirmValue("$-5", -5); + confirmValue("$.5", 0.5); + confirmValue("123e+5", 12300000); + confirmValue("1,000e2", 100000); + confirmValue("$10e2", 1000); + confirmValue("$1,000e2", 100000); + } + + public void testErrors() { + confirmValueError("1+1"); + confirmValueError("1 1"); + confirmValueError("1,00.0"); + confirmValueError("1,00"); + confirmValueError("$1,00.5e1"); + confirmValueError("1,00.5e1"); + confirmValueError("1,0,000"); + confirmValueError("1,00,000"); + confirmValueError("++100"); + confirmValueError("$$5"); + confirmValueError("-"); + confirmValueError("+"); + confirmValueError("$"); + confirmValueError(",300"); + confirmValueError("0.233,4"); + confirmValueError("1e2.5"); + } +} diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestXYNumericFunction.java b/src/testcases/org/apache/poi/ss/formula/functions/TestXYNumericFunction.java new file mode 100644 index 0000000000..cc7f91a993 --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestXYNumericFunction.java @@ -0,0 +1,135 @@ +/* ==================================================================== + 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.ss.formula.functions; + +import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.ValueEval; +/** + * Tests for Excel functions SUMX2MY2(), SUMX2PY2(), SUMXMY2() + * + * @author Josh Micich + */ +public final class TestXYNumericFunction extends TestCase { + private static final Function SUM_SQUARES = new Sumx2py2(); + private static final Function DIFF_SQUARES = new Sumx2my2(); + private static final Function SUM_SQUARES_OF_DIFFS = new Sumxmy2(); + + private static ValueEval invoke(Function function, ValueEval xArray, ValueEval yArray) { + ValueEval[] args = new ValueEval[] { xArray, yArray, }; + return function.evaluate(args, -1, (short)-1); + } + + private void confirm(Function function, ValueEval xArray, ValueEval yArray, double expected) { + ValueEval result = invoke(function, xArray, yArray); + assertEquals(NumberEval.class, result.getClass()); + assertEquals(expected, ((NumberEval)result).getNumberValue(), 0); + } + private void confirmError(Function function, ValueEval xArray, ValueEval yArray, ErrorEval expectedError) { + ValueEval result = invoke(function, xArray, yArray); + assertEquals(ErrorEval.class, result.getClass()); + assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode()); + } + + private void confirmError(ValueEval xArray, ValueEval yArray, ErrorEval expectedError) { + confirmError(SUM_SQUARES, xArray, yArray, expectedError); + confirmError(DIFF_SQUARES, xArray, yArray, expectedError); + confirmError(SUM_SQUARES_OF_DIFFS, xArray, yArray, expectedError); + } + + public void testBasic() { + ValueEval[] xValues = { + new NumberEval(1), + new NumberEval(2), + }; + ValueEval areaEvalX = createAreaEval(xValues); + confirm(SUM_SQUARES, areaEvalX, areaEvalX, 10.0); + confirm(DIFF_SQUARES, areaEvalX, areaEvalX, 0.0); + confirm(SUM_SQUARES_OF_DIFFS, areaEvalX, areaEvalX, 0.0); + + ValueEval[] yValues = { + new NumberEval(3), + new NumberEval(4), + }; + ValueEval areaEvalY = createAreaEval(yValues); + confirm(SUM_SQUARES, areaEvalX, areaEvalY, 30.0); + confirm(DIFF_SQUARES, areaEvalX, areaEvalY, -20.0); + confirm(SUM_SQUARES_OF_DIFFS, areaEvalX, areaEvalY, 8.0); + } + + /** + * number of items in array is not limited to 30 + */ + public void testLargeArrays() { + ValueEval[] xValues = createMockNumberArray(100, 3); + ValueEval[] yValues = createMockNumberArray(100, 2); + + confirm(SUM_SQUARES, createAreaEval(xValues), createAreaEval(yValues), 1300.0); + confirm(DIFF_SQUARES, createAreaEval(xValues), createAreaEval(yValues), 500.0); + confirm(SUM_SQUARES_OF_DIFFS, createAreaEval(xValues), createAreaEval(yValues), 100.0); + } + + + private ValueEval[] createMockNumberArray(int size, double value) { + ValueEval[] result = new ValueEval[size]; + for (int i = 0; i < result.length; i++) { + result[i] = new NumberEval(value); + } + return result; + } + + private static ValueEval createAreaEval(ValueEval[] values) { + String refStr = "A1:A" + values.length; + return EvalFactory.createAreaEval(refStr, values); + } + + public void testErrors() { + ValueEval[] xValues = { + ErrorEval.REF_INVALID, + new NumberEval(2), + }; + ValueEval areaEvalX = createAreaEval(xValues); + ValueEval[] yValues = { + new NumberEval(2), + ErrorEval.NULL_INTERSECTION, + }; + ValueEval areaEvalY = createAreaEval(yValues); + ValueEval[] zValues = { // wrong size + new NumberEval(2), + }; + ValueEval areaEvalZ = createAreaEval(zValues); + + // if either arg is an error, that error propagates + confirmError(ErrorEval.REF_INVALID, ErrorEval.NAME_INVALID, ErrorEval.REF_INVALID); + confirmError(areaEvalX, ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID); + confirmError(ErrorEval.NAME_INVALID, areaEvalX, ErrorEval.NAME_INVALID); + + // array sizes must match + confirmError(areaEvalX, areaEvalZ, ErrorEval.NA); + confirmError(areaEvalZ, areaEvalY, ErrorEval.NA); + + // any error in an array item propagates up + confirmError(areaEvalX, areaEvalX, ErrorEval.REF_INVALID); + + // search for errors array by array, not pair by pair + confirmError(areaEvalX, areaEvalY, ErrorEval.REF_INVALID); + confirmError(areaEvalY, areaEvalX, ErrorEval.NULL_INTERSECTION); + } +} diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestHyperlink.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestHyperlink.java index 833e5aab9a..e0be21b0fd 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestHyperlink.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestHyperlink.java @@ -19,7 +19,6 @@ package org.apache.poi.ss.usermodel; import junit.framework.TestCase; -import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.ss.ITestDataProvider; /** diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java index d2518effb1..f9346a67af 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestNamedRange.java @@ -20,7 +20,6 @@ package org.apache.poi.ss.usermodel; import junit.framework.AssertionFailedError; import junit.framework.TestCase; -import org.apache.poi.hssf.usermodel.HSSFName; import org.apache.poi.ss.ITestDataProvider; import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellReference; @@ -506,7 +505,7 @@ public abstract class BaseTestNamedRange extends TestCase { * 00000010 | 00 00 00 55 50 53 53 74 61 74 65 | ...UPSState * * - * This caused trouble for anything that requires {@link HSSFName#getRefersToFormula()} + * This caused trouble for anything that requires {@link Name#getRefersToFormula()} * It is easy enough to re-create the the same data (by not setting the formula). Excel * seems to gracefully remove this uninitialized name record. It would be nice if POI * could do the same, but that would involve adjusting subsequent name indexes across