From 860f2c663746a4cf969668e1a57f38faa14c1219 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:21:57 -0800 Subject: [PATCH] Restore Tests Whose Absence Led to Omitted Coverage --- .../Calculation/CalculationParserOnly.php | 6 + .../Calculation/CalculationTest.php | 24 +++ .../Cell/DefaultValueBinderTest.php | 144 +++++++++++------- 3 files changed, 121 insertions(+), 53 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/CalculationParserOnly.php b/src/PhpSpreadsheet/Calculation/CalculationParserOnly.php index ee7248419..cfbc928b2 100644 --- a/src/PhpSpreadsheet/Calculation/CalculationParserOnly.php +++ b/src/PhpSpreadsheet/Calculation/CalculationParserOnly.php @@ -34,4 +34,10 @@ final class CalculationParserOnly extends Calculation return self::$parserInstance; } + + /** @param mixed $enabled Unused, property will always be false in this class */ + public function setBranchPruningEnabled(mixed $enabled): self + { + return $this; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index 25bcfb331..b5ae45e74 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpOffice\PhpSpreadsheetTests\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\CalculationParserOnly; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; @@ -424,4 +425,27 @@ class CalculationTest extends TestCase { return require 'tests/data/Calculation/Calculation.php'; } + + public function testBranchPruningFlag(): void + { + $calc1 = Calculation::getInstance(); + $calc2 = CalculationParserOnly::getParserInstance(); + self::assertNotSame($calc1, $calc2); + $calc1a = Calculation::getInstance(); + $calc2a = CalculationParserOnly::getParserInstance(); + self::assertSame($calc1, $calc1a); + self::assertSame($calc2, $calc2a); + + self::assertFalse($calc2->getBranchPruningEnabled()); + $calc2->enableBranchPruning(); + self::assertFalse($calc2->getBranchPruningEnabled(), 'no change for ParserOnly'); + $calc2->disableBranchPruning(); + self::assertFalse($calc2->getBranchPruningEnabled()); + + self::assertTrue($calc1->getBranchPruningEnabled(), 'parserOnly did not affect Calculation singleton'); + $calc1->disableBranchPruning(); + self::assertFalse($calc1->getBranchPruningEnabled()); + $calc1->enableBranchPruning(); + self::assertTrue($calc1->getBranchPruningEnabled()); + } } diff --git a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php index 6090c3566..919a05a25 100644 --- a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php @@ -4,9 +4,13 @@ declare(strict_types=1); namespace PhpOffice\PhpSpreadsheetTests\Cell; +use DateTime; +use DateTimeImmutable; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder; +use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; use PhpOffice\PhpSpreadsheet\RichText\RichText; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Stringable; @@ -22,8 +26,14 @@ class DefaultValueBinderTest extends TestCase #[DataProvider('binderProvider')] public function testBindValue(mixed $value, string $expectedDataType): void { - $result = DefaultValueBinder::dataTypeForValue($value); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $cell = $sheet->getCell('A1'); + $binder = new DefaultValueBinder(); + self::assertTrue($binder->bindValue($cell, $value)); + $result = $cell->getDataType(); self::assertSame($expectedDataType, $result); + $spreadsheet->disconnectWorksheets(); } /** @@ -44,6 +54,10 @@ class DefaultValueBinderTest extends TestCase 'positive integer' => [42, DataType::TYPE_NUMERIC], 'negative integer' => [-100, DataType::TYPE_NUMERIC], + // Very large integers treated as string to prevent precision loss + 'large positive' => [1_000_000_000_000_000, DataType::TYPE_STRING], + 'large negative' => [-1_000_000_000_000_000, DataType::TYPE_STRING], + // Floats 'float' => [3.14159, DataType::TYPE_NUMERIC], 'negative float' => [-2.5, DataType::TYPE_NUMERIC], @@ -80,6 +94,18 @@ class DefaultValueBinderTest extends TestCase 'error NAME' => ['#NAME?', DataType::TYPE_ERROR], 'error NUM' => ['#NUM!', DataType::TYPE_ERROR], 'error NA' => ['#N/A', DataType::TYPE_ERROR], + + // DateTime strings should be treated as string + 'datetime format' => ['2024-01-15 10:30:00', DataType::TYPE_STRING], + 'date only' => ['2024-01-15', DataType::TYPE_STRING], + 'time only' => ['10:30:00', DataType::TYPE_STRING], + + // DateTime objects should be treated as string + 'DateTime' => [new DateTime(), DataType::TYPE_STRING], + 'DateTimeImmutable' => [new DateTimeImmutable(), DataType::TYPE_STRING], + + // Stringable object + 'Stringable object' => [new StringableObject(), DataType::TYPE_STRING], ]; } @@ -88,49 +114,82 @@ class DefaultValueBinderTest extends TestCase */ public function testRichTextReturnsTypeInline(): void { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); $richText = new RichText(); $richText->createTextRun('Hello World'); - - $result = DefaultValueBinder::dataTypeForValue($richText); + $cell = $sheet->getCell('A1'); + $binder = new DefaultValueBinder(); + self::assertTrue($binder->bindValue($cell, $richText)); + $result = $cell->getDataType(); self::assertSame(DataType::TYPE_INLINE, $result); + $spreadsheet->disconnectWorksheets(); } - /** - * Test that DateTime string format values are handled correctly. - */ - #[DataProvider('dateTimeStringProvider')] - public function testDateTimeStringReturnsTypeString(string $dateTimeString): void + public function testNonStringableBindValue(): void { - $result = DefaultValueBinder::dataTypeForValue($dateTimeString); - self::assertSame(DataType::TYPE_STRING, $result); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + try { + $sheet->getCell('A1')->setValue($this); + self::fail('Did not receive expected Exception'); + } catch (SpreadsheetException $e) { + self::assertStringContainsString('Unable to bind unstringable', $e->getMessage()); + } + $sheet->getCell('A2')->setValue(new StringableObject()); + self::assertSame('abc', $sheet->getCell('A2')->getValue()); + + try { + $sheet->getCell('A3')->setValue(fopen(__FILE__, 'rb')); + self::fail('Did not receive expected Exception'); + } catch (SpreadsheetException $e) { + self::assertStringContainsString('Unable to bind unstringable', $e->getMessage()); + } + + try { + $sheet->getCell('A3')->setValue([]); + self::fail('Did not receive expected Exception'); + } catch (SpreadsheetException $e) { + self::assertStringContainsString('Unable to bind unstringable', $e->getMessage()); + } + + $spreadsheet->disconnectWorksheets(); } - /** - * @return array - */ - public static function dateTimeStringProvider(): array + #[DataProvider('providerDataTypeForValue')] + public function testDataTypeForValue(mixed $expectedResult, mixed $value): void { - return [ - 'datetime format' => ['2024-01-15 10:30:00'], - 'date only' => ['2024-01-15'], - 'time only' => ['10:30:00'], - ]; + $result = DefaultValueBinder::dataTypeForValue($value); + self::assertEquals($expectedResult, $result); } - /** - * Test Stringable objects are converted and handled as strings. - */ - public function testStringableReturnsTypeString(): void + public static function providerDataTypeForValue(): array { - $stringable = new class() implements Stringable { - public function __toString(): string - { - return 'Hello from Stringable'; - } - }; + return require 'tests/data/Cell/DefaultValueBinder.php'; + } - $result = DefaultValueBinder::dataTypeForValue($stringable); - self::assertSame(DataType::TYPE_STRING, $result); + public function testDataTypeForValueExceptions(): void + { + try { + self::assertSame('s', DefaultValueBinder::dataTypeForValue(new SpreadsheetException())); + } catch (SpreadsheetException $e) { + self::fail('Should not have failed for stringable'); + } + + try { + DefaultValueBinder::dataTypeForValue([]); + self::fail('Should have failed for array'); + } catch (SpreadsheetException $e) { + self::assertStringContainsString('unusable type array', $e->getMessage()); + } + + try { + DefaultValueBinder::dataTypeForValue(new DateTime()); + self::fail('Should have failed for DateTime'); + } catch (SpreadsheetException $e) { + self::assertStringContainsString('unusable type DateTime', $e->getMessage()); + } } /** @@ -138,7 +197,7 @@ class DefaultValueBinderTest extends TestCase */ public function testStringableFormulaReturnsTypeFormula(): void { - $stringable = new class() implements Stringable { + $stringable = new class () implements Stringable { public function __toString(): string { return '=SUM(A1:A10)'; @@ -149,27 +208,6 @@ class DefaultValueBinderTest extends TestCase self::assertSame(DataType::TYPE_FORMULA, $result); } - /** - * Test very large integers are treated as strings to prevent precision loss. - */ - #[DataProvider('largeIntegerProvider')] - public function testLargeIntegersReturnTypeString(int $value): void - { - $result = DefaultValueBinder::dataTypeForValue($value); - self::assertSame(DataType::TYPE_STRING, $result); - } - - /** - * @return array - */ - public static function largeIntegerProvider(): array - { - return [ - 'large positive' => [1_000_000_000_000_000], - 'large negative' => [-1_000_000_000_000_000], - ]; - } - /** * Test that calling dataTypeForValue multiple times with formulas * works correctly (verifies singleton reuse doesn't cause issues).