mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-16 13:06:31 +00:00
1187825738
* PhpUnit 10 Compatibility Part 1
This is not a change to move to PhpUnit 10. There is no compelling reason to do so at this time, although it is bound to happen eventually. There are a staggering number of problems (somewhere around 3,000) with the current test suite under PhpUnit 10; this is an attempt to get ahead of the curve by addressing them now.
Method `setOutputCallback` has gone away. This affects only Helper/SampleTest. It appears that `ob_start` and its allies provide an effective equivalent. FWIW, the absence of `setOutputCallback` is a good indication of whether or not PhpUnit 10 is in use, and I will use that fact in a few tests.
Class `ComplexAssert` with no constructor, and always used with `new ComplexAssert()`, extends `TestCase`. Apparently, the constructor for TestCase requires an argument, and PhpUnit 10 complains about not supplying one. Adding an empty constructor to ComplexAssert avoids this problem.
There are two very minor source changes, to Calculation/Calculation and Reader/Xlsx, where problems were exposed with PhpUnit 10 that had not been previously been exposed. AFAIK, these are the only source changes required; the rest of the changes are to test members.
The bulk of the problems are because PhpUnit 10 insists that provider methods be static. Most of those can be changed by a script without any further action; those changes will constitute the Part 2 counterpart of this PR. In this PR you will find the exceptional cases that can't be automated for one reason or another. The tests for Database functions have mild complications that are easily handled. Most of the other provider changes in this PR are because the method names didn't follow an established pattern ('provider' isn't part of the method name); those are also easily handled manually. Modifying the following tests provided significant challenges:
- Writer/Xls/WorkbookTest testAddColor
- Worksheet/Table/TableTest testSetRangeValidRange
The handling of warning messages issued by the code differs in PhpUnit 10. According to the change log, "This means that using PHP functionality which triggers E_DEPRECATED, E_NOTICE, E_STRICT, or E_WARNING or calling code which triggers E_USER_DEPRECATED, E_USER_NOTICE, or E_USER_WARNING can no longer hide a bug in your code." To me, the effect of that change seems to be exactly the opposite - such messages were available to the test with PhpUnit 9 (so we could test for them), and are no longer available (so we can't). I haven't even succeeded with a custom error message handler as part of the script. I will continue to investigate, but, for now, will skip some tests under PhpUnit 10 for the following:
- Shared/OleTest testChainedWriteMode and testChainedBadPath
- Reader/Html/HtmlLoadStringTest testLoadInvalidString
- Reader/Html/HtmlTest testBadHtml
* Scrutinize, and Parent Construct
Parent construct suggested by @MarkBaker.
* Redo Tests Dependent on Warning Messages
Warning (and other) messages are handled differently in PhpUnit 10 than in earlier versions.
427 lines
17 KiB
PHP
427 lines
17 KiB
PHP
<?php
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Reader\Html;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
|
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
|
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
|
use PhpOffice\PhpSpreadsheet\Style\Border;
|
|
use PhpOffice\PhpSpreadsheet\Style\Font;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class HtmlTest extends TestCase
|
|
{
|
|
public function testCsvWithAngleBracket(): void
|
|
{
|
|
$filename = 'tests/data/Reader/HTML/csv_with_angle_bracket.csv';
|
|
$reader = new Html();
|
|
self::assertFalse($reader->canRead($filename));
|
|
}
|
|
|
|
public function testBadHtml(): void
|
|
{
|
|
$filename = 'tests/data/Reader/HTML/badhtml.html';
|
|
$reader = new Html();
|
|
self::assertTrue($reader->canRead($filename));
|
|
|
|
if (method_exists($this, 'setOutputCallback')) {
|
|
// The meat of this test is moved to HtmlPhpunit10Test
|
|
// to run under all PhpUnit versions.
|
|
$this->expectException(ReaderException::class);
|
|
$reader->load($filename);
|
|
}
|
|
}
|
|
|
|
public function testNonHtml(): void
|
|
{
|
|
$filename = __FILE__;
|
|
$reader = new Html();
|
|
self::assertFalse($reader->canRead($filename));
|
|
|
|
$this->expectException(ReaderException::class);
|
|
$reader->load($filename);
|
|
}
|
|
|
|
public function testInvalidFilename(): void
|
|
{
|
|
$reader = new Html();
|
|
self::assertEquals(0, $reader->getSheetIndex());
|
|
self::assertFalse($reader->canRead(''));
|
|
}
|
|
|
|
public static function providerCanReadVerySmallFile(): array
|
|
{
|
|
$padding = str_repeat('a', 2048);
|
|
|
|
return [
|
|
[true, ' <html> ' . $padding . ' </html> '],
|
|
[true, ' <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html>' . $padding . '</html>'],
|
|
[true, '<html></html>'],
|
|
[false, ''],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerCanReadVerySmallFile
|
|
*
|
|
* @param bool $expected
|
|
* @param string $content
|
|
*/
|
|
public function testCanReadVerySmallFile($expected, $content): void
|
|
{
|
|
$filename = HtmlHelper::createHtml($content);
|
|
$reader = new Html();
|
|
$actual = $reader->canRead($filename);
|
|
|
|
self::assertSame($expected, $actual);
|
|
|
|
unlink($filename);
|
|
}
|
|
|
|
public function testBackgroundColorInRanding(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td style="background-color: #0000FF;color: #FFFFFF">Blue background</td>
|
|
<td style="background-color: unknown1;color: unknown2">Unknown fore/background</td>
|
|
<td style="background-color: antiquewhite2;color: aliceblue">Unknown fore/background</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
$style = $firstSheet->getCell('A1')->getStyle();
|
|
self::assertEquals('FFFFFF', $style->getFont()->getColor()->getRGB());
|
|
self::assertEquals('0000FF', $style->getFill()->getStartColor()->getRGB());
|
|
self::assertEquals('0000FF', $style->getFill()->getEndColor()->getRGB());
|
|
$style = $firstSheet->getCell('B1')->getStyle();
|
|
self::assertEquals('000000', $style->getFont()->getColor()->getRGB());
|
|
self::assertEquals('000000', $style->getFill()->getEndColor()->getRGB());
|
|
self::assertEquals('FFFFFF', $style->getFill()->getstartColor()->getRGB());
|
|
$style = $firstSheet->getCell('C1')->getStyle();
|
|
self::assertEquals('f0f8ff', $style->getFont()->getColor()->getRGB());
|
|
self::assertEquals('eedfcc', $style->getFill()->getEndColor()->getRGB());
|
|
self::assertEquals('eedfcc', $style->getFill()->getstartColor()->getRGB());
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyInlineFontStyles(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td style="font-size: 16px;">16px</td>
|
|
<td style="font-family: \'Times New Roman\'">Times New Roman</td>
|
|
<td style="font-weight: bold;">Bold</td>
|
|
<td style="font-style: italic;">Italic</td>
|
|
<td style="text-decoration: underline;">Underline</td>
|
|
<td style="text-decoration: line-through;">Line through</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
$style = $firstSheet->getCell('A1')->getStyle();
|
|
self::assertEquals(16, $style->getFont()->getSize());
|
|
|
|
$style = $firstSheet->getCell('B1')->getStyle();
|
|
self::assertEquals('Times New Roman', $style->getFont()->getName());
|
|
|
|
$style = $firstSheet->getCell('C1')->getStyle();
|
|
self::assertTrue($style->getFont()->getBold());
|
|
|
|
$style = $firstSheet->getCell('D1')->getStyle();
|
|
self::assertTrue($style->getFont()->getItalic());
|
|
|
|
$style = $firstSheet->getCell('E1')->getStyle();
|
|
self::assertEquals(Font::UNDERLINE_SINGLE, $style->getFont()->getUnderline());
|
|
|
|
$style = $firstSheet->getCell('F1')->getStyle();
|
|
self::assertTrue($style->getFont()->getStrikethrough());
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyInlineWidth(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td width="50">50px</td>
|
|
<td style="width: 100px;">100px</td>
|
|
<td width="50px">50px</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
$dimension = $firstSheet->getColumnDimension('A');
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(50, $dimension->getWidth());
|
|
|
|
$dimension = $firstSheet->getColumnDimension('B');
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(100, $dimension->getWidth('px'));
|
|
|
|
$dimension = $firstSheet->getColumnDimension('C');
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(50, $dimension->getWidth('px'));
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyInlineHeight(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td height="50">1</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="height: 100px;">2</td>
|
|
</tr>
|
|
<tr>
|
|
<td height="50px">1</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
$dimension = $firstSheet->getRowDimension(1);
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(50, $dimension->getRowHeight());
|
|
|
|
$dimension = $firstSheet->getRowDimension(2);
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(100, $dimension->getRowHeight('px'));
|
|
|
|
$dimension = $firstSheet->getRowDimension(3);
|
|
self::assertNotNull($dimension);
|
|
self::assertEquals(50, $dimension->getRowHeight('px'));
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyAlignment(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td align="center">Center align</td>
|
|
<td valign="center">Center valign</td>
|
|
<td style="text-align: center;">Center align</td>
|
|
<td style="vertical-align: center;">Center valign</td>
|
|
<td style="text-indent: 10px;">Text indent</td>
|
|
<td style="word-wrap: break-word;">Wraptext</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
$style = $firstSheet->getCell('A1')->getStyle();
|
|
self::assertEquals(Alignment::HORIZONTAL_CENTER, $style->getAlignment()->getHorizontal());
|
|
|
|
$style = $firstSheet->getCell('B1')->getStyle();
|
|
self::assertEquals(Alignment::VERTICAL_CENTER, $style->getAlignment()->getVertical());
|
|
|
|
$style = $firstSheet->getCell('C1')->getStyle();
|
|
self::assertEquals(Alignment::HORIZONTAL_CENTER, $style->getAlignment()->getHorizontal());
|
|
|
|
$style = $firstSheet->getCell('D1')->getStyle();
|
|
self::assertEquals(Alignment::VERTICAL_CENTER, $style->getAlignment()->getVertical());
|
|
|
|
$style = $firstSheet->getCell('E1')->getStyle();
|
|
self::assertEquals(10, $style->getAlignment()->getIndent());
|
|
|
|
$style = $firstSheet->getCell('F1')->getStyle();
|
|
self::assertTrue($style->getAlignment()->getWrapText());
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyInlineDataFormat(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td data-format="mmm-yy">2019-02-02 12:34:00</td>
|
|
<td data-format="#.000">3</td>
|
|
<td data-format="#.000">x</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$sheet = $spreadsheet->getSheet(0);
|
|
|
|
self::assertEquals('mmm-yy', $sheet->getStyle('A1')->getNumberFormat()->getFormatCode());
|
|
self::assertEquals('2019-02-02 12:34:00', $sheet->getCell('A1')->getFormattedValue(), 'field is string not number so not formatted');
|
|
self::assertEquals('#.000', $sheet->getStyle('B1')->getNumberFormat()->getFormatCode());
|
|
self::assertEquals('3.000', $sheet->getCell('B1')->getFormattedValue(), 'format applied to numeric value');
|
|
self::assertEquals('#.000', $sheet->getStyle('C1')->getNumberFormat()->getFormatCode());
|
|
self::assertEquals('x', $sheet->getCell('C1')->getFormattedValue(), 'format not applied to non-numeric value');
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testCanApplyCellWrapping(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td>Hello World</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Hello<br />World</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Hello<br>World</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
$cellStyle = $firstSheet->getStyle('A1');
|
|
self::assertFalse($cellStyle->getAlignment()->getWrapText());
|
|
|
|
$cellStyle = $firstSheet->getStyle('A2');
|
|
self::assertTrue($cellStyle->getAlignment()->getWrapText());
|
|
$cellValue = $firstSheet->getCell('A2')->getValue();
|
|
self::assertStringContainsString("\n", $cellValue);
|
|
|
|
$cellStyle = $firstSheet->getStyle('A3');
|
|
self::assertTrue($cellStyle->getAlignment()->getWrapText());
|
|
$cellValue = $firstSheet->getCell('A3')->getValue();
|
|
self::assertStringContainsString("\n", $cellValue);
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testRowspanInRendering(): void
|
|
{
|
|
$filename = 'tests/data/Reader/HTML/rowspan.html';
|
|
$reader = new Html();
|
|
$spreadsheet = $reader->load($filename);
|
|
|
|
$actual = $spreadsheet->getActiveSheet()->getMergeCells();
|
|
self::assertSame(['A2:C2' => 'A2:C2'], $actual);
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testTextIndentUseRowspan(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td>1</td>
|
|
<td rowspan="2" style="vertical-align: center;">Center Align</td>
|
|
<td>Row</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2</td>
|
|
<td style="text-indent:10px">Text Indent</td>
|
|
</tr>
|
|
</table>';
|
|
$filename = HtmlHelper::createHtml($html);
|
|
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
$style = $firstSheet->getCell('C2')->getStyle();
|
|
self::assertEquals(10, $style->getAlignment()->getIndent());
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testBorderWithRowspanAndColspan(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td style="border: 1px solid black;">NOT SPANNED</td>
|
|
<td rowspan="2" colspan="2" style="border: 1px solid black;">SPANNED</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="border: 1px solid black;">NOT SPANNED</td>
|
|
</tr>
|
|
</table>';
|
|
|
|
$reader = new Html();
|
|
$spreadsheet = $reader->loadFromString($html);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
$style = $firstSheet->getStyle('B1:C2');
|
|
|
|
$borders = $style->getBorders();
|
|
|
|
$totalBorders = [
|
|
$borders->getTop(),
|
|
$borders->getLeft(),
|
|
$borders->getBottom(),
|
|
$borders->getRight(),
|
|
];
|
|
|
|
foreach ($totalBorders as $border) {
|
|
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
|
|
}
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testBorderWithColspan(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td style="border: 1px solid black;">NOT SPANNED</td>
|
|
<td colspan="2" style="border: 1px solid black;">SPANNED</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="border: 1px solid black;">NOT SPANNED</td>
|
|
</tr>
|
|
</table>';
|
|
|
|
$reader = new Html();
|
|
$spreadsheet = $reader->loadFromString($html);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
$style = $firstSheet->getStyle('B1:B2');
|
|
|
|
$borders = $style->getBorders();
|
|
|
|
$totalBorders = [
|
|
$borders->getTop(),
|
|
$borders->getLeft(),
|
|
$borders->getBottom(),
|
|
$borders->getRight(),
|
|
];
|
|
|
|
foreach ($totalBorders as $border) {
|
|
self::assertEquals(Border::BORDER_THIN, $border->getBorderStyle());
|
|
}
|
|
$spreadsheet->disconnectWorksheets();
|
|
}
|
|
|
|
public function testDataType(): void
|
|
{
|
|
$html = '<table>
|
|
<tr>
|
|
<td data-type="b">1</td>
|
|
<td data-type="s">12345678987654</td>
|
|
<!-- in some cases, you may want to treat the string with beginning equal sign as a string rather than a formula -->
|
|
<td data-type="s">=B1</td>
|
|
<td data-type="d">2022-02-21 10:20:30</td>
|
|
<td data-type="null">null</td>
|
|
<td data-type="invalid-datatype">text with invalid datatype</td>
|
|
</tr>
|
|
</table>';
|
|
|
|
$reader = new Html();
|
|
$spreadsheet = $reader->loadFromString($html);
|
|
$firstSheet = $spreadsheet->getSheet(0);
|
|
|
|
// check boolean data type
|
|
self::assertEquals(DataType::TYPE_BOOL, $firstSheet->getCell('A1')->getDataType());
|
|
self::assertIsBool($firstSheet->getCell('A1')->getValue());
|
|
|
|
// check string data type
|
|
self::assertEquals(DataType::TYPE_STRING, $firstSheet->getCell('B1')->getDataType());
|
|
self::assertIsString($firstSheet->getCell('B1')->getValue());
|
|
|
|
// check string with beginning equal sign (=B1) and string datatype,is not formula
|
|
self::assertEquals(DataType::TYPE_STRING, $firstSheet->getCell('C1')->getDataType());
|
|
self::assertEquals('=B1', $firstSheet->getCell('C1')->getValue());
|
|
self::assertTrue($firstSheet->getCell('C1')->getStyle()->getQuotePrefix());
|
|
|
|
//check iso date
|
|
self::assertEqualsWithDelta($firstSheet->getCell('D1')->getValue(), 44613.43090277778, 1.0e-12);
|
|
|
|
//null
|
|
self::assertEquals($firstSheet->getCell('E1')->getValue(), null);
|
|
}
|
|
}
|