diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5f62562a..eaea1d3b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7930,26 +7930,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php - - - message: "#^Parameter \\#1 \\$cellAddress of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:COLUMN\\(\\) expects array\\|string\\|null, mixed given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php - - - - message: "#^Parameter \\#1 \\$cellAddress of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:OFFSET\\(\\) expects string\\|null, mixed given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php - - - - message: "#^Parameter \\#1 \\$cellAddress of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:ROW\\(\\) expects array\\|string\\|null, mixed given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php - - - - message: "#^Parameter \\#1 \\$matrixData of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:TRANSPOSE\\(\\) expects array, mixed given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php - - message: "#^Part \\$number \\(mixed\\) of encapsed string cannot be cast to string\\.$#" count: 1 @@ -8220,11 +8200,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php - - - message: "#^Parameter \\#1 \\$string of function substr expects string, mixed given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php - - message: "#^Parameter \\#1 \\$currencyCode of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:setCurrencyCode\\(\\) expects string, mixed given\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php index 7e1e287d..7e33f55a 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php @@ -48,7 +48,7 @@ class Offset $width = Functions::flattenSingleValue($width); if ($cellAddress === null || $cellAddress === '') { - return 0; + return Functions::VALUE(); } if (!is_object($cell)) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php index 2dfb22d9..2cd0b735 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php @@ -2,27 +2,19 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; -use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PHPUnit\Framework\TestCase; -class ColumnTest extends TestCase +class ColumnTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCOLUMN * * @param mixed $expectedResult - * @param null|mixed $cellReference + * @param null|array|string $cellReference */ public function testCOLUMN($expectedResult, $cellReference = null): void { - $result = LookupRef::COLUMN($cellReference); + $result = LookupRef\RowColumnInformation::COLUMN($cellReference); self::assertSame($expectedResult, $result); } @@ -33,14 +25,15 @@ class ColumnTest extends TestCase public function testCOLUMNwithNull(): void { - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getColumn']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getColumn') - ->willReturn('D'); - - $result = LookupRef::COLUMN(null, $cell); - self::assertSame(4, $result); + $sheet = $this->getSheet(); + $sheet->getCell('D1')->setValue('=COLUMN()'); + self::assertSame(4, $sheet->getCell('D1')->getCalculatedValue()); + $sheet->getCell('D2')->setValue('=COLUMN(C13)'); + self::assertSame(3, $sheet->getCell('D2')->getCalculatedValue()); + // Sheetnames don't have to exist + $sheet->getCell('D3')->setValue('=COLUMN(Sheet17!E15)'); + self::assertSame(5, $sheet->getCell('D3')->getCalculatedValue()); + $sheet->getCell('D4')->setValue("=COLUMN('Worksheet #5'!X500)"); + self::assertSame(24, $sheet->getCell('D4')->getCalculatedValue()); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/FormulaTextTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/FormulaTextTest.php new file mode 100644 index 00000000..ccd689b1 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/FormulaTextTest.php @@ -0,0 +1,37 @@ +getSheet(); + $reference = 'A1'; + if ($value !== null) { + $sheet->getCell($reference)->setValue($value); + } + $sheet->getCell('D1')->setValue("=FORMULATEXT($reference)"); + $result = $sheet->getCell('D1')->getCalculatedValue(); + self::assertSame($expectedResult, $result); + } + + public function providerFormulaText(): array + { + return require 'tests/data/Calculation/LookupRef/FORMULATEXT.php'; + } + + public function testNoCell(): void + { + self::assertSame('#REF!', Formula::text('B5')); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HyperlinkTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HyperlinkTest.php index e71992ed..0aef51de 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HyperlinkTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HyperlinkTest.php @@ -4,40 +4,91 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; -use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PhpOffice\PhpSpreadsheet\Cell\Hyperlink; -use PHPUnit\Framework\TestCase; -class HyperlinkTest extends TestCase +class HyperlinkTest extends AllSetupTeardown { + /** @var bool */ + protected $issue2464 = true; + /** * @dataProvider providerHYPERLINK * - * @param mixed $expectedResult - * @param null|string $linkUrl - * @param null|string $description + * @param array|string $expectedResult */ - public function testHYPERLINK($expectedResult, $linkUrl, $description): void + public function testHYPERLINK($expectedResult, ?string $linkUrl, ?string $description): void { - $hyperlink = new Hyperlink(); + $this->mightHaveException($expectedResult); + $sheet = $this->getSheet(); + $formula = '=HYPERLINK('; + if ($linkUrl !== null) { + $formula .= '"' . $linkUrl . '"'; + if ($description !== null) { + $formula .= ',"' . $description . '"'; + } + } + $formula .= ')'; + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getHyperlink']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getHyperlink') - ->willReturn($hyperlink); - - $result = LookupRef::HYPERLINK($linkUrl, $description, $cell); if (!is_array($expectedResult)) { self::assertSame($expectedResult, $result); } else { self::assertSame($expectedResult[1], $result); + $hyperlink = $sheet->getCell('A1')->getHyperlink(); self::assertSame($expectedResult[0], $hyperlink->getUrl()); self::assertSame($expectedResult[1], $hyperlink->getTooltip()); } } + /** + * @dataProvider providerHYPERLINK + * + * @param array|string $expectedResult + */ + public function testHYPERLINKcellRef($expectedResult, ?string $linkUrl, ?string $description): void + { + $this->mightHaveException($expectedResult); + $sheet = $this->getSheet(); + $formula = '=HYPERLINK('; + if ($linkUrl !== null) { + $sheet->getCell('A2')->setValue($linkUrl); + $formula .= 'A2'; + if ($description !== null) { + $sheet->getCell('A3')->setValue($description); + $formula .= ',A3'; + } + } + $formula .= ')'; + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + + if (!is_array($expectedResult)) { + self::assertSame($expectedResult, $result); + } else { + self::assertSame($expectedResult[1], $result); + if (!$this->issue2464) { + $hyperlink = $sheet->getCell('A1')->getHyperlink(); + self::assertSame($expectedResult[0], $hyperlink->getUrl()); + self::assertSame($expectedResult[1], $hyperlink->getTooltip()); + } + } + } + + public function testLen(): void + { + $sheet = $this->getSheet(); + $sheet->getCell('A1')->setValue('=LEN(HYPERLINK("http://www.example.com","Example"))'); + $value = $sheet->getCell('A1')->getCalculatedValue(); + self::assertSame(7, $value); + if ($this->issue2464) { + self::markTestIncomplete('testLen and testHYPERLINKcellRef incomplete due to issue 2464'); + } else { + $hyperlink = $sheet->getCell('A1')->getHyperlink(); + self::assertSame('', $hyperlink->getUrl()); + self::assertSame('', $hyperlink->getTooltip()); + } + } + public function providerHYPERLINK(): array { return require 'tests/data/Calculation/LookupRef/HYPERLINK.php'; @@ -45,7 +96,7 @@ class HyperlinkTest extends TestCase public function testHYPERLINKwithoutCell(): void { - $result = LookupRef::HYPERLINK('https://phpspreadsheet.readthedocs.io/en/latest/', 'Read the Docs'); + $result = LookupRef\Hyperlink::set('https://phpspreadsheet.readthedocs.io/en/latest/', 'Read the Docs'); self::assertSame(Functions::REF(), $result); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MovedFunctionsTest.php new file mode 100644 index 00000000..e69af7d9 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MovedFunctionsTest.php @@ -0,0 +1,28 @@ +getSheet(); + $sheet->getCell('B6')->setValue(4); + $sheet->getCell('B7')->setValue(8); + $sheet->getCell('B8')->setValue(3); + $sheet->getCell('D6')->setValue(10); + $sheet->getCell('D7')->setValue(3); + $sheet->getCell('D8')->setValue(6); + + $sheet->getCell('A1')->setValue('=OFFSET(D3,3,-2,1,1)'); + self::assertSame(4, $sheet->getCell('A1')->getCalculatedValue()); + $sheet->getCell('A2')->setValue('=SUM(OFFSET(D3:F5,3,-2, 3, 3))'); + self::assertSame(34, $sheet->getCell('A2')->getCalculatedValue()); + $sheet->getCell('A3')->setValue('=OFFSET(D3, -3, -3)'); + self::assertSame('#REF!', $sheet->getCell('A3')->getCalculatedValue()); + + $sheet->getCell('C1')->setValue(5); + $sheet->getCell('A4')->setValue('=OFFSET(C1, 0, 0, 0, 0)'); + self::assertSame('#REF!', $sheet->getCell('A4')->getCalculatedValue()); + $sheet->getCell('A5')->setValue('=OFFSET(C1, 0, 0)'); + self::assertSame(5, $sheet->getCell('A5')->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php index 0e73e829..8364630d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php @@ -2,27 +2,19 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; -use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PHPUnit\Framework\TestCase; -class RowTest extends TestCase +class RowTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerROW * * @param mixed $expectedResult - * @param null|mixed $cellReference + * @param null|array|string $cellReference */ public function testROW($expectedResult, $cellReference = null): void { - $result = LookupRef::ROW($cellReference); + $result = LookupRef\RowColumnInformation::ROW($cellReference); self::assertSame($expectedResult, $result); } @@ -33,14 +25,15 @@ class RowTest extends TestCase public function testROWwithNull(): void { - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getRow']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getRow') - ->willReturn(3); - - $result = LookupRef::ROW(null, $cell); - self::assertSame(3, $result); + $sheet = $this->getSheet(); + $sheet->getCell('C4')->setValue('=ROW()'); + self::assertSame(4, $sheet->getCell('C4')->getCalculatedValue()); + $sheet->getCell('D2')->setValue('=ROW(C13)'); + self::assertSame(13, $sheet->getCell('D2')->getCalculatedValue()); + // Sheetnames don't have to exist + $sheet->getCell('D3')->setValue('=ROW(Sheet17!E15)'); + self::assertSame(15, $sheet->getCell('D3')->getCalculatedValue()); + $sheet->getCell('D4')->setValue("=ROW('Worksheet #5'!X500)"); + self::assertSame(500, $sheet->getCell('D4')->getCalculatedValue()); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php index 7654f1bd..ac37a9ff 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php @@ -21,7 +21,7 @@ class TransposeTest extends TestCase */ public function testTRANSPOSE($expectedResult, $matrix): void { - $result = LookupRef::TRANSPOSE($matrix); + $result = LookupRef\Matrix::transpose($matrix); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php b/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php deleted file mode 100644 index 9f4c90b3..00000000 --- a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php +++ /dev/null @@ -1,86 +0,0 @@ -getMockBuilder(Cell::class) - ->disableOriginalConstructor() - ->getMock(); - $remoteCell->method('isFormula') - ->willReturn(substr($value, 0, 1) == '='); - $remoteCell->method('getValue') - ->willReturn($value); - - $remoteSheet = $this->getMockBuilder(Worksheet::class) - ->disableOriginalConstructor() - ->getMock(); - $remoteSheet->method('cellExists') - ->willReturn(true); - $remoteSheet->method('getCell') - ->willReturn($remoteCell); - - $workbook = $this->getMockBuilder(Spreadsheet::class) - ->disableOriginalConstructor() - ->getMock(); - $workbook->method('getSheetByName') - ->willReturn($remoteSheet); - - $sheet = $this->getMockBuilder(Worksheet::class) - ->disableOriginalConstructor() - ->getMock(); - $sheet->method('cellExists') - ->willReturn(true); - $sheet->method('getCell') - ->willReturn($remoteCell); - $sheet->method('getParent') - ->willReturn($workbook); - - $ourCell = $this->getMockBuilder(Cell::class) - ->disableOriginalConstructor() - ->getMock(); - $ourCell->method('getWorksheet') - ->willReturn($sheet); - } - - $result = LookupRef::FORMULATEXT($reference, $ourCell); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerFormulaText(): array - { - return require 'tests/data/Calculation/LookupRef/FORMULATEXT.php'; - } - - public function testFormulaTextWithoutCell(): void - { - $result = LookupRef::FORMULATEXT('A1'); - self::assertEquals(Functions::REF(), $result); - } -} diff --git a/tests/PhpSpreadsheetTests/Functional/ReadFilterFilter.php b/tests/PhpSpreadsheetTests/Functional/ReadFilterFilter.php new file mode 100644 index 00000000..a9a26a5e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Functional/ReadFilterFilter.php @@ -0,0 +1,41 @@ + $rowMax || $r < $rowMin) { + return false; + } + + $col = sprintf('%04s', $column); + if ( + $col > sprintf('%04s', $columnMax) || + $col < sprintf('%04s', $columnMin) + ) { + return false; + } + + return true; + } +} diff --git a/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php b/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php index 930288a7..d85b83c7 100644 --- a/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php @@ -2,7 +2,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Functional; -use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; use PhpOffice\PhpSpreadsheet\Spreadsheet; class ReadFilterTest extends AbstractFunctional @@ -69,12 +68,8 @@ class ReadFilterTest extends AbstractFunctional $spreadsheet->getActiveSheet()->fromArray($arrayData, null, 'A1'); $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $format, function ($reader): void { - // Create a stub for the readFilter class. - $readFilterStub = $this->createMock(IReadFilter::class); - $readFilterStub->method('readCell') - ->willReturnCallback([$this, 'readFilterReadCell']); // apply filter - $reader->setReadFilter($readFilterStub); + $reader->setReadFilter(new ReadFilterFilter()); }); $sheet = $reloadedSpreadsheet->getSheet(0); // test highest column (very specific num of columns because of some 3rd party software) @@ -88,37 +83,4 @@ class ReadFilterTest extends AbstractFunctional $coordinateTopLeft = reset($sortedCoordinates); self::assertSame('B2', $coordinateTopLeft); } - - /** - * @param string $column Column address (as a string value like "A", or "IV") - * @param int $row Row number - * @param string $worksheetName Optional worksheet name - * - * @return bool - * - * @see \PhpOffice\PhpSpreadsheet\Reader\IReadFilter::readCell() - */ - public function readFilterReadCell($column, $row, $worksheetName = '') - { - // define filter range - $rowMin = 2; - $rowMax = 6; - $columnMin = 'B'; - $columnMax = 'D'; - - $r = (int) $row; - if ($r > $rowMax || $r < $rowMin) { - return false; - } - - $col = sprintf('%04s', $column); - if ( - $col > sprintf('%04s', $columnMax) || - $col < sprintf('%04s', $columnMin) - ) { - return false; - } - - return true; - } } diff --git a/tests/data/Calculation/LookupRef/FORMULATEXT.php b/tests/data/Calculation/LookupRef/FORMULATEXT.php index 48d528bf..46639c28 100644 --- a/tests/data/Calculation/LookupRef/FORMULATEXT.php +++ b/tests/data/Calculation/LookupRef/FORMULATEXT.php @@ -3,47 +3,42 @@ return [ [ '#N/A', - 'A1', - '2', + 2, ], [ '="ABC"', - 'A2', '="ABC"', ], [ '=A1', - 'A3', '=A1', ], [ '=\'Worksheet1\'!A1', - 'A4', '=\'Worksheet1\'!A1', ], [ '=\'Works heet1\'!A1', - 'A4', '=\'Works heet1\'!A1', ], [ '="HELLO WORLD"', - '\'Worksheet1\'!A5', '="HELLO WORLD"', ], [ - '="HELLO WORLD"', - '\'Work sheet1\'!A5', - '="HELLO WORLD"', - ], - [ - '="HELLO WORLD"', - '\'Work!sheet1\'!A5', - '="HELLO WORLD"', + '=\'Work!sheet1\'!A5', + '=\'Work!sheet1\'!A5', ], [ '#N/A', - '\'Worksheet1\'!A6', - '123', + 'A1', + ], + [ + '#N/A', + null, + ], + [ + '=SUM(B1,B2,B3)', + '=SUM(B1,B2,B3)', ], ]; diff --git a/tests/data/Calculation/LookupRef/HYPERLINK.php b/tests/data/Calculation/LookupRef/HYPERLINK.php index 9a5e4c2e..b8602d19 100644 --- a/tests/data/Calculation/LookupRef/HYPERLINK.php +++ b/tests/data/Calculation/LookupRef/HYPERLINK.php @@ -14,7 +14,7 @@ return [ 'Read the Docs', ], [ - Functions::REF(), + 'exception', null, null, ], diff --git a/tests/data/Calculation/LookupRef/OFFSET.php b/tests/data/Calculation/LookupRef/OFFSET.php index 2386ecd6..9c2f52c1 100644 --- a/tests/data/Calculation/LookupRef/OFFSET.php +++ b/tests/data/Calculation/LookupRef/OFFSET.php @@ -2,7 +2,11 @@ return [ [ - 0, + '#VALUE!', null, ], + [ + '#REF!', + 'B5', + ], ];