+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
package org.apache.poi.hssf.model;\r
\r
import junit.framework.TestCase;\r
+import org.apache.poi.ddf.EscherClientDataRecord;\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
import org.apache.poi.ddf.EscherDggRecord;\r
+import org.apache.poi.ddf.EscherRecord;\r
+import org.apache.poi.ddf.EscherSpRecord;\r
import org.apache.poi.hssf.HSSFTestDataSamples;\r
-import org.apache.poi.hssf.record.ContinueRecord;\r
-import org.apache.poi.hssf.record.DrawingRecord;\r
-import org.apache.poi.hssf.record.EOFRecord;\r
-import org.apache.poi.hssf.record.EscherAggregate;\r
-import org.apache.poi.hssf.record.ObjRecord;\r
-import org.apache.poi.hssf.record.Record;\r
-import org.apache.poi.hssf.record.RecordBase;\r
-import org.apache.poi.hssf.record.RecordFactory;\r
-import org.apache.poi.hssf.record.TextObjectRecord;\r
-import org.apache.poi.hssf.record.WindowTwoRecord;\r
+import org.apache.poi.hssf.record.*;\r
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;\r
import org.apache.poi.hssf.usermodel.HSSFSheet;\r
import org.apache.poi.hssf.usermodel.HSSFTestHelper;\r
import org.apache.poi.util.HexRead;\r
\r
import java.io.ByteArrayInputStream;\r
+import java.util.ArrayList;\r
+import java.util.LinkedHashMap;\r
import java.util.List;\r
+import java.util.Map;\r
\r
/**\r
* @author Yegor Kozlov\r
* @author Evgeniy Berlog\r
*/\r
public class TestDrawingAggregate extends TestCase {\r
+ /**\r
+ * Serialize escher aggregate, read back and assert that the drawing data is preserved.\r
+ *\r
+ * @param agg the aggregate to test\r
+ * @return verified aggregate (serialized and read back)\r
+ */\r
+ public static EscherAggregate assertWriteAndReadBack(EscherAggregate agg) {\r
+ byte[] dgBytes = agg.serialize();\r
+\r
+\r
+ List<Record> dgRecords = RecordFactory.createRecords(new ByteArrayInputStream(dgBytes));\r
+\r
+ DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord());\r
+\r
+ // create a dummy sheet consisting of our test data\r
+ InternalSheet sheet = InternalSheet.createSheet();\r
+ List<RecordBase> records = sheet.getRecords();\r
+ records.clear();\r
+ records.addAll(dgRecords);\r
+ records.add(EOFRecord.instance);\r
+\r
+\r
+ sheet.aggregateDrawingRecords(drawingManager, false);\r
+ assertEquals("drawing was not fully aggregated", 2, records.size());\r
+ assertTrue("expected EscherAggregate", records.get(0) instanceof EscherAggregate);\r
+ assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);\r
+ EscherAggregate agg2 = (EscherAggregate) records.get(0);\r
+\r
+ assertEquals(agg.getEscherRecords().size(), agg2.getEscherRecords().size());\r
+\r
+ // assert that both pre- and after- serialize aggregates have the same xml representation\r
+ for (int i = 0; i < agg.getEscherRecords().size(); i++) {\r
+ EscherRecord r1 = agg.getEscherRecords().get(i);\r
+ EscherRecord r2 = agg2.getEscherRecords().get(i);\r
+\r
+ assertEquals(r1.toXml(), r2.toXml());\r
+ }\r
+\r
+ return agg2;\r
+ }\r
+\r
+ /**\r
+ * assert that mapping of Obj records to escher shape containers is the same in both aggregates\r
+ */\r
+ public static void assertObjectMappingSame(EscherAggregate agg1, EscherAggregate agg2) {\r
+\r
+ // map EscherClientDataRecord and EscherTextboxRecord to their parents\r
+ Map<EscherRecord, EscherContainerRecord> map1 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();\r
+ for (EscherRecord r : agg1.getEscherRecords()) mapShapeContainers(r, map1);\r
+\r
+ Map<EscherRecord, EscherContainerRecord> map2 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();\r
+ for (EscherRecord r : agg2.getEscherRecords()) mapShapeContainers(r, map2);\r
+\r
+ assertEquals("aggregates have different number of shapes", map1.size(), map2.size());\r
+\r
+ // for each EscherClientDataRecord get parent SP_CONTAINER and corresponding ObjRecord\r
+ // verify that ObjRecord to\r
+ List<EscherRecord> l1 = new ArrayList<EscherRecord>(map1.keySet());\r
+ List<EscherRecord> l2 = new ArrayList<EscherRecord>(map2.keySet());\r
+ for (int i = 0; i < l1.size(); i++) {\r
+ EscherRecord e1 = l1.get(i);\r
+ EscherRecord e2 = l2.get(i);\r
+ ObjRecord obj1 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg1).get(e1);\r
+ ObjRecord obj2 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg2).get(e2);\r
+\r
+ CommonObjectDataSubRecord cmo1 = (CommonObjectDataSubRecord) obj1.getSubRecords().get(0);\r
+ CommonObjectDataSubRecord cmo2 = (CommonObjectDataSubRecord) obj2.getSubRecords().get(0);\r
+\r
+ assertEquals(cmo1.getObjectId(), cmo2.getObjectId());\r
+ assertEquals(obj1.toString(), obj2.toString());\r
+\r
+ // test that obj parents have the same shapeId, that is, that shape is the same\r
+ EscherContainerRecord p1 = map1.get(e1);\r
+ EscherContainerRecord p2 = map2.get(e2);\r
+ EscherSpRecord sp1 = (EscherSpRecord) p1.getChildById(EscherSpRecord.RECORD_ID);\r
+ EscherSpRecord sp2 = (EscherSpRecord) p2.getChildById(EscherSpRecord.RECORD_ID);\r
+ assertEquals(sp1.getShapeId(), sp2.getShapeId());\r
+\r
+ assertEquals("wrong shape2obj mapping", sp1.getShapeId() % 1024, cmo1.getObjectId());\r
+ assertEquals(p1.toXml(), p2.toXml());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * recursively map EscherClientDataRecords to their parent shape containers:\r
+ * <p/>\r
+ * EscherClientDataRecord1 --> EscherContainerRecord1\r
+ * EscherClientDataRecord2 --> EscherContainerRecord2\r
+ * ...\r
+ * <p/>\r
+ * TODO: YK: this method can be avoided if we have EscherRecord.getParent()\r
+ */\r
+ private static void mapShapeContainers(EscherRecord parent, Map<EscherRecord, EscherContainerRecord> map) {\r
+ if (parent.isContainerRecord()) {\r
+ if (parent.getRecordId() == EscherContainerRecord.SP_CONTAINER) {\r
+ // iterate over shape's children and search for EscherClientDataRecord\r
+ for (EscherRecord r : parent.getChildRecords()) {\r
+ if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {\r
+ map.put(r, (EscherContainerRecord) parent);\r
+ }\r
+ }\r
+ } else {\r
+ for (EscherRecord ch : parent.getChildRecords()) {\r
+ mapShapeContainers(ch, map);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
/**\r
* test reading drawing aggregate from a test file from Bugzilla 45129\r
*/\r
// The subrange [19, 388] is expected to be replaced with a EscherAggregate object\r
DrawingManager2 drawingManager = iworkbook.findDrawingGroup();\r
int loc = isheet.aggregateDrawingRecords(drawingManager, false);\r
- EscherAggregate ag = (EscherAggregate) records.get(loc);\r
+ EscherAggregate agg = (EscherAggregate) records.get(loc);\r
\r
assertEquals("wrong size of the aggregated sheet records stream", 25, records.size());\r
assertTrue(\r
assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),\r
records.get(20) instanceof WindowTwoRecord);\r
\r
- // TODO figure out why serialization fails\r
- // byte[] bytes = ag.serialize();\r
+ EscherAggregate agg2 = assertWriteAndReadBack(agg);\r
+\r
+ assertObjectMappingSame(agg, agg2);\r
}\r
\r
public void testFileWithPictures() {\r
\r
List<RecordBase> records = isheet.getRecords();\r
\r
- for (RecordBase recordBase : records) {\r
- System.out.println(recordBase.toString());\r
- }\r
-\r
// the sheet's drawing is not aggregated\r
assertEquals("wrong size of sheet records stream", 315, records.size());\r
// the last record before the drawing block\r
// The subrange [19, 388] is expected to be replaced with a EscherAggregate object\r
DrawingManager2 drawingManager = iworkbook.findDrawingGroup();\r
int loc = isheet.aggregateDrawingRecords(drawingManager, false);\r
- EscherAggregate ag = (EscherAggregate) records.get(loc);\r
+ EscherAggregate agg = (EscherAggregate) records.get(loc);\r
\r
assertEquals("wrong size of the aggregated sheet records stream", 38, records.size());\r
assertTrue(\r
records.get(22) instanceof EscherAggregate);\r
assertTrue("records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName(),\r
records.get(23) instanceof WindowTwoRecord);\r
+\r
+ EscherAggregate agg2 = assertWriteAndReadBack(agg);\r
+\r
+ assertObjectMappingSame(agg, agg2);\r
}\r
\r
public void testUnhandledContinue() {\r
assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);\r
EscherAggregate agg = (EscherAggregate) records.get(0);\r
\r
- // TODO figure out why serialization fails\r
-// byte[] writtenBytes = agg.serialize();\r
+ // serialize, read back and assert that the drawing data is preserved\r
+ EscherAggregate agg2 = assertWriteAndReadBack(agg);\r
+\r
+ assertObjectMappingSame(agg, agg2);\r
}\r
\r
public void testUnhandledContinue2() {\r
records.addAll(dgRecords);\r
records.add(EOFRecord.instance);\r
\r
-\r
sheet.aggregateDrawingRecords(drawingManager, false);\r
assertEquals("drawing was not fully aggregated", 2, records.size());\r
assertTrue("expected EscherAggregate", records.get(0) instanceof EscherAggregate);\r
assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);\r
+\r
+ EscherAggregate agg = (EscherAggregate) records.get(0);\r
+\r
+ EscherAggregate agg2 = assertWriteAndReadBack(agg);\r
+\r
+ assertObjectMappingSame(agg, agg2);\r
}\r
}\r