Finish converting ErrorEval to only use the FormulaError constants, and then finish unit test for 57535

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1658190 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2015-02-08 15:37:14 +00:00
parent d566e3948d
commit 702f8b9ee7
3 changed files with 43 additions and 36 deletions

View File

@ -17,13 +17,17 @@
package org.apache.poi.ss.formula.eval; package org.apache.poi.ss.formula.eval;
import org.apache.poi.ss.usermodel.ErrorConstants; import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ss.usermodel.FormulaError; import org.apache.poi.ss.usermodel.FormulaError;
/** /**
* Evaluations for formula errors * Evaluations for formula errors
*/ */
public final class ErrorEval implements ValueEval { public final class ErrorEval implements ValueEval {
private static final Map<FormulaError,ErrorEval> evals = new HashMap<FormulaError, ErrorEval>();
/** <b>#NULL!</b> - Intersection of two cell ranges is empty */ /** <b>#NULL!</b> - Intersection of two cell ranges is empty */
public static final ErrorEval NULL_INTERSECTION = new ErrorEval(FormulaError.NULL); public static final ErrorEval NULL_INTERSECTION = new ErrorEval(FormulaError.NULL);
/** <b>#DIV/0!</b> - Division by zero */ /** <b>#DIV/0!</b> - Division by zero */
@ -40,29 +44,23 @@ public final class ErrorEval implements ValueEval {
public static final ErrorEval NA = new ErrorEval(FormulaError.NA); public static final ErrorEval NA = new ErrorEval(FormulaError.NA);
// POI internal error codes // POI internal error codes
private static final int CIRCULAR_REF_ERROR_CODE = 0xFFFFFFC4; public static final ErrorEval FUNCTION_NOT_IMPLEMENTED = new ErrorEval(FormulaError.FUNCTION_NOT_IMPLEMENTED);
private static final int FUNCTION_NOT_IMPLEMENTED_CODE = 0xFFFFFFE2;
// Note - Excel does not seem to represent this condition with an error code // Note - Excel does not seem to represent this condition with an error code
public static final ErrorEval CIRCULAR_REF_ERROR = new ErrorEval(CIRCULAR_REF_ERROR_CODE); public static final ErrorEval CIRCULAR_REF_ERROR = new ErrorEval(FormulaError.CIRCULAR_REF);
/** /**
* Translates an Excel internal error code into the corresponding POI ErrorEval instance * Translates an Excel internal error code into the corresponding POI ErrorEval instance
* @param errorCode * @param errorCode
*/ */
public static ErrorEval valueOf(int errorCode) { public static ErrorEval valueOf(int errorCode) {
switch(errorCode) { FormulaError error = FormulaError.forInt(errorCode);
case ErrorConstants.ERROR_NULL: return NULL_INTERSECTION; ErrorEval eval = evals.get(error);
case ErrorConstants.ERROR_DIV_0: return DIV_ZERO; if (eval != null) {
case ErrorConstants.ERROR_VALUE: return VALUE_INVALID; return eval;
case ErrorConstants.ERROR_REF: return REF_INVALID; } else {
case ErrorConstants.ERROR_NAME: return NAME_INVALID; throw new RuntimeException("Unhandled error type " + eval + " for code " + errorCode);
case ErrorConstants.ERROR_NUM: return NUM_ERROR;
case ErrorConstants.ERROR_NA: return NA;
// non-std errors (conditions modelled as errors by POI)
case CIRCULAR_REF_ERROR_CODE: return CIRCULAR_REF_ERROR;
} }
throw new RuntimeException("Unexpected error code (" + errorCode + ")");
} }
/** /**
@ -72,36 +70,28 @@ public final class ErrorEval implements ValueEval {
*/ */
public static String getText(int errorCode) { public static String getText(int errorCode) {
if(FormulaError.isValidCode(errorCode)) { if(FormulaError.isValidCode(errorCode)) {
return FormulaError.forInt((byte)errorCode).getString(); return FormulaError.forInt(errorCode).getString();
}
// It is desirable to make these (arbitrary) strings look clearly different from any other
// value expression that might appear in a formula. In addition these error strings should
// look unlike the standard Excel errors. Hence tilde ('~') was used.
switch(errorCode) {
case CIRCULAR_REF_ERROR_CODE: return "~CIRCULAR~REF~";
case FUNCTION_NOT_IMPLEMENTED_CODE: return "~FUNCTION~NOT~IMPLEMENTED~";
} }
// Give a special string, based on ~, to make clear this isn't a standard Excel error
return "~non~std~err(" + errorCode + ")~"; return "~non~std~err(" + errorCode + ")~";
} }
private int _errorCode; private FormulaError _error;
/**
* @param errorCode an 8-bit value
*/
private ErrorEval(int errorCode) {
_errorCode = errorCode;
}
private ErrorEval(FormulaError error) { private ErrorEval(FormulaError error) {
_errorCode = error.getCode(); _error = error;
evals.put(error, this);
} }
public int getErrorCode() { public int getErrorCode() {
return _errorCode; return _error.getLongCode();
}
public String getErrorString() {
return _error.getString();
} }
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(64); StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" ["); sb.append(getClass().getName()).append(" [");
sb.append(getText(_errorCode)); sb.append(_error.getString());
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();
} }

View File

@ -93,7 +93,23 @@ public enum FormulaError {
* </p> * </p>
* This error value can be produced by calling the function NA * This error value can be produced by calling the function NA
*/ */
NA(0x2A, "#N/A"); NA(0x2A, "#N/A"),
// These are POI-specific error codes
// It is desirable to make these (arbitrary) strings look clearly different from any other
// value expression that might appear in a formula. In addition these error strings should
// look unlike the standard Excel errors. Hence tilde ('~') was used.
/**
* POI specific code to indicate that there is a circular reference
* in the formula
*/
CIRCULAR_REF(0xFFFFFFC4, "~CIRCULAR~REF~"),
/**
* POI specific code to indicate that the funcition required is
* not implemented in POI
*/
FUNCTION_NOT_IMPLEMENTED(0xFFFFFFE2, "~FUNCTION~NOT~IMPLEMENTED~");
private final byte type; private final byte type;
private final int longType; private final int longType;
@ -151,6 +167,7 @@ public enum FormulaError {
} }
public static FormulaError forInt(int type){ public static FormulaError forInt(int type){
FormulaError err = imap.get(type); FormulaError err = imap.get(type);
if(err == null) err = bmap.get((byte)type);
if(err == null) throw new IllegalArgumentException("Unknown error type: " + type); if(err == null) throw new IllegalArgumentException("Unknown error type: " + type);
return err; return err;
} }

View File

@ -2151,7 +2151,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
CellValue value = evaluator.evaluate(cell); CellValue value = evaluator.evaluate(cell);
assertEquals(Cell.CELL_TYPE_ERROR, value.getCellType()); assertEquals(Cell.CELL_TYPE_ERROR, value.getCellType());
assertEquals(-60, value.getErrorValue()); assertEquals(-60, value.getErrorValue());
// TODO Fix this assertEquals("~CIRCULAR~REF~", FormulaError.forInt(value.getErrorValue()).getString());
// assertEquals("", FormulaError.forInt(value.getErrorValue()).toString()); assertEquals("CIRCULAR_REF", FormulaError.forInt(value.getErrorValue()).toString());
} }
} }