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