Files
baseProject/vendor/tecnickcom/tc-lib-pdf/test/MetaInfoTest.php
T

581 lines
20 KiB
PHP
Raw Normal View History

<?php
/**
* MetaInfoTest.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 MetaInfoTest extends TestUtil
{
/** @throws \Throwable */
protected function getTestObject(): \Com\Tecnick\Pdf\Tcpdf
{
return new \Com\Tecnick\Pdf\Tcpdf();
}
/** @throws \Throwable */
protected function getInternalTestObject(): TestablMetaInfo
{
return new TestablMetaInfo();
}
/** @throws \Throwable */
public function testGetVersionReturnsNonEmptyString(): void
{
$obj = $this->getTestObject();
$this->assertNotSame('', $obj->getVersion());
}
/** @throws \Throwable */
public function testMetadataSettersStoreNonEmptyValuesAndReturnSameInstance(): void
{
$obj = $this->getTestObject();
$this->assertSame($obj, $obj->setCreator('creator-app'));
$this->assertSame($obj, $obj->setAuthor('author-name'));
$this->assertSame($obj, $obj->setSubject('subject-line'));
$this->assertSame($obj, $obj->setTitle('doc-title'));
$this->assertSame($obj, $obj->setKeywords('one two'));
$this->assertSame('creator-app', $this->getObjectProperty($obj, 'creator'));
$this->assertSame('author-name', $this->getObjectProperty($obj, 'author'));
$this->assertSame('subject-line', $this->getObjectProperty($obj, 'subject'));
$this->assertSame('doc-title', $this->getObjectProperty($obj, 'title'));
$this->assertSame('one two', $this->getObjectProperty($obj, 'keywords'));
}
/** @throws \Throwable */
public function testMetadataSettersIgnoreEmptyValues(): void
{
$obj = $this->getTestObject();
$before = (string) $this->getObjectProperty($obj, 'title');
$obj->setTitle('');
$this->assertSame($before, $this->getObjectProperty($obj, 'title'));
}
/** @throws \Throwable */
public function testSetPDFVersionStoresExplicitVersion(): void
{
$obj = $this->getTestObject();
$ret = $obj->setPDFVersion('1.6');
$this->assertSame($obj, $ret);
$this->assertSame('1.6', $this->getObjectProperty($obj, 'pdfver'));
}
/** @throws \Throwable */
#[DataProvider('pdfaVersionFixtureProvider')]
public function testSetPDFVersionHonorsPdfaModes(int $pdfaMode, string $inputVersion, string $expectedVersion): void
{
$obj = $this->getTestObject();
$pdfa = new \ReflectionProperty(\Com\Tecnick\Pdf\Tcpdf::class, 'pdfa');
$pdfa->setValue($obj, $pdfaMode);
$obj->setPDFVersion($inputVersion);
$this->assertSame($expectedVersion, $this->getObjectProperty($obj, 'pdfver'));
}
/** @throws \Throwable */
#[DataProvider('pdfuaVersionFixtureProvider')]
public function testSetPDFVersionHonorsPdfuaModes(
string $pdfuaMode,
string $inputVersion,
string $expectedVersion,
): void {
$obj = $this->getTestObject();
$pdfua = new \ReflectionProperty(\Com\Tecnick\Pdf\Tcpdf::class, 'pdfuaMode');
$pdfua->setValue($obj, $pdfuaMode);
$obj->setPDFVersion($inputVersion);
$this->assertSame($expectedVersion, $this->getObjectProperty($obj, 'pdfver'));
}
/** @throws \Throwable */
public function testSetPDFVersionThrowsOnInvalidFormat(): void
{
$obj = $this->getTestObject();
$this->expectException(\Com\Tecnick\Pdf\Exception::class);
$this->expectExceptionMessageMatches('/' . preg_quote('Invalid PDF version format', '/') . '/');
$obj->setPDFVersion('1.A');
}
/** @throws \Throwable */
public function testSetPDFVersionThrowsOnInvalidFormatWhenPdfxEnabled(): void
{
$obj = $this->getTestObject();
$this->setObjectProperty($obj, 'pdfx', true);
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx4');
$this->expectException(\Com\Tecnick\Pdf\Exception::class);
$this->expectExceptionMessageMatches('/' . preg_quote('Invalid PDF version format', '/') . '/');
$obj->setPDFVersion('1.A');
}
/** @throws \Throwable */
public function testSetSRGBTogglesFlag(): void
{
$obj = $this->getTestObject();
$this->assertSame($obj, $obj->setSRGB(true));
$this->assertTrue($this->getObjectProperty($obj, 'sRGB'));
$obj->setSRGB(false);
$this->assertFalse($this->getObjectProperty($obj, 'sRGB'));
}
/** @throws \Throwable */
public function testSetCustomXMPUpdatesKnownKeyOnly(): void
{
$obj = $this->getTestObject();
$this->assertSame($obj, $obj->setCustomXMP('x:xmpmeta', '<custom/>'));
/** @var array<string, string> $custom */
$custom = $this->getObjectProperty($obj, 'custom_xmp');
$this->assertArrayHasKey('x:xmpmeta', $custom);
$this->assertSame('<custom/>', $custom['x:xmpmeta'] ?? null);
$obj->setCustomXMP('unknown-key', '<ignored/>');
/** @var array<string, string> $custom */
$custom = $this->getObjectProperty($obj, 'custom_xmp');
$this->assertArrayNotHasKey('unknown-key', $custom);
}
/** @throws \Throwable */
public function testSetCustomXMPIgnoresEmptyKeyOrPayload(): void
{
$obj = $this->getTestObject();
/** @var array<string, string> $before */
$before = $this->getObjectProperty($obj, 'custom_xmp');
$this->assertSame($obj, $obj->setCustomXMP('', '<custom/>'));
$this->assertSame($obj, $obj->setCustomXMP('x:xmpmeta', ''));
/** @var array<string, string> $after */
$after = $this->getObjectProperty($obj, 'custom_xmp');
$this->assertSame($before, $after);
}
/** @throws \Throwable */
public function testSetViewerPreferencesStoresPreferences(): void
{
$obj = $this->getTestObject();
$pref = ['HideToolbar' => true, 'NumCopies' => 2, 'PrintScaling' => 'none'];
$this->assertSame($obj, $obj->setViewerPreferences($pref));
$this->assertSame($pref, $this->getObjectProperty($obj, 'viewerpref'));
}
/**
* @param ?array<string, mixed> $viewerPref
* @throws \Throwable
*/
#[DataProvider('pagePrintScalingFixtureProvider')]
public function testGetPagePrintScalingReturnsExpectedValue(
?array $viewerPref,
#[\SensitiveParameter]
string $expectedToken,
): void {
$obj = $this->getInternalTestObject();
if ($viewerPref !== null) {
$this->setObjectProperty($obj, 'viewerpref', $viewerPref);
}
$result = $obj->exposeGetPagePrintScaling();
$this->assertStringContainsString('/PrintScaling', $result);
$this->assertStringContainsString($expectedToken, $result);
}
/** @throws \Throwable */
public function testGetDuplexModeReturnsEmptyByDefault(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetDuplexMode();
$this->assertSame('', $result);
}
/** @throws \Throwable */
public function testGetPageBoxNameReturnsMappedValueWhenAvailable(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'page', new TestableObjPageForMetaInfo());
$this->setObjectProperty($obj, 'viewerpref', ['ViewArea' => 'MediaBox']);
$result = $obj->exposeGetPageBoxName('ViewArea');
$this->assertSame(' /ViewArea /MediaBox', $result);
}
/** @throws \Throwable */
public function testGetBooleanModeReturnsEmptyWhenNotSet(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetBooleanMode('HideToolbar');
$this->assertSame('', $result);
}
/** @throws \Throwable */
#[DataProvider('duplexModeFixtureProvider')]
public function testGetDuplexModeReturnsMappedValue(string $duplexMode, string $expectedOutput): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'viewerpref', ['Duplex' => $duplexMode]);
$result = $obj->exposeGetDuplexMode();
$this->assertStringContainsString($expectedOutput, $result);
}
/** @throws \Throwable */
#[DataProvider('booleanModeFixtureProvider')]
public function testGetBooleanModeReturnsMappedValue(bool $value, string $expectedWord): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'viewerpref', ['HideToolbar' => $value]);
$result = $obj->exposeGetBooleanMode('HideToolbar');
$this->assertStringContainsString('/HideToolbar ' . $expectedWord, $result);
}
/** @throws \Throwable */
public function testGetFormattedDateReturnsPdfDateStyle(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetFormattedDate(1710000000);
$this->assertMatchesRegularExpression('/^[0-9]{14}[\+\-Z\']/', $result);
}
/** @throws \Throwable */
public function testGetXMPFormattedDateReturnsIsoStyle(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetXMPFormattedDate(1710000000);
$this->assertStringContainsString('T', $result);
}
/** @throws \Throwable */
public function testGetOutDateTimeStringBuildsEscapedDate(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutDateTimeString(1710000000, 1);
$this->assertStringContainsString('D:', $result);
}
/** @throws \Throwable */
public function testGetOutDateTimeStringUsesDocumentTimeWhenInputIsZero(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'doctime', 1710001234);
$result = $obj->exposeGetOutDateTimeString(0, 1);
$this->assertStringContainsString('D:', $result);
}
/** @throws \Throwable */
public function testGetEscapedXMLEscapesSpecialChars(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetEscapedXML('<a&b>');
$this->assertSame('&lt;a&amp;b&gt;', $result);
}
/** @throws \Throwable */
public function testGetOutMetaInfoContainsDocumentInfoKeys(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutMetaInfo();
$this->assertStringContainsString('/Creator', $result);
$this->assertStringContainsString('/Producer', $result);
$this->assertStringContainsString('/Trapped /False', $result);
}
/** @throws \Throwable */
public function testGetOutXMPContainsMetadataStreamStructure(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutXMP();
$this->assertStringContainsString('/Type /Metadata', $result);
$this->assertStringContainsString('<x:xmpmeta', $result);
$this->assertStringContainsString('endobj', $result);
}
/** @throws \Throwable */
public function testGetOutXMPIncludesPdfaBlockWhenPdfaEnabled(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfa', 3);
$this->setObjectProperty($obj, 'pdfaConformance', 'U');
$result = $obj->exposeGetOutXMP();
$this->assertStringContainsString('<pdfaid:part>3</pdfaid:part>', $result);
$this->assertStringContainsString('<pdfaid:conformance>U</pdfaid:conformance>', $result);
}
/** @throws \Throwable */
public function testGetOutXMPIncludesPdfuaBlockWhenPdfuaEnabled(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfuaMode', 'pdfua2');
$result = $obj->exposeGetOutXMP();
$this->assertStringContainsString('xmlns:pdfuaid="http://www.aiim.org/pdfua/ns/id/"', $result);
$this->assertStringContainsString('<pdfuaid:part>2</pdfuaid:part>', $result);
}
/** @throws \Throwable */
#[DataProvider('pdfxVersionFixtureProvider')]
public function testSetPDFVersionHonorsPdfxModes(
string $pdfxMode,
string $inputVersion,
string $expectedVersion,
): void {
$obj = $this->getTestObject();
$this->setObjectProperty($obj, 'pdfx', true);
$this->setObjectProperty($obj, 'pdfxMode', $pdfxMode);
$obj->setPDFVersion($inputVersion);
$this->assertSame($expectedVersion, $this->getObjectProperty($obj, 'pdfver'));
}
/** @throws \Throwable */
#[DataProvider('pdfxGtsVersionStringFixtureProvider')]
public function testGetGtsPdfxVersionStringReturnsExpectedValue(string $pdfxMode, string $expected): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfx', true);
$this->setObjectProperty($obj, 'pdfxMode', $pdfxMode);
$this->assertSame($expected, $obj->exposeGetGtsPdfxVersionString());
}
/** @throws \Throwable */
public function testGetOutMetaInfoIncludesGtsPdfxVersionWhenPdfxEnabled(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfx', true);
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx4');
$result = $obj->exposeGetOutMetaInfo();
// The key is a PDF name (ASCII); the value is encoded as a PDF text string.
$this->assertStringContainsString('/GTS_PDFXVersion', $result);
}
/** @throws \Throwable */
public function testGetOutMetaInfoOmitsGtsPdfxVersionWhenPdfxDisabled(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutMetaInfo();
$this->assertStringNotContainsString('/GTS_PDFXVersion', $result);
}
/** @throws \Throwable */
public function testGetOutXMPIncludesPdfxidBlockWhenPdfxEnabled(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfx', true);
$this->setObjectProperty($obj, 'pdfxMode', 'pdfx1a');
$result = $obj->exposeGetOutXMP();
$this->assertStringContainsString('xmlns:pdfxid="http://www.npes.org/pdfx/ns/id/"', $result);
$this->assertStringContainsString('<pdfxid:GTS_PDFXVersion>PDF/X-1a:2003</pdfxid:GTS_PDFXVersion>', $result);
}
/** @throws \Throwable */
public function testGetOutXMPOmitsPdfxidBlockWhenPdfxDisabled(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutXMP();
$this->assertStringNotContainsString('pdfxid', $result);
}
/** @throws \Throwable */
public function testGetOutViewerPrefIncludesDirectionAndKnownFlags(): void
{
$obj = $this->getInternalTestObject();
$obj->setRTL(true);
$obj->setViewerPreferences(['HideToolbar' => true, 'NumCopies' => 2]);
$result = $obj->exposeGetOutViewerPref();
$this->assertStringContainsString('/ViewerPreferences <<', $result);
$this->assertStringContainsString('/Direction /R2L', $result);
$this->assertStringContainsString('/HideToolbar true', $result);
$this->assertStringContainsString('/NumCopies 2', $result);
}
/** @throws \Throwable */
public function testGetOutViewerPrefIncludesPageRangeAndDisplayMode(): void
{
$obj = $this->getInternalTestObject();
$this->initFontAndPage($obj);
$obj->setViewerPreferences([
'NonFullScreenPageMode' => 'UseOutlines',
'PrintPageRange' => [1, 3],
'NumCopies' => 2,
'PrintScaling' => 'none',
'PickTrayByPDFSize' => false,
'ViewArea' => 'MediaBox',
'ViewClip' => 'CropBox',
'PrintArea' => 'TrimBox',
'PrintClip' => 'BleedBox',
]);
$result = $obj->exposeGetOutViewerPref();
$this->assertStringContainsString('/NonFullScreenPageMode /UseOutlines', $result);
$this->assertStringContainsString('/PrintPageRange [ 0 2 ]', $result);
$this->assertStringContainsString('/PrintScaling /None', $result);
$this->assertStringContainsString('/NumCopies 2', $result);
}
/** @throws \Throwable */
public function testGetOutViewerPrefForceDisplayDocTitleTrueInPdfuaMode(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfuaMode', 'pdfua1');
$result = $obj->exposeGetOutViewerPref();
$this->assertStringContainsString('/DisplayDocTitle true', $result);
}
/** @throws \Throwable */
public function testGetOutViewerPrefRespectsExplicitDisplayDocTitleFalseInPdfuaMode(): void
{
$obj = $this->getInternalTestObject();
$this->setObjectProperty($obj, 'pdfuaMode', 'pdfua1');
$obj->setViewerPreferences(['DisplayDocTitle' => false]);
$result = $obj->exposeGetOutViewerPref();
$this->assertStringContainsString('/DisplayDocTitle false', $result);
}
/** @throws \Throwable */
public function testGetOutViewerPrefDoesNotForceDisplayDocTitleOutsidePdfuaMode(): void
{
$obj = $this->getInternalTestObject();
$result = $obj->exposeGetOutViewerPref();
$this->assertStringNotContainsString('/DisplayDocTitle', $result);
}
/** @return array<string, array{0: string, 1: string, 2: string}> */
public static function pdfxVersionFixtureProvider(): array
{
return [
'pdfx1a_enforces_min_1_3_when_lower' => ['pdfx1a', '1.1', '1.3'],
'pdfx1a_allows_higher_explicit' => ['pdfx1a', '1.6', '1.6'],
'pdfx3_enforces_min_1_3' => ['pdfx3', '1.2', '1.3'],
'pdfx4_enforces_min_1_6_when_lower' => ['pdfx4', '1.3', '1.6'],
'pdfx4_allows_higher_explicit' => ['pdfx4', '1.7', '1.7'],
'pdfx5_enforces_min_1_6' => ['pdfx5', '1.4', '1.6'],
'pdfx_generic_enforces_min_1_3' => ['pdfx', '1.1', '1.3'],
];
}
/** @return array<string, array{0: string, 1: string}> */
public static function pdfxGtsVersionStringFixtureProvider(): array
{
return [
'pdfx1a' => ['pdfx1a', 'PDF/X-1a:2003'],
'pdfx3' => ['pdfx3', 'PDF/X-3:2003'],
'pdfx4' => ['pdfx4', 'PDF/X-4:2010'],
'pdfx5' => ['pdfx5', 'PDF/X-5g:2010'],
'pdfx_generic_defaults_to_x3' => ['pdfx', 'PDF/X-3:2003'],
];
}
/** @return array<string, array{0: int, 1: string, 2: string}> */
public static function pdfaVersionFixtureProvider(): array
{
return [
'pdfa1_forces_1_4' => [1, '1.9', '1.4'],
'pdfa2_forces_1_7' => [2, '1.5', '1.7'],
'pdfa4_forces_2_0' => [4, '1.5', '2.0'],
];
}
/** @return array<string, array{0: string, 1: string, 2: string}> */
public static function pdfuaVersionFixtureProvider(): array
{
return [
'pdfua_defaults_to_1_7' => ['pdfua', '1.4', '1.7'],
'pdfua1_forces_1_7' => ['pdfua1', '1.5', '1.7'],
'pdfua2_forces_2_0' => ['pdfua2', '1.7', '2.0'],
];
}
/** @return array<string, array{0: ?array<string, mixed>, 1: string}> */
public static function pagePrintScalingFixtureProvider(): array
{
return [
'default_value' => [null, 'AppDefault'],
'explicit_none' => [['PrintScaling' => 'none'], '/None'],
];
}
/** @return array<string, array{0: string, 1: string}> */
public static function duplexModeFixtureProvider(): array
{
return [
'simplex' => ['Simplex', '/Duplex /Simplex'],
'short_edge' => ['DuplexFlipShortEdge', '/Duplex /DuplexFlipShortEdge'],
];
}
/** @return array<string, array{0: bool, 1: string}> */
public static function booleanModeFixtureProvider(): array
{
return [
'true_value' => [true, 'true'],
'false_value' => [false, 'false'],
];
}
}