From: Yegor Kozlov
Date: Sat, 16 Mar 2013 12:33:08 +0000 (+0000)
Subject: Bug 54673 - [PATCH] Simple wildcard support in HLOOKUP, VOOLKUP, MATCH, COUNTIF
X-Git-Tag: 3.10-beta1~49
X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4d2be808066991482c00b74e1789c1cfcd3701d0;p=poi.git
Bug 54673 - [PATCH] Simple wildcard support in HLOOKUP, VOOLKUP, MATCH, COUNTIF
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1457243 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/src/java/org/apache/poi/ss/formula/functions/Countif.java b/src/java/org/apache/poi/ss/formula/functions/Countif.java
index ef524acde3..9a8a034104 100644
--- a/src/java/org/apache/poi/ss/formula/functions/Countif.java
+++ b/src/java/org/apache/poi/ss/formula/functions/Countif.java
@@ -43,6 +43,7 @@ import org.apache.poi.ss.usermodel.ErrorConstants;
*
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
public final class Countif extends Fixed2ArgFunction {
@@ -309,7 +310,7 @@ public final class Countif extends Fixed2ArgFunction {
return false;
}
}
- private static final class StringMatcher extends MatcherBase {
+ public static final class StringMatcher extends MatcherBase {
private final String _value;
private final Pattern _pattern;
@@ -378,19 +379,19 @@ public final class Countif extends Fixed2ArgFunction {
* Translates Excel countif wildcard strings into java regex strings
* @return null
if the specified value contains no special wildcard characters.
*/
- private static Pattern getWildCardPattern(String value) {
+ public static Pattern getWildCardPattern(String value) {
int len = value.length();
StringBuffer sb = new StringBuffer(len);
boolean hasWildCard = false;
for(int i=0; i
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
public final class Vlookup extends Var3or4ArgFunction {
private static final ValueEval DEFAULT_ARG3 = BoolEval.TRUE;
@@ -47,16 +48,16 @@ public final class Vlookup extends Var3or4ArgFunction {
return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3);
}
- public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
- ValueEval arg2, ValueEval arg3) {
+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval lookup_value, ValueEval table_array,
+ ValueEval col_index, ValueEval range_lookup) {
try {
// Evaluation order:
- // arg0 lookup_value, arg1 table_array, arg3 range_lookup, find lookup value, arg2 col_index, fetch result
- ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
- TwoDEval tableArray = LookupUtils.resolveTableArrayArg(arg1);
- boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcRowIndex, srcColumnIndex);
+ // lookup_value , table_array, range_lookup, find lookup value, col_index, fetch result
+ ValueEval lookupValue = OperandResolver.getSingleValue(lookup_value, srcRowIndex, srcColumnIndex);
+ TwoDEval tableArray = LookupUtils.resolveTableArrayArg(table_array);
+ boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(range_lookup, srcRowIndex, srcColumnIndex);
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
- int colIndex = LookupUtils.resolveRowOrColIndexArg(arg2, srcRowIndex, srcColumnIndex);
+ int colIndex = LookupUtils.resolveRowOrColIndexArg(col_index, srcRowIndex, srcColumnIndex);
ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
return resultCol.getItem(rowIndex);
} catch (EvaluationException e) {
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/BaseTestFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/BaseTestFunctionsFromSpreadsheet.java
new file mode 100644
index 0000000000..920593c83f
--- /dev/null
+++ b/src/testcases/org/apache/poi/ss/formula/functions/BaseTestFunctionsFromSpreadsheet.java
@@ -0,0 +1,360 @@
+/* ====================================================================
+ 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;
+
+/**
+ * @author Josh Micich
+ * @author Cedric Walter at innoveo.com
+ */
+public abstract class BaseTestFunctionsFromSpreadsheet 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) */
+
+
+ /** Name of the first sheet in the spreadsheet (contains comments) */
+ public final static String README_SHEET_NAME = "Read Me";
+
+ /** Row (zero-based) in each sheet where the evaluation cases start. */
+ public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5'
+ /** Index of the column that contains the function names */
+ public static final int COLUMN_INDEX_MARKER = 0; // Column 'A'
+ public static final int COLUMN_INDEX_EVALUATION = 1; // Column 'B'
+ public static final int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C'
+ public static final int COLUMN_ROW_COMMENT = 3; // Column 'D'
+
+ /** Used to indicate when there are no more test cases on the current sheet */
+ public static final String TEST_CASES_END_MARKER = "";
+ /** Used to indicate that the test on the current row should be ignored */
+ public static final String SKIP_CURRENT_TEST_CASE_MARKER = "";
+
+ }
+
+ // Note - multiple failures are aggregated before ending.
+ // If one or more functions fail, a single AssertionFailedError is thrown at the end
+ private int _sheetFailureCount;
+ private int _sheetSuccessCount;
+ private int _evaluationFailureCount;
+ private int _evaluationSuccessCount;
+
+
+
+ private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) {
+ if (expected == null) {
+ throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
+ }
+ if(actual == null) {
+ throw new AssertionFailedError(msg + " - actual value was null");
+ }
+ if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
+ confirmErrorResult(msg, expected.getErrorCellValue(), actual);
+ return;
+ }
+ if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
+ throw unexpectedError(msg, expected, actual.getErrorValue());
+ }
+ if(actual.getCellType() != expected.getCellType()) {
+ throw wrongTypeError(msg, expected, actual);
+ }
+
+
+ switch (expected.getCellType()) {
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
+ break;
+ case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
+ throw new IllegalStateException("Cannot expect formula as result of formula evaluation: " + msg);
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
+ break;
+ case HSSFCell.CELL_TYPE_STRING:
+ assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
+ break;
+ }
+ }
+
+
+ private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
+ return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
+ + actualValue.formatAsString()
+ + " but the expected result was "
+ + formatValue(expectedCell)
+ );
+ }
+ private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
+ return new AssertionFailedError(msgPrefix + " Error code ("
+ + ErrorEval.getText(actualErrorCode)
+ + ") was evaluated, but the expected result was "
+ + formatValue(expected)
+ );
+ }
+
+
+ private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
+ if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
+ throw new AssertionFailedError(msgPrefix + " Expected cell error ("
+ + ErrorEval.getText(expectedErrorCode) + ") but actual value was "
+ + actual.formatAsString());
+ }
+ if(expectedErrorCode != actual.getErrorValue()) {
+ throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
+ + ErrorEval.getText(expectedErrorCode)
+ + ") but actual error code was ("
+ + ErrorEval.getText(actual.getErrorValue())
+ + ")");
+ }
+ }
+
+
+ private static String formatValue(HSSFCell expecedCell) {
+ switch (expecedCell.getCellType()) {
+ case HSSFCell.CELL_TYPE_BLANK: return "";
+ case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue());
+ case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue());
+ case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString();
+ }
+ throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
+ }
+
+
+ protected void setUp() {
+ _sheetFailureCount = 0;
+ _sheetSuccessCount = 0;
+ _evaluationFailureCount = 0;
+ _evaluationSuccessCount = 0;
+ }
+
+ public void testFunctionsFromTestSpreadsheet() {
+ HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(this.getFilename());
+
+ 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);
+ }
+ }
+
+ protected abstract String getFilename();
+
+ private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) {
+ HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook);
+ int maxRows = sheet.getLastRowNum()+1;
+ int result = Result.NO_EVALUATIONS_FOUND; // so far
+
+ String currentGroupComment = null;
+ for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex= endIx) {
+ // something went wrong. just print the whole stack trace
+ e.printStackTrace(ps);
+ }
+ endIx -= 4; // skip 4 frames of reflection invocation
+ ps.println(e.toString());
+ for(int i=startIx; inull if cell is missing, empty or blank
+ */
+ private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) {
+ if(r == null) {
+ return null;
+ }
+ HSSFCell cell = r.getCell(colIndex);
+ if(cell == null) {
+ return null;
+ }
+ if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
+ return null;
+ }
+ if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
+ return cell.getRichStringCellValue().getString();
+ }
+
+ throw new RuntimeException("Bad cell type for '" + columnName + "' column: ("
+ + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
+ }
+
+}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java b/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java
index 2d340ad8f1..02992fc5db 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestCountFuncs.java
@@ -43,6 +43,7 @@ import org.apache.poi.ss.util.CellReference;
* Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
public final class TestCountFuncs extends TestCase {
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java
index c2978435a1..6d900e1ef4 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestIndexFunctionFromSpreadsheet.java
@@ -17,234 +17,16 @@
package org.apache.poi.ss.formula.functions;
-import java.io.PrintStream;
-
-import junit.framework.Assert;
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
-import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.ss.formula.eval.ErrorEval;
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.CellReference;
-import org.apache.poi.ss.usermodel.CellValue;
-
/**
* Tests INDEX() as loaded from a test data spreadsheet.
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
-public final class TestIndexFunctionFromSpreadsheet extends TestCase {
-
- private static final class Result {
- public static final int SOME_EVALUATIONS_FAILED = -1;
- public static final int ALL_EVALUATIONS_SUCCEEDED = +1;
- public static final int NO_EVALUATIONS_FOUND = 0;
- }
-
- /**
- * This class defines constants for navigating around the test data spreadsheet used for these tests.
- */
- private static final class SS {
-
- /** Name of the test spreadsheet (found in the standard test data folder) */
- public final static String FILENAME = "IndexFunctionTestCaseData.xls";
-
- public static final int COLUMN_INDEX_EVALUATION = 2; // Column 'C'
- public static final int COLUMN_INDEX_EXPECTED_RESULT = 3; // Column 'D'
-
- }
-
- // Note - multiple failures are aggregated before ending.
- // If one or more functions fail, a single AssertionFailedError is thrown at the end
- private int _evaluationFailureCount;
- private int _evaluationSuccessCount;
-
-
-
- private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) {
- if (expected == null) {
- throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
- }
- if(actual == null) {
- throw new AssertionFailedError(msg + " - actual value was null");
- }
- if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
- confirmErrorResult(msg, expected.getErrorCellValue(), actual);
- return;
- }
- if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
- throw unexpectedError(msg, expected, actual.getErrorValue());
- }
- if(actual.getCellType() != expected.getCellType()) {
- throw wrongTypeError(msg, expected, actual);
- }
-
-
- switch (expected.getCellType()) {
- case HSSFCell.CELL_TYPE_BOOLEAN:
- assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
- break;
- case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
- throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
- case HSSFCell.CELL_TYPE_NUMERIC:
- assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
- break;
- case HSSFCell.CELL_TYPE_STRING:
- assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
- break;
- }
- }
-
-
- private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
- return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
- + actualValue.formatAsString()
- + " but the expected result was "
- + formatValue(expectedCell)
- );
- }
- private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
- return new AssertionFailedError(msgPrefix + " Error code ("
- + ErrorEval.getText(actualErrorCode)
- + ") was evaluated, but the expected result was "
- + formatValue(expected)
- );
- }
-
-
- private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
- if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error ("
- + ErrorEval.getText(expectedErrorCode) + ") but actual value was "
- + actual.formatAsString());
- }
- if(expectedErrorCode != actual.getErrorValue()) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
- + ErrorEval.getText(expectedErrorCode)
- + ") but actual error code was ("
- + ErrorEval.getText(actual.getErrorValue())
- + ")");
- }
- }
-
-
- private static String formatValue(HSSFCell expecedCell) {
- switch (expecedCell.getCellType()) {
- case HSSFCell.CELL_TYPE_BLANK: return "";
- case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue());
- case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue());
- case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString();
- }
- throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
- }
-
-
- protected void setUp() {
- _evaluationFailureCount = 0;
- _evaluationSuccessCount = 0;
- }
-
- public void testFunctionsFromTestSpreadsheet() {
- HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
-
- processTestSheet(workbook, workbook.getSheetName(0));
-
- // confirm results
- String successMsg = "There were "
- + _evaluationSuccessCount + " function(s) without error";
- if(_evaluationFailureCount > 0) {
- String msg = _evaluationFailureCount + " evaluation(s) failed. " + successMsg;
- throw new AssertionFailedError(msg);
- }
- if(false) { // normally no output for successful tests
- System.out.println(getClass().getName() + ": " + successMsg);
- }
- }
-
- private void processTestSheet(HSSFWorkbook workbook, String sheetName) {
- HSSFSheet sheet = workbook.getSheetAt(0);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook);
- int maxRows = sheet.getLastRowNum()+1;
- int result = Result.NO_EVALUATIONS_FOUND; // so far
-
- for(int rowIndex=0; rowIndex= endIx) {
- // something went wrong. just print the whole stack trace
- e.printStackTrace(ps);
- }
- endIx -= 4; // skip 4 frames of reflection invocation
- ps.println(e.toString());
- for(int i=startIx; i
@@ -43,323 +29,12 @@ import org.apache.poi.ss.usermodel.CellValue;
* more easily.
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
-public final class TestLookupFunctionsFromSpreadsheet extends TestCase {
-
- private static final class Result {
- public static final int SOME_EVALUATIONS_FAILED = -1;
- public static final int ALL_EVALUATIONS_SUCCEEDED = +1;
- public static final int NO_EVALUATIONS_FOUND = 0;
- }
-
- /**
- * This class defines constants for navigating around the test data spreadsheet used for these tests.
- */
- private static final class SS {
-
- /** Name of the test spreadsheet (found in the standard test data folder) */
- public final static String FILENAME = "LookupFunctionsTestCaseData.xls";
-
- /** Name of the first sheet in the spreadsheet (contains comments) */
- public final static String README_SHEET_NAME = "Read Me";
-
-
- /** Row (zero-based) in each sheet where the evaluation cases start. */
- public static final int START_TEST_CASES_ROW_INDEX = 4; // Row '5'
- /** Index of the column that contains the function names */
- public static final int COLUMN_INDEX_MARKER = 0; // Column 'A'
- public static final int COLUMN_INDEX_EVALUATION = 1; // Column 'B'
- public static final int COLUMN_INDEX_EXPECTED_RESULT = 2; // Column 'C'
- public static final int COLUMN_ROW_COMMENT = 3; // Column 'D'
-
- /** Used to indicate when there are no more test cases on the current sheet */
- public static final String TEST_CASES_END_MARKER = "";
- /** Used to indicate that the test on the current row should be ignored */
- public static final String SKIP_CURRENT_TEST_CASE_MARKER = "";
-
- }
-
- // Note - multiple failures are aggregated before ending.
- // If one or more functions fail, a single AssertionFailedError is thrown at the end
- private int _sheetFailureCount;
- private int _sheetSuccessCount;
- private int _evaluationFailureCount;
- private int _evaluationSuccessCount;
-
-
-
- private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) {
- if (expected == null) {
- throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
- }
- if(actual == null) {
- throw new AssertionFailedError(msg + " - actual value was null");
- }
- if(expected.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
- confirmErrorResult(msg, expected.getErrorCellValue(), actual);
- return;
- }
- if(actual.getCellType() == HSSFCell.CELL_TYPE_ERROR) {
- throw unexpectedError(msg, expected, actual.getErrorValue());
- }
- if(actual.getCellType() != expected.getCellType()) {
- throw wrongTypeError(msg, expected, actual);
- }
-
-
- switch (expected.getCellType()) {
- case HSSFCell.CELL_TYPE_BOOLEAN:
- assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
- break;
- case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
- throw new IllegalStateException("Cannot expect formula as result of formula evaluation: " + msg);
- case HSSFCell.CELL_TYPE_NUMERIC:
- assertEquals(expected.getNumericCellValue(), actual.getNumberValue(), 0.0);
- break;
- case HSSFCell.CELL_TYPE_STRING:
- assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getStringValue());
- break;
- }
- }
-
-
- private static AssertionFailedError wrongTypeError(String msgPrefix, HSSFCell expectedCell, CellValue actualValue) {
- return new AssertionFailedError(msgPrefix + " Result type mismatch. Evaluated result was "
- + actualValue.formatAsString()
- + " but the expected result was "
- + formatValue(expectedCell)
- );
- }
- private static AssertionFailedError unexpectedError(String msgPrefix, HSSFCell expected, int actualErrorCode) {
- return new AssertionFailedError(msgPrefix + " Error code ("
- + ErrorEval.getText(actualErrorCode)
- + ") was evaluated, but the expected result was "
- + formatValue(expected)
- );
- }
-
-
- private static void confirmErrorResult(String msgPrefix, int expectedErrorCode, CellValue actual) {
- if(actual.getCellType() != HSSFCell.CELL_TYPE_ERROR) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error ("
- + ErrorEval.getText(expectedErrorCode) + ") but actual value was "
- + actual.formatAsString());
- }
- if(expectedErrorCode != actual.getErrorValue()) {
- throw new AssertionFailedError(msgPrefix + " Expected cell error code ("
- + ErrorEval.getText(expectedErrorCode)
- + ") but actual error code was ("
- + ErrorEval.getText(actual.getErrorValue())
- + ")");
- }
- }
-
-
- private static String formatValue(HSSFCell expecedCell) {
- switch (expecedCell.getCellType()) {
- case HSSFCell.CELL_TYPE_BLANK: return "";
- case HSSFCell.CELL_TYPE_BOOLEAN: return String.valueOf(expecedCell.getBooleanCellValue());
- case HSSFCell.CELL_TYPE_NUMERIC: return String.valueOf(expecedCell.getNumericCellValue());
- case HSSFCell.CELL_TYPE_STRING: return expecedCell.getRichStringCellValue().getString();
- }
- throw new RuntimeException("Unexpected cell type of expected value (" + expecedCell.getCellType() + ")");
- }
-
-
- protected void setUp() {
- _sheetFailureCount = 0;
- _sheetSuccessCount = 0;
- _evaluationFailureCount = 0;
- _evaluationSuccessCount = 0;
- }
-
- public void testFunctionsFromTestSpreadsheet() {
- HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook(SS.FILENAME);
-
- confirmReadMeSheet(workbook);
- int nSheets = workbook.getNumberOfSheets();
- for(int i=1; i< nSheets; i++) {
- int sheetResult = processTestSheet(workbook, i, workbook.getSheetName(i));
- switch(sheetResult) {
- case Result.ALL_EVALUATIONS_SUCCEEDED: _sheetSuccessCount ++; break;
- case Result.SOME_EVALUATIONS_FAILED: _sheetFailureCount ++; break;
- }
- }
-
- // confirm results
- String successMsg = "There were "
- + _sheetSuccessCount + " successful sheets(s) and "
- + _evaluationSuccessCount + " function(s) without error";
- if(_sheetFailureCount > 0) {
- String msg = _sheetFailureCount + " sheets(s) failed with "
- + _evaluationFailureCount + " evaluation(s). " + successMsg;
- throw new AssertionFailedError(msg);
- }
- if(false) { // normally no output for successful tests
- System.out.println(getClass().getName() + ": " + successMsg);
- }
- }
-
- private int processTestSheet(HSSFWorkbook workbook, int sheetIndex, String sheetName) {
- HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(workbook);
- int maxRows = sheet.getLastRowNum()+1;
- int result = Result.NO_EVALUATIONS_FOUND; // so far
-
- String currentGroupComment = null;
- for(int rowIndex=SS.START_TEST_CASES_ROW_INDEX; rowIndex= endIx) {
- // something went wrong. just print the whole stack trace
- e.printStackTrace(ps);
- }
- endIx -= 4; // skip 4 frames of reflection invocation
- ps.println(e.toString());
- for(int i=startIx; inull if cell is missing, empty or blank
- */
- private static String getCellTextValue(HSSFRow r, int colIndex, String columnName) {
- if(r == null) {
- return null;
- }
- HSSFCell cell = r.getCell(colIndex);
- if(cell == null) {
- return null;
- }
- if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
- return null;
- }
- if(cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
- return cell.getRichStringCellValue().getString();
- }
+public final class TestLookupFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
- throw new RuntimeException("Bad cell type for '" + columnName + "' column: ("
- + cell.getCellType() + ") row (" + (r.getRowNum() +1) + ")");
- }
+ @Override
+ protected String getFilename() {
+ return "LookupFunctionsTestCaseData.xls";
+ }
}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java
index f9fdab6a79..ee6e45c1fa 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMatch.java
@@ -19,6 +19,8 @@ package org.apache.poi.ss.formula.functions;
import junit.framework.TestCase;
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
@@ -26,11 +28,13 @@ 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;
+import org.apache.poi.ss.usermodel.CellValue;
/**
* Test cases for MATCH()
*
* @author Josh Micich
+ * @author Cedric Walter at innoveo.com
*/
public final class TestMatch extends TestCase {
/** less than or equal to */
@@ -93,7 +97,7 @@ public final class TestMatch extends TestCase {
}
public void testSimpleString() {
-
+ // Arrange
ValueEval[] values = {
new StringEval("Albert"),
new StringEval("Charles"),
@@ -109,10 +113,52 @@ public final class TestMatch extends TestCase {
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 testSimpleWildcardValuesString() {
+ // Arrange
+ 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("e*"), ae, MATCH_EXACT));
+ confirmInt(3, invokeMatch(new StringEval("*d"), ae, MATCH_EXACT));
+
+ confirmInt(1, invokeMatch(new StringEval("Al*"), ae, MATCH_EXACT));
+ confirmInt(2, invokeMatch(new StringEval("Char*"), ae, MATCH_EXACT));
+
+ confirmInt(4, invokeMatch(new StringEval("*eg"), ae, MATCH_EXACT));
+ confirmInt(4, invokeMatch(new StringEval("G?eg"), ae, MATCH_EXACT));
+ confirmInt(4, invokeMatch(new StringEval("??eg"), ae, MATCH_EXACT));
+ confirmInt(4, invokeMatch(new StringEval("G*?eg"), ae, MATCH_EXACT));
+ confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
+
+ confirmInt(5, invokeMatch(new StringEval("*Ian*"), ae, MATCH_EXACT));
+ confirmInt(5, invokeMatch(new StringEval("*Ian*"), ae, MATCH_LARGEST_LTE));
+ }
+
+ public void testTildeString() {
+
+ ValueEval[] values = {
+ new StringEval("what?"),
+ new StringEval("all*")
+ };
+
+ AreaEval ae = EvalFactory.createAreaEval("A1:A2", values);
+
+ confirmInt(1, invokeMatch(new StringEval("what~?"), ae, MATCH_EXACT));
+ confirmInt(2, invokeMatch(new StringEval("all~*"), ae, MATCH_EXACT));
+ }
+
public void testSimpleBoolean() {
ValueEval[] values = {
@@ -159,11 +205,17 @@ public final class TestMatch extends TestCase {
confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT));
+ //wildcard values
+ confirmInt(8, invokeMatch(new StringEval("CHAR*"), 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(13, invokeMatch(new StringEval("ED*"), ae, MATCH_LARGEST_LTE));
+ confirmInt(13, invokeMatch(new StringEval("*ED"), ae, MATCH_LARGEST_LTE));
confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT));
+ 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));
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMatchFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMatchFunctionsFromSpreadsheet.java
new file mode 100644
index 0000000000..7fcb1fa13b
--- /dev/null
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMatchFunctionsFromSpreadsheet.java
@@ -0,0 +1,40 @@
+/* ====================================================================
+ 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;
+
+
+
+/**
+ * Tests lookup functions (VLOOKUP, HLOOKUP, LOOKUP, MATCH) as loaded from a test data spreadsheet.
+ * These tests have been separated from the common function and operator tests because the lookup
+ * functions have more complex test cases and test data setup.
+ *
+ * Tests for bug fixes and specific/tricky behaviour can be found in the corresponding test class
+ * (TestXxxx) of the target (Xxxx) implementor, where execution can be observed
+ * more easily.
+ *
+ * @author Josh Micich
+ * @author Cedric Walter at innoveo.com
+ */
+public final class TestMatchFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
+
+ @Override
+ protected String getFilename() {
+ return "MatchFunctionTestCaseData.xls";
+ }
+}
diff --git a/test-data/spreadsheet/IndexFunctionTestCaseData.xls b/test-data/spreadsheet/IndexFunctionTestCaseData.xls
index d1de304576..64df3ecd86 100644
Binary files a/test-data/spreadsheet/IndexFunctionTestCaseData.xls and b/test-data/spreadsheet/IndexFunctionTestCaseData.xls differ
diff --git a/test-data/spreadsheet/LookupFunctionsTestCaseData.xls b/test-data/spreadsheet/LookupFunctionsTestCaseData.xls
index ea7fad9f3d..56b6f12a00 100644
Binary files a/test-data/spreadsheet/LookupFunctionsTestCaseData.xls and b/test-data/spreadsheet/LookupFunctionsTestCaseData.xls differ
diff --git a/test-data/spreadsheet/MatchFunctionTestCaseData.xls b/test-data/spreadsheet/MatchFunctionTestCaseData.xls
new file mode 100644
index 0000000000..0b98a17713
Binary files /dev/null and b/test-data/spreadsheet/MatchFunctionTestCaseData.xls differ