From b6dd3bca347a264d07b321743f795477aaeae5e2 Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Tue, 22 Jul 2014 12:31:56 +0000 Subject: [PATCH] Bug 56688: Fix border cases in EDATE function: handle RefEval and BlankEval and also return #VALUE, not #REF if case of error git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1612557 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/functions/EDate.java | 15 ++- .../poi/xssf/usermodel/TestXSSFBugs.java | 113 ++++++++++++------ .../poi/hssf/usermodel/TestHSSFDateUtil.java | 26 +++- .../poi/ss/formula/functions/TestEDate.java | 91 ++++++++++++-- test-data/spreadsheet/56688_1.xlsx | Bin 0 -> 8846 bytes test-data/spreadsheet/56688_2.xlsx | Bin 0 -> 9181 bytes test-data/spreadsheet/56688_3.xlsx | Bin 0 -> 9188 bytes test-data/spreadsheet/56688_4.xlsx | Bin 0 -> 8926 bytes 8 files changed, 192 insertions(+), 53 deletions(-) create mode 100644 test-data/spreadsheet/56688_1.xlsx create mode 100644 test-data/spreadsheet/56688_2.xlsx create mode 100644 test-data/spreadsheet/56688_3.xlsx create mode 100644 test-data/spreadsheet/56688_4.xlsx diff --git a/src/java/org/apache/poi/ss/formula/functions/EDate.java b/src/java/org/apache/poi/ss/formula/functions/EDate.java index 22832690e..75e550994 100644 --- a/src/java/org/apache/poi/ss/formula/functions/EDate.java +++ b/src/java/org/apache/poi/ss/formula/functions/EDate.java @@ -36,8 +36,7 @@ public class EDate implements FreeRefFunction { } try { double startDateAsNumber = getValue(args[0]); - NumberEval offsetInYearsValue = (NumberEval) args[1]; - int offsetInMonthAsNumber = (int) offsetInYearsValue.getNumberValue(); + int offsetInMonthAsNumber = (int) getValue(args[1]); Date startDate = DateUtil.getJavaDate(startDateAsNumber); Calendar calendar = Calendar.getInstance(); @@ -53,10 +52,18 @@ public class EDate implements FreeRefFunction { if (arg instanceof NumberEval) { return ((NumberEval) arg).getNumberValue(); } + if(arg instanceof BlankEval) { + return 0; + } if (arg instanceof RefEval) { ValueEval innerValueEval = ((RefEval) arg).getInnerValueEval(); - return ((NumberEval) innerValueEval).getNumberValue(); + if(innerValueEval instanceof NumberEval) { + return ((NumberEval) innerValueEval).getNumberValue(); + } + if(innerValueEval instanceof BlankEval) { + return 0; + } } - throw new EvaluationException(ErrorEval.REF_INVALID); + throw new EvaluationException(ErrorEval.VALUE_INVALID); } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java index 696e32c53..fcf2b5162 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -18,13 +18,7 @@ package org.apache.poi.xssf.usermodel; import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -48,25 +42,7 @@ import org.apache.poi.ss.formula.WorkbookEvaluator; import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.functions.Function; -import org.apache.poi.ss.usermodel.BaseTestBugzillaIssues; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.CellValue; -import org.apache.poi.ss.usermodel.ClientAnchor; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.CreationHelper; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.Drawing; -import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.FormulaError; -import org.apache.poi.ss.usermodel.FormulaEvaluator; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Name; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; @@ -589,6 +565,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { r = s.getRow(0); c = r.getCell(0); assertEquals("hello world", c.getRichStringCellValue().toString()); + wb.close(); } /** @@ -639,7 +616,8 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals("A7", cc.getCTCalcChain().getCArray(5).getR()); assertEquals("A8", cc.getCTCalcChain().getCArray(6).getR()); assertEquals(40, cc.getCTCalcChain().sizeOfCArray()); - + wbRead.close(); + wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); // Try various ways of changing the formulas @@ -648,18 +626,23 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { sheet.getRow(1).getCell(0).setCellFormula("A1"); // stay sheet.getRow(2).getCell(0).setCellFormula(null); // go sheet.getRow(3).getCell(0).setCellType(Cell.CELL_TYPE_FORMULA); // stay + wbRead.close(); wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); sheet.getRow(4).getCell(0).setCellType(Cell.CELL_TYPE_STRING); // go + wbRead.close(); wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); validateCells(sheet); sheet.getRow(5).removeCell(sheet.getRow(5).getCell(0)); // go validateCells(sheet); + wbRead.close(); wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); sheet.getRow(6).getCell(0).setCellType(Cell.CELL_TYPE_BLANK); // go + wbRead.close(); wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); sheet.getRow(7).getCell(0).setCellValue((String) null); // go + wbRead.close(); wbRead = XSSFTestDataSamples.writeOutAndReadBack(wb); @@ -671,6 +654,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals("A2", cc.getCTCalcChain().getCArray(0).getR()); assertEquals("A4", cc.getCTCalcChain().getCArray(1).getR()); assertEquals("A9", cc.getCTCalcChain().getCArray(2).getR()); + wbRead.close(); } @Test @@ -954,14 +938,15 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { String r3 = cell.getRichStringCellValue().getCTRst().getRList().get(2).getT(); assertEquals("line.\n", r3.substring(r3.length()-6)); - + // Save and re-check wb = XSSFTestDataSamples.writeOutAndReadBack(wb); sheet = wb.getSheetAt(0); row = sheet.getRow(2); cell = row.getCell(2); assertEquals(text, cell.getStringCellValue()); - + wb.close(); + // FileOutputStream out = new FileOutputStream("/tmp/test48877.xlsx"); // wb.write(out); // out.close(); @@ -1125,6 +1110,9 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals(true, s2.getCTWorksheet().isSetPageMargins()); assertEquals(true, ps2.getValidSettings()); assertEquals(false, ps2.getLandscape()); + + wb1.close(); + wb2.close(); } /** @@ -1201,6 +1189,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { assertEquals(pinkStyle, s.getColumnStyle(0)); assertEquals(defaultStyle, s.getColumnStyle(2)); assertEquals(blueStyle, s.getColumnStyle(3)); + wb.close(); } /** @@ -1532,6 +1521,8 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { byte secondSave[] = bos.toByteArray(); assertThat(firstSave, equalTo(secondSave)); + + wb.close(); } /** @@ -1720,19 +1711,63 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { FileInputStream is = new FileInputStream(outFile); try { - final Workbook newWB; - if(wb instanceof XSSFWorkbook) { - newWB = new XSSFWorkbook(is); - } else if(wb instanceof HSSFWorkbook) { - newWB = new HSSFWorkbook(is); - } else if(wb instanceof SXSSFWorkbook) { - newWB = new SXSSFWorkbook(new XSSFWorkbook(is)); - } else { - throw new IllegalStateException("Unknown workbook: " + wb); + Workbook newWB = null; + try { + if(wb instanceof XSSFWorkbook) { + newWB = new XSSFWorkbook(is); + } else if(wb instanceof HSSFWorkbook) { + newWB = new HSSFWorkbook(is); + } else if(wb instanceof SXSSFWorkbook) { + newWB = new SXSSFWorkbook(new XSSFWorkbook(is)); + } else { + throw new IllegalStateException("Unknown workbook: " + wb); + } + assertNotNull(newWB.getSheet("test")); + } finally { + newWB.close(); } - assertNotNull(newWB.getSheet("test")); } finally { is.close(); } } + + @Test + public void testBug56688_1() { + XSSFWorkbook excel = XSSFTestDataSamples.openSampleWorkbook("56688_1.xlsx"); + checkValue(excel, "-1.0"); /* Not 0.0 because POI sees date "0" minus one month as invalid date, which is -1! */ + } + + @Test + public void testBug56688_2() { + XSSFWorkbook excel = XSSFTestDataSamples.openSampleWorkbook("56688_2.xlsx"); + checkValue(excel, "#VALUE!"); + } + + @Test + public void testBug56688_3() { + XSSFWorkbook excel = XSSFTestDataSamples.openSampleWorkbook("56688_3.xlsx"); + checkValue(excel, "#VALUE!"); + } + + @Test + public void testBug56688_4() { + XSSFWorkbook excel = XSSFTestDataSamples.openSampleWorkbook("56688_4.xlsx"); + +// Calendar calendar = Calendar.getInstance(); +// calendar.add(Calendar.MONTH, 2); +// double excelDate = DateUtil.getExcelDate(calendar.getTime()); +// NumberEval eval = new NumberEval(Math.floor(excelDate)); +// checkValue(excel, eval.getStringValue() + ".0"); + checkValue(excel, "41904.0"); + } + + private void checkValue(XSSFWorkbook excel, String expect) { + XSSFFormulaEvaluator evaluator = new XSSFFormulaEvaluator(excel); + evaluator.evaluateAll(); + + XSSFCell cell = excel.getSheetAt(0).getRow(1).getCell(1); + CellValue value = evaluator.evaluate(cell); + + assertEquals(expect, value.formatAsString()); + } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java index 022975d9a..f5ea7a1cc 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java @@ -21,6 +21,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -28,6 +31,7 @@ import java.util.TimeZone; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.InternalWorkbook; +import org.apache.poi.ss.usermodel.DateUtil; import org.junit.Test; /** @@ -337,9 +341,10 @@ public final class TestHSSFDateUtil { /** * Test that against a real, test file, we still do everything * correctly + * @throws IOException */ @Test - public void onARealFile() { + public void onARealFile() throws IOException { HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("DateFormats.xls"); HSSFSheet sheet = workbook.getSheetAt(0); @@ -394,6 +399,18 @@ public final class TestHSSFDateUtil { assertFalse(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat())); assertTrue(HSSFDateUtil.isADateFormat(style.getDataFormat(), style.getDataFormatString())); assertTrue(HSSFDateUtil.isCellDateFormatted(cell)); + + workbook.close(); + } + + @Test + public void excelDateBorderCases() throws ParseException { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + + assertEquals(1.0, DateUtil.getExcelDate(df.parse("1900-01-01")), 0.00001); + assertEquals(31.0, DateUtil.getExcelDate(df.parse("1900-01-31")), 0.00001); + assertEquals(32.0, DateUtil.getExcelDate(df.parse("1900-02-01")), 0.00001); + assertEquals(/* BAD_DATE! */ -1.0, DateUtil.getExcelDate(df.parse("1899-12-31")), 0.00001); } @Test @@ -495,9 +512,10 @@ public final class TestHSSFDateUtil { /** * User reported a datetime issue in POI-2.5: * Setting Cell's value to Jan 1, 1900 without a time doesn't return the same value set to + * @throws IOException */ @Test - public void bug19172() + public void bug19172() throws IOException { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); @@ -505,7 +523,7 @@ public final class TestHSSFDateUtil { Calendar cal = Calendar.getInstance(); - // A pseduo special Excel dates + // A pseudo special Excel dates cal.set(1900, 0, 1); Date valueToTest = cal.getTime(); @@ -515,6 +533,8 @@ public final class TestHSSFDateUtil { Date returnedValue = cell.getDateCellValue(); assertEquals(valueToTest.getTime(), returnedValue.getTime()); + + workbook.close(); } /** diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestEDate.java b/src/testcases/org/apache/poi/ss/formula/functions/TestEDate.java index 96cc31c1b..6e337003b 100644 --- a/src/testcases/org/apache/poi/ss/formula/functions/TestEDate.java +++ b/src/testcases/org/apache/poi/ss/formula/functions/TestEDate.java @@ -17,24 +17,67 @@ package org.apache.poi.ss.formula.functions; +import java.util.Calendar; +import java.util.Date; + import junit.framework.TestCase; + +import org.apache.poi.ss.formula.eval.AreaEval; +import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.NumberEval; +import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.ErrorConstants; -import java.util.Calendar; -import java.util.Date; - public class TestEDate extends TestCase{ - public void testEDateProperValues() { - EDate eDate = new EDate(); - NumberEval result = (NumberEval) eDate.evaluate(new ValueEval[]{new NumberEval(1000), new NumberEval(0)}, null); - assertEquals(1000d, result.getNumberValue()); + private final class RefEvalImplementation implements RefEval { + private final ValueEval value; + + public RefEvalImplementation(ValueEval value) { + super(); + this.value = value; + } + + public AreaEval offset(int relFirstRowIx, int relLastRowIx, + int relFirstColIx, int relLastColIx) { + throw new UnsupportedOperationException(); + } + + public int getRow() { + throw new UnsupportedOperationException(); + } + + public ValueEval getInnerValueEval() { + return value; + } + + public int getColumn() { + throw new UnsupportedOperationException(); + } } + public void testEDateProperValues() { + // verify some border-case combinations of startDate and month-increase + checkValue(1000, 0, 1000d); + checkValue(1, 0, 1d); + checkValue(0, 1, 31d); + checkValue(1, 1, 32d); + checkValue(0, 0, /* BAD_DATE! */ -1.0d); + checkValue(0, -2, /* BAD_DATE! */ -1.0d); + checkValue(0, -3, /* BAD_DATE! */ -1.0d); + checkValue(49104, 0, 49104d); + checkValue(49104, 1, 49134d); + } + + private void checkValue(int startDate, int monthInc, double expectedResult) { + EDate eDate = new EDate(); + NumberEval result = (NumberEval) eDate.evaluate(new ValueEval[]{new NumberEval(startDate), new NumberEval(monthInc)}, null); + assertEquals(expectedResult, result.getNumberValue()); + } + public void testEDateInvalidValues() { EDate eDate = new EDate(); ErrorEval result = (ErrorEval) eDate.evaluate(new ValueEval[]{new NumberEval(1000)}, null); @@ -65,4 +108,38 @@ public class TestEDate extends TestCase{ instance.add(Calendar.MONTH, offset); assertEquals(resultDate, instance.getTime()); } + + public void testBug56688() { + EDate eDate = new EDate(); + NumberEval result = (NumberEval) eDate.evaluate(new ValueEval[]{new NumberEval(1000), new RefEvalImplementation(new NumberEval(0))}, null); + assertEquals(1000d, result.getNumberValue()); + } + + public void testRefEvalStartDate() { + EDate eDate = new EDate(); + NumberEval result = (NumberEval) eDate.evaluate(new ValueEval[]{new RefEvalImplementation(new NumberEval(1000)), new NumberEval(0)}, null); + assertEquals(1000d, result.getNumberValue()); + } + + public void testEDateInvalidValueEval() { + ValueEval evaluate = new EDate().evaluate(new ValueEval[]{new ValueEval() {}, new NumberEval(0)}, null); + assertTrue(evaluate instanceof ErrorEval); + assertEquals(ErrorEval.VALUE_INVALID, evaluate); + } + + public void testEDateBlankValueEval() { + NumberEval evaluate = (NumberEval) new EDate().evaluate(new ValueEval[]{BlankEval.instance, new NumberEval(0)}, null); + assertEquals(-1.0d, evaluate.getNumberValue()); + } + + public void testEDateBlankRefValueEval() { + EDate eDate = new EDate(); + NumberEval result = (NumberEval) eDate.evaluate(new ValueEval[]{new RefEvalImplementation(BlankEval.instance), new NumberEval(0)}, null); + assertEquals("0 startDate triggers BAD_DATE currently, thus -1.0!", + -1.0d, result.getNumberValue()); + + result = (NumberEval) eDate.evaluate(new ValueEval[]{new NumberEval(1), new RefEvalImplementation(BlankEval.instance)}, null); + assertEquals("Blank is handled as 0 otherwise", + 1.0d, result.getNumberValue()); + } } diff --git a/test-data/spreadsheet/56688_1.xlsx b/test-data/spreadsheet/56688_1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4246e96791cb1428f2ba107234063ba769a93c8b GIT binary patch literal 8846 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 J5V{}V{tq^11v&r# literal 0 HcmV?d00001 diff --git a/test-data/spreadsheet/56688_2.xlsx b/test-data/spreadsheet/56688_2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..24098bd51073018c6eeb5ec61d6c300b99f9773b GIT binary patch literal 9181 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 fX*(H|N}15FA_@01!X`003A4UB0Oa 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 literal 0 HcmV?d00001 diff --git a/test-data/spreadsheet/56688_4.xlsx b/test-data/spreadsheet/56688_4.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5aeb4ee4b45b05c17e0c743230d4bbd173911857 GIT binary patch literal 8926 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 literal 0 HcmV?d00001