From 899ff0569ba9859e4947c2358ea5a1c5c4ffd372 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Thu, 24 Jul 2014 20:48:29 +0000 Subject: [PATCH] Disabled unit tests for multi-sheet references, see bug #55906 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613282 13f79535-47bb-0310-9956-ffa450edef68 --- .../usermodel/TestXSSFFormulaEvaluation.java | 69 ++++++++++++++++ .../xssf/usermodel/TestXSSFFormulaParser.java | 78 +++++++++++++++++- .../spreadsheet/55906-MultiSheetRefs.xls | Bin 0 -> 23552 bytes .../spreadsheet/55906-MultiSheetRefs.xlsx | Bin 0 -> 9420 bytes 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 test-data/spreadsheet/55906-MultiSheetRefs.xls create mode 100644 test-data/spreadsheet/55906-MultiSheetRefs.xlsx diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java index 4100b5f9c2..657739f998 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaEvaluation.java @@ -26,8 +26,11 @@ import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.FormulaEvaluator; 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.util.CellReference; import org.apache.poi.xssf.XSSFITestDataProvider; +import org.apache.poi.xssf.XSSFTestDataSamples; public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator { @@ -174,4 +177,70 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator { public void TODOtestCachedReferencesToOtherWorkbooks() throws Exception { // TODO } + + /** + * A handful of functions (such as SUM, COUNTA, MIN) support + * multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from + * Sheets 1 through Sheet 3). + * This test, based on common test files for HSSF and XSSF, checks + * that we can correctly evaluate these + * + * DISABLED pending support, see bug #55906 + */ + public void DISABLEDtestMultiSheetReferencesHSSFandXSSF() throws Exception { + Workbook[] wbs = new Workbook[] { + HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"), + XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx") + }; + for (Workbook wb : wbs) { + FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); + Sheet s1 = wb.getSheetAt(0); + + + // Simple SUM over numbers + Cell sumF = s1.getRow(2).getCell(0); + assertNotNull(sumF); + assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula()); + assertEquals("66", evaluator.evaluate(sumF).formatAsString()); + + + // Various Stats formulas on numbers + Cell avgF = s1.getRow(2).getCell(1); + assertNotNull(avgF); + assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula()); + assertEquals("22", evaluator.evaluate(avgF).formatAsString()); + + Cell minF = s1.getRow(3).getCell(1); + assertNotNull(minF); + assertEquals("MIX(Sheet1:Sheet3!A$1)", minF.getCellFormula()); + assertEquals("11", evaluator.evaluate(minF).formatAsString()); + + Cell maxF = s1.getRow(4).getCell(1); + assertNotNull(maxF); + assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula()); + assertEquals("33", evaluator.evaluate(maxF).formatAsString()); + + Cell countF = s1.getRow(5).getCell(1); + assertNotNull(countF); + assertEquals("COUNT(Sheet1:Sheet3!A$1)", countF.getCellFormula()); + assertEquals("3", evaluator.evaluate(countF).formatAsString()); + + + // Various CountAs on Strings + Cell countA_1F = s1.getRow(2).getCell(2); + assertNotNull(countA_1F); + assertEquals("COUNTA(Sheet1:Sheet3!C1)", countA_1F.getCellFormula()); + assertEquals("3", evaluator.evaluate(countA_1F).formatAsString()); + + Cell countA_2F = s1.getRow(2).getCell(3); + assertNotNull(countA_2F); + assertEquals("COUNTA(Sheet1:Sheet3!D1)", countA_2F.getCellFormula()); + assertEquals("0", evaluator.evaluate(countA_2F).formatAsString()); + + Cell countA_3F = s1.getRow(2).getCell(4); + assertNotNull(countA_3F); + assertEquals("COUNTA(Sheet1:Sheet3!E1)", countA_3F.getCellFormula()); + assertEquals("3", evaluator.evaluate(countA_3F).formatAsString()); + } + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java index 13bde7910c..c006227931 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFFormulaParser.java @@ -18,11 +18,16 @@ package org.apache.poi.xssf.usermodel; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.formula.FormulaParseException; import org.apache.poi.ss.formula.FormulaParser; +import org.apache.poi.ss.formula.FormulaParsingWorkbook; import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.ptg.Area3DPxg; import org.apache.poi.ss.formula.ptg.AreaPtg; @@ -35,11 +40,15 @@ import org.apache.poi.ss.formula.ptg.NameXPxg; import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ref3DPxg; import org.apache.poi.ss.formula.ptg.RefPtg; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.XSSFTestDataSamples; +import org.junit.Ignore; import org.junit.Test; public final class TestXSSFFormulaParser { - private static Ptg[] parse(XSSFEvaluationWorkbook fpb, String fmla) { + private static Ptg[] parse(FormulaParsingWorkbook fpb, String fmla) { return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1); } @@ -227,4 +236,71 @@ public final class TestXSSFFormulaParser { assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName()); assertEquals("[1]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString()); } + + /** + * A handful of functions (such as SUM, COUNTA, MIN) support + * multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from + * Sheets 1 through Sheet 3). + * This test, based on common test files for HSSF and XSSF, checks + * that we can read and parse these kinds of references + * (but not evaluate - that's elsewhere in the test suite) + * + * DISABLED pending support, see bug #55906 + */ + @Test + @Ignore + public void multiSheetReferencesHSSFandXSSF() throws Exception { + Workbook[] wbs = new Workbook[] { + HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"), + XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx") + }; + for (Workbook wb : wbs) { + Sheet s1 = wb.getSheetAt(0); + Ptg[] ptgs; + + // Check the contents + Cell sumF = s1.getRow(2).getCell(0); + assertNotNull(sumF); + assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula()); + + Cell avgF = s1.getRow(2).getCell(1); + assertNotNull(avgF); + assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula()); + + Cell countAF = s1.getRow(2).getCell(2); + assertNotNull(countAF); + assertEquals("COUNTA(Sheet1:Sheet3!C1)", countAF.getCellFormula()); + + Cell maxF = s1.getRow(4).getCell(1); + assertNotNull(maxF); + assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula()); + + // Create a formula parser + FormulaParsingWorkbook fpb = null; + if (wb instanceof HSSFWorkbook) + fpb = HSSFEvaluationWorkbook.create((HSSFWorkbook)wb); + else + fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook)wb); + + // Check things parse as expected: + + // SUM to one cell over 3 workbooks, relative reference + ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1"); + // TODO +// assertEquals(1, ptgs.length); +// assertEquals(Ref3DPxg.class, ptgs[0].getClass()); + + // MAX to one cell over 3 workbooks, absolute row reference + ptgs = parse(fpb, "MAX(Sheet1:Sheet3!A$1"); + // TODO +// assertEquals(1, ptgs.length); +// assertEquals(Ref3DPxg.class, ptgs[0].getClass()); + + // MIN to one cell over 3 workbooks, absolute reference + ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1"); + // TODO +// assertEquals(1, ptgs.length); +// assertEquals(Ref3DPxg.class, ptgs[0].getClass()); + } + } } diff --git a/test-data/spreadsheet/55906-MultiSheetRefs.xls b/test-data/spreadsheet/55906-MultiSheetRefs.xls new file mode 100644 index 0000000000000000000000000000000000000000..5e471ccc8b25c3ce71050e57d3b50a529f589e54 GIT binary patch literal 23552 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