From: Josh Micich Date: Thu, 3 Dec 2009 22:18:12 +0000 (+0000) Subject: More fixes for Cell.setCellType() when converting from CELL_TYPE_FORMULA to CELL_TYPE... X-Git-Tag: REL_3_6~8 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ce310ec11a13b7bd6cb91e92e37bf15e627dc6a3;p=poi.git More fixes for Cell.setCellType() when converting from CELL_TYPE_FORMULA to CELL_TYPE_STRING. Similar to issues fixed with bugzilla 46479. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@886951 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index ad1c53545d..551d503560 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -50,6 +50,7 @@ import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.RichTextString; +import org.apache.poi.ss.util.NumberToTextConverter; import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.util.POILogger; @@ -811,14 +812,29 @@ public class HSSFCell implements Cell { int sstIndex = ((LabelSSTRecord)_record).getSSTIndex(); return _book.getWorkbook().getSSTString(sstIndex).getString(); case CELL_TYPE_NUMERIC: - return String.valueOf(((NumberRecord)_record).getValue()); + return NumberToTextConverter.toText(((NumberRecord)_record).getValue()); case CELL_TYPE_ERROR: return HSSFErrorConstants.getText(((BoolErrRecord) _record).getErrorValue()); case CELL_TYPE_FORMULA: // should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator - return ""; + // just use cached formula result instead + break; + default: + throw new IllegalStateException("Unexpected cell type (" + _cellType + ")"); } - throw new RuntimeException("Unexpected cell type (" + _cellType + ")"); + FormulaRecordAggregate fra = ((FormulaRecordAggregate)_record); + FormulaRecord fr = fra.getFormulaRecord(); + switch (fr.getCachedResultType()) { + case CELL_TYPE_BOOLEAN: + return fr.getCachedBooleanValue() ? "TRUE" : "FALSE"; + case CELL_TYPE_STRING: + return fra.getStringValue(); + case CELL_TYPE_NUMERIC: + return NumberToTextConverter.toText(fr.getValue()); + case CELL_TYPE_ERROR: + return HSSFErrorConstants.getText(fr.getCachedErrorValue()); + } + throw new IllegalStateException("Unexpected formula result type (" + _cellType + ")"); } /** diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java index a3cc23a795..55aa71cfcf 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -271,6 +271,7 @@ public final class XSSFCell implements Cell { } break; case CELL_TYPE_FORMULA: + checkFormulaCachedValueType(CELL_TYPE_STRING, getBaseCellType(false)); rt = new XSSFRichTextString(_cell.isSetV() ? _cell.getV() : ""); break; default: @@ -280,7 +281,13 @@ public final class XSSFCell implements Cell { return rt; } - /** + private static void checkFormulaCachedValueType(int expectedTypeCode, int cachedValueType) { + if (cachedValueType != expectedTypeCode) { + throw typeMismatch(expectedTypeCode, cachedValueType, true); + } + } + + /** * Set a string value for the cell. * * @param str value to set the cell to. For formulas we'll set the formula @@ -697,6 +704,9 @@ public final class XSSFCell implements Cell { default: throw new IllegalArgumentException("Illegal cell type: " + cellType); } + if (cellType != CELL_TYPE_FORMULA && _cell.isSetF()) { + _cell.unsetF(); + } } /** @@ -903,14 +913,32 @@ public final class XSSFCell implements Cell { XSSFRichTextString rt = new XSSFRichTextString(_sharedStringSource.getEntryAt(sstIndex)); return rt.getString(); case CELL_TYPE_NUMERIC: - return String.valueOf(Double.parseDouble(_cell.getV())); case CELL_TYPE_ERROR: - return _cell.getV(); + return _cell.getV(); case CELL_TYPE_FORMULA: // should really evaluate, but HSSFCell can't call HSSFFormulaEvaluator - return ""; + // just use cached formula result instead + break; + default: + throw new IllegalStateException("Unexpected cell type (" + cellType + ")"); } - throw new RuntimeException("Unexpected cell type (" + cellType + ")"); + cellType = getBaseCellType(false); + String textValue = _cell.getV(); + switch (cellType) { + case CELL_TYPE_BOOLEAN: + if (TRUE_AS_STRING.equals(textValue)) { + return "TRUE"; + } + if (FALSE_AS_STRING.equals(textValue)) { + return "FALSE"; + } + throw new IllegalStateException("Unexpected boolean cached formula value '" + + textValue + "'."); + case CELL_TYPE_STRING: + case CELL_TYPE_NUMERIC: + case CELL_TYPE_ERROR: + return textValue; + } + throw new IllegalStateException("Unexpected formula result type (" + cellType + ")"); } - } diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java index 4e747b2898..39d21dd85f 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java @@ -102,27 +102,24 @@ public abstract class BaseTestCell extends TestCase { switch (type) { case Cell.CELL_TYPE_NUMERIC: cell.getNumericCellValue(); - fail(); break; case Cell.CELL_TYPE_STRING: cell.getStringCellValue(); - fail(); break; case Cell.CELL_TYPE_BOOLEAN: cell.getBooleanCellValue(); - fail(); break; case Cell.CELL_TYPE_FORMULA: cell.getCellFormula(); - fail(); break; case Cell.CELL_TYPE_ERROR: cell.getErrorCellValue(); - fail(); break; } + fail("Should get exception when reading cell type (" + type + ")."); } catch (IllegalStateException e){ - ; + // expected during successful test + assertTrue(e.getMessage().startsWith("Cannot get a")); } } } @@ -346,6 +343,73 @@ public abstract class BaseTestCell extends TestCase { assertEquals(true, cell.getBooleanCellValue()); } + /** + * Test for a bug observed around svn r886733 when using + * {@link FormulaEvaluator#evaluateInCell(Cell)} with a + * string result type. + */ + public final void testConvertStringFormulaCell() { + Cell cellA1 = createACell(); + cellA1.setCellFormula("\"abc\""); + + // default cached formula result is numeric zero + assertEquals(0.0, cellA1.getNumericCellValue(), 0.0); + + FormulaEvaluator fe = cellA1.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); + + fe.evaluateFormulaCell(cellA1); + assertEquals("abc", cellA1.getStringCellValue()); + + fe.evaluateInCell(cellA1); + if (cellA1.getStringCellValue().equals("")) { + throw new AssertionFailedError("Identified bug with writing back formula result of type string"); + } + assertEquals("abc", cellA1.getStringCellValue()); + } + /** + * similar to {@link #testConvertStringFormulaCell()} but checks at a + * lower level that {#link {@link Cell#setCellType(int)} works properly + */ + public final void testSetTypeStringOnFormulaCell() { + Cell cellA1 = createACell(); + FormulaEvaluator fe = cellA1.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator(); + + cellA1.setCellFormula("\"DEF\""); + fe.clearAllCachedResultValues(); + fe.evaluateFormulaCell(cellA1); + assertEquals("DEF", cellA1.getStringCellValue()); + cellA1.setCellType(Cell.CELL_TYPE_STRING); + assertEquals("DEF", cellA1.getStringCellValue()); + + cellA1.setCellFormula("25.061"); + fe.clearAllCachedResultValues(); + fe.evaluateFormulaCell(cellA1); + confirmCannotReadString(cellA1); + assertEquals(25.061, cellA1.getNumericCellValue(), 0.0); + cellA1.setCellType(Cell.CELL_TYPE_STRING); + assertEquals("25.061", cellA1.getStringCellValue()); + + cellA1.setCellFormula("TRUE"); + fe.clearAllCachedResultValues(); + fe.evaluateFormulaCell(cellA1); + confirmCannotReadString(cellA1); + assertEquals(true, cellA1.getBooleanCellValue()); + cellA1.setCellType(Cell.CELL_TYPE_STRING); + assertEquals("TRUE", cellA1.getStringCellValue()); + + cellA1.setCellFormula("#NAME?"); + fe.clearAllCachedResultValues(); + fe.evaluateFormulaCell(cellA1); + confirmCannotReadString(cellA1); + assertEquals(ErrorConstants.ERROR_NAME, cellA1.getErrorCellValue()); + cellA1.setCellType(Cell.CELL_TYPE_STRING); + assertEquals("#NAME?", cellA1.getStringCellValue()); + } + + private static void confirmCannotReadString(Cell cell) { + assertProhibitedValueAccess(cell, Cell.CELL_TYPE_STRING); + } + /** * Test for bug in convertCellValueToBoolean to make sure that formula results get converted */