@RunWith(Suite.class)
@Suite.SuiteClasses({
TestFormulaEvaluatorOnXSSF.class,
+ TestMultiSheetFormulaEvaluatorOnXSSF.class,
TestSheetHiding.class,
TestXSSFBugs.class,
TestXSSFDataFormat.class,
--- /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.xssf.usermodel;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Collection;
+
+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.TestFormulasFromSpreadsheet;
+import org.apache.poi.ss.formula.functions.TestMathX;
+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.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Tests formulas for multi sheet reference (i.e. SUM(Sheet1:Sheet5!A1))
+ */
+public final class TestMultiSheetFormulaEvaluatorOnXSSF extends TestCase {
+ private static final POILogger logger = POILogFactory.getLogger(TestFormulasFromSpreadsheet.class);
+
+ 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 = "FormulaSheetRange.xlsx";
+ /**
+ * Row (zero-based) in the test spreadsheet where the function examples start.
+ */
+ public static final int START_FUNCTIONS_ROW_INDEX = 10; // Row '11'
+ /**
+ * Index of the column that contains the function names
+ */
+ public static final int COLUMN_INDEX_FUNCTION_NAME = 0; // Column 'A'
+ /**
+ * Index of the column that contains the test names
+ */
+ public static final int COLUMN_INDEX_TEST_NAME = 1; // Column 'B'
+ /**
+ * Used to indicate when there are no more functions left
+ */
+ public static final String FUNCTION_NAMES_END_SENTINEL = "<END>";
+
+ /**
+ * Index of the column where the test expected value is present
+ */
+ public static final short COLUMN_INDEX_EXPECTED_VALUE = 2; // Column 'C'
+ /**
+ * Index of the column where the test actual value is present
+ */
+ public static final short COLUMN_INDEX_ACTUAL_VALUE = 3; // Column 'D'
+ /**
+ * Test sheet name (sheet with all test formulae)
+ */
+ public static final String TEST_SHEET_NAME = "test";
+ }
+
+ private XSSFWorkbook 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 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());
+ if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
+ assertEquals(msg, expected.getErrorCellValue(), 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);
+// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
+// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
+// assertTrue(msg, delta <= pctExpected);
+ 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() throws Exception {
+ if (workbook == null) {
+ InputStream is = HSSFTestDataSamples.openSampleFileStream(SS.FILENAME);
+ OPCPackage pkg = OPCPackage.open(is);
+ workbook = new XSSFWorkbook( pkg );
+ sheet = workbook.getSheet( SS.TEST_SHEET_NAME );
+ }
+ _functionFailureCount = 0;
+ _functionSuccessCount = 0;
+ _evaluationFailureCount = 0;
+ _evaluationSuccessCount = 0;
+ }
+
+ public void testFunctionsFromTestSpreadsheet() {
+
+ processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
+
+ // 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);
+ }
+ logger.log(POILogger.INFO, 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) {
+ FormulaEvaluator evaluator = new XSSFFormulaEvaluator(workbook);
+
+ int rowIndex = startRowIndex;
+ while (true) {
+ Row r = sheet.getRow(rowIndex);
+
+ // only evaluate non empty row
+ if( r != null )
+ {
+ String targetFunctionName = getTargetFunctionName(r);
+ String targetTestName = getTargetTestName(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
+ Cell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_VALUE);
+ if(expectedValueCell == null) {
+ int missingRowNum = rowIndex + 1;
+ throw new AssertionFailedError("Missing expected values cell for function '"
+ + targetFunctionName + ", test" + targetTestName + " (row " +
+ missingRowNum + ")");
+ }
+
+ switch(processFunctionRow(evaluator, targetFunctionName, targetTestName, r, expectedValueCell)) {
+ 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
+ break;
+ }
+ }
+ }
+ rowIndex ++;
+ }
+ }
+
+ /**
+ *
+ * @return a constant from the local Result class denoting whether there were any evaluation
+ * cases, and whether they all succeeded.
+ */
+ private int processFunctionRow(FormulaEvaluator evaluator, String targetFunctionName,
+ String targetTestName, Row formulasRow, Cell expectedValueCell) {
+
+ int result = Result.NO_EVALUATIONS_FOUND; // so far
+
+ Cell c = formulasRow.getCell(SS.COLUMN_INDEX_ACTUAL_VALUE);
+ if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) {
+ return result;
+ }
+
+ CellValue actualValue = evaluator.evaluate(c);
+
+ try {
+ confirmExpectedResult("Function '" + targetFunctionName + "': Test: '" + targetTestName + "' Formula: " + c.getCellFormula()
+ + " @ " + formulasRow.getRowNum() + ":" + SS.COLUMN_INDEX_ACTUAL_VALUE,
+ 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) + ")");
+ }
+ /**
+ * @return <code>null</code> if cell is missing, empty or blank
+ */
+ private static String getTargetTestName(Row r) {
+ if(r == null) {
+ System.err.println("Warning - given null row, can't figure out test name");
+ return null;
+ }
+ Cell cell = r.getCell(SS.COLUMN_INDEX_TEST_NAME);
+ if(cell == null) {
+ System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_TEST_NAME + ", can't figure out test 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 'test name' column: ("
+ + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
+ }
+
+}
assertEquals("4.0", evaluator.evaluate(countFA).formatAsString());
}
}
+
+ public void testMultisheetFormulaEval() {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ XSSFSheet sheet1 = wb.createSheet("Sheet1");
+ XSSFSheet sheet2 = wb.createSheet("Sheet2");
+ XSSFSheet sheet3 = wb.createSheet("Sheet3");
+
+ // sheet1 A1
+ XSSFCell cell = sheet1.createRow(0).createCell(0);
+ cell.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell.setCellValue(1.0);
+
+ // sheet2 A1
+ cell = sheet2.createRow(0).createCell(0);
+ cell.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell.setCellValue(1.0);
+
+ // sheet2 B1
+ cell = sheet2.getRow(0).createCell(1);
+ cell.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell.setCellValue(1.0);
+
+ // sheet3 A1
+ cell = sheet3.createRow(0).createCell(0);
+ cell.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell.setCellValue(1.0);
+
+ // sheet1 A2 formulae
+ cell = sheet1.createRow(1).createCell(0);
+ cell.setCellType(Cell.CELL_TYPE_FORMULA);
+ cell.setCellFormula("SUM(Sheet1:Sheet3!A1)");
+
+ // sheet1 A3 formulae
+ cell = sheet1.createRow(2).createCell(0);
+ cell.setCellType(Cell.CELL_TYPE_FORMULA);
+ cell.setCellFormula("SUM(Sheet1:Sheet3!A1:B1)");
+
+ wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
+
+ cell = sheet1.getRow(1).getCell(0);
+ assertEquals(3.0, cell.getNumericCellValue());
+
+ cell = sheet1.getRow(2).getCell(0);
+ assertEquals(4.0, cell.getNumericCellValue());
+ }
}
--- /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 java.util.Collection;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.functions.TestMathX;
+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;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Tests formulas for multi sheet reference (i.e. SUM(Sheet1:Sheet5!A1))
+ */
+public final class TestMultiSheetEval extends TestCase {
+ private static final POILogger logger = POILogFactory.getLogger(TestFormulasFromSpreadsheet.class);
+
+ 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 = "FormulaSheetRange.xls";
+ /**
+ * Row (zero-based) in the test spreadsheet where the function examples start.
+ */
+ public static final int START_FUNCTIONS_ROW_INDEX = 10; // Row '11'
+ /**
+ * Index of the column that contains the function names
+ */
+ public static final int COLUMN_INDEX_FUNCTION_NAME = 0; // Column 'A'
+ /**
+ * Index of the column that contains the test names
+ */
+ public static final int COLUMN_INDEX_TEST_NAME = 1; // Column 'B'
+ /**
+ * Used to indicate when there are no more functions left
+ */
+ public static final String FUNCTION_NAMES_END_SENTINEL = "<END>";
+
+ /**
+ * Index of the column where the test expected value is present
+ */
+ public static final short COLUMN_INDEX_EXPECTED_VALUE = 2; // Column 'C'
+ /**
+ * Index of the column where the test actual value is present
+ */
+ public static final short COLUMN_INDEX_ACTUAL_VALUE = 3; // Column 'D'
+ /**
+ * Test sheet name (sheet with all test formulae)
+ */
+ public static final String TEST_SHEET_NAME = "test";
+ }
+
+ 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 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.getSheet( SS.TEST_SHEET_NAME );
+ }
+ _functionFailureCount = 0;
+ _functionSuccessCount = 0;
+ _evaluationFailureCount = 0;
+ _evaluationSuccessCount = 0;
+ }
+
+ public void testFunctionsFromTestSpreadsheet() {
+
+ processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
+
+ // 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);
+ }
+ logger.log(POILogger.INFO, 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);
+ Collection<String> funcs = FunctionEval.getSupportedFunctionNames();
+
+ int rowIndex = startRowIndex;
+ while (true) {
+ Row r = sheet.getRow(rowIndex);
+
+ // only evaluate non empty row
+ if( r != null )
+ {
+ String targetFunctionName = getTargetFunctionName(r);
+ String targetTestName = getTargetTestName(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
+ Cell expectedValueCell = r.getCell(SS.COLUMN_INDEX_EXPECTED_VALUE);
+ if(expectedValueCell == null) {
+ int missingRowNum = rowIndex + 1;
+ throw new AssertionFailedError("Missing expected values cell for function '"
+ + targetFunctionName + ", test" + targetTestName + " (row " +
+ missingRowNum + ")");
+ }
+
+ switch(processFunctionRow(evaluator, targetFunctionName, targetTestName, r, expectedValueCell)) {
+ 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
+ String uname = targetFunctionName.toUpperCase();
+ if(startRowIndex >= SS.START_FUNCTIONS_ROW_INDEX &&
+ funcs.contains(uname)) {
+ logger.log(POILogger.WARN, uname + ": function is supported but missing test data");
+ }
+ break;
+ }
+ }
+ }
+ rowIndex ++;
+ }
+ }
+
+ /**
+ *
+ * @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,
+ String targetTestName, Row formulasRow, Cell expectedValueCell) {
+
+ int result = Result.NO_EVALUATIONS_FOUND; // so far
+
+ Cell c = formulasRow.getCell(SS.COLUMN_INDEX_ACTUAL_VALUE);
+ if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) {
+ return result;
+ }
+
+ CellValue actualValue = evaluator.evaluate(c);
+
+ try {
+ confirmExpectedResult("Function '" + targetFunctionName + "': Test: '" + targetTestName + "' Formula: " + c.getCellFormula()
+ + " @ " + formulasRow.getRowNum() + ":" + SS.COLUMN_INDEX_ACTUAL_VALUE,
+ 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) + ")");
+ }
+ /**
+ * @return <code>null</code> if cell is missing, empty or blank
+ */
+ private static String getTargetTestName(Row r) {
+ if(r == null) {
+ System.err.println("Warning - given null row, can't figure out test name");
+ return null;
+ }
+ Cell cell = r.getCell(SS.COLUMN_INDEX_TEST_NAME);
+ if(cell == null) {
+ System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_TEST_NAME + ", can't figure out test 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 'test name' column: ("
+ + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
+ }
+
+}