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