mirror of https://github.com/apache/poi.git
[bug-65467] support IFNA() function. Thanks to Ross Patterson
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1891876 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1b527ceca5
commit
cd7b6b7197
|
@ -80,7 +80,7 @@ public final class AnalysisToolPak implements UDFFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, FreeRefFunction> createFunctionsMap() {
|
private Map<String, FreeRefFunction> createFunctionsMap() {
|
||||||
Map<String, FreeRefFunction> m = new HashMap<>(108);
|
Map<String, FreeRefFunction> m = new HashMap<>(127);
|
||||||
|
|
||||||
r(m, "ACCRINT", null);
|
r(m, "ACCRINT", null);
|
||||||
r(m, "ACCRINTM", null);
|
r(m, "ACCRINTM", null);
|
||||||
|
@ -136,6 +136,7 @@ public final class AnalysisToolPak implements UDFFinder {
|
||||||
r(m, "HEX2DEC", Hex2Dec.instance);
|
r(m, "HEX2DEC", Hex2Dec.instance);
|
||||||
r(m, "HEX2OCT", null);
|
r(m, "HEX2OCT", null);
|
||||||
r(m, "IFERROR", IfError.instance);
|
r(m, "IFERROR", IfError.instance);
|
||||||
|
r(m, "IFNA", IfNa.instance);
|
||||||
r(m, "IFS", Ifs.instance);
|
r(m, "IFS", Ifs.instance);
|
||||||
r(m, "IMABS", null);
|
r(m, "IMABS", null);
|
||||||
r(m, "IMAGINARY", Imaginary.instance);
|
r(m, "IMAGINARY", Imaginary.instance);
|
||||||
|
@ -260,7 +261,7 @@ public final class AnalysisToolPak implements UDFFinder {
|
||||||
FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByName(name);
|
FunctionMetadata metaData = FunctionMetadataRegistry.getFunctionByName(name);
|
||||||
if(metaData != null) {
|
if(metaData != null) {
|
||||||
throw new IllegalArgumentException(name + " is a built-in Excel function. " +
|
throw new IllegalArgumentException(name + " is a built-in Excel function. " +
|
||||||
"Use FunctoinEval.registerFunction(String name, Function func) instead.");
|
"Use FunctionEval.registerFunction(String name, Function func) instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(name + " is not a function from the Excel Analysis Toolpack.");
|
throw new IllegalArgumentException(name + " is not a function from the Excel Analysis Toolpack.");
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.atp;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
||||||
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
|
import org.apache.poi.ss.formula.eval.EvaluationException;
|
||||||
|
import org.apache.poi.ss.formula.eval.OperandResolver;
|
||||||
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
|
import org.apache.poi.ss.formula.functions.FreeRefFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of 'Analysis Toolpak' the Excel function IFNA()
|
||||||
|
*
|
||||||
|
* <b>Syntax</b>:<br>
|
||||||
|
* <b>IFNA</b>(<b>test_value</b>,<b>default_value</b>)<p>
|
||||||
|
*
|
||||||
|
* <b>test_value</b> The value to be tested<br>
|
||||||
|
* <b>default_value</b> The value to be tested<br>
|
||||||
|
* <br>
|
||||||
|
* Returns {@code default_value} if {@code test_value} is '#N/A', {@code test_value} otherwise.
|
||||||
|
*/
|
||||||
|
public final class IfNa implements FreeRefFunction {
|
||||||
|
|
||||||
|
public static final FreeRefFunction instance = new IfNa();
|
||||||
|
|
||||||
|
private IfNa() {
|
||||||
|
// Enforce singleton
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
|
||||||
|
if (args.length != 2) {
|
||||||
|
return ErrorEval.VALUE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec.getColumnIndex());
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
ValueEval error = e.getErrorEval();
|
||||||
|
if (error != ErrorEval.NA) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return OperandResolver.getSingleValue(args[1], ec.getRowIndex(), ec.getColumnIndex());
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -163,7 +163,7 @@ class TestFunctionRegistry {
|
||||||
() -> AnalysisToolPak.registerFunction("SUM", TestFunctionRegistry::atpFunc)
|
() -> AnalysisToolPak.registerFunction("SUM", TestFunctionRegistry::atpFunc)
|
||||||
);
|
);
|
||||||
assertEquals("SUM is a built-in Excel function. " +
|
assertEquals("SUM is a built-in Excel function. " +
|
||||||
"Use FunctoinEval.registerFunction(String name, Function func) instead.",
|
"Use FunctionEval.registerFunction(String name, Function func) instead.",
|
||||||
ex.getMessage());
|
ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.atp;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IfNa unit tests.
|
||||||
|
*/
|
||||||
|
class TestIfna {
|
||||||
|
|
||||||
|
HSSFWorkbook wb;
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFFormulaEvaluator fe;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
wb = new HSSFWorkbook();
|
||||||
|
cell = wb.createSheet().createRow(0).createCell(0);
|
||||||
|
fe = new HSSFFormulaEvaluator(wb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNumbericArgsWorkCorrectly() {
|
||||||
|
confirmResult(fe, cell, "IFNA(-1,42)", new CellValue(-1.0));
|
||||||
|
confirmResult(fe, cell, "IFNA(NA(),42)", new CellValue(42.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStringArgsWorkCorrectly() {
|
||||||
|
confirmResult(fe, cell, "IFNA(\"a1\",\"a2\")", new CellValue("a1"));
|
||||||
|
confirmResult(fe, cell, "IFNA(NA(),\"a2\")", new CellValue("a2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUsageErrorsThrowErrors() {
|
||||||
|
confirmError(fe, cell, "IFNA(1)", ErrorEval.VALUE_INVALID);
|
||||||
|
confirmError(fe, cell, "IFNA(1,2,3)", ErrorEval.VALUE_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testErrorInArgSelectsNAResult() {
|
||||||
|
confirmError(fe, cell, "IFNA(1/0,42)", ErrorEval.DIV_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testErrorFromNAArgPassesThrough() {
|
||||||
|
confirmError(fe, cell, "IFNA(NA(),1/0)", ErrorEval.DIV_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNaArgNotEvaledIfUnneeded() {
|
||||||
|
confirmResult(fe, cell, "IFNA(42,1/0)", new CellValue(42.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
|
||||||
|
CellValue expectedResult) {
|
||||||
|
fe.setDebugEvaluationOutputForNextEval(true);
|
||||||
|
cell.setCellFormula(formulaText);
|
||||||
|
fe.notifyUpdateCell(cell);
|
||||||
|
CellValue result = fe.evaluate(cell);
|
||||||
|
assertEquals(expectedResult.getCellType(), result.getCellType(), "Testing result type for: " + formulaText);
|
||||||
|
assertEquals(expectedResult.formatAsString(), result.formatAsString(), "Testing result for: " + formulaText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
|
||||||
|
ErrorEval expectedError) {
|
||||||
|
fe.setDebugEvaluationOutputForNextEval(true);
|
||||||
|
cell.setCellFormula(formulaText);
|
||||||
|
fe.notifyUpdateCell(cell);
|
||||||
|
CellValue result = fe.evaluate(cell);
|
||||||
|
assertEquals(CellType.ERROR, result.getCellType(), "Testing result type for: " + formulaText);
|
||||||
|
assertEquals(expectedError.getErrorString(), result.formatAsString(), "Testing error type for: " + formulaText);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for IFNA function as loaded from a test data spreadsheet.<p>
|
||||||
|
*/
|
||||||
|
class TestIfnaFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
|
||||||
|
|
||||||
|
public static Stream<Arguments> data() throws Exception {
|
||||||
|
return data(TestIfnaFromSpreadsheet.class, "IfNaTestCaseData.xls");
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in New Issue