diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 923adb4b..4d4b6e1b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -220,11 +220,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getHighestDataColumn\\(\\) expects string\\|null, mixed given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Parameter \\#1 \\$str of function preg_quote expects string, int\\|string given\\.$#" count: 1 @@ -2950,46 +2945,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Collection/Cells.php - - - message: "#^Cannot call method detach\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:get\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null but returns mixed\\.$#" count: 1 path: src/PhpSpreadsheet/Collection/Cells.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getCurrentCoordinate\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getParent\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet but returns PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - - - message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, int\\|false given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - - - message: "#^Parameter \\#1 \\$str of function sscanf expects string, string\\|null given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Collection/Cells.php - - - - message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - - - message: "#^Possibly invalid array key type \\(array\\|string\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:\\$currentCell \\(PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\) does not accept mixed\\.$#" count: 1 @@ -8680,11 +8640,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - - message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getHighestColumn\\(\\) expects string\\|null, int given\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - message: "#^Parameter \\#1 \\$propertyName of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:getCustomPropertyType\\(\\) expects string, mixed given\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 5dee0fde..8ff5abef 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -4230,7 +4230,9 @@ class Calculation if (ctype_digit($val) && $val <= 1048576) { // Row range $stackItemType = 'Row Reference'; - $endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataColumn($val) : 'XFD'; // Max 16,384 columns for Excel2007 + /** @var string */ + $valx = $val; + $endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataColumn($valx) : 'XFD'; // Max 16,384 columns for Excel2007 $val = "{$rangeWS2}{$endRowColRef}{$val}"; } elseif (ctype_alpha($val) && strlen($val) <= 3) { // Column range diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 56604f1e..13fe0d8e 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -9,6 +9,7 @@ use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Style\Style; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Throwable; class Cell { @@ -139,7 +140,16 @@ class Cell */ public function getCoordinate() { - return $this->parent->getCurrentCoordinate(); + try { + $coordinate = $this->parent->getCurrentCoordinate(); + } catch (Throwable $e) { + $coordinate = null; + } + if ($coordinate === null) { + throw new Exception('Coordinate no longer exists'); + } + + return $coordinate; } /** @@ -478,7 +488,17 @@ class Cell */ public function getWorksheet() { - return $this->parent->getParent(); + try { + $worksheet = $this->parent->getParent(); + } catch (Throwable $e) { + $worksheet = null; + } + + if ($worksheet === null) { + throw new Exception('Worksheet no longer exists'); + } + + return $worksheet; } /** diff --git a/src/PhpSpreadsheet/Collection/Cells.php b/src/PhpSpreadsheet/Collection/Cells.php index 3bbf76fc..10369e14 100644 --- a/src/PhpSpreadsheet/Collection/Cells.php +++ b/src/PhpSpreadsheet/Collection/Cells.php @@ -76,7 +76,7 @@ class Cells /** * Return the parent worksheet for this cell collection. * - * @return Worksheet + * @return null|Worksheet */ public function getParent() { @@ -181,7 +181,7 @@ class Cells // Determine highest column and row $highestRow = max($row); - $highestColumn = substr(max($col), 1); + $highestColumn = substr((string) @max($col), 1); return [ 'row' => $highestRow, @@ -192,7 +192,7 @@ class Cells /** * Return the cell coordinate of the currently active cell object. * - * @return string + * @return null|string */ public function getCurrentCoordinate() { @@ -209,7 +209,7 @@ class Cells $column = ''; $row = 0; - sscanf($this->currentCoordinate, '%[A-Z]%d', $column, $row); + sscanf($this->currentCoordinate ?? '', '%[A-Z]%d', $column, $row); return $column; } @@ -224,7 +224,7 @@ class Cells $column = ''; $row = 0; - sscanf($this->currentCoordinate, '%[A-Z]%d', $column, $row); + sscanf($this->currentCoordinate ?? '', '%[A-Z]%d', $column, $row); return (int) $row; } @@ -232,7 +232,7 @@ class Cells /** * Get highest worksheet column. * - * @param string $row Return the highest column for the specified row, + * @param null|int|string $row Return the highest column for the specified row, * or the highest column of any row if no row number is passed * * @return string Highest column name @@ -257,13 +257,13 @@ class Cells $columnList[] = Coordinate::columnIndexFromString($c); } - return Coordinate::stringFromColumnIndex(max($columnList)); + return Coordinate::stringFromColumnIndex((int) @max($columnList)); } /** * Get highest worksheet row. * - * @param string $column Return the highest row for the specified column, + * @param null|string $column Return the highest row for the specified column, * or the highest row of any column if no column letter is passed * * @return int Highest row number @@ -304,8 +304,6 @@ class Cells /** * Clone the cell collection. * - * @param Worksheet $worksheet The new worksheet that we're copying to - * * @return self */ public function cloneCellCollection(Worksheet $worksheet) @@ -314,7 +312,7 @@ class Cells $newCollection = clone $this; $newCollection->parent = $worksheet; - if (($newCollection->currentCell !== null) && (is_object($newCollection->currentCell))) { + if (is_object($newCollection->currentCell)) { $newCollection->currentCell->attach($this); } @@ -327,16 +325,14 @@ class Cells // Change prefix $newCollection->cachePrefix = $newCollection->getUniqueID(); foreach ($oldValues as $oldKey => $value) { - $newValues[str_replace($oldCachePrefix, $newCollection->cachePrefix, $oldKey)] = clone $value; + /** @var string */ + $newKey = str_replace($oldCachePrefix, $newCollection->cachePrefix, $oldKey); + $newValues[$newKey] = clone $value; } // Store new values $stored = $newCollection->cache->setMultiple($newValues); - if (!$stored) { - $newCollection->__destruct(); - - throw new PhpSpreadsheetException('Failed to copy cells in cache'); - } + $this->destructIfNeeded($stored, $newCollection, 'Failed to copy cells in cache'); return $newCollection; } @@ -383,15 +379,11 @@ class Cells */ private function storeCurrentCell(): void { - if ($this->currentCellIsDirty && !empty($this->currentCoordinate)) { + if ($this->currentCellIsDirty && isset($this->currentCoordinate, $this->currentCell)) { $this->currentCell->detach(); $stored = $this->cache->set($this->cachePrefix . $this->currentCoordinate, $this->currentCell); - if (!$stored) { - $this->__destruct(); - - throw new PhpSpreadsheetException("Failed to store cell {$this->currentCoordinate} in cache"); - } + $this->destructIfNeeded($stored, $this, "Failed to store cell {$this->currentCoordinate} in cache"); $this->currentCellIsDirty = false; } @@ -399,6 +391,15 @@ class Cells $this->currentCell = null; } + private function destructIfNeeded(bool $stored, self $cells, string $message): void + { + if (!$stored) { + $cells->__destruct(); + + throw new PhpSpreadsheetException($message); + } + } + /** * Add or update a cell identified by its coordinate into the collection. * diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index a61b8001..9ef9958f 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -1036,14 +1036,14 @@ class Worksheet implements IComparable /** * Get highest worksheet column. * - * @param string $row Return the data highest column for the specified row, + * @param null|int|string $row Return the data highest column for the specified row, * or the highest column of any row if no row number is passed * * @return string Highest column name */ public function getHighestColumn($row = null) { - if ($row == null) { + if (empty($row)) { return Coordinate::stringFromColumnIndex($this->cachedHighestColumn); } @@ -1053,7 +1053,7 @@ class Worksheet implements IComparable /** * Get highest worksheet column that contains data. * - * @param string $row Return the highest data column for the specified row, + * @param null|int|string $row Return the highest data column for the specified row, * or the highest data column of any row if no row number is passed * * @return string Highest column name that contains data @@ -1066,7 +1066,7 @@ class Worksheet implements IComparable /** * Get highest worksheet row. * - * @param string $column Return the highest data row for the specified column, + * @param null|string $column Return the highest data row for the specified column, * or the highest row of any column if no column letter is passed * * @return int Highest row number @@ -1083,7 +1083,7 @@ class Worksheet implements IComparable /** * Get highest worksheet row that contains data. * - * @param string $column Return the highest data row for the specified column, + * @param null|string $column Return the highest data row for the specified column, * or the highest data row of any column if no column letter is passed * * @return int Highest row number that contains data diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index 3fa8b69b..34ff2121 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -4,12 +4,9 @@ namespace PhpOffice\PhpSpreadsheetTests\Cell; use PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder; use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PhpOffice\PhpSpreadsheet\Cell\DataType; -use PhpOffice\PhpSpreadsheet\Collection\Cells; +use PhpOffice\PhpSpreadsheet\Cell\IValueBinder; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; -use PhpOffice\PhpSpreadsheet\Style\NumberFormat; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\MockObject\MockObject; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class AdvancedValueBinderTest extends TestCase @@ -29,11 +26,18 @@ class AdvancedValueBinderTest extends TestCase */ private $thousandsSeparator; + /** + * @var IValueBinder + */ + private $valueBinder; + protected function setUp(): void { $this->currencyCode = StringHelper::getCurrencyCode(); $this->decimalSeparator = StringHelper::getDecimalSeparator(); $this->thousandsSeparator = StringHelper::getThousandsSeparator(); + $this->valueBinder = Cell::getValueBinder(); + Cell::setValueBinder(new AdvancedValueBinder()); } protected function tearDown(): void @@ -41,23 +45,16 @@ class AdvancedValueBinderTest extends TestCase StringHelper::setCurrencyCode($this->currencyCode); StringHelper::setDecimalSeparator($this->decimalSeparator); StringHelper::setThousandsSeparator($this->thousandsSeparator); + Cell::setValueBinder($this->valueBinder); } public function testNullValue(): void { - /** @var Cell&MockObject $cellStub */ - $cellStub = $this->getMockBuilder(Cell::class) - ->disableOriginalConstructor() - ->getMock(); - - // Configure the stub. - $cellStub->expects(self::once()) - ->method('setValueExplicit') - ->with(null, DataType::TYPE_NULL) - ->willReturn(true); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cellStub, null); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue(null); + self::assertNull($sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } /** @@ -65,65 +62,34 @@ class AdvancedValueBinderTest extends TestCase * * @param mixed $value * @param mixed $valueBinded - * @param mixed $format * @param mixed $thousandsSeparator * @param mixed $decimalSeparator * @param mixed $currencyCode */ - public function testCurrency($value, $valueBinded, $format, $thousandsSeparator, $decimalSeparator, $currencyCode): void + public function testCurrency($value, $valueBinded, $thousandsSeparator, $decimalSeparator, $currencyCode): void { - $sheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['getStyle', 'getCellCollection']) - ->addMethods(['getNumberFormat', 'setFormatCode']) - ->getMock(); - $cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $cellCollection->expects(self::any()) - ->method('getParent') - ->willReturn($sheet); - - $sheet->expects(self::once()) - ->method('getStyle') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('getNumberFormat') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('setFormatCode') - ->with($format) - ->willReturnSelf(); - $sheet->expects(self::any()) - ->method('getCellCollection') - ->willReturn($cellCollection); - StringHelper::setCurrencyCode($currencyCode); StringHelper::setDecimalSeparator($decimalSeparator); StringHelper::setThousandsSeparator($thousandsSeparator); - $cell = new Cell(null, DataType::TYPE_STRING, $sheet); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cell, $value); - self::assertEquals($valueBinded, $cell->getValue()); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($value); + self::assertEquals($valueBinded, $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } public function currencyProvider(): array { - $currencyUSD = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE; - $currencyEURO = str_replace('$', '€', NumberFormat::FORMAT_CURRENCY_USD_SIMPLE); - return [ - ['$10.11', 10.11, $currencyUSD, ',', '.', '$'], - ['$1,010.12', 1010.12, $currencyUSD, ',', '.', '$'], - ['$20,20', 20.2, $currencyUSD, '.', ',', '$'], - ['$2.020,20', 2020.2, $currencyUSD, '.', ',', '$'], - ['€2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], - ['€ 2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], - ['€2,020.22', 2020.22, $currencyEURO, ',', '.', '€'], - ['$10.11', 10.11, $currencyUSD, ',', '.', '€'], + ['$10.11', 10.11, ',', '.', '$'], + ['$1,010.12', 1010.12, ',', '.', '$'], + ['$20,20', 20.2, '.', ',', '$'], + ['$2.020,20', 2020.2, '.', ',', '$'], + ['€2.020,20', 2020.2, '.', ',', '€'], + ['€ 2.020,20', 2020.2, '.', ',', '€'], + ['€2,020.22', 2020.22, ',', '.', '€'], + ['$10.11', 10.11, ',', '.', '€'], ]; } @@ -132,59 +98,30 @@ class AdvancedValueBinderTest extends TestCase * * @param mixed $value * @param mixed $valueBinded - * @param mixed $format */ - public function testFractions($value, $valueBinded, $format): void + public function testFractions($value, $valueBinded): void { - $sheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['getStyle', 'getCellCollection']) - ->addMethods(['getNumberFormat', 'setFormatCode']) - ->getMock(); - - $cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $cellCollection->expects(self::any()) - ->method('getParent') - ->willReturn($sheet); - - $sheet->expects(self::once()) - ->method('getStyle') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('getNumberFormat') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('setFormatCode') - ->with($format) - ->willReturnSelf(); - $sheet->expects(self::any()) - ->method('getCellCollection') - ->willReturn($cellCollection); - - $cell = new Cell(null, DataType::TYPE_STRING, $sheet); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cell, $value); - self::assertEquals($valueBinded, $cell->getValue()); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($value); + self::assertEquals($valueBinded, $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } public function fractionProvider(): array { return [ - ['1/5', 0.2, '?/?'], - ['-1/5', -0.2, '?/?'], - ['12/5', 2.4, '??/?'], - ['2/100', 0.02, '?/???'], - ['15/12', 1.25, '??/??'], - ['20/100', 0.2, '??/???'], - ['1 3/5', 1.6, '# ?/?'], - ['-1 3/5', -1.6, '# ?/?'], - ['1 4/20', 1.2, '# ?/??'], - ['1 16/20', 1.8, '# ??/??'], - ['12 20/100', 12.2, '# ??/???'], + ['1/5', 0.2], + ['-1/5', -0.2], + ['12/5', 2.4], + ['2/100', 0.02], + ['15/12', 1.25], + ['20/100', 0.2], + ['1 3/5', 1.6], + ['-1 3/5', -1.6], + ['1 4/20', 1.2], + ['1 16/20', 1.8], + ['12 20/100', 12.2], ]; } @@ -193,51 +130,23 @@ class AdvancedValueBinderTest extends TestCase * * @param mixed $value * @param mixed $valueBinded - * @param mixed $format */ - public function testPercentages($value, $valueBinded, $format): void + public function testPercentages($value, $valueBinded): void { - $sheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['getStyle', 'getCellCollection']) - ->addMethods(['getNumberFormat', 'setFormatCode']) - ->getMock(); - $cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $cellCollection->expects(self::any()) - ->method('getParent') - ->willReturn($sheet); - - $sheet->expects(self::once()) - ->method('getStyle') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('getNumberFormat') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('setFormatCode') - ->with($format) - ->willReturnSelf(); - $sheet->expects(self::any()) - ->method('getCellCollection') - ->willReturn($cellCollection); - - $cell = new Cell(null, DataType::TYPE_STRING, $sheet); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cell, $value); - self::assertEquals($valueBinded, $cell->getValue()); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($value); + self::assertEquals($valueBinded, $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } public function percentageProvider(): array { return [ - ['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00], - ['-12%', -0.12, NumberFormat::FORMAT_PERCENTAGE_00], - ['120%', 1.2, NumberFormat::FORMAT_PERCENTAGE_00], - ['12.5%', 0.125, NumberFormat::FORMAT_PERCENTAGE_00], + ['10%', 0.1], + ['-12%', -0.12], + ['120%', 1.2], + ['12.5%', 0.125], ]; } @@ -246,92 +155,37 @@ class AdvancedValueBinderTest extends TestCase * * @param mixed $value * @param mixed $valueBinded - * @param mixed $format */ - public function testTimes($value, $valueBinded, $format): void + public function testTimes($value, $valueBinded): void { - $sheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['getStyle', 'getCellCollection']) - ->addMethods(['getNumberFormat', 'setFormatCode']) - ->getMock(); - - $cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $cellCollection->expects(self::any()) - ->method('getParent') - ->willReturn($sheet); - - $sheet->expects(self::once()) - ->method('getStyle') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('getNumberFormat') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects(self::once()) - ->method('setFormatCode') - ->with($format) - ->willReturnSelf(); - $sheet->expects(self::any()) - ->method('getCellCollection') - ->willReturn($cellCollection); - - $cell = new Cell(null, DataType::TYPE_STRING, $sheet); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cell, $value); - self::assertEquals($valueBinded, $cell->getValue()); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($value); + self::assertEquals($valueBinded, $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } public function timeProvider(): array { return [ - ['1:20', 0.05555555556, NumberFormat::FORMAT_DATE_TIME3], - ['09:17', 0.386805555556, NumberFormat::FORMAT_DATE_TIME3], - ['15:00', 0.625, NumberFormat::FORMAT_DATE_TIME3], - ['17:12:35', 0.71707175926, NumberFormat::FORMAT_DATE_TIME4], - ['23:58:20', 0.99884259259, NumberFormat::FORMAT_DATE_TIME4], + ['1:20', 0.05555555556], + ['09:17', 0.386805555556], + ['15:00', 0.625], + ['17:12:35', 0.71707175926], + ['23:58:20', 0.99884259259], ]; } /** * @dataProvider stringProvider */ - public function testStringWrapping(string $value, bool $wrapped): void + public function testStringWrapping(string $value): void { - $sheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['getStyle', 'getCellCollection']) - ->addMethods(['getAlignment', 'setWrapText']) - ->getMock(); - $cellCollection = $this->getMockBuilder(Cells::class) - ->disableOriginalConstructor() - ->getMock(); - $cellCollection->expects(self::any()) - ->method('getParent') - ->willReturn($sheet); - - $sheet->expects($wrapped ? self::once() : self::never()) - ->method('getStyle') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects($wrapped ? self::once() : self::never()) - ->method('getAlignment') - ->willReturnSelf(); - // @phpstan-ignore-next-line - $sheet->expects($wrapped ? self::once() : self::never()) - ->method('setWrapText') - ->with($wrapped) - ->willReturnSelf(); - $sheet->expects(self::any()) - ->method('getCellCollection') - ->willReturn($cellCollection); - - $cell = new Cell(null, DataType::TYPE_STRING, $sheet); - - $binder = new AdvancedValueBinder(); - $binder->bindValue($cell, $value); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($value); + self::assertEquals($value, $sheet->getCell('A1')->getValue()); + $spreadsheet->disconnectWorksheets(); } public function stringProvider(): array diff --git a/tests/PhpSpreadsheetTests/Cell/CellTest.php b/tests/PhpSpreadsheetTests/Cell/CellTest.php index 980f0170..83a28758 100644 --- a/tests/PhpSpreadsheetTests/Cell/CellTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CellTest.php @@ -21,6 +21,7 @@ class CellTest extends TestCase $cell->setValueExplicit($value, $dataType); self::assertSame($expected, $cell->getValue()); + $spreadsheet->disconnectWorksheets(); } public function providerSetValueExplicit(): array @@ -64,5 +65,42 @@ class CellTest extends TestCase $value = $spreadsheet->getActiveSheet()->getCell($cell)->getCalculatedValue(); self::assertEquals(0, $spreadsheet->getActiveSheetIndex()); self::assertEquals(247, $value); + $spreadsheet->disconnectWorksheets(); + } + + public function testDestroyWorksheet(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + self::assertSame($sheet, $cell->getWorksheet()); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Worksheet no longer exists'); + $spreadsheet->disconnectWorksheets(); + $cell->getWorksheet(); + } + + public function testDestroyCell1(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + self::assertSame('A1', $cell->getCoordinate()); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Coordinate no longer exists'); + $spreadsheet->disconnectWorksheets(); + $cell->getCoordinate(); + } + + public function testDestroyCell2(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + self::assertSame('A1', $cell->getCoordinate()); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Coordinate no longer exists'); + $cell->getParent()->delete('A1'); + $cell->getCoordinate(); } } diff --git a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php index cc9098bf..eba75b2e 100644 --- a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php @@ -4,31 +4,14 @@ namespace PhpOffice\PhpSpreadsheetTests\Cell; use DateTime; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder; use PhpOffice\PhpSpreadsheet\RichText\RichText; -use PHPUnit\Framework\MockObject\MockObject; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class DefaultValueBinderTest extends TestCase { - private function createCellStub(): Cell - { - // Create a stub for the Cell class. - /** @var Cell&MockObject $cellStub */ - $cellStub = $this->getMockBuilder(Cell::class) - ->disableOriginalConstructor() - ->getMock(); - - // Configure the stub. - $cellStub->expects(self::any()) - ->method('setValueExplicit') - ->willReturn(true); - - return $cellStub; - } - /** * @dataProvider binderProvider * @@ -36,10 +19,13 @@ class DefaultValueBinderTest extends TestCase */ public function testBindValue($value): void { - $cellStub = $this->createCellStub(); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); $binder = new DefaultValueBinder(); - $result = $binder->bindValue($cellStub, $value); + $result = $binder->bindValue($cell, $value); self::assertTrue($result); + $spreadsheet->disconnectWorksheets(); } public function binderProvider(): array @@ -91,11 +77,14 @@ class DefaultValueBinderTest extends TestCase public function testCanOverrideStaticMethodWithoutOverridingBindValue(): void { - $cellStub = $this->createCellStub(); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); $binder = new ValueBinderWithOverriddenDataTypeForValue(); self::assertFalse($binder::$called); - $binder->bindValue($cellStub, 123); + $binder->bindValue($cell, 123); self::assertTrue($binder::$called); + $spreadsheet->disconnectWorksheets(); } } diff --git a/tests/PhpSpreadsheetTests/Cell/StringValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/StringValueBinderTest.php index 411af353..8a399cf7 100644 --- a/tests/PhpSpreadsheetTests/Cell/StringValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/StringValueBinderTest.php @@ -6,41 +6,27 @@ use DateTime; use DateTimeZone; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\DataType; +use PhpOffice\PhpSpreadsheet\Cell\IValueBinder; use PhpOffice\PhpSpreadsheet\Cell\StringValueBinder; use PhpOffice\PhpSpreadsheet\RichText\RichText; -use PhpOffice\PhpSpreadsheet\Style\Style; -use PHPUnit\Framework\MockObject\MockObject; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class StringValueBinderTest extends TestCase { /** - * @param mixed $expectedValue - * - * @return Cell&MockObject + * @var IValueBinder */ - protected function createCellStub($expectedValue, string $expectedDataType, bool $quotePrefix = false): MockObject + private $valueBinder; + + protected function setUp(): void { - /** @var Style&MockObject $styleStub */ - $styleStub = $this->getMockBuilder(Style::class) - ->disableOriginalConstructor() - ->getMock(); + $this->valueBinder = Cell::getValueBinder(); + } - /** @var Cell&MockObject $cellStub */ - $cellStub = $this->getMockBuilder(Cell::class) - ->disableOriginalConstructor() - ->getMock(); - - // Configure the stub. - $cellStub->expects(self::once()) - ->method('setValueExplicit') - ->with($expectedValue, $expectedDataType) - ->willReturn(true); - $cellStub->expects($quotePrefix ? self::once() : self::never()) - ->method('getStyle') - ->willReturn($styleStub); - - return $cellStub; + protected function tearDown(): void + { + Cell::setValueBinder($this->valueBinder); } /** @@ -52,13 +38,16 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderDefaultBehaviour( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - - $binder = new StringValueBinder(); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder(new StringValueBinder()); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesDefault(): array @@ -76,7 +65,7 @@ class StringValueBinderTest extends TestCase ['-.123', '-.123', DataType::TYPE_STRING], ['1.23e-4', '1.23e-4', DataType::TYPE_STRING], ['ABC', 'ABC', DataType::TYPE_STRING], - ['=SUM(A1:C3)', '=SUM(A1:C3)', DataType::TYPE_STRING, true], + ['=SUM(A1:C3)', '=SUM(A1:C3)', DataType::TYPE_STRING], [123, '123', DataType::TYPE_STRING], [123.456, '123.456', DataType::TYPE_STRING], [0.123, '0.123', DataType::TYPE_STRING], @@ -98,20 +87,26 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderSuppressNullConversion( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - $binder = new StringValueBinder(); $binder->setNullConversion(false); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesSuppressNullConversion(): array { return [ [null, null, DataType::TYPE_NULL], + [true, '1', DataType::TYPE_STRING], + [123, '123', DataType::TYPE_STRING], ]; } @@ -124,14 +119,18 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderSuppressBooleanConversion( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - $binder = new StringValueBinder(); $binder->setBooleanConversion(false); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesSuppressBooleanConversion(): array @@ -139,6 +138,8 @@ class StringValueBinderTest extends TestCase return [ [true, true, DataType::TYPE_BOOL], [false, false, DataType::TYPE_BOOL], + [null, '', DataType::TYPE_STRING], + [123, '123', DataType::TYPE_STRING], ]; } @@ -151,14 +152,18 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderSuppressNumericConversion( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - $binder = new StringValueBinder(); $binder->setNumericConversion(false); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesSuppressNumericConversion(): array @@ -172,6 +177,9 @@ class StringValueBinderTest extends TestCase [-.123, -0.123, DataType::TYPE_NUMERIC], [1.23e-4, 0.000123, DataType::TYPE_NUMERIC], [1.23e-24, 1.23E-24, DataType::TYPE_NUMERIC], + [true, '1', DataType::TYPE_STRING], + [false, '', DataType::TYPE_STRING], + [null, '', DataType::TYPE_STRING], ]; } @@ -184,14 +192,18 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderSuppressFormulaConversion( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - $binder = new StringValueBinder(); $binder->setFormulaConversion(false); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesSuppressFormulaConversion(): array @@ -210,14 +222,18 @@ class StringValueBinderTest extends TestCase public function testStringValueBinderSuppressAllConversion( $value, $expectedValue, - string $expectedDataType, - bool $quotePrefix = false + string $expectedDataType ): void { - $cellStub = $this->createCellStub($expectedValue, $expectedDataType, $quotePrefix); - $binder = new StringValueBinder(); $binder->setConversionForAllValueTypes(false); - $binder->bindValue($cellStub, $value); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($value); + self::assertSame($expectedValue, $cell->getValue()); + self::assertSame($expectedDataType, $cell->getDataType()); + $spreadsheet->disconnectWorksheets(); } public function providerDataValuesSuppressAllConversion(): array @@ -252,10 +268,15 @@ class StringValueBinderTest extends TestCase $objRichText = new RichText(); $objRichText->createText('Hello World'); - $cellStub = $this->createCellStub($objRichText, DataType::TYPE_INLINE); - $binder = new StringValueBinder(); $binder->setConversionForAllValueTypes(false); - $binder->bindValue($cellStub, $objRichText); + Cell::setValueBinder($binder); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $cell->setValue($objRichText); + self::assertSame('inlineStr', $cell->getDataType()); + self::assertSame('Hello World', $cell->getCalculatedValue()); + $spreadsheet->disconnectWorksheets(); } }