You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2021/05/22 20:56:49 UTC
svn commit: r1890120 [36/43] - in /poi/trunk/poi/src:
main/java/org/apache/poi/ main/java/org/apache/poi/ddf/
main/java/org/apache/poi/extractor/ main/java/org/apache/poi/hpsf/
main/java/org/apache/poi/hssf/ main/java/org/apache/poi/hssf/dev/
main/java...
Modified: poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestPropertyTable.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestPropertyTable.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestPropertyTable.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestPropertyTable.java Sat May 22 20:56:44 2021
@@ -44,148 +44,148 @@ import org.junit.jupiter.api.Test;
*/
final class TestPropertyTable {
- private static void confirmBlockEncoding(String expectedDataStr, PropertyTable table) throws IOException {
- final UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
- byte[] expectedData = RawDataUtil.decompress(expectedDataStr);
-
- POIFSStream stream = new POIFSStream(null) {
- @Override
- public OutputStream getOutputStream() {
- return bos;
- }
- };
-
- table.write(stream);
-
- assertArrayEquals(expectedData, bos.toByteArray());
- }
-
- /**
- * Test PropertyTable
- * <p>
- * Running individual tests of the PropertyTable methods, which is the
- * traditional way to write unit tests (at least for me), seems somewhat
- * useless in this case. Of greater relevance: if one follows the normal
- * steps of creating a PropertyTable, and then checking the output, does it
- * make sense? In other words, more of an integration test.
- * <p>
- * So, the test consists of creating a PropertyTable instance, adding three
- * DocumentProperty instances to it, and then getting the output (including
- * the preWrite phase first), and comparing it against a real property table
- * extracted from a file known to be acceptable to Excel.
- */
- @Test
- void testWriterPropertyTable() throws IOException {
-
- // create the PropertyTable
- HeaderBlock headerBlock = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
- PropertyTable table = new PropertyTable(headerBlock);
-
- // create three DocumentProperty instances and add them to the
- // PropertyTable
- DocumentProperty workbook = new DocumentProperty("Workbook", 0x00046777);
-
- workbook.setStartBlock(0);
- DocumentProperty summary1 = new DocumentProperty(SummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
-
- summary1.setStartBlock(0x00000234);
- DocumentProperty summary2 = new DocumentProperty(DocumentSummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
-
- summary2.setStartBlock(0x0000023C);
- table.addProperty(workbook);
- RootProperty root = table.getRoot();
-
- root.addChild(workbook);
- table.addProperty(summary1);
- root = table.getRoot();
- root.addChild(summary1);
- table.addProperty(summary2);
- root = table.getRoot();
- root.addChild(summary2);
- table.preWrite();
-
- final String testblock =
- "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDN" +
- "yhDMUMqQC4SJYL97AkMhDewmkEgJQyaQnYfHHA2g/YxAmhmIibXfBBRQAgxQ+12ANiSD3ZAKjgHS3GNBhv9tkOwHAFGXmbcAAgAA";
- confirmBlockEncoding(testblock, table);
-
- table.removeProperty(summary1);
- root = table.getRoot();
- root.deleteChild(summary1);
- table.preWrite();
-
- final String testblock2 =
- "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJ" +
- "gfJ0FjDNyuACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsgPYzAmlS7LcBBZQAhA0Ae5Y5UIABAAA=";
- // (N)POIFS only returns 384 bytes here, instead of 512
- confirmBlockEncoding(testblock2, table);
-
- table.addProperty(summary1);
- root = table.getRoot();
- root.addChild(summary1);
- table.preWrite();
-
- final String testblock3 =
- "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FzETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDNyu" +
- "ACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsyLDfhglICDBA7SfNPnSgAbSfEUiDjCTWfhMk+wEk2TJjAAIAAA==";
- confirmBlockEncoding(testblock3, table);
- }
-
- @Test
- void testReadingConstructor() throws IOException {
-
- // first, we need the raw data blocks
- String raw_data_array =
- "H4sIAAAAAAAAAO2Z608TQRDA5wqVlreIyFMP5AMaMUAMMcYvQIVoUAivxI9HOeCkpaS9GvjmX67OzO61S1930zOpJJ2muUd" +
- "u9zfv3V4PoIAfH2z4BNd4LMIdSGQCktYfLVbEMf34/dWnzjPgggM55H9G/jnqUoQ83vHBw/Pr0LkWwKrwn4o0V7INx6iDDT" +
- "vI9eBMrMdrSDB/GM/pKOVncPYynKIHXGQH3vCQeKF1OcOrLGtCOtXKmuanhfxefdyCS5w/x5bvI72ILJczwUEN3MrdPD7l4" +
- "8fFJ01Z1/w+Ad+6x3eQRswcfqr+tjEyLvO38c4tc204Ye+U8SqQD5r/SMBPGPxjtOwU7Qv4Nuyy96+ghOcO+5984OB1iT1z" +
- "wf4o6fEfNT+QKHxTwu1vFJWqvNf8pMD+HsN+le0Oz03556FlWc5Jdad19AHeaX6vgN8LkvhvoS5FjhA9V9udAn5KwCdf6fY" +
- "Dezi7jxmgLKZYHyHLgZ+sEXnEYbtLTeZ6o/kDAj7l6rw+30RuiTPO5Qyz4QvfIT+cVyq/eQ96q/k9Aj7ZHjX+9RXX2P4hAT" +
- "9l8PeQcsk5ZnMuFLkPq+tDPGZ13wvzf7+Anzb439A26gCKWEBftKr2egn6/6CA32/wD9m/Lkd+g7PcYU8UMBeb+dwUG/mzm" +
- "h2VPwCN/X+Ax3OjDlzsu37IXIvIfybkDxr8r2jvLUY8z3GgmFOPu6t0Ho890VyWtP/HIbr/h8CMv8t5TrarLhfe8xrxnwj4" +
- "wwa/8Zqr8vA7V0IuEj8h4I+AaT/1lzJnXsA94Tr0Iu3CAv6YgD/Kdiup339lOBvIHyVNb159ik/zPRbwSdfA/ur+M8NVmGU" +
- "9bgT7z4Q1BbL8p1xJ6/MjzLwTrPz2978Ja1LIp1qp5l+RmWqVU50nr/3vt/R8lT8h5JsS8DzuuMHaH7bq3OePCPn0OyGs/0" +
- "SVaeTbQj75K6nPq/nXep/TTGaRPyfkU78O9j9busIoB3yu+erqEx59tf7MCPmm1O9/jtD2m0hrHwnZPy3kU73U17+MG8g48" +
- "l8K+VNgrv9l7v+X3HMv2uLPC/nTBn+DmarWbV4N8iIdJpH/QsifMfjbbLcby//PhfxZuO//U+OXt1TGkL8o5M+B6f9drDdZ" +
- "zZlC9i8I+aaofQ/F4ErMJhmN+fs3rgT7ni6/PX7teKnEHZ/q8Pj4+vfAzuZ+jPFzsLTxanV9eS/rL6+trKzafsE2LkPHP3T" +
- "/Pezx8evH6rj+Kd0H/sVRzp+MaX8Sfjh5t9Tm+M7nrwVhNd56fNz+063/OOPj2t9p+R3zS+9d2hnXlf9DLN27g/+E6L0E/T" +
- "/Rp/t5WseX3hnTe9uhmnh35WHLX544XEIAIAAA";
-
- // Fake up a header
- HeaderBlock header_block = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
- header_block.setPropertyStart(0);
-
- List<ByteBuffer> data_blocks = new ArrayList<>();
- try (InputStream is = new ByteArrayInputStream(RawDataUtil.decompress(raw_data_array))) {
- byte[] buf = new byte[header_block.getBigBlockSize().getBigBlockSize()];
-
- for (int readBytes; (readBytes = is.read(buf)) != -1; ) {
- data_blocks.add(ByteBuffer.wrap(buf.clone(), 0, readBytes));
- }
- }
-
-
- // get property table from the document
- PropertyTable table = new PropertyTable(header_block, data_blocks);
-
- assertEquals(30 * 64, table.getRoot().getSize());
- int count = 0;
- Property lastChild = null;
- for (Property p : table.getRoot()) {
- assertNotNull(p);
- lastChild = p;
- ++count;
- }
-
- assertNotNull(lastChild, "no children found");
- assertEquals(1, count);
- assertTrue(lastChild.isDirectory());
- count = 0;
- for (Property p : (DirectoryProperty) lastChild) {
- assertNotNull(p);
- ++count;
- }
- assertEquals(35, count);
- }
+ private static void confirmBlockEncoding(String expectedDataStr, PropertyTable table) throws IOException {
+ final UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
+ byte[] expectedData = RawDataUtil.decompress(expectedDataStr);
+
+ POIFSStream stream = new POIFSStream(null) {
+ @Override
+ public OutputStream getOutputStream() {
+ return bos;
+ }
+ };
+
+ table.write(stream);
+
+ assertArrayEquals(expectedData, bos.toByteArray());
+ }
+
+ /**
+ * Test PropertyTable
+ * <p>
+ * Running individual tests of the PropertyTable methods, which is the
+ * traditional way to write unit tests (at least for me), seems somewhat
+ * useless in this case. Of greater relevance: if one follows the normal
+ * steps of creating a PropertyTable, and then checking the output, does it
+ * make sense? In other words, more of an integration test.
+ * <p>
+ * So, the test consists of creating a PropertyTable instance, adding three
+ * DocumentProperty instances to it, and then getting the output (including
+ * the preWrite phase first), and comparing it against a real property table
+ * extracted from a file known to be acceptable to Excel.
+ */
+ @Test
+ void testWriterPropertyTable() throws IOException {
+
+ // create the PropertyTable
+ HeaderBlock headerBlock = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
+ PropertyTable table = new PropertyTable(headerBlock);
+
+ // create three DocumentProperty instances and add them to the
+ // PropertyTable
+ DocumentProperty workbook = new DocumentProperty("Workbook", 0x00046777);
+
+ workbook.setStartBlock(0);
+ DocumentProperty summary1 = new DocumentProperty(SummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
+
+ summary1.setStartBlock(0x00000234);
+ DocumentProperty summary2 = new DocumentProperty(DocumentSummaryInformation.DEFAULT_STREAM_NAME, 0x00001000);
+
+ summary2.setStartBlock(0x0000023C);
+ table.addProperty(workbook);
+ RootProperty root = table.getRoot();
+
+ root.addChild(workbook);
+ table.addProperty(summary1);
+ root = table.getRoot();
+ root.addChild(summary1);
+ table.addProperty(summary2);
+ root = table.getRoot();
+ root.addChild(summary2);
+ table.preWrite();
+
+ final String testblock =
+ "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDN" +
+ "yhDMUMqQC4SJYL97AkMhDewmkEgJQyaQnYfHHA2g/YxAmhmIibXfBBRQAgxQ+12ANiSD3ZAKjgHS3GNBhv9tkOwHAFGXmbcAAgAA";
+ confirmBlockEncoding(testblock, table);
+
+ table.removeProperty(summary1);
+ root = table.getRoot();
+ root.deleteChild(summary1);
+ table.preWrite();
+
+ final String testblock2 =
+ "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FTETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJ" +
+ "gfJ0FjDNyuACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsgPYzAmlS7LcBBZQAhA0Ae5Y5UIABAAA=";
+ // (N)POIFS only returns 384 bytes here, instead of 512
+ confirmBlockEncoding(testblock2, table);
+
+ table.addProperty(summary1);
+ root = table.getRoot();
+ root.addChild(summary1);
+ table.preWrite();
+
+ final String testblock3 =
+ "H4sIAAAAAAAAAAtiyAfCEgYFBleGPCBdxFDJQAoQY2Bl/A8FzETq+QdUC2OHA20vYshmSAK7I5sku0FAiIEJbv9/JHMJgfJ0FjDNyu" +
+ "ACtDeZoZQhlyEVHALBYHYuQyI4LDyBYmlgN4JEShgygew8JHMsyLDfhglICDBA7SfNPnSgAbSfEUiDjCTWfhMk+wEk2TJjAAIAAA==";
+ confirmBlockEncoding(testblock3, table);
+ }
+
+ @Test
+ void testReadingConstructor() throws IOException {
+
+ // first, we need the raw data blocks
+ String raw_data_array =
+ "H4sIAAAAAAAAAO2Z608TQRDA5wqVlreIyFMP5AMaMUAMMcYvQIVoUAivxI9HOeCkpaS9GvjmX67OzO61S1930zOpJJ2muUd" +
+ "u9zfv3V4PoIAfH2z4BNd4LMIdSGQCktYfLVbEMf34/dWnzjPgggM55H9G/jnqUoQ83vHBw/Pr0LkWwKrwn4o0V7INx6iDDT" +
+ "vI9eBMrMdrSDB/GM/pKOVncPYynKIHXGQH3vCQeKF1OcOrLGtCOtXKmuanhfxefdyCS5w/x5bvI72ILJczwUEN3MrdPD7l4" +
+ "8fFJ01Z1/w+Ad+6x3eQRswcfqr+tjEyLvO38c4tc204Ye+U8SqQD5r/SMBPGPxjtOwU7Qv4Nuyy96+ghOcO+5984OB1iT1z" +
+ "wf4o6fEfNT+QKHxTwu1vFJWqvNf8pMD+HsN+le0Oz03556FlWc5Jdad19AHeaX6vgN8LkvhvoS5FjhA9V9udAn5KwCdf6fY" +
+ "Dezi7jxmgLKZYHyHLgZ+sEXnEYbtLTeZ6o/kDAj7l6rw+30RuiTPO5Qyz4QvfIT+cVyq/eQ96q/k9Aj7ZHjX+9RXX2P4hAT" +
+ "9l8PeQcsk5ZnMuFLkPq+tDPGZ13wvzf7+Anzb439A26gCKWEBftKr2egn6/6CA32/wD9m/Lkd+g7PcYU8UMBeb+dwUG/mzm" +
+ "h2VPwCN/X+Ax3OjDlzsu37IXIvIfybkDxr8r2jvLUY8z3GgmFOPu6t0Ho890VyWtP/HIbr/h8CMv8t5TrarLhfe8xrxnwj4" +
+ "wwa/8Zqr8vA7V0IuEj8h4I+AaT/1lzJnXsA94Tr0Iu3CAv6YgD/Kdiup339lOBvIHyVNb159ik/zPRbwSdfA/ur+M8NVmGU" +
+ "9bgT7z4Q1BbL8p1xJ6/MjzLwTrPz2978Ja1LIp1qp5l+RmWqVU50nr/3vt/R8lT8h5JsS8DzuuMHaH7bq3OePCPn0OyGs/0" +
+ "SVaeTbQj75K6nPq/nXep/TTGaRPyfkU78O9j9busIoB3yu+erqEx59tf7MCPmm1O9/jtD2m0hrHwnZPy3kU73U17+MG8g48" +
+ "l8K+VNgrv9l7v+X3HMv2uLPC/nTBn+DmarWbV4N8iIdJpH/QsifMfjbbLcby//PhfxZuO//U+OXt1TGkL8o5M+B6f9drDdZ" +
+ "zZlC9i8I+aaofQ/F4ErMJhmN+fs3rgT7ni6/PX7teKnEHZ/q8Pj4+vfAzuZ+jPFzsLTxanV9eS/rL6+trKzafsE2LkPHP3T" +
+ "/Pezx8evH6rj+Kd0H/sVRzp+MaX8Sfjh5t9Tm+M7nrwVhNd56fNz+063/OOPj2t9p+R3zS+9d2hnXlf9DLN27g/+E6L0E/T" +
+ "/Rp/t5WseX3hnTe9uhmnh35WHLX544XEIAIAAA";
+
+ // Fake up a header
+ HeaderBlock header_block = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS);
+ header_block.setPropertyStart(0);
+
+ List<ByteBuffer> data_blocks = new ArrayList<>();
+ try (InputStream is = new ByteArrayInputStream(RawDataUtil.decompress(raw_data_array))) {
+ byte[] buf = new byte[header_block.getBigBlockSize().getBigBlockSize()];
+
+ for (int readBytes; (readBytes = is.read(buf)) != -1; ) {
+ data_blocks.add(ByteBuffer.wrap(buf.clone(), 0, readBytes));
+ }
+ }
+
+
+ // get property table from the document
+ PropertyTable table = new PropertyTable(header_block, data_blocks);
+
+ assertEquals(30 * 64, table.getRoot().getSize());
+ int count = 0;
+ Property lastChild = null;
+ for (Property p : table.getRoot()) {
+ assertNotNull(p);
+ lastChild = p;
+ ++count;
+ }
+
+ assertNotNull(lastChild, "no children found");
+ assertEquals(1, count);
+ assertTrue(lastChild.isDirectory());
+ count = 0;
+ for (Property p : (DirectoryProperty) lastChild) {
+ assertNotNull(p);
+ ++count;
+ }
+ assertEquals(35, count);
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestRootProperty.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestRootProperty.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestRootProperty.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/poifs/property/TestRootProperty.java Sat May 22 20:56:44 2021
@@ -35,88 +35,88 @@ import org.junit.jupiter.api.Test;
* Class to test RootProperty functionality
*/
final class TestRootProperty {
- private RootProperty _property;
- private byte[] _testblock;
+ private RootProperty _property;
+ private byte[] _testblock;
- @Test
- void testConstructor() throws IOException {
- createBasicRootProperty();
-
- UnsynchronizedByteArrayOutputStream stream = new UnsynchronizedByteArrayOutputStream(512);
- _property.writeData(stream);
- assertArrayEquals(_testblock, stream.toByteArray());
-
- }
-
- private void createBasicRootProperty() {
- _property = new RootProperty();
- _testblock = new byte[128];
- int index = 0;
-
- for (; index < 0x40; index++) {
- _testblock[index] = (byte) 0;
- }
- String name = "Root Entry";
- int limit = name.length();
-
- _testblock[index++] = (byte) (2 * (limit + 1));
- _testblock[index++] = (byte) 0;
- _testblock[index++] = (byte) 5;
- _testblock[index++] = (byte) 1;
- for (; index < 0x50; index++) {
- _testblock[index] = (byte) 0xff;
- }
- for (; index < 0x74; index++) {
- _testblock[index] = (byte) 0;
- }
- _testblock[index++] = (byte) POIFSConstants.END_OF_CHAIN;
- for (; index < 0x78; index++) {
- _testblock[index] = (byte) 0xff;
- }
- for (; index < 0x80; index++) {
- _testblock[index] = (byte) 0;
- }
- byte[] name_bytes = name.getBytes(LocaleUtil.CHARSET_1252);
-
- for (index = 0; index < limit; index++) {
- _testblock[index * 2] = name_bytes[index];
- }
- }
-
- @Test
- void testSetSize() {
- for (int j = 0; j < 10; j++) {
- createBasicRootProperty();
- _property.setSize(j);
- assertEquals(j * 64, _property.getSize(), "trying block count of " + j);
- }
- }
-
- @Test
- void testReadingConstructor() throws IOException {
- String[] inputBytes = {
- "52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00",
- "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
- "16 00 05 01 FF FF FF FF FF FF FF FF 02 00 00 00 20 08 02 00 00 00 00 00 C0 00 00 00 00 00 00 46",
- "00 00 00 00 00 00 00 00 00 00 00 00 C0 5C E8 23 9E 6B C1 01 FE FF FF FF 00 00 00 00 00 00 00 00",
- };
- int index = 0;
- byte[] input = RawDataUtil.decode(inputBytes);
- int offset = 0;
-
- RootProperty property = new RootProperty(index, input, offset);
- UnsynchronizedByteArrayOutputStream stream = new UnsynchronizedByteArrayOutputStream(128);
- byte[] expected = Arrays.copyOfRange(input, offset, offset+128);
- property.writeData(stream);
- byte[] output = stream.toByteArray();
-
- assertEquals(128, output.length);
- for (int j = 0; j < 128; j++) {
- assertEquals(expected[j], output[j], "mismatch at offset " + j);
- }
- assertEquals(index, property.getIndex());
- assertEquals("Root Entry", property.getName());
- assertFalse(property.getChildren().hasNext());
- assertEquals(ClassIDPredefined.EXCEL_V8.getClassID(), property.getStorageClsid());
- }
+ @Test
+ void testConstructor() throws IOException {
+ createBasicRootProperty();
+
+ UnsynchronizedByteArrayOutputStream stream = new UnsynchronizedByteArrayOutputStream(512);
+ _property.writeData(stream);
+ assertArrayEquals(_testblock, stream.toByteArray());
+
+ }
+
+ private void createBasicRootProperty() {
+ _property = new RootProperty();
+ _testblock = new byte[128];
+ int index = 0;
+
+ for (; index < 0x40; index++) {
+ _testblock[index] = (byte) 0;
+ }
+ String name = "Root Entry";
+ int limit = name.length();
+
+ _testblock[index++] = (byte) (2 * (limit + 1));
+ _testblock[index++] = (byte) 0;
+ _testblock[index++] = (byte) 5;
+ _testblock[index++] = (byte) 1;
+ for (; index < 0x50; index++) {
+ _testblock[index] = (byte) 0xff;
+ }
+ for (; index < 0x74; index++) {
+ _testblock[index] = (byte) 0;
+ }
+ _testblock[index++] = (byte) POIFSConstants.END_OF_CHAIN;
+ for (; index < 0x78; index++) {
+ _testblock[index] = (byte) 0xff;
+ }
+ for (; index < 0x80; index++) {
+ _testblock[index] = (byte) 0;
+ }
+ byte[] name_bytes = name.getBytes(LocaleUtil.CHARSET_1252);
+
+ for (index = 0; index < limit; index++) {
+ _testblock[index * 2] = name_bytes[index];
+ }
+ }
+
+ @Test
+ void testSetSize() {
+ for (int j = 0; j < 10; j++) {
+ createBasicRootProperty();
+ _property.setSize(j);
+ assertEquals(j * 64, _property.getSize(), "trying block count of " + j);
+ }
+ }
+
+ @Test
+ void testReadingConstructor() throws IOException {
+ String[] inputBytes = {
+ "52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00",
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
+ "16 00 05 01 FF FF FF FF FF FF FF FF 02 00 00 00 20 08 02 00 00 00 00 00 C0 00 00 00 00 00 00 46",
+ "00 00 00 00 00 00 00 00 00 00 00 00 C0 5C E8 23 9E 6B C1 01 FE FF FF FF 00 00 00 00 00 00 00 00",
+ };
+ int index = 0;
+ byte[] input = RawDataUtil.decode(inputBytes);
+ int offset = 0;
+
+ RootProperty property = new RootProperty(index, input, offset);
+ UnsynchronizedByteArrayOutputStream stream = new UnsynchronizedByteArrayOutputStream(128);
+ byte[] expected = Arrays.copyOfRange(input, offset, offset+128);
+ property.writeData(stream);
+ byte[] output = stream.toByteArray();
+
+ assertEquals(128, output.length);
+ for (int j = 0; j < 128; j++) {
+ assertEquals(expected[j], output[j], "mismatch at offset " + j);
+ }
+ assertEquals(index, property.getIndex());
+ assertEquals("Root Entry", property.getName());
+ assertFalse(property.getChildren().hasNext());
+ assertEquals(ClassIDPredefined.EXCEL_V8.getClassID(), property.getStorageClsid());
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/RawDataUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/RawDataUtil.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/RawDataUtil.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/RawDataUtil.java Sat May 22 20:56:44 2021
@@ -32,17 +32,17 @@ import org.apache.poi.util.IOUtils;
*/
public final class RawDataUtil {
- private RawDataUtil() {}
+ private RawDataUtil() {}
- public static byte[] decode(String[] hexDataLines) {
- UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream(hexDataLines.length * 32 + 32);
+ public static byte[] decode(String[] hexDataLines) {
+ UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream(hexDataLines.length * 32 + 32);
- for (String hexDataLine : hexDataLines) {
- byte[] lineData = HexRead.readFromString(hexDataLine);
- baos.write(lineData, 0, lineData.length);
- }
- return baos.toByteArray();
- }
+ for (String hexDataLine : hexDataLines) {
+ byte[] lineData = HexRead.readFromString(hexDataLine);
+ baos.write(lineData, 0, lineData.length);
+ }
+ return baos.toByteArray();
+ }
/**
* Decompress previously gziped/base64ed data
Modified: poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/TestHeaderBlockReading.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/TestHeaderBlockReading.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/TestHeaderBlockReading.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/poifs/storage/TestHeaderBlockReading.java Sat May 22 20:56:44 2021
@@ -31,43 +31,43 @@ import org.junit.jupiter.api.Test;
*/
final class TestHeaderBlockReading {
- @Test
- void testConstructors() throws IOException {
- String[] hexData = {
- "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00",
- "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF",
- "01 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
- };
- byte[] content = RawDataUtil.decode(hexData);
- HeaderBlock block = new HeaderBlock(new ByteArrayInputStream(content));
+ @Test
+ void testConstructors() throws IOException {
+ String[] hexData = {
+ "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00",
+ "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF",
+ "01 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF",
+ };
+ byte[] content = RawDataUtil.decode(hexData);
+ HeaderBlock block = new HeaderBlock(new ByteArrayInputStream(content));
- assertEquals(-2, block.getPropertyStart());
+ assertEquals(-2, block.getPropertyStart());
- // verify we can't read a short block
- byte[] shortblock = Arrays.copyOf(content, 511);
- assertThrows(IOException.class, () -> new HeaderBlock(new ByteArrayInputStream(shortblock)));
+ // verify we can't read a short block
+ byte[] shortblock = Arrays.copyOf(content, 511);
+ assertThrows(IOException.class, () -> new HeaderBlock(new ByteArrayInputStream(shortblock)));
- // try various forms of corruption
- for (int index = 0; index < 8; index++) {
- content[index] = (byte) (content[index] - 1);
- assertThrows(IOException.class, () -> new HeaderBlock(new ByteArrayInputStream(content)),
- "Should have caught IOException corrupting byte " + index);
+ // try various forms of corruption
+ for (int index = 0; index < 8; index++) {
+ content[index] = (byte) (content[index] - 1);
+ assertThrows(IOException.class, () -> new HeaderBlock(new ByteArrayInputStream(content)),
+ "Should have caught IOException corrupting byte " + index);
- // restore byte value
- content[index] = (byte) (content[index] + 1);
- }
- }
+ // restore byte value
+ content[index] = (byte) (content[index] + 1);
+ }
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/BaseTestMissingWorkbook.java Sat May 22 20:56:44 2021
@@ -48,99 +48,99 @@ public abstract class BaseTestMissingWor
protected final String SOURCE_WORKBOOK_FILENAME;
protected BaseTestMissingWorkbook(String MAIN_WORKBOOK_FILENAME,
- String SOURCE_DUMMY_WORKBOOK_FILENAME, String SOURCE_WORKBOOK_FILENAME) {
+ String SOURCE_DUMMY_WORKBOOK_FILENAME, String SOURCE_WORKBOOK_FILENAME) {
this.MAIN_WORKBOOK_FILENAME = MAIN_WORKBOOK_FILENAME;
this.SOURCE_DUMMY_WORKBOOK_FILENAME = SOURCE_DUMMY_WORKBOOK_FILENAME;
this.SOURCE_WORKBOOK_FILENAME = SOURCE_WORKBOOK_FILENAME;
}
- @BeforeEach
- protected void setUp() throws Exception {
- mainWorkbook = HSSFTestDataSamples.openSampleWorkbook(MAIN_WORKBOOK_FILENAME);
- sourceWorkbook = HSSFTestDataSamples.openSampleWorkbook(SOURCE_WORKBOOK_FILENAME);
-
- assertNotNull(mainWorkbook);
- assertNotNull(sourceWorkbook);
- }
-
- @AfterEach
- void tearDown() throws Exception {
- if(mainWorkbook != null) {
- mainWorkbook.close();
- }
-
- if(sourceWorkbook != null) {
- sourceWorkbook.close();
- }
- }
-
- @Test
- void testMissingWorkbookMissing() {
- FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
-
- Sheet lSheet = mainWorkbook.getSheetAt(0);
- Row lARow = lSheet.getRow(0);
- Cell lA1Cell = lARow.getCell(0);
-
- assertEquals(CellType.FORMULA, lA1Cell.getCellType());
- RuntimeException re = assertThrows(RuntimeException.class, () -> evaluator.evaluateFormulaCell(lA1Cell),
- "Missing external workbook reference exception expected!");
- assertTrue(re.getMessage().contains(SOURCE_DUMMY_WORKBOOK_FILENAME));
- }
-
- @Test
- void testMissingWorkbookMissingOverride() {
- Sheet lSheet = mainWorkbook.getSheetAt(0);
- Cell lA1Cell = lSheet.getRow(0).getCell(0);
- Cell lB1Cell = lSheet.getRow(1).getCell(0);
- Cell lC1Cell = lSheet.getRow(2).getCell(0);
-
- assertEquals(CellType.FORMULA, lA1Cell.getCellType());
- assertEquals(CellType.FORMULA, lB1Cell.getCellType());
- assertEquals(CellType.FORMULA, lC1Cell.getCellType());
+ @BeforeEach
+ protected void setUp() throws Exception {
+ mainWorkbook = HSSFTestDataSamples.openSampleWorkbook(MAIN_WORKBOOK_FILENAME);
+ sourceWorkbook = HSSFTestDataSamples.openSampleWorkbook(SOURCE_WORKBOOK_FILENAME);
- // Check cached values
+ assertNotNull(mainWorkbook);
+ assertNotNull(sourceWorkbook);
+ }
+
+ @AfterEach
+ void tearDown() throws Exception {
+ if(mainWorkbook != null) {
+ mainWorkbook.close();
+ }
+
+ if(sourceWorkbook != null) {
+ sourceWorkbook.close();
+ }
+ }
+
+ @Test
+ void testMissingWorkbookMissing() {
+ FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+
+ Sheet lSheet = mainWorkbook.getSheetAt(0);
+ Row lARow = lSheet.getRow(0);
+ Cell lA1Cell = lARow.getCell(0);
+
+ assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+ RuntimeException re = assertThrows(RuntimeException.class, () -> evaluator.evaluateFormulaCell(lA1Cell),
+ "Missing external workbook reference exception expected!");
+ assertTrue(re.getMessage().contains(SOURCE_DUMMY_WORKBOOK_FILENAME));
+ }
+
+ @Test
+ void testMissingWorkbookMissingOverride() {
+ Sheet lSheet = mainWorkbook.getSheetAt(0);
+ Cell lA1Cell = lSheet.getRow(0).getCell(0);
+ Cell lB1Cell = lSheet.getRow(1).getCell(0);
+ Cell lC1Cell = lSheet.getRow(2).getCell(0);
+
+ assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+ assertEquals(CellType.FORMULA, lB1Cell.getCellType());
+ assertEquals(CellType.FORMULA, lC1Cell.getCellType());
+
+ // Check cached values
assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
assertEquals("POI rocks!", lB1Cell.getStringCellValue());
- assertTrue(lC1Cell.getBooleanCellValue());
+ assertTrue(lC1Cell.getBooleanCellValue());
// Evaluate
- FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+ FormulaEvaluator evaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
evaluator.setIgnoreMissingWorkbooks(true);
- assertEquals(CellType.NUMERIC, evaluator.evaluateFormulaCell(lA1Cell));
- assertEquals(CellType.STRING, evaluator.evaluateFormulaCell(lB1Cell));
- assertEquals(CellType.BOOLEAN, evaluator.evaluateFormulaCell(lC1Cell));
-
- assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
- assertEquals("POI rocks!", lB1Cell.getStringCellValue());
- assertTrue(lC1Cell.getBooleanCellValue());
- }
-
- @Test
- void testExistingWorkbook() {
- Sheet lSheet = mainWorkbook.getSheetAt(0);
- Cell lA1Cell = lSheet.getRow(0).getCell(0);
- Cell lB1Cell = lSheet.getRow(1).getCell(0);
- Cell lC1Cell = lSheet.getRow(2).getCell(0);
-
- assertEquals(CellType.FORMULA, lA1Cell.getCellType());
- assertEquals(CellType.FORMULA, lB1Cell.getCellType());
- assertEquals(CellType.FORMULA, lC1Cell.getCellType());
-
- FormulaEvaluator lMainWorkbookEvaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
- FormulaEvaluator lSourceEvaluator = sourceWorkbook.getCreationHelper().createFormulaEvaluator();
- Map<String,FormulaEvaluator> workbooks = new HashMap<>();
- workbooks.put(MAIN_WORKBOOK_FILENAME, lMainWorkbookEvaluator);
- workbooks.put(SOURCE_DUMMY_WORKBOOK_FILENAME, lSourceEvaluator);
- lMainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);
-
- assertEquals(CellType.NUMERIC, lMainWorkbookEvaluator.evaluateFormulaCell(lA1Cell));
- assertEquals(CellType.STRING, lMainWorkbookEvaluator.evaluateFormulaCell(lB1Cell));
- assertEquals(CellType.BOOLEAN, lMainWorkbookEvaluator.evaluateFormulaCell(lC1Cell));
-
- assertEquals(20.0d, lA1Cell.getNumericCellValue(), 0.00001d);
- assertEquals("Apache rocks!", lB1Cell.getStringCellValue());
- assertFalse(lC1Cell.getBooleanCellValue());
- }
+ assertEquals(CellType.NUMERIC, evaluator.evaluateFormulaCell(lA1Cell));
+ assertEquals(CellType.STRING, evaluator.evaluateFormulaCell(lB1Cell));
+ assertEquals(CellType.BOOLEAN, evaluator.evaluateFormulaCell(lC1Cell));
+
+ assertEquals(10.0d, lA1Cell.getNumericCellValue(), 0.00001d);
+ assertEquals("POI rocks!", lB1Cell.getStringCellValue());
+ assertTrue(lC1Cell.getBooleanCellValue());
+ }
+
+ @Test
+ void testExistingWorkbook() {
+ Sheet lSheet = mainWorkbook.getSheetAt(0);
+ Cell lA1Cell = lSheet.getRow(0).getCell(0);
+ Cell lB1Cell = lSheet.getRow(1).getCell(0);
+ Cell lC1Cell = lSheet.getRow(2).getCell(0);
+
+ assertEquals(CellType.FORMULA, lA1Cell.getCellType());
+ assertEquals(CellType.FORMULA, lB1Cell.getCellType());
+ assertEquals(CellType.FORMULA, lC1Cell.getCellType());
+
+ FormulaEvaluator lMainWorkbookEvaluator = mainWorkbook.getCreationHelper().createFormulaEvaluator();
+ FormulaEvaluator lSourceEvaluator = sourceWorkbook.getCreationHelper().createFormulaEvaluator();
+ Map<String,FormulaEvaluator> workbooks = new HashMap<>();
+ workbooks.put(MAIN_WORKBOOK_FILENAME, lMainWorkbookEvaluator);
+ workbooks.put(SOURCE_DUMMY_WORKBOOK_FILENAME, lSourceEvaluator);
+ lMainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);
+
+ assertEquals(CellType.NUMERIC, lMainWorkbookEvaluator.evaluateFormulaCell(lA1Cell));
+ assertEquals(CellType.STRING, lMainWorkbookEvaluator.evaluateFormulaCell(lB1Cell));
+ assertEquals(CellType.BOOLEAN, lMainWorkbookEvaluator.evaluateFormulaCell(lC1Cell));
+
+ assertEquals(20.0d, lA1Cell.getNumericCellValue(), 0.00001d);
+ assertEquals("Apache rocks!", lB1Cell.getStringCellValue());
+ assertFalse(lC1Cell.getBooleanCellValue());
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/EvaluationListener.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/EvaluationListener.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/EvaluationListener.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/EvaluationListener.java Sat May 22 20:56:44 2021
@@ -25,41 +25,41 @@ import org.apache.poi.ss.formula.eval.Va
* Default method implementations all do nothing
*/
public abstract class EvaluationListener implements IEvaluationListener {
- @Override
+ @Override
public void onCacheHit(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ICacheEntry entry) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onEndEvaluate(ICacheEntry entry, ValueEval result) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onClearWholeCache() {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onClearCachedValue(ICacheEntry entry) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onChangeFromBlankValue(int sheetIndex, int rowIndex, int columnIndex,
- EvaluationCell cell, ICacheEntry entry) {
- // do nothing
- }
- @Override
+ EvaluationCell cell, ICacheEntry entry) {
+ // do nothing
+ }
+ @Override
public void sortDependentCachedValues(ICacheEntry[] entries) {
- // do nothing
- }
- @Override
+ // do nothing
+ }
+ @Override
public void onClearDependentCachedValue(ICacheEntry entry, int depth) {
- // do nothing
- }
+ // do nothing
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestCellCacheEntry.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestCellCacheEntry.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestCellCacheEntry.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestCellCacheEntry.java Sat May 22 20:56:44 2021
@@ -28,16 +28,16 @@ import org.junit.jupiter.api.Test;
*/
class TestCellCacheEntry {
- @Test
- void testBasic() {
- CellCacheEntry pcce = new PlainValueCellCacheEntry(new NumberEval(42.0));
- ValueEval ve = pcce.getValue();
- assertEquals(42, ((NumberEval)ve).getNumberValue(), 0.0);
+ @Test
+ void testBasic() {
+ CellCacheEntry pcce = new PlainValueCellCacheEntry(new NumberEval(42.0));
+ ValueEval ve = pcce.getValue();
+ assertEquals(42, ((NumberEval)ve).getNumberValue(), 0.0);
- FormulaCellCacheEntry fcce = new FormulaCellCacheEntry();
- fcce.updateFormulaResult(new NumberEval(10.0), CellCacheEntry.EMPTY_ARRAY, null);
+ FormulaCellCacheEntry fcce = new FormulaCellCacheEntry();
+ fcce.updateFormulaResult(new NumberEval(10.0), CellCacheEntry.EMPTY_ARRAY, null);
- ve = fcce.getValue();
- assertEquals(10, ((NumberEval)ve).getNumberValue(), 0.0);
- }
+ ve = fcce.getValue();
+ assertEquals(10, ((NumberEval)ve).getNumberValue(), 0.0);
+ }
}
Modified: poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestEvaluationCache.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestEvaluationCache.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestEvaluationCache.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestEvaluationCache.java Sat May 22 20:56:44 2021
@@ -61,614 +61,614 @@ import org.junit.jupiter.api.Test;
*/
class TestEvaluationCache {
- private static final class FormulaCellCacheEntryComparer implements Comparator<ICacheEntry> {
+ private static final class FormulaCellCacheEntryComparer implements Comparator<ICacheEntry> {
- private final Map<ICacheEntry,EvaluationCell> _formulaCellsByCacheEntry;
+ private final Map<ICacheEntry,EvaluationCell> _formulaCellsByCacheEntry;
- public FormulaCellCacheEntryComparer(Map<ICacheEntry,EvaluationCell> formulaCellsByCacheEntry) {
- _formulaCellsByCacheEntry = formulaCellsByCacheEntry;
- }
- private EvaluationCell getCell(ICacheEntry a) {
- return _formulaCellsByCacheEntry.get(a);
- }
- @Override
+ public FormulaCellCacheEntryComparer(Map<ICacheEntry,EvaluationCell> formulaCellsByCacheEntry) {
+ _formulaCellsByCacheEntry = formulaCellsByCacheEntry;
+ }
+ private EvaluationCell getCell(ICacheEntry a) {
+ return _formulaCellsByCacheEntry.get(a);
+ }
+ @Override
public int compare(ICacheEntry oa, ICacheEntry ob) {
- EvaluationCell a = getCell(oa);
- EvaluationCell b = getCell(ob);
- int cmp;
- cmp = a.getRowIndex() - b.getRowIndex();
- if (cmp != 0) {
- return cmp;
- }
- cmp = a.getColumnIndex() - b.getColumnIndex();
- if (cmp != 0) {
- return cmp;
- }
- if (a.getSheet() == b.getSheet()) {
- return 0;
- }
- throw new RuntimeException("Incomplete code - don't know how to order sheets");
- }
- }
-
- private static final class EvalListener extends EvaluationListener {
-
- private final List<String> _logList;
- private final HSSFWorkbook _book;
- private final Map<ICacheEntry,EvaluationCell> _formulaCellsByCacheEntry;
- private final Map<ICacheEntry,Loc> _plainCellLocsByCacheEntry;
-
- public EvalListener(HSSFWorkbook wb) {
- _book = wb;
- _logList = new ArrayList<>();
- _formulaCellsByCacheEntry = new HashMap<>();
- _plainCellLocsByCacheEntry = new HashMap<>();
- }
- @Override
+ EvaluationCell a = getCell(oa);
+ EvaluationCell b = getCell(ob);
+ int cmp;
+ cmp = a.getRowIndex() - b.getRowIndex();
+ if (cmp != 0) {
+ return cmp;
+ }
+ cmp = a.getColumnIndex() - b.getColumnIndex();
+ if (cmp != 0) {
+ return cmp;
+ }
+ if (a.getSheet() == b.getSheet()) {
+ return 0;
+ }
+ throw new RuntimeException("Incomplete code - don't know how to order sheets");
+ }
+ }
+
+ private static final class EvalListener extends EvaluationListener {
+
+ private final List<String> _logList;
+ private final HSSFWorkbook _book;
+ private final Map<ICacheEntry,EvaluationCell> _formulaCellsByCacheEntry;
+ private final Map<ICacheEntry,Loc> _plainCellLocsByCacheEntry;
+
+ public EvalListener(HSSFWorkbook wb) {
+ _book = wb;
+ _logList = new ArrayList<>();
+ _formulaCellsByCacheEntry = new HashMap<>();
+ _plainCellLocsByCacheEntry = new HashMap<>();
+ }
+ @Override
public void onCacheHit(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
- log("hit", rowIndex, columnIndex, result);
- }
- @Override
+ log("hit", rowIndex, columnIndex, result);
+ }
+ @Override
public void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ICacheEntry entry) {
- Loc loc = new Loc(0, sheetIndex, rowIndex, columnIndex);
- _plainCellLocsByCacheEntry.put(entry, loc);
- log("value", rowIndex, columnIndex, entry.getValue());
- }
- @Override
+ Loc loc = new Loc(0, sheetIndex, rowIndex, columnIndex);
+ _plainCellLocsByCacheEntry.put(entry, loc);
+ log("value", rowIndex, columnIndex, entry.getValue());
+ }
+ @Override
public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry) {
- _formulaCellsByCacheEntry.put(entry, cell);
- HSSFCell hc = _book.getSheetAt(0).getRow(cell.getRowIndex()).getCell(cell.getColumnIndex());
- log("start", cell.getRowIndex(), cell.getColumnIndex(), FormulaExtractor.getPtgs(hc));
- }
- @Override
+ _formulaCellsByCacheEntry.put(entry, cell);
+ HSSFCell hc = _book.getSheetAt(0).getRow(cell.getRowIndex()).getCell(cell.getColumnIndex());
+ log("start", cell.getRowIndex(), cell.getColumnIndex(), FormulaExtractor.getPtgs(hc));
+ }
+ @Override
public void onEndEvaluate(ICacheEntry entry, ValueEval result) {
- EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
- log("end", cell.getRowIndex(), cell.getColumnIndex(), result);
- }
- @Override
+ EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
+ log("end", cell.getRowIndex(), cell.getColumnIndex(), result);
+ }
+ @Override
public void onClearCachedValue(ICacheEntry entry) {
- int rowIndex;
- int columnIndex;
- EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
- if (cell == null) {
- Loc loc = _plainCellLocsByCacheEntry.get(entry);
- if (loc == null) {
- throw new IllegalStateException("can't find cell or location");
- }
- rowIndex = loc.getRowIndex();
- columnIndex = loc.getColumnIndex();
- } else {
- rowIndex = cell.getRowIndex();
- columnIndex = cell.getColumnIndex();
- }
- log("clear", rowIndex, columnIndex, entry.getValue());
- }
- @Override
+ int rowIndex;
+ int columnIndex;
+ EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
+ if (cell == null) {
+ Loc loc = _plainCellLocsByCacheEntry.get(entry);
+ if (loc == null) {
+ throw new IllegalStateException("can't find cell or location");
+ }
+ rowIndex = loc.getRowIndex();
+ columnIndex = loc.getColumnIndex();
+ } else {
+ rowIndex = cell.getRowIndex();
+ columnIndex = cell.getColumnIndex();
+ }
+ log("clear", rowIndex, columnIndex, entry.getValue());
+ }
+ @Override
public void sortDependentCachedValues(ICacheEntry[] entries) {
- Arrays.sort(entries, new FormulaCellCacheEntryComparer(_formulaCellsByCacheEntry));
- }
- @Override
+ Arrays.sort(entries, new FormulaCellCacheEntryComparer(_formulaCellsByCacheEntry));
+ }
+ @Override
public void onClearDependentCachedValue(ICacheEntry entry, int depth) {
- EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
- log("clear" + depth, cell.getRowIndex(), cell.getColumnIndex(), entry.getValue());
- }
+ EvaluationCell cell = _formulaCellsByCacheEntry.get(entry);
+ log("clear" + depth, cell.getRowIndex(), cell.getColumnIndex(), entry.getValue());
+ }
- @Override
+ @Override
public void onChangeFromBlankValue(int sheetIndex, int rowIndex, int columnIndex,
- EvaluationCell cell, ICacheEntry entry) {
- log("changeFromBlank", rowIndex, columnIndex, entry.getValue());
- if (entry.getValue() == null) { // hack to tell the difference between formula and plain value
- // perhaps the API could be improved: onChangeFromBlankToValue, onChangeFromBlankToFormula
- _formulaCellsByCacheEntry.put(entry, cell);
- } else {
- Loc loc = new Loc(0, sheetIndex, rowIndex, columnIndex);
- _plainCellLocsByCacheEntry.put(entry, loc);
- }
- }
- private void log(String tag, int rowIndex, int columnIndex, Object value) {
- StringBuilder sb = new StringBuilder(64);
- sb.append(tag).append(' ');
- sb.append(new CellReference(rowIndex, columnIndex, false, false).formatAsString());
- if (value != null) {
- sb.append(' ').append(formatValue(value));
- }
- _logList.add(sb.toString());
- }
- private String formatValue(Object value) {
- if (value instanceof Ptg[]) {
- Ptg[] ptgs = (Ptg[]) value;
- return HSSFFormulaParser.toFormulaString(_book, ptgs);
- }
- if (value instanceof NumberEval) {
- NumberEval ne = (NumberEval) value;
- return ne.getStringValue();
- }
- if (value instanceof StringEval) {
- StringEval se = (StringEval) value;
- return "'" + se.getStringValue() + "'";
- }
- if (value instanceof BoolEval) {
- BoolEval be = (BoolEval) value;
- return be.getStringValue();
- }
- if (value == BlankEval.instance) {
- return "#BLANK#";
- }
- if (value instanceof ErrorEval) {
- ErrorEval ee = (ErrorEval) value;
- return ErrorEval.getText(ee.getErrorCode());
- }
- throw new IllegalArgumentException("Unexpected value class ("
- + value.getClass().getName() + ")");
- }
- public String[] getAndClearLog() {
- String[] result = new String[_logList.size()];
- _logList.toArray(result);
- _logList.clear();
- return result;
- }
- }
- /**
- * Wrapper class to manage repetitive tasks from this test,
- *
- * Note - this class does a little bit more than just plain set-up of data. The method
- * {@link WorkbookEvaluator#notifyUpdateCell(EvaluationCell)} is called whenever a
- * cell value is changed.
- */
- private static final class MySheet {
-
- private final HSSFSheet _sheet;
- private final WorkbookEvaluator _evaluator;
- private final EvalListener _evalListener;
-
- public MySheet() {
- HSSFWorkbook _wb = new HSSFWorkbook();
- _evalListener = new EvalListener(_wb);
- _evaluator = WorkbookEvaluatorTestHelper.createEvaluator(_wb, _evalListener);
- _sheet = _wb.createSheet("Sheet1");
- }
-
- private static EvaluationCell wrapCell(HSSFCell cell) {
- return HSSFEvaluationTestHelper.wrapCell(cell);
- }
-
- public void setCellValue(String cellRefText, double value) {
- HSSFCell cell = getOrCreateCell(cellRefText);
- // be sure to blank cell, in case it is currently a formula
- cell.setBlank();
- // otherwise this line will only set the formula cached result;
- cell.setCellValue(value);
- _evaluator.notifyUpdateCell(wrapCell(cell));
- }
- public void clearCell(String cellRefText) {
- HSSFCell cell = getOrCreateCell(cellRefText);
- cell.setBlank();
- _evaluator.notifyUpdateCell(wrapCell(cell));
- }
-
- public void setCellFormula(String cellRefText, String formulaText) {
- HSSFCell cell = getOrCreateCell(cellRefText);
- cell.setCellFormula(formulaText);
- _evaluator.notifyUpdateCell(wrapCell(cell));
- }
-
- private HSSFCell getOrCreateCell(String cellRefText) {
- CellReference cr = new CellReference(cellRefText);
- int rowIndex = cr.getRow();
- HSSFRow row = _sheet.getRow(rowIndex);
- if (row == null) {
- row = _sheet.createRow(rowIndex);
- }
- int cellIndex = cr.getCol();
- HSSFCell cell = row.getCell(cellIndex);
- if (cell == null) {
- cell = row.createCell(cellIndex);
- }
- return cell;
- }
-
- public ValueEval evaluateCell(String cellRefText) {
- return _evaluator.evaluate(wrapCell(getOrCreateCell(cellRefText)));
- }
-
- public String[] getAndClearLog() {
- return _evalListener.getAndClearLog();
- }
-
- public void clearAllCachedResultValues() {
- _evaluator.clearAllCachedResultValues();
- }
- }
-
- private static MySheet createMediumComplex() {
- MySheet ms = new MySheet();
-
- // plain data in D1:F3
- ms.setCellValue("D1", 12);
- ms.setCellValue("E1", 13);
- ms.setCellValue("D2", 14);
- ms.setCellValue("E2", 15);
- ms.setCellValue("D3", 16);
- ms.setCellValue("E3", 17);
-
-
- ms.setCellFormula("C1", "SUM(D1:E2)");
- ms.setCellFormula("C2", "SUM(D2:E3)");
- ms.setCellFormula("C3", "SUM(D3:E4)");
-
- ms.setCellFormula("B1", "C2-C1");
- ms.setCellFormula("B2", "B3*C1-C2");
- ms.setCellValue("B3", 2);
-
- ms.setCellFormula("A1", "MAX(B1:B2)");
- ms.setCellFormula("A2", "MIN(B3,D2:F2)");
- ms.setCellFormula("A3", "B3*C3");
-
- // clear all the logging from the above initialisation
- ms.getAndClearLog();
- ms.clearAllCachedResultValues();
- return ms;
- }
-
- @Test
- void testMediumComplex() {
- MySheet ms = createMediumComplex();
- // completely fresh evaluation
- confirmEvaluate(ms, "A1", 46);
- confirmLog(ms, new String[] {
- "start A1 MAX(B1:B2)",
- "start B1 C2-C1",
- "start C2 SUM(D2:E3)",
- "value D2 14", "value E2 15", "value D3 16", "value E3 17",
- "end C2 62",
- "start C1 SUM(D1:E2)",
- "value D1 12", "value E1 13", "hit D2 14", "hit E2 15",
- "end C1 54",
- "end B1 8",
- "start B2 B3*C1-C2",
- "value B3 2",
- "hit C1 54",
- "hit C2 62",
- "end B2 46",
- "end A1 46",
- });
-
-
- // simple cache hit - immediate re-evaluation with no changes
- confirmEvaluate(ms, "A1", 46);
- confirmLog(ms, new String[] { "hit A1 46", });
-
- // change a low level cell
- ms.setCellValue("D1", 10);
- confirmLog(ms, new String[] {
- "clear D1 10",
- "clear1 C1 54",
- "clear2 B1 8",
- "clear3 A1 46",
- "clear2 B2 46",
- });
- confirmEvaluate(ms, "A1", 42);
- confirmLog(ms, new String[] {
- "start A1 MAX(B1:B2)",
- "start B1 C2-C1",
- "hit C2 62",
- "start C1 SUM(D1:E2)",
- "hit D1 10", "hit E1 13", "hit D2 14", "hit E2 15",
- "end C1 52",
- "end B1 10",
- "start B2 B3*C1-C2",
- "hit B3 2",
- "hit C1 52",
- "hit C2 62",
- "end B2 42",
- "end A1 42",
- });
-
- // Reset and try changing an intermediate value
- ms = createMediumComplex();
- confirmEvaluate(ms, "A1", 46);
- ms.getAndClearLog();
-
- ms.setCellValue("B3", 3); // B3 is in the middle of the dependency tree
- confirmLog(ms, new String[] {
- "clear B3 3",
- "clear1 B2 46",
- "clear2 A1 46",
- });
- confirmEvaluate(ms, "A1", 100);
- confirmLog(ms, new String[] {
- "start A1 MAX(B1:B2)",
- "hit B1 8",
- "start B2 B3*C1-C2",
- "hit B3 3",
- "hit C1 54",
- "hit C2 62",
- "end B2 100",
- "end A1 100",
- });
- }
-
- @Test
- void testMediumComplexWithDependencyChange() {
- // Changing an intermediate formula
- MySheet ms = createMediumComplex();
- confirmEvaluate(ms, "A1", 46);
- ms.getAndClearLog();
- ms.setCellFormula("B2", "B3*C2-C3"); // used to be "B3*C1-C2"
- confirmLog(ms, new String[] {
- "clear B2 46",
- "clear1 A1 46",
- });
-
- confirmEvaluate(ms, "A1", 91);
- confirmLog(ms, new String[] {
- "start A1 MAX(B1:B2)",
- "hit B1 8",
- "start B2 B3*C2-C3",
- "hit B3 2",
- "hit C2 62",
- "start C3 SUM(D3:E4)",
- "hit D3 16", "hit E3 17",
-// "value D4 #BLANK#", "value E4 #BLANK#",
- "end C3 33",
- "end B2 91",
- "end A1 91",
- });
-
- //----------------
- // Note - From now on the demonstrated POI behaviour is not optimal
- //----------------
-
- // Now change a value that should no longer affect B2
- ms.setCellValue("D1", 11);
- confirmLog(ms, new String[] {
- "clear D1 11",
- "clear1 C1 54",
- // note there is no "clear2 B2 91" here because B2 doesn't depend on C1 anymore
- "clear2 B1 8",
- "clear3 A1 91",
- });
-
- confirmEvaluate(ms, "B2", 91);
- confirmLog(ms, new String[] {
- "hit B2 91", // further confirmation that B2 was not cleared due to changing D1 above
- });
-
- // things should be back to normal now
- ms.setCellValue("D1", 11);
- confirmLog(ms, new String[] { });
- confirmEvaluate(ms, "B2", 91);
- confirmLog(ms, new String[] {
- "hit B2 91",
- });
- }
-
- /**
- * verifies that when updating a plain cell, depending (formula) cell cached values are cleared
- * only when the plain cell's value actually changes
- */
- @Test
- void testRedundantUpdate() {
- MySheet ms = new MySheet();
-
- ms.setCellValue("B1", 12);
- ms.setCellValue("C1", 13);
- ms.setCellFormula("A1", "B1+C1");
-
- // evaluate twice to confirm caching looks OK
- ms.evaluateCell("A1");
- ms.getAndClearLog();
- confirmEvaluate(ms, "A1", 25);
- confirmLog(ms, new String[] {
- "hit A1 25",
- });
-
- // Make redundant update, and check re-evaluation
- ms.setCellValue("B1", 12); // value didn't change
- confirmLog(ms, new String[] {});
- confirmEvaluate(ms, "A1", 25);
- confirmLog(ms, new String[] {
- "hit A1 25",
- });
-
- ms.setCellValue("B1", 11); // value changing
- confirmLog(ms, new String[] {
- "clear B1 11",
- "clear1 A1 25", // expect consuming formula cached result to get cleared
- });
- confirmEvaluate(ms, "A1", 24);
- confirmLog(ms, new String[] {
- "start A1 B1+C1",
- "hit B1 11",
- "hit C1 13",
- "end A1 24",
- });
- }
-
- /**
- * Changing any input to a formula may cause the formula to 'use' a different set of cells.
- * Functions like INDEX and OFFSET make this effect obvious, with functions like MATCH
- * and VLOOKUP the effect can be subtle. The presence of error values can also produce this
- * effect in almost every function and operator.
- */
- @Test
- void testSimpleWithDependencyChange() {
- MySheet ms = new MySheet();
-
- ms.setCellFormula("A1", "INDEX(C1:E1,1,B1)");
- ms.setCellValue("B1", 1);
- ms.setCellValue("C1", 17);
- ms.setCellValue("D1", 18);
- ms.setCellValue("E1", 19);
- ms.clearAllCachedResultValues();
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 17);
- confirmLog(ms, new String[] {
- "start A1 INDEX(C1:E1,1,B1)",
- "value B1 1",
- "value C1 17",
- "end A1 17",
- });
- ms.setCellValue("B1", 2);
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 18);
- confirmLog(ms, new String[] {
- "start A1 INDEX(C1:E1,1,B1)",
- "hit B1 2",
- "value D1 18",
- "end A1 18",
- });
-
- // change C1. Note - last time A1 evaluated C1 was not used
- ms.setCellValue("C1", 15);
- ms.getAndClearLog();
- confirmEvaluate(ms, "A1", 18);
- confirmLog(ms, new String[] {
- "hit A1 18",
- });
-
- // but A1 still uses D1, so if it changes...
- ms.setCellValue("D1", 25);
- ms.getAndClearLog();
- confirmEvaluate(ms, "A1", 25);
- confirmLog(ms, new String[] {
- "start A1 INDEX(C1:E1,1,B1)",
- "hit B1 2",
- "hit D1 25",
- "end A1 25",
- });
- }
-
- @Test
- void testBlankCells() {
- MySheet ms = new MySheet();
-
- ms.setCellFormula("A1", "sum(B1:D4,B5:E6)");
- ms.setCellValue("B1", 12);
- ms.clearAllCachedResultValues();
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 12);
- confirmLog(ms, new String[] {
- "start A1 SUM(B1:D4,B5:E6)",
- "value B1 12",
- "end A1 12",
- });
- ms.setCellValue("B6", 2);
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 14);
- confirmLog(ms, new String[] {
- "start A1 SUM(B1:D4,B5:E6)",
- "hit B1 12",
- "hit B6 2",
- "end A1 14",
- });
- ms.setCellValue("E4", 2);
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 14);
- confirmLog(ms, new String[] {
- "hit A1 14",
- });
-
- ms.setCellValue("D1", 1);
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 15);
- confirmLog(ms, new String[] {
- "start A1 SUM(B1:D4,B5:E6)",
- "hit B1 12",
- "hit D1 1",
- "hit B6 2",
- "end A1 15",
- });
- }
-
- /**
- * Make sure that when blank cells are changed to value/formula cells, any dependent formulas
- * have their cached results cleared.
- */
- @Test
- void testBlankCellChangedToValueCell_bug46053() {
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet("Sheet1");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cellA1 = row.createCell(0);
- HSSFCell cellB1 = row.createCell(1);
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
-
- cellA1.setCellFormula("B1+2.2");
- cellB1.setCellValue(1.5);
-
- fe.notifyUpdateCell(cellA1);
- fe.notifyUpdateCell(cellB1);
-
- CellValue cv;
- cv = fe.evaluate(cellA1);
- assertEquals(3.7, cv.getNumberValue(), 0.0);
-
- cellB1.setBlank();
- fe.notifyUpdateCell(cellB1);
- cv = fe.evaluate(cellA1); // B1 was used to evaluate A1
- assertEquals(2.2, cv.getNumberValue(), 0.0);
-
- cellB1.setCellValue(0.4); // changing B1, so A1 cached result should be cleared
- fe.notifyUpdateCell(cellB1);
- cv = fe.evaluate(cellA1);
-
- // looks like left-over cached result from before change to B1
- assertNotEquals(2.2, cv.getNumberValue(), "Identified bug 46053");
- assertEquals(2.6, cv.getNumberValue(), 0.0);
- }
-
- /**
- * same use-case as the test for bug 46053, but checking trace values too
- */
- @Test
- void testBlankCellChangedToValueCell() {
-
- MySheet ms = new MySheet();
-
- ms.setCellFormula("A1", "B1+2.2");
- ms.setCellValue("B1", 1.5);
- ms.clearAllCachedResultValues();
- ms.clearCell("B1");
- ms.getAndClearLog();
-
- confirmEvaluate(ms, "A1", 2.2);
- confirmLog(ms, new String[] {
- "start A1 B1+2.2",
- "end A1 2.2",
- });
- ms.setCellValue("B1", 0.4);
- confirmLog(ms, new String[] {
- "changeFromBlank B1 0.4",
- "clear A1",
- });
-
- confirmEvaluate(ms, "A1", 2.6);
- confirmLog(ms, new String[] {
- "start A1 B1+2.2",
- "hit B1 0.4",
- "end A1 2.6",
- });
- }
-
- private static void confirmEvaluate(MySheet ms, String cellRefText, double expectedValue) {
- ValueEval v = ms.evaluateCell(cellRefText);
- assertEquals(NumberEval.class, v.getClass());
- assertEquals(expectedValue, ((NumberEval)v).getNumberValue(), 0.0);
- }
-
- private static void confirmLog(MySheet ms, String[] expectedLog) {
- String[] actualLog = ms.getAndClearLog();
- assertArrayEquals(expectedLog, actualLog, "Log entry mismatch");
- }
+ EvaluationCell cell, ICacheEntry entry) {
+ log("changeFromBlank", rowIndex, columnIndex, entry.getValue());
+ if (entry.getValue() == null) { // hack to tell the difference between formula and plain value
+ // perhaps the API could be improved: onChangeFromBlankToValue, onChangeFromBlankToFormula
+ _formulaCellsByCacheEntry.put(entry, cell);
+ } else {
+ Loc loc = new Loc(0, sheetIndex, rowIndex, columnIndex);
+ _plainCellLocsByCacheEntry.put(entry, loc);
+ }
+ }
+ private void log(String tag, int rowIndex, int columnIndex, Object value) {
+ StringBuilder sb = new StringBuilder(64);
+ sb.append(tag).append(' ');
+ sb.append(new CellReference(rowIndex, columnIndex, false, false).formatAsString());
+ if (value != null) {
+ sb.append(' ').append(formatValue(value));
+ }
+ _logList.add(sb.toString());
+ }
+ private String formatValue(Object value) {
+ if (value instanceof Ptg[]) {
+ Ptg[] ptgs = (Ptg[]) value;
+ return HSSFFormulaParser.toFormulaString(_book, ptgs);
+ }
+ if (value instanceof NumberEval) {
+ NumberEval ne = (NumberEval) value;
+ return ne.getStringValue();
+ }
+ if (value instanceof StringEval) {
+ StringEval se = (StringEval) value;
+ return "'" + se.getStringValue() + "'";
+ }
+ if (value instanceof BoolEval) {
+ BoolEval be = (BoolEval) value;
+ return be.getStringValue();
+ }
+ if (value == BlankEval.instance) {
+ return "#BLANK#";
+ }
+ if (value instanceof ErrorEval) {
+ ErrorEval ee = (ErrorEval) value;
+ return ErrorEval.getText(ee.getErrorCode());
+ }
+ throw new IllegalArgumentException("Unexpected value class ("
+ + value.getClass().getName() + ")");
+ }
+ public String[] getAndClearLog() {
+ String[] result = new String[_logList.size()];
+ _logList.toArray(result);
+ _logList.clear();
+ return result;
+ }
+ }
+ /**
+ * Wrapper class to manage repetitive tasks from this test,
+ *
+ * Note - this class does a little bit more than just plain set-up of data. The method
+ * {@link WorkbookEvaluator#notifyUpdateCell(EvaluationCell)} is called whenever a
+ * cell value is changed.
+ */
+ private static final class MySheet {
+
+ private final HSSFSheet _sheet;
+ private final WorkbookEvaluator _evaluator;
+ private final EvalListener _evalListener;
+
+ public MySheet() {
+ HSSFWorkbook _wb = new HSSFWorkbook();
+ _evalListener = new EvalListener(_wb);
+ _evaluator = WorkbookEvaluatorTestHelper.createEvaluator(_wb, _evalListener);
+ _sheet = _wb.createSheet("Sheet1");
+ }
+
+ private static EvaluationCell wrapCell(HSSFCell cell) {
+ return HSSFEvaluationTestHelper.wrapCell(cell);
+ }
+
+ public void setCellValue(String cellRefText, double value) {
+ HSSFCell cell = getOrCreateCell(cellRefText);
+ // be sure to blank cell, in case it is currently a formula
+ cell.setBlank();
+ // otherwise this line will only set the formula cached result;
+ cell.setCellValue(value);
+ _evaluator.notifyUpdateCell(wrapCell(cell));
+ }
+ public void clearCell(String cellRefText) {
+ HSSFCell cell = getOrCreateCell(cellRefText);
+ cell.setBlank();
+ _evaluator.notifyUpdateCell(wrapCell(cell));
+ }
+
+ public void setCellFormula(String cellRefText, String formulaText) {
+ HSSFCell cell = getOrCreateCell(cellRefText);
+ cell.setCellFormula(formulaText);
+ _evaluator.notifyUpdateCell(wrapCell(cell));
+ }
+
+ private HSSFCell getOrCreateCell(String cellRefText) {
+ CellReference cr = new CellReference(cellRefText);
+ int rowIndex = cr.getRow();
+ HSSFRow row = _sheet.getRow(rowIndex);
+ if (row == null) {
+ row = _sheet.createRow(rowIndex);
+ }
+ int cellIndex = cr.getCol();
+ HSSFCell cell = row.getCell(cellIndex);
+ if (cell == null) {
+ cell = row.createCell(cellIndex);
+ }
+ return cell;
+ }
+
+ public ValueEval evaluateCell(String cellRefText) {
+ return _evaluator.evaluate(wrapCell(getOrCreateCell(cellRefText)));
+ }
+
+ public String[] getAndClearLog() {
+ return _evalListener.getAndClearLog();
+ }
+
+ public void clearAllCachedResultValues() {
+ _evaluator.clearAllCachedResultValues();
+ }
+ }
+
+ private static MySheet createMediumComplex() {
+ MySheet ms = new MySheet();
+
+ // plain data in D1:F3
+ ms.setCellValue("D1", 12);
+ ms.setCellValue("E1", 13);
+ ms.setCellValue("D2", 14);
+ ms.setCellValue("E2", 15);
+ ms.setCellValue("D3", 16);
+ ms.setCellValue("E3", 17);
+
+
+ ms.setCellFormula("C1", "SUM(D1:E2)");
+ ms.setCellFormula("C2", "SUM(D2:E3)");
+ ms.setCellFormula("C3", "SUM(D3:E4)");
+
+ ms.setCellFormula("B1", "C2-C1");
+ ms.setCellFormula("B2", "B3*C1-C2");
+ ms.setCellValue("B3", 2);
+
+ ms.setCellFormula("A1", "MAX(B1:B2)");
+ ms.setCellFormula("A2", "MIN(B3,D2:F2)");
+ ms.setCellFormula("A3", "B3*C3");
+
+ // clear all the logging from the above initialisation
+ ms.getAndClearLog();
+ ms.clearAllCachedResultValues();
+ return ms;
+ }
+
+ @Test
+ void testMediumComplex() {
+ MySheet ms = createMediumComplex();
+ // completely fresh evaluation
+ confirmEvaluate(ms, "A1", 46);
+ confirmLog(ms, new String[] {
+ "start A1 MAX(B1:B2)",
+ "start B1 C2-C1",
+ "start C2 SUM(D2:E3)",
+ "value D2 14", "value E2 15", "value D3 16", "value E3 17",
+ "end C2 62",
+ "start C1 SUM(D1:E2)",
+ "value D1 12", "value E1 13", "hit D2 14", "hit E2 15",
+ "end C1 54",
+ "end B1 8",
+ "start B2 B3*C1-C2",
+ "value B3 2",
+ "hit C1 54",
+ "hit C2 62",
+ "end B2 46",
+ "end A1 46",
+ });
+
+
+ // simple cache hit - immediate re-evaluation with no changes
+ confirmEvaluate(ms, "A1", 46);
+ confirmLog(ms, new String[] { "hit A1 46", });
+
+ // change a low level cell
+ ms.setCellValue("D1", 10);
+ confirmLog(ms, new String[] {
+ "clear D1 10",
+ "clear1 C1 54",
+ "clear2 B1 8",
+ "clear3 A1 46",
+ "clear2 B2 46",
+ });
+ confirmEvaluate(ms, "A1", 42);
+ confirmLog(ms, new String[] {
+ "start A1 MAX(B1:B2)",
+ "start B1 C2-C1",
+ "hit C2 62",
+ "start C1 SUM(D1:E2)",
+ "hit D1 10", "hit E1 13", "hit D2 14", "hit E2 15",
+ "end C1 52",
+ "end B1 10",
+ "start B2 B3*C1-C2",
+ "hit B3 2",
+ "hit C1 52",
+ "hit C2 62",
+ "end B2 42",
+ "end A1 42",
+ });
+
+ // Reset and try changing an intermediate value
+ ms = createMediumComplex();
+ confirmEvaluate(ms, "A1", 46);
+ ms.getAndClearLog();
+
+ ms.setCellValue("B3", 3); // B3 is in the middle of the dependency tree
+ confirmLog(ms, new String[] {
+ "clear B3 3",
+ "clear1 B2 46",
+ "clear2 A1 46",
+ });
+ confirmEvaluate(ms, "A1", 100);
+ confirmLog(ms, new String[] {
+ "start A1 MAX(B1:B2)",
+ "hit B1 8",
+ "start B2 B3*C1-C2",
+ "hit B3 3",
+ "hit C1 54",
+ "hit C2 62",
+ "end B2 100",
+ "end A1 100",
+ });
+ }
+
+ @Test
+ void testMediumComplexWithDependencyChange() {
+ // Changing an intermediate formula
+ MySheet ms = createMediumComplex();
+ confirmEvaluate(ms, "A1", 46);
+ ms.getAndClearLog();
+ ms.setCellFormula("B2", "B3*C2-C3"); // used to be "B3*C1-C2"
+ confirmLog(ms, new String[] {
+ "clear B2 46",
+ "clear1 A1 46",
+ });
+
+ confirmEvaluate(ms, "A1", 91);
+ confirmLog(ms, new String[] {
+ "start A1 MAX(B1:B2)",
+ "hit B1 8",
+ "start B2 B3*C2-C3",
+ "hit B3 2",
+ "hit C2 62",
+ "start C3 SUM(D3:E4)",
+ "hit D3 16", "hit E3 17",
+// "value D4 #BLANK#", "value E4 #BLANK#",
+ "end C3 33",
+ "end B2 91",
+ "end A1 91",
+ });
+
+ //----------------
+ // Note - From now on the demonstrated POI behaviour is not optimal
+ //----------------
+
+ // Now change a value that should no longer affect B2
+ ms.setCellValue("D1", 11);
+ confirmLog(ms, new String[] {
+ "clear D1 11",
+ "clear1 C1 54",
+ // note there is no "clear2 B2 91" here because B2 doesn't depend on C1 anymore
+ "clear2 B1 8",
+ "clear3 A1 91",
+ });
+
+ confirmEvaluate(ms, "B2", 91);
+ confirmLog(ms, new String[] {
+ "hit B2 91", // further confirmation that B2 was not cleared due to changing D1 above
+ });
+
+ // things should be back to normal now
+ ms.setCellValue("D1", 11);
+ confirmLog(ms, new String[] { });
+ confirmEvaluate(ms, "B2", 91);
+ confirmLog(ms, new String[] {
+ "hit B2 91",
+ });
+ }
+
+ /**
+ * verifies that when updating a plain cell, depending (formula) cell cached values are cleared
+ * only when the plain cell's value actually changes
+ */
+ @Test
+ void testRedundantUpdate() {
+ MySheet ms = new MySheet();
+
+ ms.setCellValue("B1", 12);
+ ms.setCellValue("C1", 13);
+ ms.setCellFormula("A1", "B1+C1");
+
+ // evaluate twice to confirm caching looks OK
+ ms.evaluateCell("A1");
+ ms.getAndClearLog();
+ confirmEvaluate(ms, "A1", 25);
+ confirmLog(ms, new String[] {
+ "hit A1 25",
+ });
+
+ // Make redundant update, and check re-evaluation
+ ms.setCellValue("B1", 12); // value didn't change
+ confirmLog(ms, new String[] {});
+ confirmEvaluate(ms, "A1", 25);
+ confirmLog(ms, new String[] {
+ "hit A1 25",
+ });
+
+ ms.setCellValue("B1", 11); // value changing
+ confirmLog(ms, new String[] {
+ "clear B1 11",
+ "clear1 A1 25", // expect consuming formula cached result to get cleared
+ });
+ confirmEvaluate(ms, "A1", 24);
+ confirmLog(ms, new String[] {
+ "start A1 B1+C1",
+ "hit B1 11",
+ "hit C1 13",
+ "end A1 24",
+ });
+ }
+
+ /**
+ * Changing any input to a formula may cause the formula to 'use' a different set of cells.
+ * Functions like INDEX and OFFSET make this effect obvious, with functions like MATCH
+ * and VLOOKUP the effect can be subtle. The presence of error values can also produce this
+ * effect in almost every function and operator.
+ */
+ @Test
+ void testSimpleWithDependencyChange() {
+ MySheet ms = new MySheet();
+
+ ms.setCellFormula("A1", "INDEX(C1:E1,1,B1)");
+ ms.setCellValue("B1", 1);
+ ms.setCellValue("C1", 17);
+ ms.setCellValue("D1", 18);
+ ms.setCellValue("E1", 19);
+ ms.clearAllCachedResultValues();
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 17);
+ confirmLog(ms, new String[] {
+ "start A1 INDEX(C1:E1,1,B1)",
+ "value B1 1",
+ "value C1 17",
+ "end A1 17",
+ });
+ ms.setCellValue("B1", 2);
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 18);
+ confirmLog(ms, new String[] {
+ "start A1 INDEX(C1:E1,1,B1)",
+ "hit B1 2",
+ "value D1 18",
+ "end A1 18",
+ });
+
+ // change C1. Note - last time A1 evaluated C1 was not used
+ ms.setCellValue("C1", 15);
+ ms.getAndClearLog();
+ confirmEvaluate(ms, "A1", 18);
+ confirmLog(ms, new String[] {
+ "hit A1 18",
+ });
+
+ // but A1 still uses D1, so if it changes...
+ ms.setCellValue("D1", 25);
+ ms.getAndClearLog();
+ confirmEvaluate(ms, "A1", 25);
+ confirmLog(ms, new String[] {
+ "start A1 INDEX(C1:E1,1,B1)",
+ "hit B1 2",
+ "hit D1 25",
+ "end A1 25",
+ });
+ }
+
+ @Test
+ void testBlankCells() {
+ MySheet ms = new MySheet();
+
+ ms.setCellFormula("A1", "sum(B1:D4,B5:E6)");
+ ms.setCellValue("B1", 12);
+ ms.clearAllCachedResultValues();
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 12);
+ confirmLog(ms, new String[] {
+ "start A1 SUM(B1:D4,B5:E6)",
+ "value B1 12",
+ "end A1 12",
+ });
+ ms.setCellValue("B6", 2);
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 14);
+ confirmLog(ms, new String[] {
+ "start A1 SUM(B1:D4,B5:E6)",
+ "hit B1 12",
+ "hit B6 2",
+ "end A1 14",
+ });
+ ms.setCellValue("E4", 2);
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 14);
+ confirmLog(ms, new String[] {
+ "hit A1 14",
+ });
+
+ ms.setCellValue("D1", 1);
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 15);
+ confirmLog(ms, new String[] {
+ "start A1 SUM(B1:D4,B5:E6)",
+ "hit B1 12",
+ "hit D1 1",
+ "hit B6 2",
+ "end A1 15",
+ });
+ }
+
+ /**
+ * Make sure that when blank cells are changed to value/formula cells, any dependent formulas
+ * have their cached results cleared.
+ */
+ @Test
+ void testBlankCellChangedToValueCell_bug46053() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet("Sheet1");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cellA1 = row.createCell(0);
+ HSSFCell cellB1 = row.createCell(1);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+
+ cellA1.setCellFormula("B1+2.2");
+ cellB1.setCellValue(1.5);
+
+ fe.notifyUpdateCell(cellA1);
+ fe.notifyUpdateCell(cellB1);
+
+ CellValue cv;
+ cv = fe.evaluate(cellA1);
+ assertEquals(3.7, cv.getNumberValue(), 0.0);
+
+ cellB1.setBlank();
+ fe.notifyUpdateCell(cellB1);
+ cv = fe.evaluate(cellA1); // B1 was used to evaluate A1
+ assertEquals(2.2, cv.getNumberValue(), 0.0);
+
+ cellB1.setCellValue(0.4); // changing B1, so A1 cached result should be cleared
+ fe.notifyUpdateCell(cellB1);
+ cv = fe.evaluate(cellA1);
+
+ // looks like left-over cached result from before change to B1
+ assertNotEquals(2.2, cv.getNumberValue(), "Identified bug 46053");
+ assertEquals(2.6, cv.getNumberValue(), 0.0);
+ }
+
+ /**
+ * same use-case as the test for bug 46053, but checking trace values too
+ */
+ @Test
+ void testBlankCellChangedToValueCell() {
+
+ MySheet ms = new MySheet();
+
+ ms.setCellFormula("A1", "B1+2.2");
+ ms.setCellValue("B1", 1.5);
+ ms.clearAllCachedResultValues();
+ ms.clearCell("B1");
+ ms.getAndClearLog();
+
+ confirmEvaluate(ms, "A1", 2.2);
+ confirmLog(ms, new String[] {
+ "start A1 B1+2.2",
+ "end A1 2.2",
+ });
+ ms.setCellValue("B1", 0.4);
+ confirmLog(ms, new String[] {
+ "changeFromBlank B1 0.4",
+ "clear A1",
+ });
+
+ confirmEvaluate(ms, "A1", 2.6);
+ confirmLog(ms, new String[] {
+ "start A1 B1+2.2",
+ "hit B1 0.4",
+ "end A1 2.6",
+ });
+ }
+
+ private static void confirmEvaluate(MySheet ms, String cellRefText, double expectedValue) {
+ ValueEval v = ms.evaluateCell(cellRefText);
+ assertEquals(NumberEval.class, v.getClass());
+ assertEquals(expectedValue, ((NumberEval)v).getNumberValue(), 0.0);
+ }
+
+ private static void confirmLog(MySheet ms, String[] expectedLog) {
+ String[] actualLog = ms.getAndClearLog();
+ assertArrayEquals(expectedLog, actualLog, "Log entry mismatch");
+ }
- @Test
+ @Test
void testPlainValueCache() {
Workbook wb = new HSSFWorkbook();
Modified: poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestFunctionRegistry.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestFunctionRegistry.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestFunctionRegistry.java (original)
+++ poi/trunk/poi/src/test/java/org/apache/poi/ss/formula/TestFunctionRegistry.java Sat May 22 20:56:44 2021
@@ -68,7 +68,7 @@ class TestFunctionRegistry {
}
@Test
- void testRegisterInRuntimeA() {
+ void testRegisterInRuntimeA() {
HSSFCell cellA = row.createCell(0);
cellA.setCellFormula("FISHER(A5)");
assertThrows(NotImplementedException.class, () -> fe.evaluate(cellA));
@@ -99,9 +99,9 @@ class TestFunctionRegistry {
CellValue cv = fe.evaluate(cellB);
assertEquals(ErrorEval.NUM_ERROR.getErrorCode(), cv.getErrorValue());
- }
+ }
- private static ValueEval na(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+ private static ValueEval na(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
return ErrorEval.NA;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org