From f90fcee53062ae4e94ba7581fb3ff9e4c703f68c Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Thu, 19 May 2011 12:00:10 +0000 Subject: [PATCH] improved test coverage for SXSSF git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1124698 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/xssf/streaming/SXSSFCell.java | 154 +++++++++++++++--- .../apache/poi/xssf/streaming/SXSSFRow.java | 41 ++++- .../apache/poi/xssf/streaming/SXSSFSheet.java | 57 ++++--- .../poi/xssf/streaming/SXSSFWorkbook.java | 2 +- .../xssf/usermodel/XSSFFormulaEvaluator.java | 5 + .../usermodel/streaming/TestSXSSFCell.java | 74 +++------ .../usermodel/streaming/TestSXSSFRow.java | 42 ----- .../usermodel/streaming/TestSXSSFSheet.java | 46 +++++- .../streaming/TestSXSSFWorkbook.java | 28 +++- 9 files changed, 285 insertions(+), 164 deletions(-) diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java index fba4308ec..b6423189a 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java @@ -17,19 +17,16 @@ package org.apache.poi.xssf.streaming; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.RichTextString; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Hyperlink; -import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.formula.eval.ErrorEval; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.util.CellRangeAddress; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType; /** * Streaming version of XSSFRow implementing the "BigGridDemo" strategy. @@ -132,9 +129,11 @@ public class SXSSFCell implements Cell */ public int getCachedFormulaResultType() { -//TODO: Implement this correctly - assert false; - return CELL_TYPE_NUMERIC; + if (_value.getType() != CELL_TYPE_FORMULA) { + throw new IllegalStateException("Only formula cells have cached results"); + } + + return ((FormulaValue)_value).getFormulaType(); } /** @@ -146,11 +145,19 @@ public class SXSSFCell implements Cell */ public void setCellValue(double value) { - ensureTypeOrFormulaType(CELL_TYPE_NUMERIC); - if(_value.getType()==CELL_TYPE_FORMULA) - ((NumericFormulaValue)_value).setPreEvaluatedValue(value); - else - ((NumericValue)_value).setValue(value); + if(Double.isInfinite(value)) { + // Excel does not support positive/negative infinities, + // rather, it gives a #DIV/0! error in these cases. + setCellErrorValue(FormulaError.DIV0.getCode()); + } else if (Double.isNaN(value)){ + setCellErrorValue(FormulaError.NUM.getCode()); + } else { + ensureTypeOrFormulaType(CELL_TYPE_NUMERIC); + if(_value.getType()==CELL_TYPE_FORMULA) + ((NumericFormulaValue)_value).setPreEvaluatedValue(value); + else + ((NumericValue)_value).setValue(value); + } } /** @@ -244,6 +251,11 @@ public class SXSSFCell implements Cell */ public void setCellFormula(String formula) throws FormulaParseException { + if(formula == null) { + setType(Cell.CELL_TYPE_BLANK); + return; + } + ensureFormulaType(computeTypeFromFormula(formula)); ((FormulaValue)_value).setValue(formula); } @@ -328,9 +340,16 @@ public class SXSSFCell implements Cell public RichTextString getRichStringCellValue() { int cellType = getCellType(); - if(!(getCellType()==CELL_TYPE_STRING&&((StringValue)_value).isRichText())) + if(getCellType() != CELL_TYPE_STRING) throw typeMismatch(CELL_TYPE_STRING, cellType, false); - return ((RichTextValue)_value).getValue(); + + StringValue sval = (StringValue)_value; + if(sval.isRichText()) + return ((RichTextValue)_value).getValue(); + else { + String plainText = getStringCellValue(); + return getSheet().getWorkbook().getCreationHelper().createRichTextString(plainText); + } } @@ -490,7 +509,12 @@ public class SXSSFCell implements Cell */ public CellStyle getCellStyle() { - return _style; + if(_style == null){ + SXSSFWorkbook wb = (SXSSFWorkbook)getRow().getSheet().getWorkbook(); + return wb.getCellStyleAt((short)0); + } else { + return _style; + } } /** @@ -569,6 +593,37 @@ public class SXSSFCell implements Cell } //end of interface implementation + /** + * Returns a string representation of the cell + *

+ * Formula cells return the formula string, rather than the formula result. + * Dates are displayed in dd-MMM-yyyy format + * Errors are displayed as #ERR<errIdx> + *

+ */ + public String toString() { + switch (getCellType()) { + case CELL_TYPE_BLANK: + return ""; + case CELL_TYPE_BOOLEAN: + return getBooleanCellValue() ? "TRUE" : "FALSE"; + case CELL_TYPE_ERROR: + return ErrorEval.getText(getErrorCellValue()); + case CELL_TYPE_FORMULA: + return getCellFormula(); + case CELL_TYPE_NUMERIC: + if (DateUtil.isCellDateFormatted(this)) { + DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy"); + return sdf.format(getDateCellValue()); + } + return getNumericCellValue() + ""; + case CELL_TYPE_STRING: + return getRichStringCellValue().toString(); + default: + return "Unknown Cell Type: " + getCellType(); + } + } + void removeProperty(int type) { Property current=_firstProperty; @@ -693,7 +748,13 @@ public class SXSSFCell implements Cell } case CELL_TYPE_STRING: { - _value=new PlainStringValue(); + PlainStringValue sval = new PlainStringValue(); + if(_value != null){ + // if a cell is not blank then convert the old value to string + String str = convertCellValueToString(); + sval.setValue(str); + } + _value = sval; break; } case CELL_TYPE_FORMULA: @@ -708,7 +769,13 @@ public class SXSSFCell implements Cell } case CELL_TYPE_BOOLEAN: { - _value=new BooleanValue(); + BooleanValue bval = new BooleanValue(); + if(_value != null){ + // if a cell is not blank then convert the old value to string + boolean val = convertCellValueToBoolean(); + bval.setValue(val); + } + _value = bval; break; } case CELL_TYPE_ERROR: @@ -781,6 +848,49 @@ public class SXSSFCell implements Cell } return "#unknown cell type (" + cellTypeCode + ")#"; } + private boolean convertCellValueToBoolean() { + int cellType = getCellType(); + + if (cellType == CELL_TYPE_FORMULA) { + cellType = getCachedFormulaResultType(); + } + + switch (cellType) { + case CELL_TYPE_BOOLEAN: + return getBooleanCellValue(); + case CELL_TYPE_STRING: + + String text = getStringCellValue(); + return Boolean.parseBoolean(text); + case CELL_TYPE_NUMERIC: + return getNumericCellValue() != 0; + case CELL_TYPE_ERROR: + case CELL_TYPE_BLANK: + return false; + } + throw new RuntimeException("Unexpected cell type (" + cellType + ")"); + } + private String convertCellValueToString() { + int cellType = getCellType(); + + switch (cellType) { + case CELL_TYPE_BLANK: + return ""; + case CELL_TYPE_BOOLEAN: + return getBooleanCellValue() ? "TRUE" : "FALSE"; + case CELL_TYPE_STRING: + return getStringCellValue(); + case CELL_TYPE_NUMERIC: + case CELL_TYPE_ERROR: + byte errVal = getErrorCellValue(); + return FormulaError.forInt(errVal).getString(); + case CELL_TYPE_FORMULA: + return ""; + default: + throw new IllegalStateException("Unexpected cell type (" + cellType + ")"); + } + } + //END OF COPIED CODE static abstract class Property @@ -870,7 +980,7 @@ public class SXSSFCell implements Cell return false; } } - static class RichTextValue implements Value + static class RichTextValue extends StringValue { RichTextString _value; public int getType() diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java index 25808c9c5..ad7383661 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFRow.java @@ -35,8 +35,7 @@ public class SXSSFRow implements Row SXSSFCell[] _cells; int _maxColumn=-1; short _height=-1; -//TODO: Need to set the correct default value for _zHeight - boolean _zHeight; + boolean _zHeight = false; public SXSSFRow(SXSSFSheet sheet, int initialSize) { @@ -150,9 +149,29 @@ public class SXSSFRow implements Row * @return Cell representing that column or null if undefined. * @see #getCell(int, org.apache.poi.ss.usermodel.Row.MissingCellPolicy) */ - public Cell getCell(int cellnum) - { - return cellnum>_maxColumn?null:_cells[cellnum]; + public Cell getCell(int cellnum) { + if(cellnum < 0) throw new IllegalArgumentException("Cell index must be >= 0"); + + Cell cell = cellnum > _maxColumn ? null : _cells[cellnum]; + + MissingCellPolicy policy = _sheet.getWorkbook().getMissingCellPolicy(); + if(policy == RETURN_NULL_AND_BLANK) { + return cell; + } + if (policy == RETURN_BLANK_AS_NULL) { + if (cell == null) return cell; + if (cell.getCellType() == Cell.CELL_TYPE_BLANK) { + return null; + } + return cell; + } + if (policy == CREATE_NULL_AS_BLANK) { + if (cell == null) { + return createCell((short) cellnum, Cell.CELL_TYPE_BLANK); + } + return cell; + } + throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")"); } /** @@ -226,7 +245,7 @@ public class SXSSFRow implements Row */ public short getLastCellNum() { - return (short)(_maxColumn+1); + return _maxColumn == -1 ? -1 : (short)(_maxColumn+1); } /** @@ -337,6 +356,16 @@ public class SXSSFRow implements Row public class FilledCellIterator implements Iterator { int pos=0; + + FilledCellIterator(){ + for (int i = 0; i <= _maxColumn; i++) { + if (_cells[i] != null) { + pos = i; + break; + } + } + } + public boolean hasNext() { return pos <= _maxColumn; diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index 86ac77784..be90606e1 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -27,20 +27,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.PrintSetup; -import org.apache.poi.ss.usermodel.Header; -import org.apache.poi.ss.usermodel.Footer; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Drawing; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.DataValidation; -import org.apache.poi.ss.usermodel.CellRange; -import org.apache.poi.ss.usermodel.DataValidationHelper; -import org.apache.poi.ss.usermodel.AutoFilter; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xssf.usermodel.XSSFSheet; @@ -125,6 +112,10 @@ public class SXSSFSheet implements Sheet, Cloneable */ public void removeRow(Row row) { + if (row.getSheet() != this) { + throw new IllegalArgumentException("Specified row does not belong to this sheet"); + } + for(Iterator> iter=_rows.entrySet().iterator();iter.hasNext();) { Map.Entry entry=iter.next(); @@ -165,10 +156,9 @@ public class SXSSFSheet implements Sheet, Cloneable */ public int getFirstRowNum() { - if(_writer.getNumberOfFlushedRows()>0) + if(_writer.getNumberOfFlushedRows() > 0) return _writer.getLowestIndexOfFlushedRows(); - Integer firstKey=_rows.firstKey(); - return firstKey==null?-1:firstKey.intValue(); + return _rows.size() == 0 ? 0 : _rows.firstKey(); } /** @@ -178,8 +168,7 @@ public class SXSSFSheet implements Sheet, Cloneable */ public int getLastRowNum() { - Integer lastKey=_rows.lastKey(); - return lastKey==null?-1:lastKey.intValue(); + return _rows.size() == 0 ? 0 : _rows.lastKey(); } /** @@ -1306,6 +1295,8 @@ public class SXSSFSheet implements Sheet, Cloneable _out.write("