PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/poi-3.6/src/testcases/org/apache/poi/hssf/record/TestSSTRecord.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 357 lines | 248 code | 45 blank | 64 comment | 25 complexity | 0ebae7f7bf6778959503763142440c75 MD5 | raw file
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.record;
  16. import java.io.BufferedReader;
  17. import java.io.ByteArrayInputStream;
  18. import java.io.ByteArrayOutputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.util.Arrays;
  23. import java.util.Iterator;
  24. import junit.framework.AssertionFailedError;
  25. import junit.framework.TestCase;
  26. import org.apache.poi.hssf.HSSFTestDataSamples;
  27. import org.apache.poi.hssf.usermodel.HSSFSheet;
  28. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  29. import org.apache.poi.util.HexRead;
  30. import org.apache.poi.util.LittleEndian;
  31. /**
  32. * @author Marc Johnson (mjohnson at apache dot org)
  33. * @author Glen Stampoultzis (glens at apache.org)
  34. */
  35. public final class TestSSTRecord extends TestCase {
  36. /**
  37. * decodes hexdump files and concatenates the results
  38. * @param hexDumpFileNames names of sample files in the hssf test data directory
  39. */
  40. private static byte[] concatHexDumps(String... hexDumpFileNames) {
  41. int nFiles = hexDumpFileNames.length;
  42. ByteArrayOutputStream baos = new ByteArrayOutputStream(nFiles * 8228);
  43. for (int i = 0; i < nFiles; i++) {
  44. String sampleFileName = hexDumpFileNames[i];
  45. InputStream is = HSSFTestDataSamples.openSampleFileStream(sampleFileName);
  46. BufferedReader br = new BufferedReader(new InputStreamReader(is));
  47. try {
  48. while (true) {
  49. String line = br.readLine();
  50. if (line == null) {
  51. break;
  52. }
  53. baos.write(HexRead.readFromString(line));
  54. }
  55. is.close();
  56. } catch (IOException e) {
  57. throw new RuntimeException(e);
  58. }
  59. }
  60. return baos.toByteArray();
  61. }
  62. /**
  63. * @param rawData serialization of one {@link SSTRecord} and zero or more {@link ContinueRecord}s
  64. */
  65. private static SSTRecord createSSTFromRawData(byte[] rawData) {
  66. RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(rawData));
  67. in.nextRecord();
  68. SSTRecord result = new SSTRecord(in);
  69. assertEquals(0, in.remaining());
  70. assertTrue(!in.hasNextRecord());
  71. return result;
  72. }
  73. /**
  74. * SST is often split over several {@link ContinueRecord}s
  75. */
  76. public void testContinuedRecord() {
  77. byte[] origData;
  78. SSTRecord record;
  79. byte[] ser_output;
  80. origData = concatHexDumps("BigSSTRecord", "BigSSTRecordCR");
  81. record = createSSTFromRawData(origData);
  82. assertEquals( 1464, record.getNumStrings() );
  83. assertEquals( 688, record.getNumUniqueStrings() );
  84. assertEquals( 688, record.countStrings() );
  85. ser_output = record.serialize();
  86. assertTrue(Arrays.equals(origData, ser_output));
  87. // testing based on new bug report
  88. origData = concatHexDumps("BigSSTRecord2", "BigSSTRecord2CR1", "BigSSTRecord2CR2", "BigSSTRecord2CR3",
  89. "BigSSTRecord2CR4", "BigSSTRecord2CR5", "BigSSTRecord2CR6", "BigSSTRecord2CR7");
  90. record = createSSTFromRawData(origData);
  91. assertEquals( 158642, record.getNumStrings() );
  92. assertEquals( 5249, record.getNumUniqueStrings() );
  93. assertEquals( 5249, record.countStrings() );
  94. ser_output = record.serialize();
  95. if (false) { // set true to observe make sure areSameSSTs() is working
  96. ser_output[11000] = 'X';
  97. }
  98. SSTRecord rec2 = createSSTFromRawData(ser_output);
  99. if (!areSameSSTs(record, rec2)) {
  100. throw new AssertionFailedError("large SST re-serialized incorrectly");
  101. }
  102. if (false) {
  103. // TODO - trivial differences in ContinueRecord break locations
  104. // Sample data should be checked against what most recent Excel version produces.
  105. // maybe tweaks are required in ContinuableRecordOutput
  106. assertTrue(Arrays.equals(origData, ser_output));
  107. }
  108. }
  109. private boolean areSameSSTs(SSTRecord a, SSTRecord b) {
  110. if (a.getNumStrings() != b.getNumStrings()) {
  111. return false;
  112. }
  113. int nElems = a.getNumUniqueStrings();
  114. if (nElems != b.getNumUniqueStrings()) {
  115. return false;
  116. }
  117. for(int i=0; i<nElems; i++) {
  118. if (!a.getString(i).equals(b.getString(i))) {
  119. return false;
  120. }
  121. }
  122. return true;
  123. }
  124. /**
  125. * Test capability of handling mondo big strings
  126. *
  127. * @exception IOException
  128. */
  129. public void testHugeStrings() {
  130. SSTRecord record = new SSTRecord();
  131. byte[][] bstrings =
  132. {
  133. new byte[9000], new byte[7433], new byte[9002],
  134. new byte[16998]
  135. };
  136. UnicodeString[] strings = new UnicodeString[bstrings.length];
  137. int total_length = 0;
  138. for ( int k = 0; k < bstrings.length; k++ )
  139. {
  140. Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
  141. strings[k] = new UnicodeString( new String(bstrings[k]) );
  142. record.addString( strings[k] );
  143. total_length += 3 + bstrings[k].length;
  144. }
  145. // add overhead of SST record
  146. total_length += 8;
  147. // add overhead of broken strings
  148. total_length += 4;
  149. // add overhead of six records
  150. total_length += ( 6 * 4 );
  151. byte[] content = new byte[record.getRecordSize()];
  152. record.serialize( 0, content );
  153. assertEquals( total_length, content.length );
  154. //Deserialize the record.
  155. RecordInputStream recStream = new RecordInputStream(new ByteArrayInputStream(content));
  156. recStream.nextRecord();
  157. record = new SSTRecord(recStream);
  158. assertEquals( strings.length, record.getNumStrings() );
  159. assertEquals( strings.length, record.getNumUniqueStrings() );
  160. assertEquals( strings.length, record.countStrings() );
  161. for ( int k = 0; k < strings.length; k++ )
  162. {
  163. assertEquals( strings[k], record.getString( k ) );
  164. }
  165. record = new SSTRecord();
  166. bstrings[1] = new byte[bstrings[1].length - 1];
  167. for ( int k = 0; k < bstrings.length; k++ )
  168. {
  169. if ( ( bstrings[k].length % 2 ) == 1 )
  170. {
  171. Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
  172. strings[k] = new UnicodeString( new String(bstrings[k]) );
  173. }
  174. else
  175. {
  176. char[] data = new char[bstrings[k].length / 2];
  177. Arrays.fill( data, (char) ( '\u2122' + k ) );
  178. strings[k] = new UnicodeString(new String( data ));
  179. }
  180. record.addString( strings[k] );
  181. }
  182. content = new byte[record.getRecordSize()];
  183. record.serialize( 0, content );
  184. total_length--;
  185. assertEquals( total_length, content.length );
  186. recStream = new RecordInputStream(new ByteArrayInputStream(content));
  187. recStream.nextRecord();
  188. record = new SSTRecord(recStream);
  189. assertEquals( strings.length, record.getNumStrings() );
  190. assertEquals( strings.length, record.getNumUniqueStrings() );
  191. assertEquals( strings.length, record.countStrings() );
  192. for ( int k = 0; k < strings.length; k++ )
  193. {
  194. assertEquals( strings[k], record.getString( k ) );
  195. }
  196. }
  197. /**
  198. * test SSTRecord boundary conditions
  199. */
  200. public void testSSTRecordBug() {
  201. // create an SSTRecord and write a certain pattern of strings
  202. // to it ... then serialize it and verify the content
  203. SSTRecord record = new SSTRecord();
  204. // the record will start with two integers, then this string
  205. // ... that will eat up 16 of the 8224 bytes that the record
  206. // can hold
  207. record.addString( new UnicodeString("Hello") );
  208. // now we have an additional 8208 bytes, which is an exact
  209. // multiple of 16 bytes
  210. long testvalue = 1000000000000L;
  211. for ( int k = 0; k < 2000; k++ )
  212. {
  213. record.addString( new UnicodeString(String.valueOf( testvalue++ )) );
  214. }
  215. byte[] content = new byte[record.getRecordSize()];
  216. record.serialize( 0, content );
  217. assertEquals(8224, LittleEndian.getShort(content, 2));
  218. assertEquals(ContinueRecord.sid, LittleEndian.getShort(content, 8228));
  219. assertEquals(8224, LittleEndian.getShort(content, 8228+2));
  220. assertEquals( (byte) 13, content[4 + 8228] );
  221. assertEquals(ContinueRecord.sid, LittleEndian.getShort(content, 2*8228));
  222. assertEquals(8224, LittleEndian.getShort(content, 8228*2+2));
  223. assertEquals( (byte) 13, content[4 + 8228 * 2] );
  224. assertEquals(ContinueRecord.sid, LittleEndian.getShort(content, 3*8228));
  225. assertEquals( (byte) 13, content[4 + 8228 * 3] );
  226. }
  227. /**
  228. * test simple addString
  229. */
  230. public void testSimpleAddString() {
  231. SSTRecord record = new SSTRecord();
  232. UnicodeString s1 = new UnicodeString("Hello world");
  233. // \u2122 is the encoding of the trademark symbol ...
  234. UnicodeString s2 = new UnicodeString("Hello world\u2122");
  235. assertEquals( 0, record.addString( s1 ) );
  236. assertEquals( s1, record.getString( 0 ) );
  237. assertEquals( 1, record.countStrings() );
  238. assertEquals( 1, record.getNumStrings() );
  239. assertEquals( 1, record.getNumUniqueStrings() );
  240. assertEquals( 0, record.addString( s1 ) );
  241. assertEquals( s1, record.getString( 0 ) );
  242. assertEquals( 1, record.countStrings() );
  243. assertEquals( 2, record.getNumStrings() );
  244. assertEquals( 1, record.getNumUniqueStrings() );
  245. assertEquals( 1, record.addString( s2 ) );
  246. assertEquals( s2, record.getString( 1 ) );
  247. assertEquals( 2, record.countStrings() );
  248. assertEquals( 3, record.getNumStrings() );
  249. assertEquals( 2, record.getNumUniqueStrings() );
  250. Iterator iter = record.getStrings();
  251. while ( iter.hasNext() )
  252. {
  253. UnicodeString ucs = (UnicodeString) iter.next();
  254. if ( ucs.equals( s1 ) )
  255. {
  256. assertEquals( (byte) 0, ucs.getOptionFlags() );
  257. }
  258. else if ( ucs.equals( s2 ) )
  259. {
  260. assertEquals( (byte) 1, ucs.getOptionFlags() );
  261. }
  262. else
  263. {
  264. fail( "cannot match string: " + ucs.getString() );
  265. }
  266. }
  267. }
  268. /**
  269. * test simple constructor
  270. */
  271. public void testSimpleConstructor() {
  272. SSTRecord record = new SSTRecord();
  273. assertEquals( 0, record.getNumStrings() );
  274. assertEquals( 0, record.getNumUniqueStrings() );
  275. assertEquals( 0, record.countStrings() );
  276. byte[] output = record.serialize();
  277. byte[] expected =
  278. {
  279. (byte) record.getSid(), (byte) ( record.getSid() >> 8 ),
  280. (byte) 8, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
  281. (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0
  282. };
  283. assertEquals( expected.length, output.length );
  284. for ( int k = 0; k < expected.length; k++ )
  285. {
  286. assertEquals( String.valueOf( k ), expected[k], output[k] );
  287. }
  288. }
  289. /**
  290. * Tests that workbooks with rich text that duplicates a non rich text cell can be read and written.
  291. */
  292. public void testReadWriteDuplicatedRichText1() {
  293. HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("duprich1.xls");
  294. HSSFSheet sheet = wb.getSheetAt( 1 );
  295. assertEquals( "01/05 (Wed)", sheet.getRow( 0 ).getCell(8 ).getStringCellValue() );
  296. assertEquals( "01/05 (Wed)", sheet.getRow( 1 ).getCell(8 ).getStringCellValue() );
  297. HSSFTestDataSamples.writeOutAndReadBack(wb);
  298. // test the second file.
  299. wb = HSSFTestDataSamples.openSampleWorkbook("duprich2.xls");
  300. sheet = wb.getSheetAt( 0 );
  301. int row = 0;
  302. assertEquals( "Testing", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  303. assertEquals( "rich", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  304. assertEquals( "text", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  305. assertEquals( "strings", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  306. assertEquals( "Testing", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  307. assertEquals( "Testing", sheet.getRow( row++ ).getCell(0 ).getStringCellValue() );
  308. HSSFTestDataSamples.writeOutAndReadBack(wb);
  309. }
  310. }