generated from jric11/baseProject
408 lines
14 KiB
PHP
408 lines
14 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
/**
|
||
|
|
* BaseTest.php
|
||
|
|
*
|
||
|
|
* @since 2002-08-03
|
||
|
|
* @category Library
|
||
|
|
* @package Pdf
|
||
|
|
* @author Nicola Asuni <info@tecnick.com>
|
||
|
|
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
|
||
|
|
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
|
||
|
|
* @link https://github.com/tecnickcom/tc-lib-pdf
|
||
|
|
*
|
||
|
|
* This file is part of tc-lib-pdf software library.
|
||
|
|
*/
|
||
|
|
|
||
|
|
namespace Test;
|
||
|
|
|
||
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||
|
|
|
||
|
|
class BaseTest extends TestUtil
|
||
|
|
{
|
||
|
|
private function invokeBaseMethod(object $obj, string $method, mixed ...$args): mixed
|
||
|
|
{
|
||
|
|
$ref = new \ReflectionClass($obj);
|
||
|
|
return $ref->getMethod($method)->invokeArgs($obj, $args);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
protected function getTestObject(): \Com\Tecnick\Pdf\Tcpdf
|
||
|
|
{
|
||
|
|
return new \Com\Tecnick\Pdf\Tcpdf();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
protected function getInternalTestObject(): TestableBase
|
||
|
|
{
|
||
|
|
return new TestableBase();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testToPointsAndToUnitRoundTrip(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$usr = 12.34;
|
||
|
|
$pnt = $obj->toPoints($usr);
|
||
|
|
|
||
|
|
$this->assertGreaterThan(0, $pnt);
|
||
|
|
$this->bcAssertEqualsWithDelta($usr, $obj->toUnit($pnt), 0.0001);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testToYPointsAndToYUnitWithExplicitPageHeight(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$usr = 10.0;
|
||
|
|
$pageh = 200.0;
|
||
|
|
|
||
|
|
$yPoints = $obj->toYPoints($usr, $pageh);
|
||
|
|
$this->bcAssertEqualsWithDelta($pageh - $obj->toPoints($usr), $yPoints, 0.0001);
|
||
|
|
|
||
|
|
$yUnit = $obj->toYUnit($yPoints, $pageh);
|
||
|
|
$this->bcAssertEqualsWithDelta($usr, $yUnit, 0.0001);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testEnableDefaultPageContentTogglesFlag(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$obj->enableDefaultPageContent(false);
|
||
|
|
$this->assertFalse($this->getObjectProperty($obj, 'defPageContentEnabled'));
|
||
|
|
|
||
|
|
$obj->enableDefaultPageContent(true);
|
||
|
|
$this->assertTrue($this->getObjectProperty($obj, 'defPageContentEnabled'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testSetRTLReturnsSameInstanceAndSetsProperty(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$ret = $obj->setRTL(true);
|
||
|
|
|
||
|
|
$this->assertSame($obj, $ret);
|
||
|
|
$this->assertTrue($this->getObjectProperty($obj, 'rtl'));
|
||
|
|
|
||
|
|
$obj->setRTL(false);
|
||
|
|
$this->assertFalse($this->getObjectProperty($obj, 'rtl'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
#[DataProvider('unitValueConversionProvider')]
|
||
|
|
public function testGetUnitValuePointsConvertsCommonUnits(string $input, float $expected, float $delta): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
|
||
|
|
$result = $obj->exposeGetUnitValuePoints($input);
|
||
|
|
|
||
|
|
$this->bcAssertEqualsWithDelta($expected, $result, $delta);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testGetUnitValuePointsConvertsRelativeAndViewportUnits(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$ref = [
|
||
|
|
'parent' => 120.0,
|
||
|
|
'font' => ['size' => 12.0, 'xheight' => 5.0, 'zerowidth' => 6.0, 'rootsize' => 16.0],
|
||
|
|
'viewport' => ['width' => 300.0, 'height' => 200.0],
|
||
|
|
'page' => ['width' => 300.0, 'height' => 200.0],
|
||
|
|
];
|
||
|
|
|
||
|
|
$this->bcAssertEqualsWithDelta(12.0, $obj->exposeGetUnitValuePoints('2ch', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(12.0, $obj->exposeGetUnitValuePoints('10%', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(24.0, $obj->exposeGetUnitValuePoints('2em', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(10.0, $obj->exposeGetUnitValuePoints('2ex', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(24.0, $obj->exposeGetUnitValuePoints('2pc', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(32.0, $obj->exposeGetUnitValuePoints('2rem', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(20.0, $obj->exposeGetUnitValuePoints('10vh', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(30.0, $obj->exposeGetUnitValuePoints('10vw', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(30.0, $obj->exposeGetUnitValuePoints('10vmax', $ref), 0.0001);
|
||
|
|
$this->bcAssertEqualsWithDelta(20.0, $obj->exposeGetUnitValuePoints('10vmin', $ref), 0.0001);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testGetUnitValuePointsConvertsNumericDefault(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
|
||
|
|
$result = $obj->exposeGetUnitValuePoints(5.5);
|
||
|
|
|
||
|
|
$this->assertGreaterThan(0, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testGetUnitValuePointsThrowsForInvalidValue(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$this->bcExpectException(\Com\Tecnick\Pdf\Exception::class);
|
||
|
|
|
||
|
|
$obj->exposeGetUnitValuePoints('invalid!!!');
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testGetFontValuePointsConvertsNamedFontSize(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$ref = [
|
||
|
|
'parent' => 12.0,
|
||
|
|
'font' => ['size' => 12.0, 'xheight' => 1.0, 'zerowidth' => 1.0, 'rootsize' => 16.0],
|
||
|
|
'viewport' => ['width' => 800.0, 'height' => 600.0],
|
||
|
|
'page' => ['width' => 800.0, 'height' => 600.0],
|
||
|
|
];
|
||
|
|
|
||
|
|
$result = $obj->exposeGetFontValuePoints('larger', $ref);
|
||
|
|
|
||
|
|
// 'larger' should result in parent + larger factor
|
||
|
|
$this->assertGreaterThan($ref['parent'], $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testGetFontValuePointsDelegatesUnknownUnitToGetUnitValuePoints(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
|
||
|
|
$result = $obj->exposeGetFontValuePoints('10mm');
|
||
|
|
|
||
|
|
// 10 mm = 10 * 72 / 25.4 ≈ 28.35 points
|
||
|
|
$this->bcAssertEqualsWithDelta(28.35, $result, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
#[DataProvider('tmpRtlModeProvider')]
|
||
|
|
public function testSetTmpRTLWithMode(string $mode, bool $expectedRtl): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
|
||
|
|
$obj->exposeSetTmpRTL($mode);
|
||
|
|
|
||
|
|
$this->assertSame($expectedRtl, $obj->exposeIsRTL());
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
#[DataProvider('isRtlStateProvider')]
|
||
|
|
public function testIsRTLReturnsExpectedState(bool $globalRtl, bool $expected): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$obj->setRTL($globalRtl);
|
||
|
|
|
||
|
|
$result = $obj->exposeIsRTL();
|
||
|
|
|
||
|
|
$this->assertSame($expected, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testIsTransparencyAllowedReturnsTrueWhenPdfxDisabled(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$this->setObjectProperty($obj, 'pdfx', false);
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx1a');
|
||
|
|
|
||
|
|
$this->assertTrue($this->invokeBaseMethod($obj, 'isTransparencyAllowed') === true);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testIsTransparencyAllowedDependsOnPdfxMode(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$this->setObjectProperty($obj, 'pdfx', true);
|
||
|
|
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx4');
|
||
|
|
$this->assertTrue($this->invokeBaseMethod($obj, 'isTransparencyAllowed'));
|
||
|
|
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx3');
|
||
|
|
$this->assertFalse($this->invokeBaseMethod($obj, 'isTransparencyAllowed'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testRequiresPdfxDeviceCmykReturnsFalseWhenPdfxDisabled(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$this->setObjectProperty($obj, 'pdfx', false);
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx1a');
|
||
|
|
|
||
|
|
$this->assertFalse($this->invokeBaseMethod($obj, 'requiresPdfxDeviceCmyk'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testRequiresPdfxDeviceCmykDependsOnPdfxMode(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getInternalTestObject();
|
||
|
|
$this->setObjectProperty($obj, 'pdfx', true);
|
||
|
|
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx3');
|
||
|
|
$this->assertTrue($this->invokeBaseMethod($obj, 'requiresPdfxDeviceCmyk'));
|
||
|
|
|
||
|
|
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx5');
|
||
|
|
$this->assertFalse($this->invokeBaseMethod($obj, 'requiresPdfxDeviceCmyk'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testDefaultFileAllowedPathsIncludesKnownRoots(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$paths = $obj->defaultFileAllowedPaths();
|
||
|
|
|
||
|
|
$tmpRoot = \realpath(\sys_get_temp_dir());
|
||
|
|
$pkgRoot = \realpath(__DIR__ . '/..');
|
||
|
|
$fontsRoot = \defined('K_PATH_FONTS') ? \realpath((string) \constant('K_PATH_FONTS')) : false;
|
||
|
|
|
||
|
|
if (\is_string($tmpRoot) && $tmpRoot !== '') {
|
||
|
|
$this->assertContains($tmpRoot, $paths);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (\is_string($pkgRoot) && $pkgRoot !== '') {
|
||
|
|
$this->assertContains($pkgRoot, $paths);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (\is_string($fontsRoot) && $fontsRoot !== '') {
|
||
|
|
$this->assertContains($fontsRoot, $paths);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testDefaultFileAllowedPathsReturnsUniqueNonEmptyResolvedPaths(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$paths = $obj->defaultFileAllowedPaths();
|
||
|
|
|
||
|
|
foreach ($paths as $path) {
|
||
|
|
$this->assertNotSame('', $path);
|
||
|
|
$this->assertSame($path, \realpath($path));
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->assertCount(\count(\array_unique($paths)), $paths);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testDefaultMarkupAllowedPathsExcludeSystemTemp(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$paths = $obj->defaultMarkupAllowedPaths();
|
||
|
|
|
||
|
|
$tmpRoot = \realpath(\sys_get_temp_dir());
|
||
|
|
if (\is_string($tmpRoot) && $tmpRoot !== '') {
|
||
|
|
$this->assertNotContains($tmpRoot, $paths);
|
||
|
|
}
|
||
|
|
|
||
|
|
$pkgRoot = \realpath(__DIR__ . '/..');
|
||
|
|
if (\is_string($pkgRoot) && $pkgRoot !== '') {
|
||
|
|
$this->assertContains($pkgRoot, $paths);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testVendorSiblingPackagesPathDetectsComposerDependencyLayout(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
|
||
|
|
$this->assertSame('/proj/vendor/tecnickcom', $this->invokeBaseMethod(
|
||
|
|
$obj,
|
||
|
|
'vendorSiblingPackagesPath',
|
||
|
|
'/proj/vendor/tecnickcom/tc-lib-pdf/src',
|
||
|
|
));
|
||
|
|
|
||
|
|
$this->assertNull($this->invokeBaseMethod(
|
||
|
|
$obj,
|
||
|
|
'vendorSiblingPackagesPath',
|
||
|
|
'/home/dev/github.com/tecnickcom/tc-lib-pdf/src',
|
||
|
|
));
|
||
|
|
|
||
|
|
$this->assertNull($this->invokeBaseMethod(
|
||
|
|
$obj,
|
||
|
|
'vendorSiblingPackagesPath',
|
||
|
|
'/proj/custom-deps/tecnickcom/tc-lib-pdf/src',
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testDefaultFileAllowedPathsMatchVendorSiblingDetection(): void
|
||
|
|
{
|
||
|
|
$obj = $this->getTestObject();
|
||
|
|
$paths = $obj->defaultFileAllowedPaths();
|
||
|
|
|
||
|
|
$baseFileClass = new \ReflectionClass(\Com\Tecnick\Pdf\Base::class);
|
||
|
|
$baseFile = $baseFileClass->getFileName();
|
||
|
|
$this->assertIsString($baseFile);
|
||
|
|
|
||
|
|
$srcDir = \dirname($baseFile);
|
||
|
|
/** @var ?string $vendorSiblings */
|
||
|
|
$vendorSiblings = $this->invokeBaseMethod($obj, 'vendorSiblingPackagesPath', $srcDir);
|
||
|
|
|
||
|
|
if ($vendorSiblings === null) {
|
||
|
|
$siblingsDir = \realpath(\dirname($srcDir, 2));
|
||
|
|
if (\is_string($siblingsDir) && $siblingsDir !== '') {
|
||
|
|
$this->assertNotContains($siblingsDir, $paths);
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->assertIsString($vendorSiblings);
|
||
|
|
$resolvedVendorSiblings = \realpath($vendorSiblings);
|
||
|
|
if (\is_string($resolvedVendorSiblings) && $resolvedVendorSiblings !== '') {
|
||
|
|
$this->assertContains($resolvedVendorSiblings, $paths);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @throws \Throwable */
|
||
|
|
public function testAllowedRootsMatchWindowsStylePathsWithDriveLetters(): void
|
||
|
|
{
|
||
|
|
$probe = new class extends \Com\Tecnick\File\File {
|
||
|
|
/** @param array<string> $roots */
|
||
|
|
public function probeIsPathWithinAllowedRoots(string $path, array $roots): bool
|
||
|
|
{
|
||
|
|
return $this->isPathWithinAllowedRoots($path, $roots);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array<string> $roots
|
||
|
|
* @return array<string>
|
||
|
|
*/
|
||
|
|
public function probeNormalizeAllowedPaths(array $roots): array
|
||
|
|
{
|
||
|
|
return $this->normalizeAllowedPaths($roots);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
$allowedRoot = 'C:\\webdev\\project\\storage\\app\\private\\pdf\\fonts';
|
||
|
|
$allowedPath = 'c:\\webdev\\project\\storage\\app\\private\\pdf\\fonts\\core\\helvetica.json';
|
||
|
|
$blockedPath = 'C:\\webdev\\project\\storage\\app\\private\\pdf\\fontsevil\\core\\helvetica.json';
|
||
|
|
$normalizedRoots = $probe->probeNormalizeAllowedPaths([$allowedRoot]);
|
||
|
|
|
||
|
|
$this->assertSame(['c:/webdev/project/storage/app/private/pdf/fonts'], $normalizedRoots);
|
||
|
|
$this->assertTrue($probe->probeIsPathWithinAllowedRoots($allowedPath, $normalizedRoots));
|
||
|
|
$this->assertFalse($probe->probeIsPathWithinAllowedRoots($blockedPath, $normalizedRoots));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @return array<string, array{0: string, 1: float, 2: float}> */
|
||
|
|
public static function unitValueConversionProvider(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'px' => ['96px', 72.0, 0.1],
|
||
|
|
'pt' => ['12pt', 12.0, 0.0001],
|
||
|
|
'cm' => ['1cm', 28.35, 0.1],
|
||
|
|
'in' => ['1in', 72.0, 0.1],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @return array<string, array{0: string, 1: bool}> */
|
||
|
|
public static function tmpRtlModeProvider(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'R_mode' => ['R', true],
|
||
|
|
'L_mode' => ['L', false],
|
||
|
|
'empty_mode' => ['', false],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @return array<string, array{0: bool, 1: bool}> */
|
||
|
|
public static function isRtlStateProvider(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'default_false' => [false, false],
|
||
|
|
'global_true' => [true, true],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|