From 37bf44e9db8f74ae18c2f5dfbe936bae56beb107 Mon Sep 17 00:00:00 2001 From: Alex Wright Date: Sun, 13 Dec 2020 14:45:21 +0100 Subject: [PATCH] Test reading Xlsx column/row attrs with ReadFilter When reading an Xlsx file using a ReadFilter it is posible for `ColumnAndRowAttributes::load()` to (I think) erroneously skip loading of column or row attributes. This is because `isFilteredColumn` and `isFilteredRow` will return early with a true (ie the column or row should be considered filtered and their attrbutes discarded) at the first false returned from the ReadFilter. All rows for a column must past the filter for the loop to return false. I've also created the same test of column widths for row heights. * ColumnWidthTest.php Added test with a read filter. * RowHeightTest.php Mirrored column wdith tests for row height --- .../Functional/ColumnWidthTest.php | 36 +++++++++ .../Functional/RowHeightTest.php | 80 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Functional/RowHeightTest.php diff --git a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php index 5cd0aec7..3f811adc 100644 --- a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Functional; +use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; use PhpOffice\PhpSpreadsheet\Spreadsheet; class ColumnWidthTest extends AbstractFunctional @@ -31,6 +32,41 @@ class ColumnWidthTest extends AbstractFunctional $this->assertColumn($reloadedSpreadsheet); } + /** + * @dataProvider providerFormats + * + * @param $format + */ + public function testReadColumnWidthWithReadFilter($format): void + { + // Same test with a read filter removing a single row + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + foreach (range(1, 5) as $row) { + $sheet->setCellValue("A{$row}", 'Hello World !'); + } + + // isFilteredColumn iterates rowAttributes when calling the read filter + $sheet->getRowDimension(5)->setRowHeight(10); + + $sheet->getColumnDimension('A')->setWidth(20); + $this->assertColumn($spreadsheet); + + // A reader-customeiser closure and ReadFilter implementation that skips rows >4 + $readerCustomizer = function ($reader) { + $readFilterStub = $this->createMock(IReadFilter::class); + $readFilterStub->method('readCell') + ->willReturnCallback(function ($column, $row, $worksheetName = '') { + return $row <= 4; + }); + $reader->setReadFilter($readFilterStub); + }; + + // Save and reload a filtered set and assert the same width + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format, $readerCustomizer); + $this->assertColumn($reloadedSpreadsheet); + } + private function assertColumn(Spreadsheet $spreadsheet): void { $sheet = $spreadsheet->getActiveSheet(); diff --git a/tests/PhpSpreadsheetTests/Functional/RowHeightTest.php b/tests/PhpSpreadsheetTests/Functional/RowHeightTest.php new file mode 100644 index 00000000..3c6ce271 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Functional/RowHeightTest.php @@ -0,0 +1,80 @@ +getActiveSheet(); + $sheet->setCellValue('A1', 'Hello World !'); + $sheet->getRowDimension('1')->setRowHeight(20); + $this->assertRow($spreadsheet); + + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format); + $this->assertRow($reloadedSpreadsheet); + } + + /** + * @dataProvider providerFormats + * + * @param $format + */ + public function testReadRowHeightWithReadFilter($format): void + { + // Same test with a read filter removing a single row + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + foreach (range(1, 5) as $columnIndex) { + $sheet->setCellValue(Coordinate::stringFromColumnIndex($columnIndex) . '1', 'Hello World !'); + } + + // isFilteredRow iterates columnAttributes when calling the read filter + $sheet->getColumnDimension('E')->setWidth(64); + + $sheet->getRowDimension('1')->setRowHeight(20); + $this->assertRow($spreadsheet); + + // A reader-customeiser closure and ReadFilter implementation that skips column 'E' + $readerCustomizer = function ($reader) { + $readFilterStub = $this->createMock(IReadFilter::class); + $readFilterStub->method('readCell') + ->willReturnCallback(function ($column, $row, $worksheetName = '') { + return $column !== 'E'; + }); + $reader->setReadFilter($readFilterStub); + }; + + // Save and reload a filtered set and assert the same width + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format, $readerCustomizer); + $this->assertRow($reloadedSpreadsheet); + } + + private function assertRow(Spreadsheet $spreadsheet): void + { + $sheet = $spreadsheet->getActiveSheet(); + $rowDimensions = $sheet->getRowDimensions(); + + self::assertArrayHasKey('1', $rowDimensions); + $row = array_shift($rowDimensions); + self::assertEquals(20, $row->getRowHeight()); + } +}