From e637713de92410e52e2983c04277522e8789c619 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 25 Jan 2025 19:40:12 -0800 Subject: [PATCH 1/2] Make Explicit Array Return Type When Tests Require It When the Dynamic Array PR #3962 was introduced, it left the default as Return Array as Value. At some point, the default should be changed to Return Array as Array. This would, of course, be a breaking change, one which will not be part of Release 4. However, it will possibly be part of Release 5. Rather than relying on the default setting, this PR explicitly sets Return Array as Value when tests require that setting. This will make it easier to identify potential breaks when the default is changed. The entire test suite will now succeed with either setting as default. In making these changes, a few minor problems were discovered with how Array as Array is handled. These are fixed with this PR. --- samples/LookupRef/COLUMN.php | 5 ++++ .../Calculation/Calculation.php | 16 +++++++---- .../Calculation/Financial/CashFlow/Single.php | 8 +++--- .../CashFlow/Variable/NonPeriodic.php | 12 ++++---- .../Calculation/LookupRef/Matrix.php | 9 ++++++ src/PhpSpreadsheet/Cell/Cell.php | 13 +++++++-- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 3 ++ .../Calculation/ArrayFormulaTest.php | 4 +++ .../Calculation/CalculationLoggingTest.php | 4 +++ .../Calculation/FormulaAsStringTest.php | 8 +++++- .../Functions/Information/IsFormulaTest.php | 4 +++ .../Functions/Logical/AllSetupTeardown.php | 10 +++++++ .../Calculation/Functions/Logical/AndTest.php | 7 +++-- .../Calculation/Functions/Logical/XorTest.php | 1 + .../Functions/LookupRef/AllSetupTeardown.php | 11 +++++++- .../LookupRef/ColumnOnSpreadsheetTest.php | 5 +++- .../Functions/LookupRef/HLookupTest.php | 22 ++++++--------- .../LookupRef/IndexOnSpreadsheetTest.php | 8 ++++-- .../Functions/LookupRef/IndirectTest.php | 12 ++++---- .../LookupRef/RowOnSpreadsheetTest.php | 5 +++- .../Functions/LookupRef/VLookupTest.php | 18 +++++------- .../Functions/MathTrig/AllSetupTeardown.php | 12 +++++++- .../Functions/MathTrig/MMultTest.php | 4 ++- .../Functions/MathTrig/SumIfTest.php | 5 +++- .../Functions/MathTrig/SumProduct2Test.php | 6 ++-- .../Functions/MathTrig/SumTest.php | 12 ++++---- .../Statistical/AllSetupTeardown.php | 10 +++++++ .../Functions/Statistical/AverageIfTest.php | 2 +- .../Functions/Statistical/CountBlankTest.php | 4 +-- .../Functions/Statistical/SkewTest.php | 6 +++- .../TextData/ConcatenateRangeTest.php | 9 +++++- .../Functions/TextData/ConcatenateTest.php | 3 +- .../Calculation/XlfnFunctionsTest.php | 9 ++++++ .../Functional/ArrayFunctionsSpillTest.php | 4 +++ .../Reader/Ods/ArrayFormulaTest.php | 16 ++++++++--- .../Reader/Ods/DefinedNamesTest.php | 28 ++++++++++++++++++- 36 files changed, 237 insertions(+), 78 deletions(-) diff --git a/samples/LookupRef/COLUMN.php b/samples/LookupRef/COLUMN.php index 5b257d606c..c9ccf6971f 100644 --- a/samples/LookupRef/COLUMN.php +++ b/samples/LookupRef/COLUMN.php @@ -1,5 +1,6 @@ setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE +); $worksheet = $spreadsheet->getActiveSheet(); $worksheet->getCell('A1')->setValue('=COLUMN(C13)'); diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index c31ea2c749..3749307393 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -4882,17 +4882,18 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell } $result = $operand1; } else { - // In theory, we should truncate here. - // But I can't figure out a formula - // using the concatenation operator - // with literals that fits in 32K, - // so I don't think we can overflow here. if (Information\ErrorValue::isError($operand1)) { $result = $operand1; } elseif (Information\ErrorValue::isError($operand2)) { $result = $operand2; } else { - $result = self::FORMULA_STRING_QUOTE . str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)) . self::FORMULA_STRING_QUOTE; + $result = str_replace('""', self::FORMULA_STRING_QUOTE, self::unwrapResult($operand1) . self::unwrapResult($operand2)); + $result = Shared\StringHelper::substring( + $result, + 0, + DataType::MAX_STRING_LENGTH + ); + $result = self::FORMULA_STRING_QUOTE . $result . self::FORMULA_STRING_QUOTE; } } $this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($result)); @@ -5041,6 +5042,9 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell while (is_array($cellValue)) { $cellValue = array_shift($cellValue); } + if (is_string($cellValue)) { + $cellValue = preg_replace('/"/', '""', $cellValue); + } $this->debugLog->writeDebugLog('Scalar Result for cell %s is %s', $cellRef, $this->showTypeDetails($cellValue)); } $this->processingAnchorArray = false; diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php index 6f60a2af18..ba3da6bb88 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php @@ -77,13 +77,13 @@ public static function periods(mixed $rate, mixed $presentValue, mixed $futureVa * * Calculates the interest rate required for an investment to grow to a specified future value . * - * @param array|float $periods The number of periods over which the investment is made - * @param array|float $presentValue Present Value - * @param array|float $futureValue Future Value + * @param mixed $periods The number of periods over which the investment is made, expect array|float + * @param mixed $presentValue Present Value, expect array|float + * @param mixed $futureValue Future Value, expect array|float * * @return float|string Result, or a string containing an error */ - public static function interestRate(array|float $periods = 0.0, array|float $presentValue = 0.0, array|float $futureValue = 0.0): string|float + public static function interestRate(mixed $periods = 0.0, mixed $presentValue = 0.0, mixed $futureValue = 0.0): string|float { $periods = Functions::flattenSingleValue($periods); $presentValue = Functions::flattenSingleValue($presentValue); diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php index 15f9e8957b..94bfcef0e6 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php @@ -23,14 +23,14 @@ class NonPeriodic * Excel Function: * =XIRR(values,dates,guess) * - * @param float[] $values A series of cash flow payments + * @param mixed $values A series of cash flow payments, expecting float[] * The series of values must contain at least one positive value & one negative value * @param mixed[] $dates A series of payment dates * The first payment date indicates the beginning of the schedule of payments * All other dates must be later than this date, but they may occur in any order * @param mixed $guess An optional guess at the expected answer */ - public static function rate(array $values, array $dates, mixed $guess = self::DEFAULT_GUESS): float|string + public static function rate(mixed $values, mixed $dates, mixed $guess = self::DEFAULT_GUESS): float|string { $rslt = self::xirrPart1($values, $dates); if ($rslt !== '') { @@ -106,18 +106,18 @@ public static function rate(array $values, array $dates, mixed $guess = self::DE * Excel Function: * =XNPV(rate,values,dates) * - * @param array|float $rate the discount rate to apply to the cash flows - * @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates. + * @param mixed $rate the discount rate to apply to the cash flows, expect array|float + * @param mixed $values A series of cash flows that corresponds to a schedule of payments in dates, expecting floag[]. * The first payment is optional and corresponds to a cost or payment that occurs * at the beginning of the investment. * If the first value is a cost or payment, it must be a negative value. * All succeeding payments are discounted based on a 365-day year. * The series of values must contain at least one positive value and one negative value. - * @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments. + * @param mixed $dates A schedule of payment dates that corresponds to the cash flow payments, expecting mixed[]. * The first payment date indicates the beginning of the schedule of payments. * All other dates must be later than this date, but they may occur in any order. */ - public static function presentValue(array|float $rate, array $values, array $dates): float|string + public static function presentValue(mixed $rate, mixed $values, mixed $dates): float|string { return self::xnpvOrdered($rate, $values, $dates, true); } diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php index 228b464485..b8e84a669e 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php @@ -82,6 +82,15 @@ public static function index(mixed $matrix, mixed $rowNum = 0, mixed $columnNum $rowNum = $rowNum ?? 0; $columnNum = $columnNum ?? 0; + if (is_scalar($matrix)) { + if ($rowNum === 0 || $rowNum === 1) { + if ($columnNum === 0 || $columnNum === 1) { + if ($columnNum === 1 || $rowNum === 1) { + return $matrix; + } + } + } + } try { $rowNum = LookupRefValidations::validatePositiveInt($rowNum); diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 89321abeda..ef1d442899 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -408,9 +408,6 @@ public function getCalculatedValue(bool $resetLog = true): mixed $oldAttributesT = $oldAttributes['t'] ?? ''; $coordinate = $this->getCoordinate(); $oldAttributesRef = $oldAttributes['ref'] ?? $coordinate; - if (!str_contains($oldAttributesRef, ':')) { - $oldAttributesRef .= ":$oldAttributesRef"; - } $originalValue = $this->value; $originalDataType = $this->dataType; $this->formulaAttributes = []; @@ -434,6 +431,14 @@ public function getCalculatedValue(bool $resetLog = true): mixed $result = array_shift($result); } } + if ( + !is_array($result) + && $calculation->getInstanceArrayReturnType() === Calculation::RETURN_ARRAY_AS_ARRAY + && $oldAttributesT === 'array' + && ($oldAttributesRef === $coordinate || $oldAttributesRef === "$coordinate:$coordinate") + ) { + $result = [$result]; + } // if return_as_array for formula like '=sheet!cell' if (is_array($result) && count($result) === 1) { $resultKey = array_keys($result)[0]; @@ -560,6 +565,8 @@ public function getCalculatedValue(bool $resetLog = true): mixed SharedDate::setExcelCalendar($currentCalendar); if ($result === Functions::NOT_YET_IMPLEMENTED) { + $this->formulaAttributes = $oldAttributes; + return $this->calculatedValue; // Fallback if calculation engine does not support the formula. } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 28af258297..fe277a24de 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -1498,6 +1498,9 @@ private function writeCellFormula(XMLWriter $objWriter, string $cellValue, Cell if (isset($attributes['ref'])) { $ref = $this->parseRef($coordinate, $attributes['ref']); + if ($ref === "$coordinate:$coordinate") { + $ref = $coordinate; + } } else { $ref = $coordinate; } diff --git a/tests/PhpSpreadsheetTests/Calculation/ArrayFormulaTest.php b/tests/PhpSpreadsheetTests/Calculation/ArrayFormulaTest.php index 976e8d54bc..27b72dc8d1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/ArrayFormulaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/ArrayFormulaTest.php @@ -62,6 +62,10 @@ public static function providerArrayFormulae(): array public function testArrayFormulaUsingCells(): void { $spreadsheet = new Spreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $sheet = $spreadsheet->getActiveSheet(); $sheet->getCell('A4')->setValue(-3); $sheet->getCell('B4')->setValue(4); diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationLoggingTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationLoggingTest.php index 5d7a076919..8e90644c7b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationLoggingTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationLoggingTest.php @@ -42,6 +42,10 @@ public function testFormulaWithLogging(): void public function testFormulaWithMultipleCellLogging(): void { $spreadsheet = new Spreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $sheet = $spreadsheet->getActiveSheet(); $sheet->fromArray( diff --git a/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php b/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php index ab6c40e67b..d81f093421 100644 --- a/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php @@ -4,15 +4,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class FormulaAsStringTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('providerFunctionsAsString')] + #[DataProvider('providerFunctionsAsString')] public function testFunctionsAsString(mixed $expectedResult, string $formula): void { $spreadsheet = new Spreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $workSheet = $spreadsheet->getActiveSheet(); $workSheet->setCellValue('A1', 10); $workSheet->setCellValue('A2', 20); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php index 9f691d1562..8fc08c7988 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Information/IsFormulaTest.php @@ -15,6 +15,10 @@ class IsFormulaTest extends TestCase public function testIsFormula(): void { $spreadsheet = new Spreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $sheet1 = $spreadsheet->getActiveSheet(); $sheet1->setTitle('SheetOne'); // no space in sheet title $sheet2 = $spreadsheet->createSheet(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AllSetupTeardown.php index 5db3c9b918..fc8dcad3a6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AllSetupTeardown.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\DataType; @@ -100,4 +101,13 @@ protected function runTestCase(string $functionName, mixed $expectedResult, mixe $this->setCell('B1', $formula); self::assertSame($expectedResult, $sheet->getCell('B1')->getCalculatedValue()); } + + protected function setArrayAsValue(): void + { + $spreadsheet = $this->getSpreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php index e1eb46aa14..c41a527897 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php @@ -4,11 +4,14 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical; +use PHPUnit\Framework\Attributes\DataProvider; + class AndTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerAND')] + #[DataProvider('providerAND')] public function testAND(mixed $expectedResult, mixed ...$args): void { + $this->setArrayAsValue(); $this->runTestCase('AND', $expectedResult, ...$args); } @@ -17,7 +20,7 @@ public static function providerAND(): array return require 'tests/data/Calculation/Logical/AND.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerANDLiteral')] + #[DataProvider('providerANDLiteral')] public function testANDLiteral(bool|string $expectedResult, float|int|string $formula): void { $sheet = $this->getSheet(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php index 990068dde1..cc09074c2e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php @@ -9,6 +9,7 @@ class XorTest extends AllSetupTeardown #[\PHPUnit\Framework\Attributes\DataProvider('providerXOR')] public function testXOR(mixed $expectedResult, mixed ...$args): void { + $this->setArrayAsValue(); $this->runTestCase('XOR', $expectedResult, ...$args); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AllSetupTeardown.php index 0f177c81f4..882ee67337 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AllSetupTeardown.php @@ -18,7 +18,7 @@ class AllSetupTeardown extends TestCase protected string $arrayReturnType; - private ?Spreadsheet $spreadsheet = null; + protected ?Spreadsheet $spreadsheet = null; private ?Worksheet $sheet = null; @@ -86,4 +86,13 @@ protected function getSheet(): Worksheet return $this->sheet; } + + protected function setArrayAsValue(): void + { + $spreadsheet = $this->getSpreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnOnSpreadsheetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnOnSpreadsheetTest.php index 3382a1e38d..a57b91eb3f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnOnSpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnOnSpreadsheetTest.php @@ -5,13 +5,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\NamedRange; +use PHPUnit\Framework\Attributes\DataProvider; class ColumnOnSpreadsheetTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerCOLUMNonSpreadsheet')] + #[DataProvider('providerCOLUMNonSpreadsheet')] public function testColumnOnSpreadsheet(mixed $expectedResult, string $cellReference = 'omitted'): void { $this->mightHaveException($expectedResult); + $this->setArrayAsValue(); $sheet = $this->getSheet(); $this->getSpreadsheet()->addNamedRange(new NamedRange('namedrangex', $sheet, '$E$2:$E$6')); $this->getSpreadsheet()->addNamedRange(new NamedRange('namedrangey', $sheet, '$F$2:$H$2')); @@ -37,6 +39,7 @@ public static function providerCOLUMNonSpreadsheet(): array public function testCOLUMNLocalDefinedName(): void { + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet1 = $this->getSpreadsheet()->createSheet(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php index 679cbe28b1..a8f1c2acdb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php @@ -7,16 +7,15 @@ use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\NamedRange; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; -class HLookupTest extends TestCase +class HLookupTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerHLOOKUP')] + #[DataProvider('providerHLOOKUP')] public function testHLOOKUP(mixed $expectedResult, mixed $lookup, array $values, mixed $rowIndex, ?bool $rangeLookup = null): void { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->setArrayAsValue(); + $sheet = $this->getSheet(); $maxRow = 0; $maxCol = 0; $maxColLetter = 'A'; @@ -52,8 +51,6 @@ public function testHLOOKUP(mixed $expectedResult, mixed $lookup, array $values, } $sheet->getCell('ZZ1')->setValue("=HLOOKUP(ZZ8, A1:$maxColLetter$maxRow, $indexarg$boolArg)"); self::assertEquals($expectedResult, $sheet->getCell('ZZ1')->getCalculatedValue()); - - $spreadsheet->disconnectWorksheets(); } private static function parseRangeLookup(?bool $rangeLookup): string @@ -70,7 +67,7 @@ public static function providerHLOOKUP(): array return require 'tests/data/Calculation/LookupRef/HLOOKUP.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerHLookupNamedRange')] + #[DataProvider('providerHLookupNamedRange')] public function testHLookupNamedRange(string $expectedResult, string $cellAddress): void { $lookupData = [ @@ -85,12 +82,11 @@ public function testHLookupNamedRange(string $expectedResult, string $cellAddres ['Cleanliness', 3, '=HLOOKUP(C8,Lookup_Table,2,FALSE)'], ]; - $spreadsheet = new Spreadsheet(); - $worksheet = $spreadsheet->getActiveSheet(); + $worksheet = $this->getSheet(); $worksheet->fromArray($lookupData, null, 'F4'); $worksheet->fromArray($formData, null, 'B4'); - $spreadsheet->addNamedRange(new NamedRange('Lookup_Table', $worksheet, '=$G$4:$J$5')); + $this->getSpreadsheet()->addNamedRange(new NamedRange('Lookup_Table', $worksheet, '=$G$4:$J$5')); $result = $worksheet->getCell($cellAddress)->getCalculatedValue(); self::assertEquals($expectedResult, $result); @@ -106,7 +102,7 @@ public static function providerHLookupNamedRange(): array ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerHLookupArray')] + #[DataProvider('providerHLookupArray')] public function testHLookupArray(array $expectedResult, string $values, string $database, string $index): void { $calculation = Calculation::getInstance(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php index 08cf905c5c..45993d8938 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexOnSpreadsheetTest.php @@ -4,12 +4,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; +use PHPUnit\Framework\Attributes\DataProvider; + class IndexOnSpreadsheetTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerINDEXonSpreadsheet')] + #[DataProvider('providerINDEXonSpreadsheet')] public function testIndexOnSpreadsheet(mixed $expectedResult, array $matrix, null|int|string $rowNum = null, null|int|string $colNum = null): void { $this->mightHaveException($expectedResult); + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->fromArray($matrix); $maxRow = $sheet->getHighestRow(); @@ -33,9 +36,10 @@ public static function providerINDEXonSpreadsheet(): array return require 'tests/data/Calculation/LookupRef/INDEXonSpreadsheet.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerIndexLiteralArrays')] + #[DataProvider('providerIndexLiteralArrays')] public function testLiteralArrays(mixed $expectedResult, string $indexArgs): void { + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->getCell('A10')->setValue(10); $sheet->getCell('B10')->setValue(11); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php index 2ffa013818..176d96a50d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php @@ -7,10 +7,11 @@ use PhpOffice\PhpSpreadsheet\NamedFormula; use PhpOffice\PhpSpreadsheet\NamedRange; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as ReaderXlsx; +use PHPUnit\Framework\Attributes\DataProvider; class IndirectTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerINDIRECT')] + #[DataProvider('providerINDIRECT')] public function testINDIRECT(mixed $expectedResult, mixed $cellReference = 'omitted', mixed $a1 = 'omitted'): void { $this->mightHaveException($expectedResult); @@ -106,13 +107,13 @@ public function testIndirectFile2(): void { $reader = new ReaderXlsx(); $file = 'tests/data/Calculation/LookupRef/IndirectFormulaSelection.xlsx'; - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); + $this->spreadsheet = $reader->load($file); + $sheet = $this->spreadsheet->getActiveSheet(); $result = $sheet->getCell('A5')->getCalculatedValue(); self::assertSame(100, $result); $value = $sheet->getCell('A5')->getValue(); self::assertSame('=CURRENCY_SELECTOR', $value); - $formula = $spreadsheet->getNamedFormula('CURRENCY_SELECTOR'); + $formula = $this->spreadsheet->getNamedFormula('CURRENCY_SELECTOR'); if ($formula === null) { self::fail('Expected named formula was not defined'); } else { @@ -130,9 +131,10 @@ public function testDeprecatedCall(): void self::assertSame('This is it', $result); } - #[\PHPUnit\Framework\Attributes\DataProvider('providerRelative')] + #[DataProvider('providerRelative')] public function testR1C1Relative(string|int|null $expectedResult, string $address): void { + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->fromArray([ ['a1', 'b1', 'c1'], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowOnSpreadsheetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowOnSpreadsheetTest.php index ca22fdcc86..28edd256b3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowOnSpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowOnSpreadsheetTest.php @@ -5,13 +5,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\NamedRange; +use PHPUnit\Framework\Attributes\DataProvider; class RowOnSpreadsheetTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerROWonSpreadsheet')] + #[DataProvider('providerROWonSpreadsheet')] public function testRowOnSpreadsheet(mixed $expectedResult, string $cellReference = 'omitted'): void { $this->mightHaveException($expectedResult); + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->setTitle('ThisSheet'); $this->getSpreadsheet()->addNamedRange(new NamedRange('namedrangex', $sheet, '$E$2:$E$6')); @@ -41,6 +43,7 @@ public static function providerROWOnSpreadsheet(): array public function testINDIRECTLocalDefinedName(): void { $sheet = $this->getSheet(); + $this->setArrayAsValue(); $sheet1 = $this->getSpreadsheet()->createSheet(); $sheet1->setTitle('OtherSheet'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php index 169f203a0c..612bdb3d1d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php @@ -6,16 +6,15 @@ use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Cell\DataType; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\DataProvider; -class VLookupTest extends TestCase +class VLookupTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerVLOOKUP')] + #[DataProvider('providerVLOOKUP')] public function testVLOOKUP(mixed $expectedResult, mixed $value, mixed $table, mixed $index, ?bool $lookup = null): void { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->setArrayAsValue(); + $sheet = $this->getSheet(); if (is_array($table)) { $sheet->fromArray($table); $dimension = $sheet->calculateWorksheetDimension(); @@ -40,7 +39,6 @@ public function testVLOOKUP(mixed $expectedResult, mixed $value, mixed $table, m $sheet->getCell('Z99')->setValue("=VLOOKUP(Z98,$dimension,$indexarg$lastarg)"); $result = $sheet->getCell('Z99')->getCalculatedValue(); self::assertEquals($expectedResult, $result); - $spreadsheet->disconnectWorksheets(); } public static function providerVLOOKUP(): array @@ -48,7 +46,7 @@ public static function providerVLOOKUP(): array return require 'tests/data/Calculation/LookupRef/VLOOKUP.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerVLookupArray')] + #[DataProvider('providerVLookupArray')] public function testVLookupArray(array $expectedResult, string $values, string $database, string $index): void { $calculation = Calculation::getInstance(); @@ -78,8 +76,7 @@ public static function providerVLookupArray(): array public function testIssue1402(): void { - $spreadsheet = new Spreadsheet(); - $worksheet = $spreadsheet->getActiveSheet(); + $worksheet = $this->getSheet(); $worksheet->setCellValueExplicit('A1', 1, DataType::TYPE_STRING); $worksheet->setCellValue('B1', 'Text Nr 1'); @@ -93,6 +90,5 @@ public function testIssue1402(): void $worksheet->setCellValue('A5', 2); $worksheet->setCellValue('B5', '=VLOOKUP(A5,$A$1:$B$3,2,0)'); self::assertSame('Numeric result', $worksheet->getCell('B5')->getCalculatedValue()); - $spreadsheet->disconnectWorksheets(); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php index ca55bfa653..7ef732b1c1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\DataType; @@ -15,7 +16,7 @@ class AllSetupTeardown extends TestCase { private string $compatibilityMode; - private ?Spreadsheet $spreadsheet = null; + protected ?Spreadsheet $spreadsheet = null; private ?Worksheet $sheet = null; @@ -81,4 +82,13 @@ protected function getSheet(): Worksheet return $this->sheet; } + + protected function setArrayAsValue(): void + { + $spreadsheet = $this->getSpreadsheet(); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index 8925151f78..3e2edf3f8a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -5,10 +5,11 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PHPUnit\Framework\Attributes\DataProvider; class MMultTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerMMULT')] + #[DataProvider('providerMMULT')] public function testMMULT(mixed $expectedResult, mixed ...$args): void { $result = MathTrig\MatrixFunctions::multiply(...$args); @@ -23,6 +24,7 @@ public static function providerMMULT(): array public function testOnSpreadsheet(): void { // very limited ability to test this in the absence of dynamic arrays + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->getCell('A1')->setValue('=MMULT({1,2,3}, {1,2,3})'); // incompatible dimensions self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue()); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php index 9199ada28e..3ee886f708 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php @@ -4,15 +4,18 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PHPUnit\Framework\Attributes\DataProvider; + class SumIfTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerSUMIF')] + #[DataProvider('providerSUMIF')] public function testSUMIF2(mixed $expectedResult, array $array1, mixed $condition, ?array $array2 = null): void { $this->mightHaveException($expectedResult); if ($expectedResult === 'incomplete') { self::markTestIncomplete('Raises formula error - researching solution'); } + $this->setArrayAsValue(); $sheet = $this->getSheet(); $sheet->fromArray($array1, null, 'A1', true); $maxARow = count($array1); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProduct2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProduct2Test.php index 0d40b5dd92..3d1c8c252b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProduct2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProduct2Test.php @@ -12,8 +12,9 @@ public function testSUMPRODUCT(): void { $file = 'tests/data/Reader/XLSX/issue.3909b.xlsx'; $reader = new XlsxReader(); - $spreadsheet = $reader->load($file); - $sheet = $spreadsheet->getActiveSheet(); + $this->spreadsheet = $reader->load($file); + $this->setArrayAsValue(); + $sheet = $this->getSheet(); self::assertSame('=SUMPRODUCT(((calNames=I3)*(calTiers=$K$2))*calHours)', $sheet->getCell('K3')->getValue()); self::assertSame(40, $sheet->getCell('K3')->getCalculatedValue()); self::assertSame(4, $sheet->getCell('L3')->getCalculatedValue()); @@ -29,6 +30,5 @@ public function testSUMPRODUCT(): void self::assertSame(0, $sheet->getCell('N5')->getCalculatedValue()); self::assertSame('=SUMPRODUCT(calHours*((calNames=I3)*(calTiers=$K$2)))', $sheet->getCell('I14')->getValue()); self::assertSame(40, $sheet->getCell('I14')->getCalculatedValue()); - $spreadsheet->disconnectWorksheets(); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php index dfa27f35fc..69bf7d9ae8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php @@ -5,12 +5,14 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PHPUnit\Framework\Attributes\DataProvider; class SumTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerSUM')] + #[DataProvider('providerSUM')] public function testSUM(mixed $expectedResult, mixed ...$args): void { + $this->setArrayAsValue(); $sheet = $this->getSheet(); $row = 0; foreach ($args as $arg) { @@ -27,7 +29,7 @@ public static function providerSUM(): array return require 'tests/data/Calculation/MathTrig/SUM.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerSUMLiterals')] + #[DataProvider('providerSUMLiterals')] public function testSUMLiterals(mixed $expectedResult, string $args): void { $sheet = $this->getSheet(); @@ -41,10 +43,11 @@ public static function providerSUMLiterals(): array return require 'tests/data/Calculation/MathTrig/SUMLITERALS.php'; } - #[\PHPUnit\Framework\Attributes\DataProvider('providerSUMWITHINDEXMATCH')] + #[DataProvider('providerSUMWITHINDEXMATCH')] public function testSumWithIndexMatch(mixed $expectedResult, string $formula): void { - $spreadsheet = new Spreadsheet(); + $spreadsheet = $this->getSpreadsheet(); + $this->setArrayAsValue(); $sheet1 = $spreadsheet->getActiveSheet(); $sheet1->setTitle('Formula'); $sheet1->fromArray( @@ -62,7 +65,6 @@ public function testSumWithIndexMatch(mixed $expectedResult, string $formula): v ] ); self::assertSame($expectedResult, $sheet1->getCell('B2')->getCalculatedValue()); - $spreadsheet->disconnectWorksheets(); } public static function providerSUMWITHINDEXMATCH(): array diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AllSetupTeardown.php index 8aaf6e73f6..e8f444a398 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AllSetupTeardown.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\DataType; @@ -20,9 +21,12 @@ class AllSetupTeardown extends TestCase private ?Worksheet $sheet = null; + protected string $returnArrayAs; + protected function setUp(): void { $this->compatibilityMode = Functions::getCompatibilityMode(); + $this->returnArrayAs = ''; } protected function tearDown(): void @@ -108,6 +112,12 @@ protected function runTestCaseReference(string $functionName, mixed $expectedRes { $this->mightHaveException($expectedResult); $sheet = $this->getSheet(); + if ($this->returnArrayAs !== '') { + $calculation = Calculation::getInstance($this->spreadsheet); + $calculation->setInstanceArrayReturnType( + $this->returnArrayAs + ); + } $formula = "=$functionName("; $comma = ''; $row = 0; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php index 62db48efa5..c25b636b81 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php @@ -39,7 +39,7 @@ public function testOutliers(): void } catch (CalcException $e) { self::assertStringContainsString('Must specify range of cells', $e->getMessage()); } - $sheet->getCell('A3')->setValue('=AVERAGEIF(C1,"<32")'); + $sheet->getCell('A3')->setValue('=AVERAGEIF(C1:C1,"<32")'); self::assertSame(5, $sheet->getCell('A3')->getCalculatedValue(), 'first arg is single cell'); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php index 4856547617..f112557597 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php @@ -41,9 +41,9 @@ public function testOutliers(): void } catch (CalcException $e) { self::assertStringContainsString('Must specify range of cells', $e->getMessage()); } - $sheet->getCell('A3')->setValue('=COUNTBLANK(C1)'); + $sheet->getCell('A3')->setValue('=COUNTBLANK(C1:C1)'); self::assertSame(0, $sheet->getCell('A3')->getCalculatedValue(), 'arg is single non-blank cell'); - $sheet->getCell('A4')->setValue('=COUNTBLANK(D2)'); + $sheet->getCell('A4')->setValue('=COUNTBLANK(D2:D2)'); self::assertSame(1, $sheet->getCell('A4')->getCalculatedValue(), 'arg is single null cell'); $sheet->getCell('A5')->setValue('=COUNTBLANK(D3:D4)'); self::assertSame(2, $sheet->getCell('A5')->getCalculatedValue(), 'arg is two cells both null'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php index fad689b61c..7685c0724a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php @@ -4,11 +4,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; +use PHPUnit\Framework\Attributes\DataProvider; + class SkewTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerSKEW')] + #[DataProvider('providerSKEW')] public function testSKEW(mixed $expectedResult, array $args): void { + $this->returnArrayAs = Calculation::RETURN_ARRAY_AS_VALUE; $this->runTestCaseReference('SKEW', $expectedResult, ...$args); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateRangeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateRangeTest.php index e90d55922a..f665a15018 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateRangeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateRangeTest.php @@ -18,12 +18,19 @@ public function testIssue4061(): void $sheet->getCell('C2')->setValue('2'); $sheet->getCell('C3')->setValue('3'); $sheet->getCell('B1')->setValue('=CONCATENATE(A1:A3, "-", C1:C3)'); + Calculation::getInstance($this->getSpreadsheet()) + ->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); self::assertSame('a-1', $sheet->getCell('B1')->getCalculatedValue()); $sheet->getCell('X1')->setValue('=A1:A3&"-"&C1:C3'); self::assertSame('a-1', $sheet->getCell('X1')->getCalculatedValue()); $sheet->getCell('D1')->setValue('=CONCAT(A1:A3, "-", C1:C3)'); self::assertSame('abc-123', $sheet->getCell('D1')->getCalculatedValue()); - Calculation::getInstance($this->getSpreadsheet())->setInstanceArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY); + Calculation::getInstance($this->getSpreadsheet()) + ->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_ARRAY + ); $sheet->getCell('E1')->setValue('=CONCATENATE(A1:A3, "-", C1:C3)'); self::assertSame([['a-1'], ['b-2'], ['c-3']], $sheet->getCell('E1')->getCalculatedValue()); $sheet->getCell('Y1')->setValue('=A1:A3&"-"&C1:C3'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php index 7e2cfb2953..8ace2c0bfd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php @@ -6,10 +6,11 @@ use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PHPUnit\Framework\Attributes\DataProvider; class ConcatenateTest extends AllSetupTeardown { - #[\PHPUnit\Framework\Attributes\DataProvider('providerCONCATENATE')] + #[DataProvider('providerCONCATENATE')] public function testCONCATENATE(mixed $expectedResult, mixed ...$args): void { $this->mightHaveException($expectedResult); diff --git a/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php index 1579cc0aac..9d634b4afe 100644 --- a/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Color; @@ -34,6 +35,10 @@ public function testXlfn(): void ['365', 'A1', '=SORT({7;1;5})', '=SORT({7;1;5})', 1], ]; $workbook = new Spreadsheet(); + $calculation = Calculation::getInstance($workbook); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $sheet = $workbook->getActiveSheet(); $sheet->setTitle('2010'); $sheet = $workbook->createSheet(); @@ -112,6 +117,10 @@ public function testXlfn(): void $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx'); $rdobj = $reader->load($oufil); unlink($oufil); + $calculation = Calculation::getInstance($rdobj); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); foreach ($formulas as $values) { $sheet = $rdobj->setActiveSheetIndexByName($values[0]); self::assertEquals($values[3], $sheet->getCell($values[1])->getValue()); diff --git a/tests/PhpSpreadsheetTests/Functional/ArrayFunctionsSpillTest.php b/tests/PhpSpreadsheetTests/Functional/ArrayFunctionsSpillTest.php index f2309071e5..614ac11497 100644 --- a/tests/PhpSpreadsheetTests/Functional/ArrayFunctionsSpillTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ArrayFunctionsSpillTest.php @@ -86,6 +86,10 @@ public function testArrayOutput(): void public function testNonArrayOutput(): void { $spreadsheet = new Spreadsheet(); + Calculation::getInstance($spreadsheet) + ->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValue('B5', 'OCCUPIED'); diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/ArrayFormulaTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/ArrayFormulaTest.php index 9accf01ae3..ab87485408 100644 --- a/tests/PhpSpreadsheetTests/Reader/Ods/ArrayFormulaTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Ods/ArrayFormulaTest.php @@ -5,11 +5,12 @@ use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Reader\Ods; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ArrayFormulaTest extends TestCase { - #[\PHPUnit\Framework\Attributes\DataProvider('arrayFormulaReaderProvider')] + #[DataProvider('arrayFormulaReaderProvider')] public function testArrayFormulaReader( string $cellAddress, string $expectedRange, @@ -25,12 +26,19 @@ public function testArrayFormulaReader( self::assertSame(DataType::TYPE_FORMULA, $cell->getDataType()); self::assertSame(['t' => 'array', 'ref' => $expectedRange], $cell->getFormulaAttributes()); self::assertSame($expectedFormula, strtoupper($cell->getValueString())); - Calculation::getInstance($spreadsheet)->setInstanceArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY); + Calculation::getInstance($spreadsheet) + ->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_ARRAY + ); $worksheet->calculateArrays(); $cell = $worksheet->getCell($cellAddress); self::assertSame($expectedValue, $cell->getCalculatedValue()); if (is_array($expectedValue)) { - self::assertSame($expectedValue, $worksheet->rangeToArray($expectedRange, formatData: false, reduceArrays: true)); + if ($expectedRange === "$cellAddress:$cellAddress") { + self::assertSame([$expectedValue], $worksheet->rangeToArray($expectedRange, formatData: false, reduceArrays: true)); + } else { + self::assertSame($expectedValue, $worksheet->rangeToArray($expectedRange, formatData: false, reduceArrays: true)); + } } else { self::assertSame([[$expectedValue]], $worksheet->rangeToArray($expectedRange, formatData: false, reduceArrays: true)); } @@ -56,7 +64,7 @@ public static function arrayFormulaReaderProvider(): array 'E3', 'E3:E3', '=MAX(SIN({-1,0,1,2}))', - 0.9092974268256817, + [0.9092974268256817], ], [ 'D5', diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/DefinedNamesTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/DefinedNamesTest.php index d5a572f77c..c3d3655e9d 100644 --- a/tests/PhpSpreadsheetTests/Reader/Ods/DefinedNamesTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Ods/DefinedNamesTest.php @@ -4,16 +4,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Reader\Ods; use PHPUnit\Framework\TestCase; class DefinedNamesTest extends TestCase { - public function testDefinedNames(): void + public function testDefinedNamesValue(): void { $filename = 'tests/data/Reader/Ods/DefinedNames.ods'; $reader = new Ods(); $spreadsheet = $reader->load($filename); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_VALUE + ); $worksheet = $spreadsheet->getActiveSheet(); $firstDefinedNameValue = $worksheet->getCell('First')->getValue(); @@ -25,4 +30,25 @@ public function testDefinedNames(): void self::assertSame(12, $calculatedFormulaValue); $spreadsheet->disconnectWorksheets(); } + + public function testDefinedNamesArray(): void + { + $filename = 'tests/data/Reader/Ods/DefinedNames.ods'; + $reader = new Ods(); + $spreadsheet = $reader->load($filename); + $calculation = Calculation::getInstance($spreadsheet); + $calculation->setInstanceArrayReturnType( + Calculation::RETURN_ARRAY_AS_ARRAY + ); + $worksheet = $spreadsheet->getActiveSheet(); + + $firstDefinedNameValue = $worksheet->getCell('First')->getValue(); + $secondDefinedNameValue = $worksheet->getCell('Second')->getValue(); + $calculatedFormulaValue = $worksheet->getCell('B2')->getCalculatedValue(); + + self::assertSame(3, $firstDefinedNameValue); + self::assertSame(4, $secondDefinedNameValue); + self::assertSame([12], $calculatedFormulaValue); + $spreadsheet->disconnectWorksheets(); + } } From 4ad6b32a2be0f8499161ecef5726a19c2c3912b2 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 6 Feb 2025 22:52:14 -0800 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b993bc3540..ab7eff4146 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed - Xls Writer Parser Mishandling True/False Argument. [Issue #4331](https://github.com/PHPOffice/PhpSpreadsheet/issues/4331) [PR #4333](https://github.com/PHPOffice/PhpSpreadsheet/pull/4333) +- Minor changes to dynamic array calculations exposed by using explicit array return types in some tests. [PR #4328](https://github.com/PHPOffice/PhpSpreadsheet/pull/4328) ## 2025-01-26 - 3.9.0