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;
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;
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;
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
-
- }
-
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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<stes.length) {
- if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
- break;
- }
- startIx++;
- }
- // skip bottom frames (part of junit framework)
- int endIx = startIx+1;
- while(endIx < stes.length) {
- if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
- break;
- }
- endIx++;
- }
- if(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; i<endIx; i++) {
- ps.println("\tat " + stes[i].toString());
- }
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.Test;
-import junit.framework.TestSuite;
-
-/**
- * Collects all tests the package <tt>org.apache.poi.hssf.record.formula.eval</tt>.
- *
- * @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;
- }
-}
+++ /dev/null
-/* ====================================================================
- 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;
-}
+++ /dev/null
-/* ====================================================================
- 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 <tt>AreaEval</tt>
- *
- * @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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
-
-
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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)<br/>
- * 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
- * <p/>
- * 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.<p/> 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.<p/> This test was
- * added <em>long</em> 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<p/>
- *
- * 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 <p/>
- */
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.<p/>
- * This class does not test implementors of <tt>Function</tt> and <tt>OperationEval</tt> in
- * isolation. Much of the evaluation engine (i.e. <tt>HSSFFormulaEvaluator</tt>, ...) gets
- * exercised as well. Tests for bug fixes and specific/tricky behaviour can be found in the
- * corresponding test class (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) 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 = "<END-OF-FUNCTIONS>";
-
- /**
- * 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 <code>null</code> 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<stes.length) {
- if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
- break;
- }
- startIx++;
- }
- // skip bottom frames (part of junit framework)
- int endIx = startIx+1;
- while(endIx < stes.length) {
- if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
- break;
- }
- endIx++;
- }
- if(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; i<endIx; i++) {
- ps.println("\tat " + stes[i].toString());
- }
- }
-
- /**
- * @return <code>null</code> 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) + ")");
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.)
- * <p/>
- * POI attempts to emulate Excel faithfully, so this class tests
- * two aspects of '-0.0' in formula evaluation:
- * <ol>
- * <li>For most operation results '-0.0' is converted to '0.0'.</li>
- * <li>Comparison operators have slightly different rules regarding '-0.0'.</li>
- * </ol>
- * @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)));
- }
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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 <tt>OperandResolver</tt>
- *
- * @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));
- }
-
- }
-
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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)<br/>
- * 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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 <tt>org.apache.poi.hssf.record.formula.function</tt>.
- *
- * @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;
- }
-}
+++ /dev/null
-/* ====================================================================
- 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<ss.length(); i++) {
- char c = ss.charAt(i);
- if (isSimpleAscii(c)) {
- sb.append(c);
- continue;
- }
- switch (c) {
- case CHAR_NDASH_8211:
- sb.append('-');
- continue;
- case CHAR_ELLIPSIS_8230:
- sb.append("...");
- continue;
- }
- throw new RuntimeException("bad char (" + ((int)c) + ") in string '" + ss + "'");
- }
- return sb.toString();
- }
- public int getIndex() {
- return _index;
- }
- public String getName() {
- return _name;
- }
- public boolean hasFootnote() {
- return _hasFootnote;
- }
- public String formatAsDataLine() {
- return _index + "\t" + _name + "\t" + _minParams + "\t"
- + _maxParams + "\t" + _returnClass + "\t" + _paramClasses
- + "\t" + checkMark(_isVolatile) + "\t" + checkMark(_hasFootnote);
- }
- private static String checkMark(boolean b) {
- return b ? "x" : "";
- }
- }
-
- private static final class FunctionDataCollector {
-
- private final Map _allFunctionsByIndex;
- private final Map _allFunctionsByName;
- private final Set _groupFunctionIndexes;
- private final Set _groupFunctionNames;
- private final PrintStream _ps;
-
- public FunctionDataCollector(PrintStream ps) {
- _ps = ps;
- _allFunctionsByIndex = new HashMap();
- _allFunctionsByName = new HashMap();
- _groupFunctionIndexes = new HashSet();
- _groupFunctionNames = new HashSet();
- }
-
- public void addFuntion(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams,
- String returnClass, String paramClasses, String volatileFlagStr) {
- boolean isVolatile = volatileFlagStr.length() > 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;
- /** <code>true</code> 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();
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/*
-* 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);
- }
-
-}
+++ /dev/null
-/* ====================================================================
- 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 <code>Function</code>.
- *
- * @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;
- }
-}
+++ /dev/null
-/* ====================================================================
- 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 <code>Eval</code> objects
- *
- * @author Josh Micich
- */
-public final class EvalFactory {
-
- private EvalFactory() {
- // no instances of this class
- }
-
- /**
- * Creates a dummy AreaEval
- * @param values empty (<code>null</code>) 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 (<code>null</code>) 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<height; r++) {
- int srcRowIx = r + relFirstRowIx;
- for (int c=0; c<width; c++) {
- int srcColIx = c + relFirstColIx;
- int destIx = r * width + c;
- int srcIx = srcRowIx * srcWidth + srcColIx;
- result[destIx] = srcValues[srcIx];
- }
- }
- return result;
- }
- public TwoDEval getRow(int rowIndex) {
- if (rowIndex >= 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");
- }
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.
- * <p/>
- * Assumes that the cell coordinate parameters of
- * <code>Function.evaluate(args, srcCellRow, srcCellCol)</code>
- * are not required.
- * <p/>
- * 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.
- * <p/>
- * 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();
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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<maxRow; rowIx++) {
- HSSFRow row = sheet.getRow(rowIx);
- if(row == null) {
- continue;
- }
- HSSFCell cell = row.getCell(COL_IX_ACTUAL);
- CellValue cv = fe.evaluate(cell);
- double actualValue = cv.getNumberValue();
- double expectedValue = row.getCell(COL_IX_EXPECTED).getNumericCellValue();
- if (actualValue != expectedValue) {
- System.err.println("Problem with test case on row " + (rowIx+1) + " "
- + "Expected = (" + expectedValue + ") Actual=(" + actualValue + ") ");
- failureCount++;
- }
- }
-
- if (failureCount > 0) {
- throw new AssertionFailedError(failureCount + " " + functionName
- + " evaluations failed. See stderr for more details");
- }
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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 <tt>method</tt> parameter only makes a difference when the second parameter
- * is the last day of the month that does <em>not</em> 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));
- }
-}
-
+++ /dev/null
-/*
-* 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.</p>
- *
- * This class contains just a few specific cases that directly invoke {@link Index},
- * with minimum overhead.<br/>
- * Another test: {@link TestIndexFunctionFromSpreadsheet} operates from a higher level
- * and has far greater coverage of input permutations.<br/>
- *
- * @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)".<br/>
- * 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 <tt>ve</tt> 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;
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.<p/>
- *
- * @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 "<blank>";
- 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<maxRows; rowIndex++) {
- HSSFRow r = sheet.getRow(rowIndex);
- if(r == null) {
- continue;
- }
- HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
- if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
- continue;
- }
- HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
-
- String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c);
- try {
- CellValue actualValue = evaluator.evaluate(c);
- confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
- _evaluationSuccessCount ++;
- if(result != Result.SOME_EVALUATIONS_FAILED) {
- result = Result.ALL_EVALUATIONS_SUCCEEDED;
- }
- } catch (RuntimeException e) {
- _evaluationFailureCount ++;
- printShortStackTrace(System.err, e, msgPrefix);
- result = Result.SOME_EVALUATIONS_FAILED;
- } catch (AssertionFailedError e) {
- _evaluationFailureCount ++;
- printShortStackTrace(System.err, e, msgPrefix);
- result = Result.SOME_EVALUATIONS_FAILED;
- }
- }
- }
-
-
- private static String formatTestCaseDetails(String sheetName, int rowIndex, HSSFCell c) {
-
- StringBuffer sb = new StringBuffer();
- CellReference cr = new CellReference(sheetName, rowIndex, c.getColumnIndex(), false, false);
- sb.append(cr.formatAsString());
- sb.append(" [formula: ").append(c.getCellFormula()).append(" ]");
- return sb.toString();
- }
-
- /**
- * Useful to keep output concise when expecting many failures to be reported by this test case
- */
- private static void printShortStackTrace(PrintStream ps, Throwable e, String msgPrefix) {
- System.err.println("Problem with " + msgPrefix);
- StackTraceElement[] stes = e.getStackTrace();
-
- int startIx = 0;
- // skip any top frames inside junit.framework.Assert
- while(startIx<stes.length) {
- if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
- break;
- }
- startIx++;
- }
- // skip bottom frames (part of junit framework)
- int endIx = startIx+1;
- while(endIx < stes.length) {
- if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
- break;
- }
- endIx++;
- }
- if(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; i<endIx; i++) {
- ps.println("\tat " + stes[i].toString());
- }
- }
-}
-
+++ /dev/null
-/* ====================================================================
- 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.usermodel.*;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.FormulaEvaluator;
-import org.apache.poi.ss.util.CellReference;
-
-/**
- * Tests for the INDIRECT() function.</p>
- *
- * @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() + "'.");
- }
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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));
-
- }
-
-
-
-
-
-
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.<p/>
- * 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
- * (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) 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 = "<end>";
- /** Used to indicate that the test on the current row should be ignored */
- public static final String SKIP_CURRENT_TEST_CASE_MARKER = "<skip>";
-
- }
-
- // 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 "<blank>";
- 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<maxRows; rowIndex++) {
- HSSFRow r = sheet.getRow(rowIndex);
- String newMarkerValue = getMarkerColumnValue(r);
- if(r == null) {
- continue;
- }
- if(SS.TEST_CASES_END_MARKER.equalsIgnoreCase(newMarkerValue)) {
- // normal exit point
- return result;
- }
- if(SS.SKIP_CURRENT_TEST_CASE_MARKER.equalsIgnoreCase(newMarkerValue)) {
- // currently disabled test case row
- continue;
- }
- if(newMarkerValue != null) {
- currentGroupComment = newMarkerValue;
- }
- HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
- if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
- continue;
- }
- CellValue actualValue = evaluator.evaluate(c);
- HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
- String rowComment = getRowCommentColumnValue(r);
-
- String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c, currentGroupComment, rowComment);
- try {
- confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
- _evaluationSuccessCount ++;
- if(result != Result.SOME_EVALUATIONS_FAILED) {
- result = Result.ALL_EVALUATIONS_SUCCEEDED;
- }
- } catch (RuntimeException e) {
- _evaluationFailureCount ++;
- printShortStackTrace(System.err, e);
- result = Result.SOME_EVALUATIONS_FAILED;
- } catch (AssertionFailedError e) {
- _evaluationFailureCount ++;
- printShortStackTrace(System.err, e);
- result = Result.SOME_EVALUATIONS_FAILED;
- }
-
- }
- throw new RuntimeException("Missing end marker '" + SS.TEST_CASES_END_MARKER
- + "' on sheet '" + sheetName + "'");
-
- }
-
-
- private static String formatTestCaseDetails(String sheetName, int rowIndex, HSSFCell c, String currentGroupComment,
- String rowComment) {
-
- StringBuffer sb = new StringBuffer();
- CellReference cr = new CellReference(sheetName, rowIndex, c.getColumnIndex(), false, false);
- sb.append(cr.formatAsString());
- sb.append(" {=").append(c.getCellFormula()).append("}");
-
- if(currentGroupComment != null) {
- sb.append(" '");
- sb.append(currentGroupComment);
- if(rowComment != null) {
- sb.append(" - ");
- sb.append(rowComment);
- }
- sb.append("' ");
- } else {
- if(rowComment != null) {
- sb.append(" '");
- sb.append(rowComment);
- sb.append("' ");
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Asserts that the 'read me' comment page exists, and has this class' name in one of the
- * cells. This back-link is to make it easy to find this class if a reader encounters the
- * spreadsheet first.
- */
- private void confirmReadMeSheet(HSSFWorkbook workbook) {
- String firstSheetName = workbook.getSheetName(0);
- if(!firstSheetName.equalsIgnoreCase(SS.README_SHEET_NAME)) {
- throw new RuntimeException("First sheet's name was '" + firstSheetName + "' but expected '" + SS.README_SHEET_NAME + "'");
- }
- HSSFSheet sheet = workbook.getSheetAt(0);
- String specifiedClassName = sheet.getRow(2).getCell(0).getRichStringCellValue().getString();
- assertEquals("Test class name in spreadsheet comment", getClass().getName(), specifiedClassName);
- }
-
-
- /**
- * Useful to keep output concise when expecting many failures to be reported by this test case
- */
- 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<stes.length) {
- if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
- break;
- }
- startIx++;
- }
- // skip bottom frames (part of junit framework)
- int endIx = startIx+1;
- while(endIx < stes.length) {
- if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
- break;
- }
- endIx++;
- }
- if(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; i<endIx; i++) {
- ps.println("\tat " + stes[i].toString());
- }
-
- }
-
- private static String getRowCommentColumnValue(HSSFRow r) {
- return getCellTextValue(r, SS.COLUMN_ROW_COMMENT, "row comment");
- }
-
- private static String getMarkerColumnValue(HSSFRow r) {
- return getCellTextValue(r, SS.COLUMN_INDEX_MARKER, "marker");
- }
-
- /**
- * @return <code>null</code> 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) + ")");
- }
-}
+++ /dev/null
-/* ====================================================================
- 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 <tt>AreaEval</tt>.<br/>
- * 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;
- }
- }
-}
+++ /dev/null
-/*
-* 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));
- }
-
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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));
- }
-}
+++ /dev/null
-/* ====================================================================
- 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));
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/*
-* 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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));
- }
-}
+++ /dev/null
-/* ====================================================================
- 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, "");
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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());
- }
-}
+++ /dev/null
-/* ====================================================================
- 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");
- }
-}
+++ /dev/null
-/* ====================================================================
- 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);
- }
-}
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;
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;
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}.
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;
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
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;
--- /dev/null
+/* ====================================================================
+ 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);
+
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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<stes.length) {
+ if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
+ break;
+ }
+ startIx++;
+ }
+ // skip bottom frames (part of junit framework)
+ int endIx = startIx+1;
+ while(endIx < stes.length) {
+ if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
+ break;
+ }
+ endIx++;
+ }
+ if(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; i<endIx; i++) {
+ ps.println("\tat " + stes[i].toString());
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Collects all tests the package <tt>org.apache.poi.hssf.record.formula.eval</tt>.
+ *
+ * @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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+}
--- /dev/null
+/* ====================================================================
+ 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 <tt>AreaEval</tt>
+ *
+ * @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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+
+
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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)<br/>
+ * 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
+ * <p/>
+ * 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.<p/> 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.<p/> This test was
+ * added <em>long</em> 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<p/>
+ *
+ * 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 <p/>
+ */
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.<p/>
+ * This class does not test implementors of <tt>Function</tt> and <tt>OperationEval</tt> in
+ * isolation. Much of the evaluation engine (i.e. <tt>HSSFFormulaEvaluator</tt>, ...) gets
+ * exercised as well. Tests for bug fixes and specific/tricky behaviour can be found in the
+ * corresponding test class (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) 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 = "<END-OF-FUNCTIONS>";
+
+ /**
+ * 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 <code>null</code> 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<stes.length) {
+ if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
+ break;
+ }
+ startIx++;
+ }
+ // skip bottom frames (part of junit framework)
+ int endIx = startIx+1;
+ while(endIx < stes.length) {
+ if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
+ break;
+ }
+ endIx++;
+ }
+ if(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; i<endIx; i++) {
+ ps.println("\tat " + stes[i].toString());
+ }
+ }
+
+ /**
+ * @return <code>null</code> 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) + ")");
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.)
+ * <p/>
+ * POI attempts to emulate Excel faithfully, so this class tests
+ * two aspects of '-0.0' in formula evaluation:
+ * <ol>
+ * <li>For most operation results '-0.0' is converted to '0.0'.</li>
+ * <li>Comparison operators have slightly different rules regarding '-0.0'.</li>
+ * </ol>
+ * @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)));
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 <tt>OperandResolver</tt>
+ *
+ * @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));
+ }
+
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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)<br/>
+ * 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);
+ }
+}
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;
--- /dev/null
+/* ====================================================================
+ 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 <tt>org.apache.poi.hssf.record.formula.function</tt>.
+ *
+ * @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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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<ss.length(); i++) {
+ char c = ss.charAt(i);
+ if (isSimpleAscii(c)) {
+ sb.append(c);
+ continue;
+ }
+ switch (c) {
+ case CHAR_NDASH_8211:
+ sb.append('-');
+ continue;
+ case CHAR_ELLIPSIS_8230:
+ sb.append("...");
+ continue;
+ }
+ throw new RuntimeException("bad char (" + ((int)c) + ") in string '" + ss + "'");
+ }
+ return sb.toString();
+ }
+ public int getIndex() {
+ return _index;
+ }
+ public String getName() {
+ return _name;
+ }
+ public boolean hasFootnote() {
+ return _hasFootnote;
+ }
+ public String formatAsDataLine() {
+ return _index + "\t" + _name + "\t" + _minParams + "\t"
+ + _maxParams + "\t" + _returnClass + "\t" + _paramClasses
+ + "\t" + checkMark(_isVolatile) + "\t" + checkMark(_hasFootnote);
+ }
+ private static String checkMark(boolean b) {
+ return b ? "x" : "";
+ }
+ }
+
+ private static final class FunctionDataCollector {
+
+ private final Map _allFunctionsByIndex;
+ private final Map _allFunctionsByName;
+ private final Set _groupFunctionIndexes;
+ private final Set _groupFunctionNames;
+ private final PrintStream _ps;
+
+ public FunctionDataCollector(PrintStream ps) {
+ _ps = ps;
+ _allFunctionsByIndex = new HashMap();
+ _allFunctionsByName = new HashMap();
+ _groupFunctionIndexes = new HashSet();
+ _groupFunctionNames = new HashSet();
+ }
+
+ public void addFuntion(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams,
+ String returnClass, String paramClasses, String volatileFlagStr) {
+ boolean isVolatile = volatileFlagStr.length() > 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;
+ /** <code>true</code> 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();
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/*
+* 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);
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ 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 <code>Function</code>.
+ *
+ * @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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 <code>Eval</code> objects
+ *
+ * @author Josh Micich
+ */
+public final class EvalFactory {
+
+ private EvalFactory() {
+ // no instances of this class
+ }
+
+ /**
+ * Creates a dummy AreaEval
+ * @param values empty (<code>null</code>) 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 (<code>null</code>) 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<height; r++) {
+ int srcRowIx = r + relFirstRowIx;
+ for (int c=0; c<width; c++) {
+ int srcColIx = c + relFirstColIx;
+ int destIx = r * width + c;
+ int srcIx = srcRowIx * srcWidth + srcColIx;
+ result[destIx] = srcValues[srcIx];
+ }
+ }
+ return result;
+ }
+ public TwoDEval getRow(int rowIndex) {
+ if (rowIndex >= 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");
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.
+ * <p/>
+ * Assumes that the cell coordinate parameters of
+ * <code>Function.evaluate(args, srcCellRow, srcCellCol)</code>
+ * are not required.
+ * <p/>
+ * 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.
+ * <p/>
+ * 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();
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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<maxRow; rowIx++) {
+ HSSFRow row = sheet.getRow(rowIx);
+ if(row == null) {
+ continue;
+ }
+ HSSFCell cell = row.getCell(COL_IX_ACTUAL);
+ CellValue cv = fe.evaluate(cell);
+ double actualValue = cv.getNumberValue();
+ double expectedValue = row.getCell(COL_IX_EXPECTED).getNumericCellValue();
+ if (actualValue != expectedValue) {
+ System.err.println("Problem with test case on row " + (rowIx+1) + " "
+ + "Expected = (" + expectedValue + ") Actual=(" + actualValue + ") ");
+ failureCount++;
+ }
+ }
+
+ if (failureCount > 0) {
+ throw new AssertionFailedError(failureCount + " " + functionName
+ + " evaluations failed. See stderr for more details");
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 <tt>method</tt> parameter only makes a difference when the second parameter
+ * is the last day of the month that does <em>not</em> 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));
+ }
+}
+
--- /dev/null
+/*
+* 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.</p>
+ *
+ * This class contains just a few specific cases that directly invoke {@link Index},
+ * with minimum overhead.<br/>
+ * Another test: {@link TestIndexFunctionFromSpreadsheet} operates from a higher level
+ * and has far greater coverage of input permutations.<br/>
+ *
+ * @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)".<br/>
+ * 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 <tt>ve</tt> 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.<p/>
+ *
+ * @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 "<blank>";
+ 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<maxRows; rowIndex++) {
+ HSSFRow r = sheet.getRow(rowIndex);
+ if(r == null) {
+ continue;
+ }
+ HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
+ if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
+ continue;
+ }
+ HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
+
+ String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c);
+ try {
+ CellValue actualValue = evaluator.evaluate(c);
+ confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
+ _evaluationSuccessCount ++;
+ if(result != Result.SOME_EVALUATIONS_FAILED) {
+ result = Result.ALL_EVALUATIONS_SUCCEEDED;
+ }
+ } catch (RuntimeException e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e, msgPrefix);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ } catch (AssertionFailedError e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e, msgPrefix);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ }
+ }
+ }
+
+
+ private static String formatTestCaseDetails(String sheetName, int rowIndex, HSSFCell c) {
+
+ StringBuffer sb = new StringBuffer();
+ CellReference cr = new CellReference(sheetName, rowIndex, c.getColumnIndex(), false, false);
+ sb.append(cr.formatAsString());
+ sb.append(" [formula: ").append(c.getCellFormula()).append(" ]");
+ return sb.toString();
+ }
+
+ /**
+ * Useful to keep output concise when expecting many failures to be reported by this test case
+ */
+ private static void printShortStackTrace(PrintStream ps, Throwable e, String msgPrefix) {
+ System.err.println("Problem with " + msgPrefix);
+ StackTraceElement[] stes = e.getStackTrace();
+
+ int startIx = 0;
+ // skip any top frames inside junit.framework.Assert
+ while(startIx<stes.length) {
+ if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
+ break;
+ }
+ startIx++;
+ }
+ // skip bottom frames (part of junit framework)
+ int endIx = startIx+1;
+ while(endIx < stes.length) {
+ if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
+ break;
+ }
+ endIx++;
+ }
+ if(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; i<endIx; i++) {
+ ps.println("\tat " + stes[i].toString());
+ }
+ }
+}
+
--- /dev/null
+/* ====================================================================
+ 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.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+
+/**
+ * Tests for the INDIRECT() function.</p>
+ *
+ * @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() + "'.");
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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));
+
+ }
+
+
+
+
+
+
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.<p/>
+ * 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
+ * (<tt>TestXxxx</tt>) of the target (<tt>Xxxx</tt>) 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 = "<end>";
+ /** Used to indicate that the test on the current row should be ignored */
+ public static final String SKIP_CURRENT_TEST_CASE_MARKER = "<skip>";
+
+ }
+
+ // 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 "<blank>";
+ 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<maxRows; rowIndex++) {
+ HSSFRow r = sheet.getRow(rowIndex);
+ String newMarkerValue = getMarkerColumnValue(r);
+ if(r == null) {
+ continue;
+ }
+ if(SS.TEST_CASES_END_MARKER.equalsIgnoreCase(newMarkerValue)) {
+ // normal exit point
+ return result;
+ }
+ if(SS.SKIP_CURRENT_TEST_CASE_MARKER.equalsIgnoreCase(newMarkerValue)) {
+ // currently disabled test case row
+ continue;
+ }
+ if(newMarkerValue != null) {
+ currentGroupComment = newMarkerValue;
+ }
+ HSSFCell c = r.getCell(SS.COLUMN_INDEX_EVALUATION);
+ if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
+ continue;
+ }
+ CellValue actualValue = evaluator.evaluate(c);
+ HSSFCell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_RESULT);
+ String rowComment = getRowCommentColumnValue(r);
+
+ String msgPrefix = formatTestCaseDetails(sheetName, r.getRowNum(), c, currentGroupComment, rowComment);
+ try {
+ confirmExpectedResult(msgPrefix, expectedValueCell, actualValue);
+ _evaluationSuccessCount ++;
+ if(result != Result.SOME_EVALUATIONS_FAILED) {
+ result = Result.ALL_EVALUATIONS_SUCCEEDED;
+ }
+ } catch (RuntimeException e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ } catch (AssertionFailedError e) {
+ _evaluationFailureCount ++;
+ printShortStackTrace(System.err, e);
+ result = Result.SOME_EVALUATIONS_FAILED;
+ }
+
+ }
+ throw new RuntimeException("Missing end marker '" + SS.TEST_CASES_END_MARKER
+ + "' on sheet '" + sheetName + "'");
+
+ }
+
+
+ private static String formatTestCaseDetails(String sheetName, int rowIndex, HSSFCell c, String currentGroupComment,
+ String rowComment) {
+
+ StringBuffer sb = new StringBuffer();
+ CellReference cr = new CellReference(sheetName, rowIndex, c.getColumnIndex(), false, false);
+ sb.append(cr.formatAsString());
+ sb.append(" {=").append(c.getCellFormula()).append("}");
+
+ if(currentGroupComment != null) {
+ sb.append(" '");
+ sb.append(currentGroupComment);
+ if(rowComment != null) {
+ sb.append(" - ");
+ sb.append(rowComment);
+ }
+ sb.append("' ");
+ } else {
+ if(rowComment != null) {
+ sb.append(" '");
+ sb.append(rowComment);
+ sb.append("' ");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Asserts that the 'read me' comment page exists, and has this class' name in one of the
+ * cells. This back-link is to make it easy to find this class if a reader encounters the
+ * spreadsheet first.
+ */
+ private void confirmReadMeSheet(HSSFWorkbook workbook) {
+ String firstSheetName = workbook.getSheetName(0);
+ if(!firstSheetName.equalsIgnoreCase(SS.README_SHEET_NAME)) {
+ throw new RuntimeException("First sheet's name was '" + firstSheetName + "' but expected '" + SS.README_SHEET_NAME + "'");
+ }
+ HSSFSheet sheet = workbook.getSheetAt(0);
+ String specifiedClassName = sheet.getRow(2).getCell(0).getRichStringCellValue().getString();
+ assertEquals("Test class name in spreadsheet comment", getClass().getName(), specifiedClassName);
+ }
+
+
+ /**
+ * Useful to keep output concise when expecting many failures to be reported by this test case
+ */
+ 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<stes.length) {
+ if(!stes[startIx].getClassName().equals(Assert.class.getName())) {
+ break;
+ }
+ startIx++;
+ }
+ // skip bottom frames (part of junit framework)
+ int endIx = startIx+1;
+ while(endIx < stes.length) {
+ if(stes[endIx].getClassName().equals(TestCase.class.getName())) {
+ break;
+ }
+ endIx++;
+ }
+ if(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; i<endIx; i++) {
+ ps.println("\tat " + stes[i].toString());
+ }
+
+ }
+
+ private static String getRowCommentColumnValue(HSSFRow r) {
+ return getCellTextValue(r, SS.COLUMN_ROW_COMMENT, "row comment");
+ }
+
+ private static String getMarkerColumnValue(HSSFRow r) {
+ return getCellTextValue(r, SS.COLUMN_INDEX_MARKER, "marker");
+ }
+
+ /**
+ * @return <code>null</code> 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) + ")");
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 <tt>AreaEval</tt>.<br/>
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+* 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));
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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));
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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));
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/*
+* 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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));
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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, "");
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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");
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
import junit.framework.TestCase;
-import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.ss.ITestDataProvider;
/**
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;
* 00000010 | 00 00 00 55 50 53 53 74 61 74 65 | ...UPSState
* </pre>
*
- * 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