import java.util.Stack;
//import PTGs .. since we need everything, import *
+import org.apache.poi.hssf.record.UnicodeString;
+import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.record.formula.*;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public static final int FORMULA_TYPE_ARRAY =2;
public static final int FORMULA_TYPE_CONDFORMAT = 3;
public static final int FORMULA_TYPE_NAMEDRANGE = 4;
- // this constant is currently very specific. The exact differences from general data
+ // this constant is currently very specific. The exact differences from general data
// validation formulas or conditional format formulas is not known yet
- public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
+ public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
private final String formulaString;
private final int formulaLength;
/** Report What Was Expected */
private RuntimeException expected(String s) {
String msg;
-
+
if (look == '=' && formulaString.substring(0, pointer-1).trim().length() < 1) {
- msg = "The specified formula '" + formulaString
+ msg = "The specified formula '" + formulaString
+ "' starts with an equals sign which is not allowed.";
} else {
msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
/**
* Parses a sheet name, named range name, or simple cell reference.<br/>
* Note - identifiers in Excel can contain dots, so this method may return a String
- * which may need to be converted to an area reference. For example, this method
- * may return a value like "A1..B2", in which case the caller must convert it to
+ * which may need to be converted to an area reference. For example, this method
+ * may return a value like "A1..B2", in which case the caller must convert it to
* an area reference like "A1:B2"
*/
private String parseIdentifier() {
}
private Ptg parseNameOrReference(String name) {
-
+
AreaReference areaRef = parseArea(name);
if (areaRef != null) {
// will happen if dots are used instead of colon
private ParseNode function(String name) {
Ptg nameToken = null;
if(!AbstractFunctionPtg.isBuiltInFunctionName(name)) {
- // user defined function
+ // user defined function
// in the token tree, the name is more or less the first argument
-
-
- int nameIndex = book.getNameIndex(name);
- if (nameIndex >= 0) {
- HSSFName hName = book.getNameAt(nameIndex);
- if (!hName.isFunctionName()) {
- throw new FormulaParseException("Attempt to use name '" + name
- + "' as a function, but defined name in workbook does not refer to a function");
- }
-
- // calls to user-defined functions within the workbook
- // get a Name token which points to a defined name record
- nameToken = new NamePtg(name, this.book);
- } else {
-
- nameToken = book.getNameXPtg(name);
- if (nameToken == null) {
- throw new FormulaParseException("Name '" + name
- + "' is completely unknown in the current workbook");
- }
- }
+
+
+ int nameIndex = book.getNameIndex(name);
+ if (nameIndex >= 0) {
+ HSSFName hName = book.getNameAt(nameIndex);
+ if (!hName.isFunctionName()) {
+ throw new FormulaParseException("Attempt to use name '" + name
+ + "' as a function, but defined name in workbook does not refer to a function");
+ }
+
+ // calls to user-defined functions within the workbook
+ // get a Name token which points to a defined name record
+ nameToken = new NamePtg(name, this.book);
+ } else {
+
+ nameToken = book.getNameXPtg(name);
+ if (nameToken == null) {
+ throw new FormulaParseException("Name '" + name
+ + "' is completely unknown in the current workbook");
+ }
+ }
}
Match('(');
SkipWhite();
switch(look) {
case '#':
- return new ParseNode(parseErrorLiteral());
+ return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
case '-':
Match('-');
return new ParseNode(UnaryMinusPtg.instance, powerFactor());
Match(')');
return new ParseNode(ParenthesisPtg.instance, inside);
case '"':
- return new ParseNode(parseStringLiteral());
+ return new ParseNode(new StringPtg(parseStringLiteral()));
+ case '{':
+ Match('{');
+ ParseNode arrayNode = parseArray();
+ Match('}');
+ return arrayNode;
}
if (IsAlpha(look) || look == '\''){
return parseFunctionReferenceOrName();
}
+ private ParseNode parseArray() {
+ List rowsData = new ArrayList();
+ while(true) {
+ Object[] singleRowData = parseArrayRow();
+ rowsData.add(singleRowData);
+ if (look == '}') {
+ break;
+ }
+ if (look != ';') {
+ throw expected("'}' or ';'");
+ }
+ Match(';');
+ }
+ int nRows = rowsData.size();
+ Object[][] values2d = new Object[nRows][];
+ rowsData.toArray(values2d);
+ int nColumns = values2d[0].length;
+ checkRowLengths(values2d, nColumns);
+
+ return new ParseNode(new ArrayPtg(values2d));
+ }
+ private void checkRowLengths(Object[][] values2d, int nColumns) {
+ for (int i = 0; i < values2d.length; i++) {
+ int rowLen = values2d[i].length;
+ if (rowLen != nColumns) {
+ throw new FormulaParseException("Array row " + i + " has length " + rowLen
+ + " but row 0 has length " + nColumns);
+ }
+ }
+ }
+
+ private Object[] parseArrayRow() {
+ List temp = new ArrayList();
+ while (true) {
+ temp.add(parseArrayItem());
+ SkipWhite();
+ switch(look) {
+ case '}':
+ case ';':
+ break;
+ case ',':
+ Match(',');
+ continue;
+ default:
+ throw expected("'}' or ','");
+
+ }
+ break;
+ }
+
+ Object[] result = new Object[temp.size()];
+ temp.toArray(result);
+ return result;
+ }
+
+ private Object parseArrayItem() {
+ SkipWhite();
+ switch(look) {
+ case '"': return new UnicodeString(parseStringLiteral());
+ case '#': return ErrorConstant.valueOf(parseErrorLiteral());
+ case 'F': case 'f':
+ case 'T': case 't':
+ return parseBooleanLiteral();
+ }
+ // else assume number
+ return convertArrayNumber(parseNumber());
+ }
+
+ private Boolean parseBooleanLiteral() {
+ String iden = parseIdentifier();
+ if ("TRUE".equalsIgnoreCase(iden)) {
+ return Boolean.TRUE;
+ }
+ if ("FALSE".equalsIgnoreCase(iden)) {
+ return Boolean.FALSE;
+ }
+ throw expected("'TRUE' or 'FALSE'");
+ }
+
+ private static Double convertArrayNumber(Ptg ptg) {
+ if (ptg instanceof IntPtg) {
+ return new Double(((IntPtg)ptg).getValue());
+ }
+ if (ptg instanceof NumberPtg) {
+ return new Double(((NumberPtg)ptg).getValue());
+ }
+ throw new RuntimeException("Unexpected ptg (" + ptg.getClass().getName() + ")");
+ }
+
private Ptg parseNumber() {
String number2 = null;
String exponent = null;
}
- private ErrPtg parseErrorLiteral() {
+ private int parseErrorLiteral() {
Match('#');
String part1 = parseIdentifier().toUpperCase();
case 'V':
if(part1.equals("VALUE")) {
Match('!');
- return ErrPtg.VALUE_INVALID;
+ return HSSFErrorConstants.ERROR_VALUE;
}
throw expected("#VALUE!");
case 'R':
if(part1.equals("REF")) {
Match('!');
- return ErrPtg.REF_INVALID;
+ return HSSFErrorConstants.ERROR_REF;
}
throw expected("#REF!");
case 'D':
Match('/');
Match('0');
Match('!');
- return ErrPtg.DIV_ZERO;
+ return HSSFErrorConstants.ERROR_DIV_0;
}
throw expected("#DIV/0!");
case 'N':
if(part1.equals("NAME")) {
Match('?'); // only one that ends in '?'
- return ErrPtg.NAME_INVALID;
+ return HSSFErrorConstants.ERROR_NAME;
}
if(part1.equals("NUM")) {
Match('!');
- return ErrPtg.NUM_ERROR;
+ return HSSFErrorConstants.ERROR_NUM;
}
if(part1.equals("NULL")) {
Match('!');
- return ErrPtg.NULL_INTERSECTION;
+ return HSSFErrorConstants.ERROR_NULL;
}
if(part1.equals("N")) {
Match('/');
}
Match(look);
// Note - no '!' or '?' suffix
- return ErrPtg.N_A;
+ return HSSFErrorConstants.ERROR_NA;
}
throw expected("#NAME?, #NUM!, #NULL! or #N/A");
}
- private StringPtg parseStringLiteral() {
+ private String parseStringLiteral() {
Match('"');
StringBuffer token = new StringBuffer();
token.append(look);
GetChar();
}
- return new StringPtg(token.toString());
+ return token.toString();
}
/** Parse and Translate a Math Term */
}
return result;
}
-
+
private static String[] getOperands(Stack stack, int nOperands) {
String[] operands = new String[nOperands];
+ _formulaType + ") not supported yet");
}
- transformNode(rootNode, rootNodeOperandClass, false, false);
+ transformNode(rootNode, rootNodeOperandClass, false);
}
/**
* the function return value).
*/
private void transformNode(ParseNode node, byte desiredOperandClass,
- boolean callerForceArrayFlag, boolean isDirectChildOfValueOperator) {
+ boolean callerForceArrayFlag) {
Ptg token = node.getToken();
ParseNode[] children = node.getChildren();
+ boolean isSimpleValueFunc = isSimpleValueFunction(token);
+
+ if (isSimpleValueFunc) {
+ boolean localForceArray = desiredOperandClass == Ptg.CLASS_ARRAY;
+ for (int i = 0; i < children.length; i++) {
+ transformNode(children[i], desiredOperandClass, localForceArray);
+ }
+ setSimpleValueFuncClass((AbstractFunctionPtg) token, desiredOperandClass, callerForceArrayFlag);
+ return;
+ }
+
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
// Value Operator Ptgs and Control are base tokens, so token will be unchanged
-
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
+
+ // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
+ // All direct operands of value operators that are initially 'R' type will
+ // be converted to 'V' type.
+ byte localDesiredOperandClass = desiredOperandClass == Ptg.CLASS_REF ? Ptg.CLASS_VALUE : desiredOperandClass;
for (int i = 0; i < children.length; i++) {
- ParseNode child = children[i];
- transformNode(child, desiredOperandClass, callerForceArrayFlag, true);
+ transformNode(children[i], localDesiredOperandClass, callerForceArrayFlag);
}
return;
}
if (token instanceof AbstractFunctionPtg) {
- transformFunctionNode((AbstractFunctionPtg) token, children, desiredOperandClass,
- callerForceArrayFlag);
+ transformFunctionNode((AbstractFunctionPtg) token, children, desiredOperandClass, callerForceArrayFlag);
return;
}
if (children.length > 0) {
// nothing to do
return;
}
- if (isDirectChildOfValueOperator) {
- // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
- // All direct operands of value operators that are initially 'R' type will
- // be converted to 'V' type.
- if (token.getPtgClass() == Ptg.CLASS_REF) {
- token.setClass(Ptg.CLASS_VALUE);
+ token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
+ }
+
+ private static boolean isSimpleValueFunction(Ptg token) {
+ if (token instanceof AbstractFunctionPtg) {
+ AbstractFunctionPtg aptg = (AbstractFunctionPtg) token;
+ if (aptg.getDefaultOperandClass() != Ptg.CLASS_VALUE) {
+ return false;
+ }
+ int numberOfOperands = aptg.getNumberOfOperands();
+ for (int i=numberOfOperands-1; i>=0; i--) {
+ if (aptg.getParameterClass(i) != Ptg.CLASS_VALUE) {
+ return false;
+ }
}
+ return true;
}
- token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
+ return false;
}
private byte transformClass(byte currentOperandClass, byte desiredOperandClass,
switch (defaultReturnOperandClass) {
case Ptg.CLASS_REF:
afp.setClass(Ptg.CLASS_REF);
+// afp.setClass(Ptg.CLASS_ARRAY);
break;
case Ptg.CLASS_VALUE:
afp.setClass(Ptg.CLASS_ARRAY);
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
byte paramOperandClass = afp.getParameterClass(i);
- transformNode(child, paramOperandClass, localForceArrayFlag, false);
+ transformNode(child, paramOperandClass, localForceArrayFlag);
+ }
+ }
+
+ private void setSimpleValueFuncClass(AbstractFunctionPtg afp,
+ byte desiredOperandClass, boolean callerForceArrayFlag) {
+
+ if (callerForceArrayFlag || desiredOperandClass == Ptg.CLASS_ARRAY) {
+ afp.setClass(Ptg.CLASS_ARRAY);
+ } else {
+ afp.setClass(Ptg.CLASS_VALUE);
}
}
}
* (not including the data which comes after all formula tokens)
*/
public static final int PLAIN_TOKEN_SIZE = 1+RESERVED_FIELD_LEN;
+
+ private static final byte[] DEFAULT_RESERVED_DATA = new byte[RESERVED_FIELD_LEN];
+
// TODO - fix up field visibility and subclasses
- private byte[] field_1_reserved;
+ private final byte[] field_1_reserved;
// data from these fields comes after the Ptg data of all tokens in current formula
private short token_1_columns;
field_1_reserved[i] = in.readByte();
}
}
- public Object[] getTokenArrayValues() {
- return (Object[]) token_3_arrayValues.clone();
+ /**
+ * @param values2d array values arranged in rows
+ */
+ public ArrayPtg(Object[][] values2d) {
+ int nColumns = values2d[0].length;
+ int nRows = values2d.length;
+ // convert 2-d to 1-d array (row by row according to getValueIndex())
+ token_1_columns = (short) nColumns;
+ token_2_rows = (short) nRows;
+
+ Object[] vv = new Object[token_1_columns * token_2_rows];
+ for (int r=0; r<nRows; r++) {
+ Object[] rowData = values2d[r];
+ for (int c=0; c<nColumns; c++) {
+ vv[getValueIndex(c, r)] = rowData[c];
+ }
+ }
+
+ token_3_arrayValues = vv;
+ field_1_reserved = DEFAULT_RESERVED_DATA;
+ }
+ /**
+ * @return 2-d array (inner index is rowIx, outer index is colIx)
+ */
+ public Object[][] getTokenArrayValues() {
+ if (token_3_arrayValues == null) {
+ throw new IllegalStateException("array values not read yet");
+ }
+ Object[][] result = new Object[token_2_rows][token_1_columns];
+ for (int r = 0; r < token_2_rows; r++) {
+ Object[] rowData = result[r];
+ for (int c = 0; c < token_1_columns; c++) {
+ rowData[c] = token_3_arrayValues[getValueIndex(c, r)];
+ }
+ }
+ return result;
}
public boolean isBaseToken() {
token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
+ public String toString() {
+ StringBuffer sb = new StringBuffer("[ArrayPtg]\n");
- buffer.append("columns = ").append(getColumnCount()).append("\n");
- buffer.append("rows = ").append(getRowCount()).append("\n");
+ sb.append("nRows = ").append(getRowCount()).append("\n");
+ sb.append("nCols = ").append(getColumnCount()).append("\n");
if (token_3_arrayValues == null) {
- buffer.append(" #values#uninitialised#\n");
+ sb.append(" #values#uninitialised#\n");
} else {
- for (int x=0;x<getColumnCount();x++) {
- for (int y=0;y<getRowCount();y++) {
- Object o = token_3_arrayValues[getValueIndex(x, y)];
- buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
- }
- }
+ sb.append(" ").append(formatAsString());
}
- return buffer.toString();
+ return sb.toString();
}
/**
- * Note - (2D) array elements are stored column by column
+ * Note - (2D) array elements are stored row by row
* @return the index into the internal 1D array for the specified column and row
*/
/* package */ int getValueIndex(int colIx, int rowIx) {
throw new IllegalArgumentException("Specified rowIx (" + rowIx
+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
}
- return rowIx + token_2_rows * colIx;
+ return rowIx * token_1_columns + colIx;
}
public void writeBytes(byte[] data, int offset) {
+ ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
- public String toFormulaString(HSSFWorkbook book)
- {
+ public String formatAsString() {
StringBuffer b = new StringBuffer();
b.append("{");
- for (int x=0;x<getColumnCount();x++) {
- if (x > 0) {
+ for (int y=0;y<getRowCount();y++) {
+ if (y > 0) {
b.append(";");
}
- for (int y=0;y<getRowCount();y++) {
- if (y > 0) {
+ for (int x=0;x<getColumnCount();x++) {
+ if (x > 0) {
b.append(",");
}
Object o = token_3_arrayValues[getValueIndex(x, y)];
b.append("}");
return b.toString();
}
+ public String toFormulaString(HSSFWorkbook book) {
+ return formatAsString();
+ }
private static String getConstantText(Object o) {
if (o == null) {
- return ""; // TODO - how is 'empty value' represented in formulas?
+ throw new RuntimeException("Array item cannot be null");
}
if (o instanceof UnicodeString) {
return "\"" + ((UnicodeString)o).getString() + "\"";
public byte getDefaultOperandClass() {
return Ptg.CLASS_ARRAY;
}
-
- public Object clone() {
- ArrayPtg ptg = (ArrayPtg) super.clone();
- ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
- ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
- return ptg;
- }
}
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public final class ErrPtg extends ScalarConstantPtg {
-
+
// convenient access to namespace
private static final HSSFErrorConstants EC = null;
-
+
/** <b>#NULL!</b> - Intersection of two cell ranges is empty */
- public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL);
+ public static final ErrPtg NULL_INTERSECTION = new ErrPtg(EC.ERROR_NULL);
/** <b>#DIV/0!</b> - Division by zero */
public static final ErrPtg DIV_ZERO = new ErrPtg(EC.ERROR_DIV_0);
/** <b>#VALUE!</b> - Wrong type of operand */
/** <b>#REF!</b> - Illegal or deleted cell reference */
public static final ErrPtg REF_INVALID = new ErrPtg(EC.ERROR_REF);
/** <b>#NAME?</b> - Wrong function or range name */
- public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME);
+ public static final ErrPtg NAME_INVALID = new ErrPtg(EC.ERROR_NAME);
/** <b>#NUM!</b> - Value range overflow */
public static final ErrPtg NUM_ERROR = new ErrPtg(EC.ERROR_NUM);
/** <b>#N/A</b> - Argument or function not available */
public static final ErrPtg N_A = new ErrPtg(EC.ERROR_NA);
-
-
+
+
public static final short sid = 0x1c;
private static final int SIZE = 2;
private final int field_1_error_code;
/** Creates new ErrPtg */
- public ErrPtg(int errorCode) {
+ private ErrPtg(int errorCode) {
if(!HSSFErrorConstants.isValidCode(errorCode)) {
throw new IllegalArgumentException("Invalid error code (" + errorCode + ")");
}
field_1_error_code = errorCode;
}
-
- public ErrPtg(RecordInputStream in) {
- this(in.readByte());
+
+ public static ErrPtg read(RecordInputStream in) {
+ return valueOf(in.readByte());
}
public void writeBytes(byte [] array, int offset)
public int getErrorCode() {
return field_1_error_code;
}
+
+ public static ErrPtg valueOf(int code) {
+ switch(code) {
+ case HSSFErrorConstants.ERROR_DIV_0: return DIV_ZERO;
+ case HSSFErrorConstants.ERROR_NA: return N_A;
+ case HSSFErrorConstants.ERROR_NAME: return NAME_INVALID;
+ case HSSFErrorConstants.ERROR_NULL: return NULL_INTERSECTION;
+ case HSSFErrorConstants.ERROR_NUM: return NUM_ERROR;
+ case HSSFErrorConstants.ERROR_REF: return REF_INVALID;
+ case HSSFErrorConstants.ERROR_VALUE: return VALUE_INVALID;
+ }
+ throw new RuntimeException("Unexpected error code (" + code + ")");
+ }
}
case StringPtg.sid: return new StringPtg(in); // 0x17
case AttrPtg.sid:
case 0x1a: return new AttrPtg(in); // 0x19
- case ErrPtg.sid: return new ErrPtg(in); // 0x1c
+ case ErrPtg.sid: return ErrPtg.read(in); // 0x1c
case BoolPtg.sid: return new BoolPtg(in); // 0x1d
case IntPtg.sid: return new IntPtg(in); // 0x1e
case NumberPtg.sid: return new NumberPtg(in); // 0x1f
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
+import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.AddPtg;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ArrayPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
assertEquals(65535, aptg.getLastRow());
}
+ public void testParseArray() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("mode({1,2,2,#REF!;FALSE,3,3,2})");
+ assertEquals(2, ptgs.length);
+ Ptg ptg0 = ptgs[0];
+ assertEquals(ArrayPtg.class, ptg0.getClass());
+ assertEquals("{1.0,2.0,2.0,#REF!;FALSE,3.0,3.0,2.0}", ptg0.toFormulaString(null));
+
+ ArrayPtg aptg = (ArrayPtg) ptg0;
+ Object[][] values = aptg.getTokenArrayValues();
+ assertEquals(ErrorConstant.valueOf(HSSFErrorConstants.ERROR_REF), values[0][3]);
+ assertEquals(Boolean.FALSE, values[1][0]);
+
+ }
}
\ No newline at end of file
package org.apache.poi.hssf.model;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
public void testFormulas() {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testRVA.xls");
+ try {
+ wb = new HSSFWorkbook(new FileInputStream("C:/josh/client/poi/svn/trunk-h2/src/testcases/org/apache/poi/hssf/data/testRVA.xls"));
+ } catch (FileNotFoundException e1) {
+ throw new RuntimeException(e1);
+ } catch (IOException e1) {
+ throw new RuntimeException(e1);
+ }
HSSFSheet sheet = wb.getSheetAt(0);
int countFailures = 0;
int countErrors = 0;
int rowIx = 0;
+// rowIx = 34;
+// rowIx =32;
while (rowIx < 65535) {
HSSFRow row = sheet.getRow(rowIx);
if (row == null) {
try {
confirmCell(cell, formula, wb);
} catch (AssertionFailedError e) {
+ System.out.flush();
System.err.println("Problem with row[" + rowIx + "] formula '" + formula + "'");
System.err.println(e.getMessage());
+ System.err.flush();
countFailures++;
} catch (RuntimeException e) {
System.err.println("Problem with row[" + rowIx + "] formula '" + formula + "'");
e.printStackTrace();
}
rowIx++;
+// if (rowIx>30) break;
+// break;
}
if (countErrors + countFailures > 0) {
String msg = "One or more RVA tests failed: countFailures=" + countFailures
if (excelPtg.getClass() != poiPtg.getClass()) {
hasMismatch = true;
sb.append(" mismatch token type[" + i + "] " + getShortClassName(excelPtg) + " "
- + getOperandClassName(excelPtg) + " - " + getShortClassName(poiPtg) + " "
- + getOperandClassName(poiPtg));
+ + excelPtg.getRVAType() + " - " + getShortClassName(poiPtg) + " "
+ + poiPtg.getRVAType());
sb.append(NEW_LINE);
continue;
}
continue;
}
sb.append(" token[" + i + "] " + excelPtg.toString() + " "
- + getOperandClassName(excelPtg));
+ + excelPtg.getRVAType());
if (excelPtg.getPtgClass() != poiPtg.getPtgClass()) {
hasMismatch = true;
- sb.append(" - was " + getOperandClassName(poiPtg));
+ sb.append(" - was " + poiPtg.getRVAType());
}
sb.append(NEW_LINE);
}
if (false) { // set 'true' to see trace of RVA values
- System.out.println(formula);
+ System.out.println(formulaCell.getRowIndex() + " " + formula);
System.out.println(sb.toString());
}
if (hasMismatch) {
int pos = cn.lastIndexOf('.');
return cn.substring(pos + 1);
}
-
- private static String getOperandClassName(Ptg ptg) {
- byte ptgClass = ptg.getPtgClass();
- switch (ptgClass) {
- case Ptg.CLASS_REF: return "R";
- case Ptg.CLASS_VALUE: return "V";
- case Ptg.CLASS_ARRAY: return "A";
- }
- throw new RuntimeException("Unknown operand class (" + ptgClass + ")");
- }
}
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
- Object[] values = ptg.getTokenArrayValues();
- assertEquals(6, values.length);
+ Object[][] values = ptg.getTokenArrayValues();
+ assertEquals(2, values.length);
- assertEquals(Boolean.TRUE, values[0]);
- assertEquals(new UnicodeString("ABCD"), values[1]);
- assertEquals(new Double(0), values[3]);
- assertEquals(Boolean.FALSE, values[4]);
- assertEquals(new UnicodeString("FG"), values[5]);
+ assertEquals(Boolean.TRUE, values[0][0]);
+ assertEquals(new UnicodeString("ABCD"), values[0][1]);
+ assertEquals(new Double(0), values[1][0]);
+ assertEquals(Boolean.FALSE, values[1][1]);
+ assertEquals(new UnicodeString("FG"), values[1][2]);
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
ptg.writeTokenValueBytes(outBuf, 0);
assertEquals(2, ptg.getRowCount());
assertEquals(0, ptg.getValueIndex(0, 0));
- assertEquals(2, ptg.getValueIndex(1, 0));
- assertEquals(4, ptg.getValueIndex(2, 0));
- assertEquals(1, ptg.getValueIndex(0, 1));
- assertEquals(3, ptg.getValueIndex(1, 1));
+ assertEquals(1, ptg.getValueIndex(1, 0));
+ assertEquals(2, ptg.getValueIndex(2, 0));
+ assertEquals(3, ptg.getValueIndex(0, 1));
+ assertEquals(4, ptg.getValueIndex(1, 1));
assertEquals(5, ptg.getValueIndex(2, 1));
}
if (formula.equals("SUM({1.0,6.0,11.0;2.0,7.0,12.0;3.0,8.0,13.0;4.0,9.0,14.0;5.0,10.0,15.0})")) {
throw new AssertionFailedError("Identified bug 42564 b");
}
- assertEquals("SUM({1.0,2.0,3.0;4.0,5.0,6.0;7.0,8.0,9.0;10.0,11.0,12.0;13.0,14.0,15.0})", formula);
+ assertEquals("SUM({1.0,2.0,3.0,4.0,5.0;6.0,7.0,8.0,9.0,10.0;11.0,12.0,13.0,14.0,15.0})", formula);
}
public void testToFormulaString() {
}
throw e;
}
- assertEquals("{TRUE,\"ABCD\";\"E\",0.0;FALSE,\"FG\"}", actualFormula);
+ assertEquals("{TRUE,\"ABCD\",\"E\";0.0,FALSE,\"FG\"}", actualFormula);
}
/**