401 lines
16 KiB
Java
401 lines
16 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
|
|
package org.apache.poi.xssf.usermodel;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertNull;
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.nio.charset.Charset;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
import org.apache.poi.ss.usermodel.CellStyle;
|
|
import org.apache.poi.ss.usermodel.DateUtil;
|
|
import org.apache.poi.ss.usermodel.RichTextString;
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
import org.apache.poi.ss.usermodel.Sheet;
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
import org.apache.poi.ss.util.CellRangeAddress;
|
|
import org.apache.poi.ss.util.CellUtil;
|
|
import org.apache.poi.ss.util.RegionUtil;
|
|
import org.apache.poi.util.LocaleUtil;
|
|
import org.apache.poi.xssf.SXSSFITestDataProvider;
|
|
import org.apache.poi.xssf.XSSFTestDataSamples;
|
|
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
|
import org.junit.Test;
|
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
|
|
|
|
/**
|
|
* @author centic
|
|
*
|
|
* This testcase contains tests for bugs that are yet to be fixed. Therefore,
|
|
* the standard ant test target does not run these tests. Run this testcase with
|
|
* the single-test target. The names of the tests usually correspond to the
|
|
* Bugzilla id's PLEASE MOVE tests from this class to TestBugs once the bugs are
|
|
* fixed, so that they are then run automatically.
|
|
*/
|
|
public final class TestUnfixedBugs {
|
|
@Test
|
|
public void testBug54084Unicode() throws IOException {
|
|
// sample XLSX with the same text-contents as the text-file above
|
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("54084 - Greek - beyond BMP.xlsx");
|
|
|
|
verifyBug54084Unicode(wb);
|
|
|
|
// OutputStream baos = new FileOutputStream("/tmp/test.xlsx");
|
|
// try {
|
|
// wb.write(baos);
|
|
// } finally {
|
|
// baos.close();
|
|
// }
|
|
|
|
// now write the file and read it back in
|
|
XSSFWorkbook wbWritten = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
|
verifyBug54084Unicode(wbWritten);
|
|
|
|
// finally also write it out via the streaming interface and verify that we still can read it back in
|
|
SXSSFWorkbook swb = new SXSSFWorkbook(wb);
|
|
Workbook wbStreamingWritten = SXSSFITestDataProvider.instance.writeOutAndReadBack(swb);
|
|
verifyBug54084Unicode(wbStreamingWritten);
|
|
|
|
wbWritten.close();
|
|
swb.close();
|
|
wbStreamingWritten.close();
|
|
wb.close();
|
|
}
|
|
|
|
private void verifyBug54084Unicode(Workbook wb) {
|
|
// expected data is stored in UTF-8 in a text-file
|
|
byte data[] = HSSFTestDataSamples.getTestDataFileContent("54084 - Greek - beyond BMP.txt");
|
|
String testData = new String(data, Charset.forName("UTF-8")).trim();
|
|
|
|
Sheet sheet = wb.getSheetAt(0);
|
|
Row row = sheet.getRow(0);
|
|
Cell cell = row.getCell(0);
|
|
|
|
String value = cell.getStringCellValue();
|
|
//System.out.println(value);
|
|
|
|
assertEquals("The data in the text-file should exactly match the data that we read from the workbook", testData, value);
|
|
}
|
|
|
|
@Test
|
|
public void test54071() throws Exception {
|
|
Workbook workbook = XSSFTestDataSamples.openSampleWorkbook("54071.xlsx");
|
|
Sheet sheet = workbook.getSheetAt(0);
|
|
int rows = sheet.getPhysicalNumberOfRows();
|
|
System.out.println(">> file rows is:"+(rows-1)+" <<");
|
|
Row title = sheet.getRow(0);
|
|
|
|
Date prev = null;
|
|
for (int row = 1; row < rows; row++) {
|
|
Row rowObj = sheet.getRow(row);
|
|
for (int col = 0; col < 1; col++) {
|
|
String titleName = title.getCell(col).toString();
|
|
Cell cell = rowObj.getCell(col);
|
|
if (titleName.startsWith("time")) {
|
|
// here the output will produce ...59 or ...58 for the rows, probably POI is
|
|
// doing some different rounding or some other small difference...
|
|
System.out.println("==Time:"+cell.getDateCellValue());
|
|
if(prev != null) {
|
|
assertEquals(prev, cell.getDateCellValue());
|
|
}
|
|
|
|
prev = cell.getDateCellValue();
|
|
}
|
|
}
|
|
}
|
|
|
|
workbook.close();
|
|
}
|
|
|
|
@Test
|
|
public void test54071Simple() {
|
|
double value1 = 41224.999988425923;
|
|
double value2 = 41224.999988368058;
|
|
|
|
int wholeDays1 = (int)Math.floor(value1);
|
|
int millisecondsInDay1 = (int)((value1 - wholeDays1) * DateUtil.DAY_MILLISECONDS + 0.5);
|
|
|
|
int wholeDays2 = (int)Math.floor(value2);
|
|
int millisecondsInDay2 = (int)((value2 - wholeDays2) * DateUtil.DAY_MILLISECONDS + 0.5);
|
|
|
|
assertEquals(wholeDays1, wholeDays2);
|
|
// here we see that the time-value is 5 milliseconds apart, one is 86399000 and the other is 86398995,
|
|
// thus one is one second higher than the other
|
|
assertEquals("The time-values are 5 milliseconds apart",
|
|
millisecondsInDay1, millisecondsInDay2);
|
|
|
|
// when we do the calendar-stuff, there is a boolean which determines if
|
|
// the milliseconds are rounded or not, having this at "false" causes the
|
|
// second to be different here!
|
|
int startYear = 1900;
|
|
int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't
|
|
Calendar calendar1 = LocaleUtil.getLocaleCalendar(startYear,0, wholeDays1 + dayAdjust);
|
|
calendar1.set(Calendar.MILLISECOND, millisecondsInDay1);
|
|
// this is the rounding part:
|
|
calendar1.add(Calendar.MILLISECOND, 500);
|
|
calendar1.clear(Calendar.MILLISECOND);
|
|
|
|
Calendar calendar2 = LocaleUtil.getLocaleCalendar(startYear,0, wholeDays2 + dayAdjust);
|
|
calendar2.set(Calendar.MILLISECOND, millisecondsInDay2);
|
|
// this is the rounding part:
|
|
calendar2.add(Calendar.MILLISECOND, 500);
|
|
calendar2.clear(Calendar.MILLISECOND);
|
|
|
|
// now the calendars are equal
|
|
assertEquals(calendar1, calendar2);
|
|
|
|
assertEquals(DateUtil.getJavaDate(value1, false), DateUtil.getJavaDate(value2, false));
|
|
}
|
|
|
|
// When this is fixed, the test case should go to BaseTestXCell with
|
|
// adjustments to use _testDataProvider to also verify this for XSSF
|
|
@Test
|
|
public void testBug57294() throws IOException {
|
|
Workbook wb = SXSSFITestDataProvider.instance.createWorkbook();
|
|
|
|
Sheet sheet = wb.createSheet();
|
|
Row row = sheet.createRow(0);
|
|
Cell cell = row.createCell(0);
|
|
|
|
RichTextString str = new XSSFRichTextString("Test rich text string");
|
|
str.applyFont(2, 4, (short)0);
|
|
assertEquals(3, str.numFormattingRuns());
|
|
cell.setCellValue(str);
|
|
|
|
Workbook wbBack = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb);
|
|
wb.close();
|
|
|
|
// re-read after serializing and reading back
|
|
Cell cellBack = wbBack.getSheetAt(0).getRow(0).getCell(0);
|
|
assertNotNull(cellBack);
|
|
RichTextString strBack = cellBack.getRichStringCellValue();
|
|
assertNotNull(strBack);
|
|
assertEquals(3, strBack.numFormattingRuns());
|
|
assertEquals(0, strBack.getIndexOfFormattingRun(0));
|
|
assertEquals(2, strBack.getIndexOfFormattingRun(1));
|
|
assertEquals(4, strBack.getIndexOfFormattingRun(2));
|
|
|
|
wbBack.close();
|
|
}
|
|
|
|
@Test
|
|
public void testBug55752() throws IOException {
|
|
Workbook wb = new XSSFWorkbook();
|
|
try {
|
|
Sheet sheet = wb.createSheet("test");
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
Row row = sheet.createRow(i);
|
|
for (int j = 0; j < 2; j++) {
|
|
Cell cell = row.createCell(j);
|
|
cell.setCellStyle(wb.createCellStyle());
|
|
}
|
|
}
|
|
|
|
// set content
|
|
Row row1 = sheet.getRow(0);
|
|
row1.getCell(0).setCellValue("AAA");
|
|
Row row2 = sheet.getRow(1);
|
|
row2.getCell(0).setCellValue("BBB");
|
|
Row row3 = sheet.getRow(2);
|
|
row3.getCell(0).setCellValue("CCC");
|
|
Row row4 = sheet.getRow(3);
|
|
row4.getCell(0).setCellValue("DDD");
|
|
|
|
// merge cells
|
|
CellRangeAddress range1 = new CellRangeAddress(0, 0, 0, 1);
|
|
sheet.addMergedRegion(range1);
|
|
CellRangeAddress range2 = new CellRangeAddress(1, 1, 0, 1);
|
|
sheet.addMergedRegion(range2);
|
|
CellRangeAddress range3 = new CellRangeAddress(2, 2, 0, 1);
|
|
sheet.addMergedRegion(range3);
|
|
assertEquals(0, range3.getFirstColumn());
|
|
assertEquals(1, range3.getLastColumn());
|
|
assertEquals(2, range3.getLastRow());
|
|
CellRangeAddress range4 = new CellRangeAddress(3, 3, 0, 1);
|
|
sheet.addMergedRegion(range4);
|
|
|
|
// set border
|
|
RegionUtil.setBorderBottom(CellStyle.BORDER_THIN, range1, sheet, wb);
|
|
|
|
row2.getCell(0).getCellStyle().setBorderBottom(CellStyle.BORDER_THIN);
|
|
row2.getCell(1).getCellStyle().setBorderBottom(CellStyle.BORDER_THIN);
|
|
|
|
Cell cell0 = CellUtil.getCell(row3, 0);
|
|
CellUtil.setCellStyleProperty(cell0, CellUtil.BORDER_BOTTOM, CellStyle.BORDER_THIN);
|
|
Cell cell1 = CellUtil.getCell(row3, 1);
|
|
CellUtil.setCellStyleProperty(cell1, CellUtil.BORDER_BOTTOM, CellStyle.BORDER_THIN);
|
|
|
|
RegionUtil.setBorderBottom(CellStyle.BORDER_THIN, range4, sheet, wb);
|
|
|
|
// write to file
|
|
OutputStream stream = new FileOutputStream(new File("C:/temp/55752.xlsx"));
|
|
try {
|
|
wb.write(stream);
|
|
} finally {
|
|
stream.close();
|
|
}
|
|
} finally {
|
|
wb.close();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void test57423() throws IOException {
|
|
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("57423.xlsx");
|
|
|
|
Sheet testSheet = wb.getSheetAt(0);
|
|
|
|
// row shift (negative or positive) causes corrupted output xlsx file when the shift value is bigger
|
|
// than the number of rows being shifted
|
|
// Excel 2010 on opening the output file says:
|
|
// "Excel found unreadable content" and offers recovering the file by removing the unreadable content
|
|
// This can be observed in cases like the following:
|
|
// negative shift of 1 row by less than -1
|
|
// negative shift of 2 rows by less than -2
|
|
// positive shift of 1 row by 2 or more
|
|
// positive shift of 2 rows by 3 or more
|
|
|
|
//testSheet.shiftRows(4, 5, -3);
|
|
testSheet.shiftRows(10, 10, 2);
|
|
|
|
checkRows57423(testSheet);
|
|
|
|
Workbook wbBack = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
|
|
|
/*FileOutputStream stream = new FileOutputStream("C:\\temp\\57423.xlsx");
|
|
try {
|
|
wb.write(stream);
|
|
} finally {
|
|
stream.close();
|
|
}*/
|
|
|
|
wb.close();
|
|
|
|
checkRows57423(wbBack.getSheetAt(0));
|
|
|
|
wbBack.close();
|
|
}
|
|
|
|
private void checkRows57423(Sheet testSheet) throws IOException {
|
|
checkRow57423(testSheet, 0, "0");
|
|
checkRow57423(testSheet, 1, "1");
|
|
checkRow57423(testSheet, 2, "2");
|
|
checkRow57423(testSheet, 3, "3");
|
|
checkRow57423(testSheet, 4, "4");
|
|
checkRow57423(testSheet, 5, "5");
|
|
checkRow57423(testSheet, 6, "6");
|
|
checkRow57423(testSheet, 7, "7");
|
|
checkRow57423(testSheet, 8, "8");
|
|
checkRow57423(testSheet, 9, "9");
|
|
|
|
assertNull("Row number 10 should be gone after the shift",
|
|
testSheet.getRow(10));
|
|
|
|
checkRow57423(testSheet, 11, "11");
|
|
checkRow57423(testSheet, 12, "10");
|
|
checkRow57423(testSheet, 13, "13");
|
|
checkRow57423(testSheet, 14, "14");
|
|
checkRow57423(testSheet, 15, "15");
|
|
checkRow57423(testSheet, 16, "16");
|
|
checkRow57423(testSheet, 17, "17");
|
|
checkRow57423(testSheet, 18, "18");
|
|
|
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
try {
|
|
((XSSFSheet)testSheet).write(stream);
|
|
} finally {
|
|
stream.close();
|
|
}
|
|
|
|
// verify that the resulting XML has the rows in correct order as required by Excel
|
|
String xml = new String(stream.toByteArray(), "UTF-8");
|
|
int posR12 = xml.indexOf("<row r=\"12\"");
|
|
int posR13 = xml.indexOf("<row r=\"13\"");
|
|
|
|
// both need to be found
|
|
assertTrue(posR12 != -1);
|
|
assertTrue(posR13 != -1);
|
|
|
|
assertTrue("Need to find row 12 before row 13 after the shifting, but had row 12 at " + posR12 + " and row 13 at " + posR13,
|
|
posR12 < posR13);
|
|
}
|
|
|
|
private void checkRow57423(Sheet testSheet, int rowNum, String contents) {
|
|
Row row = testSheet.getRow(rowNum);
|
|
assertNotNull("Expecting row at rownum " + rowNum, row);
|
|
|
|
CTRow ctRow = ((XSSFRow)row).getCTRow();
|
|
assertEquals(rowNum+1, ctRow.getR());
|
|
|
|
Cell cell = row.getCell(0);
|
|
assertNotNull("Expecting cell at rownum " + rowNum, cell);
|
|
assertEquals("Did not have expected contents at rownum " + rowNum,
|
|
contents + ".0", cell.toString());
|
|
}
|
|
|
|
@Test
|
|
public void test58325_one() {
|
|
check58325(XSSFTestDataSamples.openSampleWorkbook("58325_lt.xlsx"), 1);
|
|
}
|
|
|
|
@Test
|
|
public void test58325_three() {
|
|
check58325(XSSFTestDataSamples.openSampleWorkbook("58325_db.xlsx"), 3);
|
|
}
|
|
|
|
private void check58325(XSSFWorkbook wb, int expectedShapes) {
|
|
XSSFSheet sheet = wb.getSheet("MetasNM001");
|
|
assertNotNull(sheet);
|
|
|
|
StringBuilder str = new StringBuilder();
|
|
str.append("sheet " + sheet.getSheetName() + " - ");
|
|
|
|
XSSFDrawing drawing = sheet.getDrawingPatriarch();
|
|
//drawing = ((XSSFSheet)sheet).createDrawingPatriarch();
|
|
|
|
List<XSSFShape> shapes = drawing.getShapes();
|
|
str.append("drawing.getShapes().size() = " + shapes.size());
|
|
Iterator<XSSFShape> it = shapes.iterator();
|
|
while(it.hasNext()) {
|
|
XSSFShape shape = it.next();
|
|
str.append(", " + shape.toString());
|
|
str.append(", Col1:"+((XSSFClientAnchor)shape.getAnchor()).getCol1());
|
|
str.append(", Col2:"+((XSSFClientAnchor)shape.getAnchor()).getCol2());
|
|
str.append(", Row1:"+((XSSFClientAnchor)shape.getAnchor()).getRow1());
|
|
str.append(", Row2:"+((XSSFClientAnchor)shape.getAnchor()).getRow2());
|
|
}
|
|
|
|
assertEquals("Having shapes: " + str,
|
|
expectedShapes, shapes.size());
|
|
}
|
|
}
|