mirror of https://github.com/apache/poi.git
Make a start on running all the formula tests for xssf. Currently not enabled, as many fail, but provides a start
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@642741 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ca402c4911
commit
4bf50d5901
|
@ -45,9 +45,16 @@ public class BoolErrRecord
|
||||||
private short field_3_xf_index;
|
private short field_3_xf_index;
|
||||||
private byte field_4_bBoolErr;
|
private byte field_4_bBoolErr;
|
||||||
private byte field_5_fError;
|
private byte field_5_fError;
|
||||||
|
|
||||||
|
public static final byte NULL = 0;
|
||||||
|
public static final byte DIV0 = 7;
|
||||||
|
public static final byte VALUE = 15;
|
||||||
|
public static final byte REF = 23;
|
||||||
|
public static final byte NAME = 29;
|
||||||
|
public static final byte NUM = 36;
|
||||||
|
public static final byte NA = 42;
|
||||||
|
|
||||||
/** Creates new BoolErrRecord */
|
/** Creates new BoolErrRecord */
|
||||||
|
|
||||||
public BoolErrRecord()
|
public BoolErrRecord()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.poi.xssf.usermodel;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.BoolErrRecord;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
|
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
|
@ -139,12 +140,47 @@ public class XSSFCell implements Cell {
|
||||||
throw new NumberFormatException("You cannot get a date value from a cell of type " + this.cell.getT());
|
throw new NumberFormatException("You cannot get a date value from a cell of type " + this.cell.getT());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the error message, such as #VALUE!
|
||||||
|
*/
|
||||||
|
public String getErrorCellString() {
|
||||||
|
if (STCellType.E != cell.getT()) {
|
||||||
|
throw new NumberFormatException("You cannot get a error value from a non-error cell");
|
||||||
|
}
|
||||||
|
if (this.cell.isSetV()) {
|
||||||
|
return this.cell.getV();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the error type, in the same way that
|
||||||
|
* HSSFCell does. See {@link BoolErrRecord} for details
|
||||||
|
*/
|
||||||
public byte getErrorCellValue() {
|
public byte getErrorCellValue() {
|
||||||
if (STCellType.E != cell.getT()) {
|
if (STCellType.E != cell.getT()) {
|
||||||
throw new NumberFormatException("You cannot get a error value from a non-error cell");
|
throw new NumberFormatException("You cannot get a error value from a non-error cell");
|
||||||
}
|
}
|
||||||
if (this.cell.isSetV()) {
|
if (this.cell.isSetV()) {
|
||||||
return Byte.parseByte(this.cell.getV());
|
String errS = this.cell.getV();
|
||||||
|
if(errS.equals("#NULL!")) {
|
||||||
|
return BoolErrRecord.NULL;
|
||||||
|
}
|
||||||
|
if(errS.equals("#DIV/0!")) {
|
||||||
|
return BoolErrRecord.DIV0;
|
||||||
|
}
|
||||||
|
if(errS.equals("#VALUE!")) {
|
||||||
|
return BoolErrRecord.VALUE;
|
||||||
|
}
|
||||||
|
if(errS.equals("#REF!")) {
|
||||||
|
return BoolErrRecord.REF;
|
||||||
|
}
|
||||||
|
if(errS.equals("#NAME?")) {
|
||||||
|
return BoolErrRecord.NAME;
|
||||||
|
}
|
||||||
|
if(errS.equals("#NUM!")) {
|
||||||
|
return BoolErrRecord.NUM;
|
||||||
|
}
|
||||||
|
return BoolErrRecord.NA;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,341 @@
|
||||||
|
/*
|
||||||
|
* 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.PrintStream;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.TestFormulasFromSpreadsheet;
|
||||||
|
import org.apache.poi.hssf.record.formula.functions.TestMathX;
|
||||||
|
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;
|
||||||
|
import org.openxml4j.opc.Package;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs much the same role as {@link TestFormulasFromSpreadsheet},
|
||||||
|
* except for a XSSF spreadsheet, not a HSSF one.
|
||||||
|
* This allows us to check that all our Formula Evaluation code
|
||||||
|
* is able to work for XSSF, as well as for HSSF.
|
||||||
|
*
|
||||||
|
* Periodically, you should open FormulaEvalTestData.xls in
|
||||||
|
* Excel 2007, and re-save it as FormulaEvalTestData_Copy.xlsx
|
||||||
|
*
|
||||||
|
* Currently disabled, as doesn't work
|
||||||
|
*/
|
||||||
|
public final class TestFormulaEvaluatorOnXSSF 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_Copy.xlsx";
|
||||||
|
/**
|
||||||
|
* 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 = 87; // Row '88'
|
||||||
|
/**
|
||||||
|
* Index of the column that contains the function names
|
||||||
|
*/
|
||||||
|
public static final short 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 Workbook 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, short columnIndex) {
|
||||||
|
if (row == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return row.getCell(columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void confirmExpectedResult(String msg, Cell expected, FormulaEvaluator.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() == Cell.CELL_TYPE_STRING) {
|
||||||
|
String value = expected.getRichStringCellValue().getString();
|
||||||
|
if (value.startsWith("#")) {
|
||||||
|
// TODO - this code never called
|
||||||
|
expected.setCellType(Cell.CELL_TYPE_ERROR);
|
||||||
|
// expected.setCellErrorValue(...?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getRichTextStringValue().getString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
if (workbook == null) {
|
||||||
|
String filePath = System.getProperty("HSSF.testdata.path")+ "/" + SS.FILENAME;
|
||||||
|
Package pkg = Package.open(filePath);
|
||||||
|
workbook = new XSSFWorkbook( pkg );
|
||||||
|
sheet = workbook.getSheetAt( 0 );
|
||||||
|
}
|
||||||
|
_functionFailureCount = 0;
|
||||||
|
_functionSuccessCount = 0;
|
||||||
|
_evaluationFailureCount = 0;
|
||||||
|
_evaluationSuccessCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that we can actually open the file
|
||||||
|
*/
|
||||||
|
public void testOpen() {
|
||||||
|
assertNotNull(workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disabled for now, as many things seem to break
|
||||||
|
* for XSSF, which is a shame
|
||||||
|
*/
|
||||||
|
public void DISABLEDtestFunctionsFromTestSpreadsheet() {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
FormulaEvaluator evaluator = new FormulaEvaluator(sheet, 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(FormulaEvaluator evaluator, String targetFunctionName,
|
||||||
|
Row formulasRow, Row expectedValuesRow) {
|
||||||
|
|
||||||
|
int result = Result.NO_EVALUATIONS_FOUND; // so far
|
||||||
|
short endcolnum = formulasRow.getLastCellNum();
|
||||||
|
evaluator.setCurrentRow(formulasRow);
|
||||||
|
|
||||||
|
// iterate across the row for all the evaluation cases
|
||||||
|
for (short 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormulaEvaluator.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) + ")");
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -25,13 +25,12 @@ import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.formula.functions.TestMathX;
|
import org.apache.poi.hssf.record.formula.functions.TestMathX;
|
||||||
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.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
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;;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests formulas and operators as loaded from a test data spreadsheet.<p/>
|
* Tests formulas and operators as loaded from a test data spreadsheet.<p/>
|
||||||
|
@ -89,8 +88,8 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4;
|
public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HSSFWorkbook workbook;
|
private Workbook workbook;
|
||||||
private HSSFSheet sheet;
|
private Sheet sheet;
|
||||||
// Note - multiple failures are aggregated before ending.
|
// Note - multiple failures are aggregated before ending.
|
||||||
// If one or more functions fail, a single AssertionFailedError is thrown at the end
|
// If one or more functions fail, a single AssertionFailedError is thrown at the end
|
||||||
private int _functionFailureCount;
|
private int _functionFailureCount;
|
||||||
|
@ -98,7 +97,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
private int _evaluationFailureCount;
|
private int _evaluationFailureCount;
|
||||||
private int _evaluationSuccessCount;
|
private int _evaluationSuccessCount;
|
||||||
|
|
||||||
private static final HSSFCell getExpectedValueCell(HSSFRow row, short columnIndex) {
|
private static final Cell getExpectedValueCell(Row row, short columnIndex) {
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -114,40 +113,40 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
throw new AssertionFailedError(msg + " - actual value was null");
|
throw new AssertionFailedError(msg + " - actual value was null");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expected.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
if (expected.getCellType() == Cell.CELL_TYPE_STRING) {
|
||||||
String value = expected.getRichStringCellValue().getString();
|
String value = expected.getRichStringCellValue().getString();
|
||||||
if (value.startsWith("#")) {
|
if (value.startsWith("#")) {
|
||||||
// TODO - this code never called
|
// TODO - this code never called
|
||||||
expected.setCellType(HSSFCell.CELL_TYPE_ERROR);
|
expected.setCellType(Cell.CELL_TYPE_ERROR);
|
||||||
// expected.setCellErrorValue(...?);
|
// expected.setCellErrorValue(...?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (expected.getCellType()) {
|
switch (expected.getCellType()) {
|
||||||
case HSSFCell.CELL_TYPE_BLANK:
|
case Cell.CELL_TYPE_BLANK:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_BLANK, actual.getCellType());
|
assertEquals(msg, Cell.CELL_TYPE_BLANK, actual.getCellType());
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_BOOLEAN:
|
case Cell.CELL_TYPE_BOOLEAN:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_BOOLEAN, actual.getCellType());
|
assertEquals(msg, Cell.CELL_TYPE_BOOLEAN, actual.getCellType());
|
||||||
assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
|
assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_ERROR:
|
case Cell.CELL_TYPE_ERROR:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType());
|
assertEquals(msg, Cell.CELL_TYPE_ERROR, actual.getCellType());
|
||||||
if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
|
if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
|
||||||
assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
|
assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
|
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);
|
throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
|
||||||
case HSSFCell.CELL_TYPE_NUMERIC:
|
case Cell.CELL_TYPE_NUMERIC:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType());
|
assertEquals(msg, Cell.CELL_TYPE_NUMERIC, actual.getCellType());
|
||||||
TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
|
TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
|
||||||
// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
|
// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
|
||||||
// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
|
// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
|
||||||
// assertTrue(msg, delta <= pctExpected);
|
// assertTrue(msg, delta <= pctExpected);
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_STRING:
|
case Cell.CELL_TYPE_STRING:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType());
|
assertEquals(msg, Cell.CELL_TYPE_STRING, actual.getCellType());
|
||||||
assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
|
assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -196,11 +195,11 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
*/
|
*/
|
||||||
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
|
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
|
||||||
|
|
||||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
|
FormulaEvaluator evaluator = new FormulaEvaluator(sheet, workbook);
|
||||||
|
|
||||||
int rowIndex = startRowIndex;
|
int rowIndex = startRowIndex;
|
||||||
while (true) {
|
while (true) {
|
||||||
HSSFRow r = sheet.getRow(rowIndex);
|
Row r = sheet.getRow(rowIndex);
|
||||||
String targetFunctionName = getTargetFunctionName(r);
|
String targetFunctionName = getTargetFunctionName(r);
|
||||||
if(targetFunctionName == null) {
|
if(targetFunctionName == null) {
|
||||||
throw new AssertionFailedError("Test spreadsheet cell empty on row ("
|
throw new AssertionFailedError("Test spreadsheet cell empty on row ("
|
||||||
|
@ -214,7 +213,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
|
if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
|
||||||
|
|
||||||
// expected results are on the row below
|
// expected results are on the row below
|
||||||
HSSFRow expectedValuesRow = sheet.getRow(rowIndex + 1);
|
Row expectedValuesRow = sheet.getRow(rowIndex + 1);
|
||||||
if(expectedValuesRow == null) {
|
if(expectedValuesRow == null) {
|
||||||
int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
|
int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
|
||||||
throw new AssertionFailedError("Missing expected values row for function '"
|
throw new AssertionFailedError("Missing expected values row for function '"
|
||||||
|
@ -237,8 +236,8 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
* @return a constant from the local Result class denoting whether there were any evaluation
|
* @return a constant from the local Result class denoting whether there were any evaluation
|
||||||
* cases, and whether they all succeeded.
|
* cases, and whether they all succeeded.
|
||||||
*/
|
*/
|
||||||
private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName,
|
private int processFunctionRow(FormulaEvaluator evaluator, String targetFunctionName,
|
||||||
HSSFRow formulasRow, HSSFRow expectedValuesRow) {
|
Row formulasRow, Row expectedValuesRow) {
|
||||||
|
|
||||||
int result = Result.NO_EVALUATIONS_FOUND; // so far
|
int result = Result.NO_EVALUATIONS_FOUND; // so far
|
||||||
short endcolnum = formulasRow.getLastCellNum();
|
short endcolnum = formulasRow.getLastCellNum();
|
||||||
|
@ -246,14 +245,14 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
|
|
||||||
// iterate across the row for all the evaluation cases
|
// iterate across the row for all the evaluation cases
|
||||||
for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
|
for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
|
||||||
HSSFCell c = formulasRow.getCell(colnum);
|
Cell c = formulasRow.getCell(colnum);
|
||||||
if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
|
if (c == null || c.getCellType() != Cell.CELL_TYPE_FORMULA) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormulaEvaluator.CellValue actualValue = evaluator.evaluate(c);
|
FormulaEvaluator.CellValue actualValue = evaluator.evaluate(c);
|
||||||
|
|
||||||
HSSFCell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum);
|
Cell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum);
|
||||||
try {
|
try {
|
||||||
confirmExpectedResult("Function '" + targetFunctionName + "': Formula: " + c.getCellFormula() + " @ " + formulasRow.getRowNum() + ":" + colnum,
|
confirmExpectedResult("Function '" + targetFunctionName + "': Formula: " + c.getCellFormula() + " @ " + formulasRow.getRowNum() + ":" + colnum,
|
||||||
expectedValueCell, actualValue);
|
expectedValueCell, actualValue);
|
||||||
|
@ -307,20 +306,20 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
/**
|
/**
|
||||||
* @return <code>null</code> if cell is missing, empty or blank
|
* @return <code>null</code> if cell is missing, empty or blank
|
||||||
*/
|
*/
|
||||||
private static String getTargetFunctionName(HSSFRow r) {
|
private static String getTargetFunctionName(Row r) {
|
||||||
if(r == null) {
|
if(r == null) {
|
||||||
System.err.println("Warning - given null row, can't figure out function name");
|
System.err.println("Warning - given null row, can't figure out function name");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
HSSFCell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME);
|
Cell cell = r.getCell(SS.COLUMN_INDEX_FUNCTION_NAME);
|
||||||
if(cell == null) {
|
if(cell == null) {
|
||||||
System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name");
|
System.err.println("Warning - Row " + r.getRowNum() + " has no cell " + SS.COLUMN_INDEX_FUNCTION_NAME + ", can't figure out function name");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
|
if(cell.getCellType() == Cell.CELL_TYPE_BLANK) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
if(cell.getCellType() == Cell.CELL_TYPE_STRING) {
|
||||||
return cell.getRichStringCellValue().getString();
|
return cell.getRichStringCellValue().getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue