a .NET library that can read/write Office formats without Microsoft Office installed. No COM+, no interop.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
15 KiB

8 years ago
4 years ago
  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. using NPOI.OpenXmlFormats.Spreadsheet;
  16. using NPOI.SS.UserModel;
  17. using NPOI.SS.Util;
  18. using NPOI.Util;
  19. using NPOI.XSSF;
  20. using NPOI.XSSF.Streaming;
  21. using NPOI.XSSF.UserModel;
  22. using NUnit.Framework;using NUnit.Framework.Legacy;
  23. using System;
  24. using System.Collections.Generic;
  25. using System.IO;
  26. using System.Text;
  27. using TestCases.HSSF;
  28. namespace TestCases.XSSF.UserModel
  29. {
  30. [TestFixture]
  31. public class TestUnfixedBugs
  32. {
  33. [Test]
  34. public void TestBug54084Unicode()
  35. {
  36. // sample XLSX with the same text-contents as the text-file above
  37. XSSFWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("54084 - Greek - beyond BMP.xlsx");
  38. verifyBug54084Unicode(wb);
  39. // OutputStream baos = new FileOutputStream("/tmp/test.xlsx");
  40. // try {
  41. // wb.Write(baos);
  42. // } finally {
  43. // baos.Close();
  44. // }
  45. // now write the file and read it back in
  46. XSSFWorkbook wbWritten = (XSSFWorkbook)XSSFTestDataSamples.WriteOutAndReadBack(wb);
  47. verifyBug54084Unicode(wbWritten);
  48. // finally also write it out via the streaming interface and verify that we still can read it back in
  49. SXSSFWorkbook swb = new SXSSFWorkbook(wb);
  50. IWorkbook wbStreamingWritten = SXSSFITestDataProvider.instance.WriteOutAndReadBack(swb);
  51. verifyBug54084Unicode(wbStreamingWritten);
  52. wbWritten.Close();
  53. swb.Close();
  54. wbStreamingWritten.Close();
  55. wb.Close();
  56. }
  57. private void verifyBug54084Unicode(IWorkbook wb)
  58. {
  59. // expected data is stored in UTF-8 in a text-file
  60. byte[] data = HSSFTestDataSamples.GetTestDataFileContent("54084 - Greek - beyond BMP.txt");
  61. String testData = Encoding.UTF8.GetString(data).Trim();
  62. ISheet sheet = wb.GetSheetAt(0);
  63. IRow row = sheet.GetRow(0);
  64. ICell cell = row.GetCell(0);
  65. String value = cell.StringCellValue;
  66. //Console.WriteLine(value);
  67. ClassicAssert.AreEqual(testData, value, "The data in the text-file should exactly match the data that we read from the workbook");
  68. }
  69. [Test]
  70. public void Test54071()
  71. {
  72. IWorkbook workbook = XSSFTestDataSamples.OpenSampleWorkbook("54071.xlsx");
  73. ISheet sheet = workbook.GetSheetAt(0);
  74. int rows = sheet.PhysicalNumberOfRows;
  75. Console.WriteLine(">> file rows is:" + (rows - 1) + " <<");
  76. IRow title = sheet.GetRow(0);
  77. DateTime? prev = null;
  78. for (int row = 1; row < rows; row++)
  79. {
  80. IRow rowObj = sheet.GetRow(row);
  81. for (int col = 0; col < 1; col++)
  82. {
  83. String titleName = title.GetCell(col).ToString();
  84. ICell cell = rowObj.GetCell(col);
  85. if (titleName.StartsWith("time"))
  86. {
  87. // here the output will produce ...59 or ...58 for the rows, probably POI is
  88. // doing some different rounding or some other small difference...
  89. Console.WriteLine("==Time:" + cell.DateCellValue);
  90. if (prev != null)
  91. {
  92. ClassicAssert.AreEqual(prev, cell.DateCellValue);
  93. prev = cell.DateCellValue;
  94. }
  95. }
  96. }
  97. }
  98. workbook.Close();
  99. }
  100. [Ignore("test")]
  101. public void Test54071Simple()
  102. {
  103. double value1 = 41224.999988425923;
  104. double value2 = 41224.999988368058;
  105. int wholeDays1 = (int)Math.Floor(value1);
  106. int millisecondsInDay1 = (int)((value1 - wholeDays1) * DateUtil.DAY_MILLISECONDS + 0.5);
  107. int wholeDays2 = (int)Math.Floor(value2);
  108. int millisecondsInDay2 = (int)((value2 - wholeDays2) * DateUtil.DAY_MILLISECONDS + 0.5);
  109. ClassicAssert.AreEqual(wholeDays1, wholeDays2);
  110. // here we see that the time-value is 5 milliseconds apart, one is 86399000 and the other is 86398995,
  111. // thus one is one second higher than the other
  112. ClassicAssert.AreEqual(millisecondsInDay1, millisecondsInDay2, "The time-values are 5 milliseconds apart");
  113. // when we do the calendar-stuff, there is a bool which determines if
  114. // the milliseconds are rounded or not, having this at "false" causes the
  115. // second to be different here!
  116. int startYear = 1900;
  117. int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
  118. //calendar1.Set(startYear, 0, wholeDays1 + dayAdjust, 0, 0, 0);
  119. //calendar1.Set(Calendar.MILLISECOND, millisecondsInDay1);
  120. DateTime calendar1 = new DateTime(startYear, 0, wholeDays1 + dayAdjust, 0, 0, 0);
  121. calendar1.AddMilliseconds(millisecondsInDay1);
  122. // this is the rounding part:
  123. //calendar1.Add(Calendar.MILLISECOND, 500);
  124. //calendar1.Clear(Calendar.MILLISECOND);
  125. calendar1.AddMilliseconds(500);
  126. calendar1.AddMilliseconds(-calendar1.Millisecond);
  127. DateTime calendar2 = new DateTime(startYear, 0, wholeDays2 + dayAdjust, 0, 0, 0);
  128. calendar2.AddMilliseconds(millisecondsInDay2);
  129. //calendar2.Set(startYear, 0, wholeDays2 + dayAdjust, 0, 0, 0);
  130. //calendar2.Set(Calendar.MILLISECOND, millisecondsInDay2);
  131. // this is the rounding part:
  132. //calendar2.Add(Calendar.MILLISECOND, 500);
  133. //calendar2.Clear(Calendar.MILLISECOND);
  134. calendar2.AddMilliseconds(500);
  135. calendar2.AddMilliseconds(-calendar2.Millisecond);
  136. // now the calendars are equal
  137. ClassicAssert.AreEqual(calendar1, calendar2);
  138. ClassicAssert.AreEqual(DateUtil.GetJavaDate(value1, false), DateUtil.GetJavaDate(value2, false));
  139. }
  140. // When this is fixed, the test case should go to BaseTestXCell with
  141. // adjustments to use _testDataProvider to also verify this for XSSF
  142. [Test]
  143. [Ignore("TODO FIX CI TESTS")]
  144. public void TestBug57294()
  145. {
  146. IWorkbook wb = SXSSFITestDataProvider.instance.CreateWorkbook();
  147. ISheet sheet = wb.CreateSheet();
  148. IRow row = sheet.CreateRow(0);
  149. ICell cell = row.CreateCell(0);
  150. IRichTextString str = new XSSFRichTextString("Test rich text string");
  151. str.ApplyFont(2, 4, (short)0);
  152. ClassicAssert.AreEqual(3, str.NumFormattingRuns);
  153. cell.SetCellValue(str);
  154. IWorkbook wbBack = SXSSFITestDataProvider.instance.WriteOutAndReadBack(wb);
  155. wb.Close();
  156. // re-read after serializing and reading back
  157. ICell cellBack = wbBack.GetSheetAt(0).GetRow(0).GetCell(0);
  158. ClassicAssert.IsNotNull(cellBack);
  159. IRichTextString strBack = cellBack.RichStringCellValue;
  160. ClassicAssert.IsNotNull(strBack);
  161. ClassicAssert.AreEqual(3, strBack.NumFormattingRuns);
  162. ClassicAssert.AreEqual(0, strBack.GetIndexOfFormattingRun(0));
  163. ClassicAssert.AreEqual(2, strBack.GetIndexOfFormattingRun(1));
  164. ClassicAssert.AreEqual(4, strBack.GetIndexOfFormattingRun(2));
  165. wbBack.Close();
  166. }
  167. [Test]
  168. public void TestBug55752()
  169. {
  170. IWorkbook wb = new XSSFWorkbook();
  171. try
  172. {
  173. ISheet sheet = wb.CreateSheet("test");
  174. for (int i = 0; i < 4; i++)
  175. {
  176. IRow row = sheet.CreateRow(i);
  177. for (int j = 0; j < 2; j++)
  178. {
  179. ICell cell = row.CreateCell(j);
  180. cell.CellStyle = (wb.CreateCellStyle());
  181. }
  182. }
  183. // set content
  184. IRow row1 = sheet.GetRow(0);
  185. row1.GetCell(0).SetCellValue("AAA");
  186. IRow row2 = sheet.GetRow(1);
  187. row2.GetCell(0).SetCellValue("BBB");
  188. IRow row3 = sheet.GetRow(2);
  189. row3.GetCell(0).SetCellValue("CCC");
  190. IRow row4 = sheet.GetRow(3);
  191. row4.GetCell(0).SetCellValue("DDD");
  192. // merge cells
  193. CellRangeAddress range1 = new CellRangeAddress(0, 0, 0, 1);
  194. sheet.AddMergedRegion(range1);
  195. CellRangeAddress range2 = new CellRangeAddress(1, 1, 0, 1);
  196. sheet.AddMergedRegion(range2);
  197. CellRangeAddress range3 = new CellRangeAddress(2, 2, 0, 1);
  198. sheet.AddMergedRegion(range3);
  199. ClassicAssert.AreEqual(0, range3.FirstColumn);
  200. ClassicAssert.AreEqual(1, range3.LastColumn);
  201. ClassicAssert.AreEqual(2, range3.LastRow);
  202. CellRangeAddress range4 = new CellRangeAddress(3, 3, 0, 1);
  203. sheet.AddMergedRegion(range4);
  204. // set border
  205. RegionUtil.SetBorderBottom((int)BorderStyle.Thin, range1, sheet);
  206. row2.GetCell(0).CellStyle.BorderBottom = BorderStyle.Thin;
  207. row2.GetCell(1).CellStyle.BorderBottom = BorderStyle.Thin;
  208. ICell cell0 = CellUtil.GetCell(row3, 0);
  209. CellUtil.SetCellStyleProperty(cell0, CellUtil.BORDER_BOTTOM, BorderStyle.Thin);
  210. ICell cell1 = CellUtil.GetCell(row3, 1);
  211. CellUtil.SetCellStyleProperty(cell1, CellUtil.BORDER_BOTTOM, BorderStyle.Thin);
  212. RegionUtil.SetBorderBottom((int)BorderStyle.Thin, range4, sheet);
  213. // write to file
  214. Stream stream = new FileStream("55752.xlsx", FileMode.Create, FileAccess.ReadWrite);
  215. try
  216. {
  217. wb.Write(stream, false);
  218. }
  219. finally
  220. {
  221. stream.Close();
  222. }
  223. }
  224. finally
  225. {
  226. wb.Close();
  227. }
  228. }
  229. [Test]
  230. public void Test57423()
  231. {
  232. IWorkbook wb = XSSFTestDataSamples.OpenSampleWorkbook("57423.xlsx");
  233. ISheet testSheet = wb.GetSheetAt(0);
  234. // row shift (negative or positive) causes corrupted output xlsx file when the shift value is bigger
  235. // than the number of rows being shifted
  236. // Excel 2010 on opening the output file says:
  237. // "Excel found unreadable content" and offers recovering the file by removing the unreadable content
  238. // This can be observed in cases like the following:
  239. // negative shift of 1 row by less than -1
  240. // negative shift of 2 rows by less than -2
  241. // positive shift of 1 row by 2 or more
  242. // positive shift of 2 rows by 3 or more
  243. //testSheet.shiftRows(4, 5, -3);
  244. testSheet.ShiftRows(10, 10, 2);
  245. checkRows57423(testSheet);
  246. IWorkbook wbBack = XSSFTestDataSamples.WriteOutAndReadBack(wb);
  247. /*FileOutputStream stream = new FileOutputStream("C:\\temp\\57423.xlsx");
  248. try {
  249. wb.write(stream);
  250. } finally {
  251. stream.close();
  252. }*/
  253. wb.Close();
  254. checkRows57423(wbBack.GetSheetAt(0));
  255. wbBack.Close();
  256. }
  257. private void checkRows57423(ISheet testSheet)
  258. {
  259. checkRow57423(testSheet, 0, "0");
  260. checkRow57423(testSheet, 1, "1");
  261. checkRow57423(testSheet, 2, "2");
  262. checkRow57423(testSheet, 3, "3");
  263. checkRow57423(testSheet, 4, "4");
  264. checkRow57423(testSheet, 5, "5");
  265. checkRow57423(testSheet, 6, "6");
  266. checkRow57423(testSheet, 7, "7");
  267. checkRow57423(testSheet, 8, "8");
  268. checkRow57423(testSheet, 9, "9");
  269. ClassicAssert.IsNull(testSheet.GetRow(10),
  270. "Row number 10 should be gone after the shift");
  271. checkRow57423(testSheet, 11, "11");
  272. checkRow57423(testSheet, 12, "10");
  273. checkRow57423(testSheet, 13, "13");
  274. checkRow57423(testSheet, 14, "14");
  275. checkRow57423(testSheet, 15, "15");
  276. checkRow57423(testSheet, 16, "16");
  277. checkRow57423(testSheet, 17, "17");
  278. checkRow57423(testSheet, 18, "18");
  279. ByteArrayOutputStream stream = new ByteArrayOutputStream();
  280. try
  281. {
  282. ((XSSFSheet)testSheet).Write(stream);
  283. }
  284. finally
  285. {
  286. stream.Close();
  287. }
  288. // verify that the resulting XML has the rows in correct order as required by Excel
  289. String xml = Encoding.UTF8.GetString(stream.ToByteArray());
  290. int posR12 = xml.IndexOf("<row r=\"12\"");
  291. int posR13 = xml.IndexOf("<row r=\"13\"");
  292. // both need to be found
  293. ClassicAssert.IsTrue(posR12 != -1);
  294. ClassicAssert.IsTrue(posR13 != -1);
  295. ClassicAssert.IsTrue(posR12 < posR13,
  296. "Need to find row 12 before row 13 after the shifting, but had row 12 at " + posR12 + " and row 13 at " + posR13);
  297. }
  298. private void checkRow57423(ISheet testSheet, int rowNum, String contents)
  299. {
  300. IRow row = testSheet.GetRow(rowNum);
  301. ClassicAssert.IsNotNull(row, "Expecting row at rownum " + rowNum);
  302. CT_Row ctRow = ((XSSFRow)row).GetCTRow();
  303. ClassicAssert.AreEqual(rowNum + 1, ctRow.r);
  304. ICell cell = row.GetCell(0);
  305. ClassicAssert.IsNotNull(cell, "Expecting cell at rownum " + rowNum);
  306. //why concate ".0"? There is no ".0" in excel.
  307. ClassicAssert.AreEqual(contents, cell.ToString(), "Did not have expected contents at rownum " + rowNum);
  308. //ClassicAssert.AreEqual(contents + ".0", cell.ToString(), "Did not have expected contents at rownum " + rowNum);
  309. }
  310. }
  311. }