poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n...@apache.org
Subject svn commit: r1613654 - in /poi/trunk: src/ooxml/testcases/org/apache/poi/xssf/usermodel/ src/testcases/org/apache/poi/ss/formula/eval/ test-data/spreadsheet/
Date Sat, 26 Jul 2014 15:20:07 GMT
Author: nick
Date: Sat Jul 26 15:20:06 2014
New Revision: 1613654

URL: http://svn.apache.org/r1613654
Log:
HSSF and XSSF Multi-Sheet formula reference tests from Radoslav from bug #55906

Added:
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestMultiSheetEval.java
    poi/trunk/test-data/spreadsheet/FormulaSheetRange.xls
    poi/trunk/test-data/spreadsheet/FormulaSheetRange.xlsx
Modified:
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java?rev=1613654&r1=1613653&r2=1613654&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
(original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
Sat Jul 26 15:20:06 2014
@@ -31,6 +31,7 @@ import org.junit.runners.Suite;
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
     TestFormulaEvaluatorOnXSSF.class,
+    TestMultiSheetFormulaEvaluatorOnXSSF.class,
     TestSheetHiding.class,
     TestXSSFBugs.class,
     TestXSSFDataFormat.class,

Added: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java?rev=1613654&view=auto
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
(added)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiSheetFormulaEvaluatorOnXSSF.java
Sat Jul 26 15:20:06 2014
@@ -0,0 +1,334 @@
+/* ====================================================================
+   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) + ")");
+	}
+	
+}

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java?rev=1613654&r1=1613653&r2=1613654&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
(original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java
Sat Jul 26 15:20:06 2014
@@ -287,4 +287,49 @@ public final class TestXSSFFormulaEvalua
             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());
+	}
 }

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestMultiSheetEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestMultiSheetEval.java?rev=1613654&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestMultiSheetEval.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/eval/TestMultiSheetEval.java Sat Jul
26 15:20:06 2014
@@ -0,0 +1,331 @@
+/* ====================================================================
+   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) + ")");
+	}
+	
+}

Added: poi/trunk/test-data/spreadsheet/FormulaSheetRange.xls
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/FormulaSheetRange.xls?rev=1613654&view=auto
==============================================================================
Files poi/trunk/test-data/spreadsheet/FormulaSheetRange.xls (added) and poi/trunk/test-data/spreadsheet/FormulaSheetRange.xls
Sat Jul 26 15:20:06 2014 differ

Added: poi/trunk/test-data/spreadsheet/FormulaSheetRange.xlsx
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/FormulaSheetRange.xlsx?rev=1613654&view=auto
==============================================================================
Files poi/trunk/test-data/spreadsheet/FormulaSheetRange.xlsx (added) and poi/trunk/test-data/spreadsheet/FormulaSheetRange.xlsx
Sat Jul 26 15:20:06 2014 differ



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message