Merge branch 'master' into issue4435

This commit is contained in:
oleibman
2025-04-05 17:29:22 -07:00
committed by GitHub
417 changed files with 2821 additions and 2074 deletions
@@ -12,6 +12,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Calculation\Functions\FormulaArguments;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class DateTest extends TestCase
@@ -36,14 +37,14 @@ class DateTest extends TestCase
Functions::setReturnDateType($this->returnDateType);
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerDATE')]
public function testDirectCallToDATE(float|string $expectedResult, int|string $year, float|int|string $month, float|int|string $day): void
#[DataProvider('providerDATE')]
public function testDirectCallToDATE(float|string $expectedResult, int|string $year, null|bool|float|int|string $month, float|int|string $day): void
{
$result = Date::fromYMD($year, $month, $day);
self::assertSame($expectedResult, $result);
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerDATE')]
#[DataProvider('providerDATE')]
public function testDATEAsFormula(mixed $expectedResult, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
@@ -55,7 +56,7 @@ class DateTest extends TestCase
self::assertSame($expectedResult, $result);
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerDATE')]
#[DataProvider('providerDATE')]
public function testDATEInWorksheet(mixed $expectedResult, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
@@ -78,7 +79,7 @@ class DateTest extends TestCase
return require 'tests/data/Calculation/DateTime/DATE.php';
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerUnhappyDATE')]
#[DataProvider('providerUnhappyDATE')]
public function testDATEUnhappyPath(string $expectedException, mixed ...$args): void
{
$arguments = new FormulaArguments(...$args);
@@ -136,7 +137,7 @@ class DateTest extends TestCase
self::assertEquals($result, ExcelError::NAN());
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerDateArray')]
#[DataProvider('providerDateArray')]
public function testDateArray(array $expectedResult, string $year, string $month, string $day): void
{
$calculation = Calculation::getInstance();
@@ -200,7 +201,7 @@ class DateTest extends TestCase
];
}
#[\PHPUnit\Framework\Attributes\DataProvider('providerDateArrayException')]
#[DataProvider('providerDateArrayException')]
public function testDateArrayException(string $year, string $month, string $day): void
{
$calculation = Calculation::getInstance();
@@ -5,13 +5,14 @@ declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
// TODO Convert to Spreadsheet context.
class ChiTestTest extends TestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('providerCHITEST')]
public function testCHITEST(mixed $expectedResult, mixed $actual, mixed $expected): void
#[DataProvider('providerCHITEST')]
public function testCHITEST(mixed $expectedResult, array $actual, array $expected): void
{
$result = Statistical\Distributions\ChiSquared::test($actual, $expected);
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class DisplayBlanksAsTest extends TestCase
{
public function testDisplayBlanksAs(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
$plotArea = new PlotArea(null, [$series]);
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
$chart1 = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
self::assertSame(DataSeries::EMPTY_AS_GAP, $chart1->getDisplayBlanksAs());
$chart1->setDisplayBlanksAs(DataSeries::EMPTY_AS_ZERO);
self::assertSame(DataSeries::EMPTY_AS_ZERO, $chart1->getDisplayBlanksAs());
$chart1->setDisplayBlanksAs('0');
self::assertSame(DataSeries::EMPTY_AS_GAP, $chart1->getDisplayBlanksAs(), 'invalid setting converted to default');
$chart2 = new Chart(
'chart2', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_SPAN, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
self::assertSame(DataSeries::EMPTY_AS_SPAN, $chart2->getDisplayBlanksAs());
$chart3 = new Chart(
'chart3', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
'0', // displayBlanksAs, PHPExcel default
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
self::assertSame(DataSeries::EMPTY_AS_GAP, $chart3->getDisplayBlanksAs(), 'invalid setting converted to default');
$spreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Helper;
use PhpOffice\PhpSpreadsheet\Helper\TextGrid;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class TextGridTest extends TestCase
{
#[DataProvider('providerTextGrid')]
public function testTextGrid(
bool $cli,
bool $rowDividers,
bool $rowHeaders,
bool $columnHeaders,
array $expected
): void {
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->fromArray([
[6, '=TEXT(A1,"yyyy-mm-dd hh:mm")', null, 0.572917],
['="6"', '=TEXT(A2,"yyyy-mm-dd hh:mm")', null, '1<>2'],
['xyz', '=TEXT(A3,"yyyy-mm-dd hh:mm")'],
], strictNullComparison: true);
$textGrid = new TextGrid(
$sheet->toArray(null, true, true, true),
$cli,
rowDividers: $rowDividers,
rowHeaders: $rowHeaders,
columnHeaders: $columnHeaders
);
$result = $textGrid->render();
// Note that, for cli, string will end with PHP_EOL,
// so explode will add an extra null-string element
// to its array output.
$lines = explode(PHP_EOL, $result);
self::assertSame($expected, $lines);
$spreadsheet->disconnectWorksheets();
}
public static function providerTextGrid(): array
{
return [
'cli default values' => [
true, false, true, true,
[
' +-----+------------------+---+----------+',
' | A | B | C | D |',
'+---+-----+------------------+---+----------+',
'| 1 | 6 | 1900-01-06 00:00 | | 0.572917 |',
'| 2 | 6 | 1900-01-06 00:00 | | 1<>2 |',
'| 3 | xyz | xyz | | |',
'+---+-----+------------------+---+----------+',
'',
],
],
'html default values' => [
false, false, true, true,
[
'<pre>',
' +-----+------------------+---+----------+',
' | A | B | C | D |',
'+---+-----+------------------+---+----------+',
'| 1 | 6 | 1900-01-06 00:00 | | 0.572917 |',
'| 2 | 6 | 1900-01-06 00:00 | | 1&lt;&gt;2 |',
'| 3 | xyz | xyz | | |',
'+---+-----+------------------+---+----------+',
'</pre>',
],
],
'cli rowDividers' => [
true, true, true, true,
[
' +-----+------------------+---+----------+',
' | A | B | C | D |',
'+---+-----+------------------+---+----------+',
'| 1 | 6 | 1900-01-06 00:00 | | 0.572917 |',
'+---+-----+------------------+---+----------+',
'| 2 | 6 | 1900-01-06 00:00 | | 1<>2 |',
'+---+-----+------------------+---+----------+',
'| 3 | xyz | xyz | | |',
'+---+-----+------------------+---+----------+',
'',
],
],
'cli no columnHeaders' => [
true, false, true, false,
[
'+---+-----+------------------+--+----------+',
'| 1 | 6 | 1900-01-06 00:00 | | 0.572917 |',
'| 2 | 6 | 1900-01-06 00:00 | | 1<>2 |',
'| 3 | xyz | xyz | | |',
'+---+-----+------------------+--+----------+',
'',
],
],
'cli no row headers' => [
true, false, false, true,
[
'+-----+------------------+---+----------+',
'| A | B | C | D |',
'+-----+------------------+---+----------+',
'| 6 | 1900-01-06 00:00 | | 0.572917 |',
'| 6 | 1900-01-06 00:00 | | 1<>2 |',
'| xyz | xyz | | |',
'+-----+------------------+---+----------+',
'',
],
],
'cli row dividers, no row nor column headers' => [
true, true, false, false,
[
'+-----+------------------+--+----------+',
'| 6 | 1900-01-06 00:00 | | 0.572917 |',
'+-----+------------------+--+----------+',
'| 6 | 1900-01-06 00:00 | | 1<>2 |',
'+-----+------------------+--+----------+',
'| xyz | xyz | | |',
'+-----+------------------+--+----------+',
'',
],
],
];
}
public function testBool(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->fromArray([
[0, 1],
[true, false],
[true, true],
], strictNullComparison: true);
$textGrid = new TextGrid(
$sheet->toArray(null, true, false, true),
true,
rowDividers: false,
rowHeaders: false,
columnHeaders: false,
);
$expected = [
'+------+-------+',
'| 0 | 1 |',
'| TRUE | FALSE |',
'| TRUE | TRUE |',
'+------+-------+',
'',
];
$result = $textGrid->render();
$lines = explode(PHP_EOL, $result);
self::assertSame($expected, $lines);
$spreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PHPUnit\Framework\TestCase;
class Issue4415Test extends TestCase
{
private static string $file = 'tests/data/Reader/XLSX/issue.4415.xlsx';
public function testPreliminaries(): void
{
$file = 'zip://';
$file .= self::$file;
$file .= '#xl/drawings/drawing1.xml';
$data = file_get_contents($file) ?: '';
$expected = '<a:alpha val="72600"/>';
self::assertStringContainsString($expected, $data);
$expected = '<a:alpha val="90100"/>';
self::assertStringContainsString($expected, $data);
self::assertSame(2, substr_count($data, '<a:alpha '), 'number of drawings with alpha');
self::assertSame(2, substr_count($data, '<xdr:oneCellAnchor>'), 'first 2 drawings');
self::assertSame(1, substr_count($data, '<xdr:twoCellAnchor>'), 'third drawings');
}
public function testFractionalAlpha(): void
{
$file = self::$file;
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$sheet = $spreadsheet->getActiveSheet();
$drawings = $sheet->getDrawingCollection();
self::assertCount(3, $drawings);
self::assertNotNull($drawings[0]);
self::assertNotNull($drawings[1]);
self::assertNotNull($drawings[2]);
self::assertSame(50, $drawings[0]->getShadow()->getAlpha());
self::assertSame(72, $drawings[1]->getShadow()->getAlpha());
self::assertSame('', $drawings[1]->getCoordinates2(), 'one cell anchor');
self::assertSame(90, $drawings[2]->getShadow()->getAlpha());
self::assertNotEquals('', $drawings[2]->getCoordinates2(), 'two cell anchor');
$spreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
class Issue4416Filter implements IReadFilter
{
public function readCell(string $columnAddress, int $row, string $worksheetName = ''): bool
{
$allowedColumns = ['A', 'B', 'C', 'D'];
$allowedRows = range(1, 5);
return in_array($columnAddress, $allowedColumns, true) && in_array($row, $allowedRows, true);
}
}
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PHPUnit\Framework\TestCase;
class Issue4416Test extends TestCase
{
private static string $file = 'tests/data/Reader/XLSX/issue.4416.smallauto.xlsx';
public function testNoFilter(): void
{
$file = self::$file;
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$sheet = $spreadsheet->getActiveSheet();
self::assertEqualsWithDelta(
16.5430,
$sheet->getColumnDimension('A')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
6.0,
$sheet->getColumnDimension('B')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
11.3633,
$sheet->getColumnDimension('C')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
41.0898,
$sheet->getColumnDimension('D')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
28.5,
$sheet->getRowDimension(6)->getRowHeight(),
1E-4
);
$spreadsheet->disconnectWorksheets();
}
public function testWithFilter(): void
{
$file = self::$file;
$reader = new XlsxReader();
$reader->setReadFilter(new Issue4416Filter());
$spreadsheet = $reader->load($file);
$sheet = $spreadsheet->getActiveSheet();
self::assertEqualsWithDelta(
16.5430,
$sheet->getColumnDimension('A')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
6.0,
$sheet->getColumnDimension('B')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
11.3633,
$sheet->getColumnDimension('C')->getWidth(),
1E-4
);
self::assertEqualsWithDelta(
41.0898,
$sheet->getColumnDimension('D')->getWidth(),
1E-4
);
self::assertEquals(
-1,
$sheet->getRowDimension(6)->getRowHeight(),
'row has been filtered away'
);
$spreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
class MySpreadsheet extends Spreadsheet
{
public function calcSquare(string $cellAddress): float|int|string
{
$value = $this->getActiveSheet()
->getCell($cellAddress)
->getValue();
if (is_numeric($value)) {
return $value * $value;
}
return '#VALUE!';
}
}
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
class MyXlsxReader extends XlsxReader
{
protected function newSpreadsheet(): Spreadsheet
{
return new MySpreadsheet();
}
}
@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PHPUnit\Framework\TestCase;
class MyXlsxTest extends TestCase
{
public function testCustomSpreadsheetCustomLoader(): void
{
$reader = new MyXlsxReader();
$infile = 'tests/data/Reader/XLSX/colorscale.xlsx';
/** @var MySpreadsheet */
$mySpreadsheet = $reader->load($infile);
self::assertSame(64, $mySpreadsheet->calcSquare('A3'));
$mySpreadsheet->disconnectWorksheets();
}
}
@@ -49,6 +49,8 @@ class SpreadsheetCopyCloneTest extends TestCase
} else {
$this->spreadsheet2 = clone $this->spreadsheet;
}
self::assertSame($this->spreadsheet, $this->spreadsheet->getCalculationEngine()?->getSpreadsheet());
self::assertSame($this->spreadsheet2, $this->spreadsheet2->getCalculationEngine()?->getSpreadsheet());
self::assertSame('A3', $sheet->getSelectedCells());
$copysheet = $this->spreadsheet2->getActiveSheet();
self::assertSame('A3', $copysheet->getSelectedCells());
@@ -112,4 +114,39 @@ class SpreadsheetCopyCloneTest extends TestCase
['clone'],
];
}
public static function providerCopyClone2(): array
{
return [
['copy', true, false, true, 'array'],
['clone', true, false, true, 'array'],
['copy', false, true, false, 'value'],
['clone', false, true, false, 'value'],
['copy', false, true, true, 'error'],
['clone', false, true, true, 'error'],
];
}
#[DataProvider('providerCopyClone2')]
public function testCopyClone2(string $type, bool $suppress, bool $cache, bool $pruning, string $return): void
{
$this->spreadsheet = new Spreadsheet();
$calc = $this->spreadsheet->getCalculationEngine();
self::assertNotNull($calc);
$calc->setSuppressFormulaErrors($suppress);
$calc->setCalculationCacheEnabled($cache);
$calc->setBranchPruningEnabled($pruning);
$calc->setInstanceArrayReturnType($return);
if ($type === 'copy') {
$this->spreadsheet2 = $this->spreadsheet->copy();
} else {
$this->spreadsheet2 = clone $this->spreadsheet;
}
$calc2 = $this->spreadsheet2->getCalculationEngine();
self::assertNotNull($calc2);
self::assertSame($suppress, $calc2->getSuppressFormulaErrors());
self::assertSame($cache, $calc2->getCalculationCacheEnabled());
self::assertSame($pruning, $calc2->getBranchPruningEnabled());
self::assertSame($return, $calc2->getInstanceArrayReturnType());
}
}
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Style;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
@@ -287,4 +288,24 @@ class ExportArrayTest extends TestCase
);
$spreadsheet->disconnectWorksheets();
}
public function testQuotePrefix(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')
->setValueExplicit('=1+2', DataType::TYPE_STRING);
self::assertSame('=1+2', $sheet->getCell('A1')->getCalculatedValue());
self::assertTrue($sheet->getStyle('A1')->getQuotePrefix());
$sheet->getCell('A2')->setValue('=1+2');
self::assertSame(3, $sheet->getCell('A2')->getCalculatedValue());
self::assertFalse($sheet->getStyle('A2')->getQuotePrefix());
$styleArray1 = $sheet->getStyle('A1')->exportArray();
$styleArray2 = $sheet->getStyle('A2')->exportArray();
$sheet->getStyle('B1')->applyFromArray($styleArray1);
$sheet->getStyle('B2')->applyFromArray($styleArray2);
self::assertTrue($sheet->getStyle('B1')->getQuotePrefix());
self::assertFalse($sheet->getStyle('B2')->getQuotePrefix());
$spreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class HtmlColourScaleTest extends TestCase
{
private string $data = '';
protected function setUp(): void
{
$file = 'samples/templates/ColourScale.xlsx';
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$writer = new HtmlWriter($spreadsheet);
$writer->setConditionalFormatting(true);
$this->data = $writer->generateHtmlAll();
$spreadsheet->disconnectWorksheets();
}
private function extractCell(string $coordinate): string
{
[$column, $row] = Coordinate::indexesFromString($coordinate);
--$column;
--$row;
// extract row into $matches
$match = preg_match('~<tr class="row' . $row . '".+?</tr>~s', $this->data, $matches);
if ($match !== 1) {
return 'unable to match row';
}
$rowData = $matches[0];
// extract cell into $matches
$match = preg_match('~<td class="column' . $column . ' .+?</td>~s', $rowData, $matches);
if ($match !== 1) {
return 'unable to match column';
}
return $matches[0];
}
public function testColourScaleHtmlOutput(): void
{
$expectedMatches = [
['E1', 'background-color:#B4CA76;">5<', 'cell E1'],
['F1', 'background-color:#CBCD71;">6<', 'cell F1'],
['G1', 'background-color:#E3D16C;">7<', 'cell G1'],
['D2', 'background-color:#57BB8A;">4<', 'cell D2'],
['E2', 'background-color:#A1C77A;">5<', 'cell E2'],
['F2', 'background-color:#F1A36D;">6<', 'cell F2'],
['D3', 'background-color:#FFD666;">4<', 'cell D3'],
['G3', 'background-color:#EC926F;">7<', 'cell G3'],
['H3', 'background-color:#E67C73;">8<', 'cell H3'],
['A4', 'background-color:#57BB8A;">1<', 'cell A4'],
['I4', 'null"><', 'empty cell I4'],
['J4', 'background-color:#E67C73;">10<', 'cell J4'],
];
foreach ($expectedMatches as $expected) {
[$coordinate, $expectedString, $message] = $expected;
$string = $this->extractCell($coordinate);
self::assertStringContainsString($expectedString, $string, $message);
}
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class HtmlConditionalFormattingTest extends TestCase
{
private string $data = '';
protected function setUp(): void
{
$file = 'samples/templates/BasicConditionalFormatting.xlsx';
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$writer = new HtmlWriter($spreadsheet);
$writer->setConditionalFormatting(true);
$this->data = $writer->generateHtmlAll();
$spreadsheet->disconnectWorksheets();
}
private function extractCell(string $coordinate): string
{
[$column, $row] = Coordinate::indexesFromString($coordinate);
--$column;
--$row;
// extract row into $matches
$match = preg_match('~<tr class="row' . $row . '".+?</tr>~s', $this->data, $matches);
if ($match !== 1) {
return 'unable to match row';
}
$rowData = $matches[0];
// extract cell into $matches
$match = preg_match('~<td class="column' . $column . ' .+?</td>~s', $rowData, $matches);
if ($match !== 1) {
return 'unable to match column';
}
return $matches[0];
}
public function testConditionalFormattingHtmLOutput(): void
{
$expectedMatches = [
['B1', 'class="column1 style1 s">Jan<', 'no conditional styling for B1'],
['F2', 'background-color:#C6EFCE;">120<', 'conditional style for F2'],
['H2', 'background-color:#FFEB9C;">90<', 'conditional style for H2'],
['F3', 'background-color:#C6EFCE;">70<', 'conditional style for cell F3'],
['H3', 'background-color:#FFEB9C;">60<', 'conditional style for cell H3'],
['F4', 'background-color:#C6EFCE;">1<', 'conditional style for cell F4'],
['L4', 'background-color:#FFC7CE;">5<', 'conditional style for cell L4'],
['F5', 'class="column5 style1 n">0<', 'no conditional styling for F5'],
];
foreach ($expectedMatches as $expected) {
[$coordinate, $expectedString, $message] = $expected;
$string = $this->extractCell($coordinate);
self::assertStringContainsString($expectedString, $string, $message);
}
}
}
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class HtmlDifferentConditionalFormattingsTest extends TestCase
{
private string $data = '';
protected function setUp(): void
{
$file = 'samples/templates/ConditionalFormattingConditions.xlsx';
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$writer = new HtmlWriter($spreadsheet);
$writer->setConditionalFormatting(true);
$this->data = $writer->generateHtmlAll();
$spreadsheet->disconnectWorksheets();
}
private function extractCell(string $coordinate): string
{
[$column, $row] = Coordinate::indexesFromString($coordinate);
--$column;
--$row;
// extract row into $matches
$match = preg_match('~<tr class="row' . $row . '".+?</tr>~s', $this->data, $matches);
if ($match !== 1) {
return 'unable to match row';
}
$rowData = $matches[0];
// extract cell into $matches
$match = preg_match('~<td class="column' . $column . ' .+?</td>~s', $rowData, $matches);
if ($match !== 1) {
return 'unable to match column';
}
return $matches[0];
}
public function testConditionalFormattingRulesHtml(): void
{
$expectedMatches = [
['A1', 'background-color:#B7E1CD;">1<', 'A1 equals hit'],
['B1', 'class="column1 style1 n">2<', 'B1 equals miss'],
['E1', 'background-color:#B7E1CD;">1<', 'E1 equals horizontal reference hit'],
['F1', 'class="column5 style1 n">2<', 'F1 equals horizontal reference miss'],
['G1', 'class="column6 style1 n">3<', 'G1 equals horizontal reference miss'],
['A2', 'background-color:#B7E1CD;">terve<', 'A2 text contains hit'],
['B2', 'class="column1 style1 s">moi<', 'B2 text contains miss'],
['A3', 'background-color:#B7E1CD;">terve<', 'A3 text does not contain hit'],
['B3', 'class="column1 style1 s">moi<', 'B2 text does not contain miss'],
['A4', 'background-color:#B7E1CD;">terve<', 'A4 text starts with hit'],
['B4', 'class="column1 style1 s">moi<', 'B2 text starts with miss'],
['A5', 'background-color:#B7E1CD;">terve<', 'A5 text ends with hit'],
['B5', 'class="column1 style1 s">moi<', 'B5 text ends with miss'],
['A6', 'background-color:#B7E1CD;">2025/01/01<', 'A6 date after hit'],
['B6', 'class="column1 style2 n">2020/01/01<', 'B6 date after miss'],
['A7', 'background-color:#B7E1CD;">terve vaan<', 'A7 text contains hit'],
['B7', 'class="column1 style1 s">moi<', 'B7 text contains miss'],
['A8', 'background-color:#B7E1CD;">terve<', 'A8 text does not contain hit'],
['B8', 'class="column1 style1 s">terve vaan<', 'B2 does not contain miss'],
['A9', 'background-color:#B7E1CD;">#DIV/0!<', 'A10 own formula is error hit'],
['B9', 'class="column1 style1 s">moi<', 'B9 own formula is error miss'],
['A10', 'background-color:#B7E1CD;">moi<', 'A10 own formula is not error hit'],
['B10', 'class="column1 style3 s">#DIV/0!<', 'B10 own formula is not error miss'],
['A11', 'background-color:#B7E1CD;">terve<', 'A11 own formula count instances of cell on line and hit when more than one hit'],
['B11', 'background-color:#B7E1CD;">terve<', 'B11 own formula count instances of cell on line and hit when more than one hit'],
['C11', 'class="column2 style1 s">moi<', 'C11 own formula count instances of cell on line and hit when more than one miss'],
['A12', 'background-color:#B7E1CD;">moi<', 'A12 own formula count instances of cell on line and hit when at most 1 hit'],
['B12', 'class="column1 style1 s">terve<', 'B12 own formula count instances of cell on line and hit when at most 1 miss'],
['C12', 'class="column2 style1 s">terve<', 'C11 own formula count instances of cell on line and hit when at most 1 miss'],
['A13', 'background-color:#B7E1CD;">12<', 'A13 own formula self reference hit'],
['B13', 'class="column1 style1 n">10<', 'B13 own formula self reference miss'],
['A14', 'background-color:#B7E1CD;">10<', 'A14 multiple conditional hits'],
['B14', 'class="column1 style1 n">1<', 'B14 multiple conditionals miss'],
['F7', 'background-color:#B7E1CD;">1<', 'F7 equals vertical reference hit'],
['F8', 'class="column5 style1 n">2<', 'F8 equals vertical reference miss'],
['F9', 'class="column5 style1 n">3<', 'F9 equals vertical reference miss'],
['F10', 'class="column5 style1 n">4<', 'F10 equals vertical reference miss'],
];
foreach ($expectedMatches as $expected) {
[$coordinate, $expectedString, $message] = $expected;
$string = $this->extractCell($coordinate);
self::assertStringContainsString($expectedString, $string, $message);
}
}
}
@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class HtmlTableFormatTest extends TestCase
{
private string $data = '';
protected function setUp(): void
{
$file = 'samples/templates/TableFormat.xlsx';
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$writer = new HtmlWriter($spreadsheet);
$writer->setTableFormats(true);
$this->data = $writer->generateHtmlAll();
$spreadsheet->disconnectWorksheets();
}
private function extractCell(string $coordinate): string
{
[$column, $row] = Coordinate::indexesFromString($coordinate);
--$column;
--$row;
// extract row into $matches
$match = preg_match('~<tr class="row' . $row . '".+?</tr>~s', $this->data, $matches);
if ($match !== 1) {
return 'unable to match row';
}
$rowData = $matches[0];
// extract cell into $matches
$match = preg_match('~<td class="column' . $column . ' .+?</td>~s', $rowData, $matches);
if ($match !== 1) {
return 'unable to match column';
}
return $matches[0];
}
public function testHtmlTableFormatOutput(): void
{
$expectedMatches = [
['J1', 'background-color:#145F82;">Sep<', 'table style for header row cell J1'],
['J2', 'background-color:#C0E4F5;">110<', 'table style for cell J2'],
['I3', 'background-color:#82CAEB;">70<', 'table style for cell I3'],
['J3', 'background-color:#82CAEB;">70<', 'table style for cell J3'], // as conditional calculations are off
['K3', 'background-color:#82CAEB;">70<', 'table style for cell K3'],
['J4', 'background-color:#C0E4F5;">1<', 'table style for cell J4'],
['J5', 'background-color:#82CAEB;">1<', 'table style for cell J5'],
];
foreach ($expectedMatches as $expected) {
[$coordinate, $expectedString, $message] = $expected;
$string = $this->extractCell($coordinate);
self::assertStringContainsString($expectedString, $string, $message);
}
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;
class HtmlTableFormatWithConditionalTest extends TestCase
{
private string $data = '';
protected function setUp(): void
{
$file = 'samples/templates/TableFormat.xlsx';
$reader = new XlsxReader();
$spreadsheet = $reader->load($file);
$writer = new HtmlWriter($spreadsheet);
$writer->setTableFormats(true);
$writer->setConditionalFormatting(true);
$this->data = $writer->generateHtmlAll();
$spreadsheet->disconnectWorksheets();
}
private function extractCell(string $coordinate): string
{
[$column, $row] = Coordinate::indexesFromString($coordinate);
--$column;
--$row;
// extract row into $matches
$match = preg_match('~<tr class="row' . $row . '".+?</tr>~s', $this->data, $matches);
if ($match !== 1) {
return 'unable to match row';
}
$rowData = $matches[0];
// extract cell into $matches
$match = preg_match('~<td class="column' . $column . ' .+?</td>~s', $rowData, $matches);
if ($match !== 1) {
return 'unable to match column';
}
return $matches[0];
}
public function testHtmlTableFormatOutput(): void
{
$expectedMatches = [
['J1', 'background-color:#145F82;">Sep<', 'table style for header row cell J1'],
['J2', 'background-color:#C0E4F5;">110<', 'table style for cell J2'],
['I3', 'background-color:#82CAEB;">70<', 'table style for cell I3'],
['J3', 'background-color:#B7E1CD;">70<', 'conditional style for cell J3'], // as conditional calculations are on
['K3', 'background-color:#82CAEB;">70<', 'table style for cell K3'],
['J4', 'background-color:#C0E4F5;">1<', 'table style for cell J4'],
['J5', 'background-color:#82CAEB;">1<', 'table style for cell J5'],
];
foreach ($expectedMatches as $expected) {
[$coordinate, $expectedString, $message] = $expected;
$string = $this->extractCell($coordinate);
self::assertStringContainsString($expectedString, $string, $message);
}
}
}
+5
View File
@@ -62,11 +62,14 @@ return [
[39844.0, 2008, 13, 31],
[39813.0, 2009, 1, 0],
[39812.0, 2009, 1, -1],
'month expressed as true' => [39812.0, 2009, true, -1],
[39782.0, 2009, 0, 0],
[39781.0, 2009, 0, -1],
[39752.0, 2009, -1, 0],
[39751.0, 2009, -1, -1],
[40146.0, 2010, 0, -1],
'month expressed as false' => [40146.0, 2010, false, -1],
'month expressed as null' => [40146.0, 2010, null, -1],
[40329.0, 2010, 5, 31],
[40199.0, 2010, 1, '21st'], // Excel can't parse ordinal, PhpSpreadsheet can
[40200.0, 2010, 1, '22nd'], // Excel can't parse ordinal, PhpSpreadsheet can
@@ -75,6 +78,8 @@ return [
[40258.0, 2010, 'March', '21st'], // ordinal and month name
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[40258.0, 2010, 'March', 21], // Excel can't parse month name, PhpSpreadsheet can
'month expressed as string' => [40258.0, 2010, '03', 21],
'month expressed as invalid string' => [ExcelError::VALUE(), 2010, '03x', 21],
[ExcelError::VALUE(), 'ABC', 1, 21],
[ExcelError::VALUE(), 2010, 'DEF', 21],
[ExcelError::VALUE(), 2010, 3, 'GHI'],
Binary file not shown.
Binary file not shown.