Initial plugin commit

This commit is contained in:
2026-04-13 21:01:07 +02:00
commit 4367aef84a
254 changed files with 104260 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
<?php
/**
* Helper class to execute magick via shell
*
* @author Philippe Jausions
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
use LogicException;
use RuntimeException;
class ImageMagick
{
/**
* @var string|null Path to magick as shell argument
*/
private $magick = null;
/**
* @var bool
*/
private $verbose;
/**
* @var string
*/
private $magickVersionInfo;
/**
* @param string $magick Path to ImageMagick `magick` executable
* @param bool $verbose
*/
public function __construct(
$magick,
$verbose = false
) {
$this->magick = escapeshellarg($magick);
$this->verbose = $verbose;
}
/**
* @return string pdfinfo version information (multiline information)
* @throws LogicException
* @throws RuntimeException
*/
public function getMagickVersionInfo()
{
if (null === $this->magick) {
throw new LogicException('No path to magick. Provide it to ImageMagick PHP class constructor.');
}
if (null === $this->magickVersionInfo) {
$exec = sprintf('%s -version 2>&1', $this->magick);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode && 99 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->magickVersionInfo = implode(PHP_EOL, $output);
}
return $this->magickVersionInfo;
}
/**
* @param string $file1 Path to image to compare
* @param string $file2 Path to image to compare
* @return bool
* @throws LogicException
*/
public function areSimilar($file1, $file2)
{
if (null === $this->magick) {
throw new LogicException('No path to magick. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
$exec = implode(' ', array(
$this->magick,
'compare',
'-metric MAE',
escapeshellarg($file1),
escapeshellarg($file2),
'null:',
' 2>&1',
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
$result = implode(PHP_EOL, $output);
if ($this->verbose) {
echo $result . PHP_EOL;
}
if (0 !== $resultCode) {
if (!preg_match('/^[-0-9.e]+\s+\([-0-9.e]+\)$/', $result)) {
throw new RuntimeException(
'An error occurred with magick compare command' . PHP_EOL
. $result,
$resultCode
);
}
}
return '0 (0)' === $result;
}
}

View File

@@ -0,0 +1,198 @@
<?php
/**
* Helper class to execute PDF-related commands via shell
*
* @author Philippe Jausions
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
use LogicException;
use RuntimeException;
class PdfTools
{
/**
* @var string|null Path to pdfinfo as shell argument
*/
private $pdfinfo = null;
/**
* @var string|null Path to pdftopng as shell argument
*/
private $pdftopng = null;
/**
* @var string|null Path to pdftoppm as shell argument
*/
private $pdftoppm = null;
/**
* @var bool
*/
private $verbose;
/**
* @var string
*/
private $pdfinfoVersionInfo;
/**
* @var string
*/
private $pdftopngVersionInfo;
/**
* @param string[] $tools Path to PDF tool executables (indexed by tool name)
* @param bool $verbose
*/
public function __construct(
array $tools,
$verbose = false
) {
if (!empty($tools['pdfinfo'])) {
$this->pdfinfo = escapeshellarg($tools['pdfinfo']);
}
if (!empty($tools['pdftopng'])) {
$this->pdftopng = escapeshellarg($tools['pdftopng']);
}
if (!empty($tools['pdftoppm'])) {
$this->pdftoppm = escapeshellarg($tools['pdftoppm']);
}
$this->verbose = $verbose;
}
/**
* @return string pdfinfo version information (multiline information)
* @throws LogicException
* @throws RuntimeException
*/
public function getPdfinfoVersionInfo()
{
if (null === $this->pdfinfo) {
throw new LogicException('No path to pdfinfo. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
if (null === $this->pdfinfoVersionInfo) {
$exec = sprintf('%s -v 2>&1', $this->pdfinfo);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode && 99 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->pdfinfoVersionInfo = implode(PHP_EOL, $output);
}
return $this->pdfinfoVersionInfo;
}
/**
* @return string pdftopng or pdftoppm version information (multiline information)
* @throws LogicException
* @throws RuntimeException
*/
public function getPdftopngVersionInfo()
{
$tool = $this->pdftopng ?: $this->pdftoppm;
if (null === $tool) {
throw new LogicException('No path to pdftopng not pdftoppm. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
if (null === $this->pdftopngVersionInfo) {
$exec = sprintf('%s -v 2>&1', $tool);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode && 99 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->pdftopngVersionInfo = implode(PHP_EOL, $output);
}
return $this->pdftopngVersionInfo;
}
/**
* @param string $file Path of file to check
* @return bool
* @throws LogicException
*/
public function isPdf($file)
{
if (null === $this->pdfinfo) {
throw new LogicException('No path to pdfinfo. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
$exec = implode(' ', array(
$this->pdfinfo,
escapeshellarg($file)
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if ($this->verbose) {
echo implode(PHP_EOL, $output) . PHP_EOL;
}
return (0 === $resultCode);
}
private function ensureFolder($path)
{
if (file_exists($path) && is_dir($path) && is_writable($path)) {
return;
}
if (!mkdir($path, 0775, true)) {
throw new RuntimeException('Could not create folder: ' . $path);
}
}
/**
* @param string $file The path of the PDF document to convert into PNG
* @param string $pngRoot The root of the generated PNG file names.
* Example: if <code>$pngRoot = '/usr/home/TCPDF/compare_runs/my-root'</code>,
* the generated PNG files will be as follows:
* <ul>
* <li><code>/usr/home/TCPDF/compare_runs/my-root-0000001.png</code>,</li>
* <li><code>/usr/home/TCPDF/compare_runs/my-root-0000002.png</code>,</li>
* <li>...</li>
* </ul>
* @return string[] List of paths for generated PNG (one per page)
* @throws LogicException
*/
public function convertToPng($file, $pngRoot)
{
if ($this->pdftopng) {
$tool = $this->pdftopng;
} elseif ($this->pdftoppm) {
// When using pdftoppm, we specify the `-png` option to get PNG files
$tool = $this->pdftoppm . ' -png';
}
if (!isset($tool)) {
throw new LogicException('No path to pdftopng nor pdftoppm. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
$this->ensureFolder(dirname($pngRoot));
$exec = implode(' ', array(
$tool,
escapeshellarg($file),
escapeshellarg($pngRoot),
' 2>&1',
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if ($this->verbose) {
echo implode(PHP_EOL, $output) . PHP_EOL;
}
if (0 !== $resultCode) {
throw new RuntimeException(implode(PHP_EOL, $output));
}
$generatedFiles = glob($pngRoot . '*.png');
if (false === $generatedFiles) {
throw new RuntimeException('Could not get the list of generated PNG files.');
}
return $generatedFiles;
}
}

View File

@@ -0,0 +1,281 @@
<?php
/**
* Helper class to execute PHP via shell
*
* @author Philippe Jausions
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
use RuntimeException;
class PhpExecutor
{
/**
* @var string PHP executable as a shell argument
*/
private $phpShell;
/**
* @var string
*/
private $extensionDir = null;
/**
* @var int
*/
private $phpVersion = null;
/**
* @var string
*/
private $phpVersionInfo = null;
/**
* @var bool[]
*/
private $builtInExtensions = array();
/**
* @var mixed[]
*/
private $extensionStatuses = array();
/**
* @var bool
*/
private $verbose;
/**
* @param string $php Path to PHP executable
* @param bool $verbose
*/
public function __construct($php, $verbose = false)
{
$this->phpShell = escapeshellarg($php);
$this->verbose = $verbose;
}
public function __toString()
{
return $this->phpShell;
}
/**
* @param string $command PHP command to execute
* @param string|null $cliOptions MUST be properly escaped for the shell
* @return string Result of the command
* @throws RuntimeException
*/
public function executeCommand($command, $cliOptions = null)
{
$exec = sprintf(
'%s %s -r %s',
$this->phpShell,
$cliOptions,
escapeshellarg($command)
);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
return $output[0];
}
/**
* @return string PHP version information (multiline information)
* @throws RuntimeException
*/
public function getPhpVersionInfo()
{
if (null === $this->phpVersionInfo) {
$exec = sprintf('%s -n -v', $this->phpShell);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->phpVersionInfo = implode(PHP_EOL, $output);
}
return $this->phpVersionInfo;
}
/**
* @return int PHP version as a integer
* @throws RuntimeException
*/
public function getPhpVersion()
{
if (null === $this->phpVersion) {
$this->phpVersion = (int)$this->executeCommand('echo PHP_VERSION_ID;');
}
return $this->phpVersion;
}
/**
* @return string
* @throws RuntimeException
*/
public function getPhpExtensionDir()
{
if (null === $this->extensionDir) {
$this->extensionDir = $this->executeCommand("echo ini_get('extension_dir');");
}
return $this->extensionDir;
}
/**
* @return bool
*/
private function isWindows()
{
return stripos(PHP_OS, 'WIN') === 0;
}
/**
* @param string $extension Extension name (without .so, .dll, or "php_" prefix)
* @return string
*/
public function makePhpExtensionFileName($extension)
{
if ($this->isWindows()) {
if ('gd' === $extension && $this->getPhpVersion() < 80000) {
$extension = 'gd2';
}
return "php_$extension.dll";
}
return $extension . '.so';
}
/**
* @param string $path
* @return string
*/
private function escapePath($path)
{
if ($this->isWindows()) {
// if ($this->getPhpVersion() < 50400) {
// $path = str_replace('\\', '/', $path);
// }
if (strpos($path, '~') !== false) {
return "'" . $path . "'";
}
}
if (strpos($path, ' ') !== false) {
return "'" . $path . "'";
}
return escapeshellarg((string)$path);
}
/**
* @param string $path
* @return string
*/
private function escapePathForCliOption($path)
{
if ($this->isWindows()) {
if ($this->getPhpVersion() < 50400) {
$path = str_replace('\\', '/', $path);
return "'" . $path . "'";
}
if (strpos($path, '~') !== false) {
return "'" . $path . "'";
}
}
if (strpos($path, ' ') !== false) {
return "'" . $path . "'";
}
return (string)$path;
}
/**
* @param string $name
* @param string $value
* @return string
*/
public function makeCliOption($name, $value)
{
switch ($name) {
case 'auto_prepend_file':
case 'extension_dir':
case 'include_path':
$arg = $this->escapePathForCliOption($value);
break;
default:
$arg = escapeshellarg($value);
}
return sprintf('-d %s=%s', $name, $arg);
}
/**
* @param string $extension Extension name (without .so, .dll, or "php_" prefix)
* @return bool Whether the extension is available for loading into PHP
*/
public function isExtensionAvailable($extension)
{
$extensionLib = $this->makePhpExtensionFileName($extension);
return file_exists($this->getPhpExtensionDir() . DIRECTORY_SEPARATOR . $extensionLib);
}
/**
* @param string $extension Extension name (without .so, .dll, or "php_" prefix)
* @return bool Whether the extension is built in PHP
* @throws RuntimeException
*/
public function isExtensionBuiltIn($extension)
{
if (!isset($this->builtInExtensions[$extension])) {
$this->builtInExtensions[$extension] = (bool)$this->executeCommand("echo extension_loaded('$extension') ? 1 : 0;", '-n');
}
return $this->builtInExtensions[$extension];
}
/**
* @param string $extension Extension name (without .so, .dll, or "php_" prefix)
* @return bool|null
* <ul>
* <li>true: built in PHP,</li>
* <li>false: available,</li>
* <li>null: not available (not detected).</li>
* </ul>
*/
public function getExtensionStatus($extension)
{
if (!array_key_exists($extension, $this->extensionStatuses)) {
if ($this->isExtensionBuiltIn($extension)) {
$this->extensionStatuses[$extension] = true;
} elseif ($this->isExtensionAvailable($extension)) {
$this->extensionStatuses[$extension] = false;
} else {
$this->extensionStatuses[$extension] = null;
}
}
return $this->extensionStatuses[$extension];
}
/**
* @param string $file Path to file to lint
* @return bool Whether the PHP syntax of the file is okay
*/
public function isValidPhpFile($file)
{
$exec = sprintf(
'%s -l %s',
$this->phpShell,
$this->escapePath($file)
);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
return (0 === $resultCode);
}
}

View File

@@ -0,0 +1,255 @@
<?php
/**
* Helper class to execute TCPDF test
*
* @author Philippe Jausions
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
class TestExecutor
{
/**
* @var PhpExecutor
*/
private $phpExecutor;
/**
* @var string
*/
private $tempDir;
/**
* @var string
*/
private $testsDir;
/**
* @var string
*/
private $cliOptions = null;
/**
* @var string
*/
private $cliExtensionOptions = null;
/**
* @var string[]
*/
private $extensionsToLoad;
/**
* @var PdfTools
*/
private $pdfTools;
/**
* @var bool
*/
private $verbose;
/**
* @param PhpExecutor $phpExecutor
* @param array $extensionsToLoad
* @param PdfTools $pdfTools
* @param string $tempDir Path to tho temporary folder
* @param string $testsDir Path to this folder
* @param bool $verbose
*/
public function __construct(
PhpExecutor $phpExecutor,
array $extensionsToLoad,
PdfTools $pdfTools,
$tempDir,
$testsDir,
$verbose = false
) {
$this->phpExecutor = $phpExecutor;
$this->tempDir = $tempDir;
$this->testsDir = $testsDir;
$this->extensionsToLoad = $extensionsToLoad;
$this->pdfTools = $pdfTools;
$this->verbose = $verbose;
}
/**
* @return string[]
*/
private function extensionsToLoad()
{
$toLoad = array();
foreach ($this->extensionsToLoad as $extension) {
// "false" means "not built-in but available"
if ($this->phpExecutor->getExtensionStatus($extension) === false) {
$toLoad[] = $extension;
}
}
return $toLoad;
}
/**
* @param string $file Path of PHP file to execute
* @param string $outputFile Path to output file
* @param string $outputFileError Path to output file error
* @return bool TRUE if successful, FALSE otherwise
*/
public function execute(
$file,
$outputFile,
$outputFileError
) {
$exec = implode(' ', array(
(string)$this->phpExecutor,
$this->getPhpCliOptions(),
'-f ' . escapeshellarg($file),
'1> ' . escapeshellarg($outputFile),
'2> ' . escapeshellarg($outputFileError)
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
return (0 === $resultCode);
}
/**
* @param string $file
* @return bool
*/
public function assertIsPhpValidFile($file)
{
return $this->phpExecutor->isValidPhpFile($file);
}
/**
* @param string $outputFile Path to output file
* @return bool
*/
private function isPdfFile($outputFile)
{
return $this->pdfTools->isPdf($outputFile);
}
/**
* @param string $outputFile Path to output file
* @param string $outputFileError Path to error file
* @param string $type Expected type of output
* @param bool $preservingFiles
* @return bool
*/
public function assertIsFileType(
$outputFile,
$outputFileError,
$type,
$preservingFiles
) {
$valid = false;
$expectedHead = array(
'PDF' => '%PDF',
'PNG' => chr(0x89) . chr(0x50) . chr(0x4e) . chr(0x47),
'HTML' => '<div ',
'SVG' => '<?xml version="1.0" standalone="no"?>',
);
$error = file_get_contents($outputFileError);
$outputHead = file_get_contents($outputFile, false, null, 0, strlen($expectedHead[$type]));
if ($error || '' === $outputHead || false === $outputHead) {
echo " Output: NOT $type FILE" . PHP_EOL;
if ($preservingFiles) {
echo ' Output file: ' . $outputFile . PHP_EOL;
echo ' Output error file: ' . $outputFileError . PHP_EOL;
}
echo ' Logs:' . PHP_EOL;
echo '---------------------------' . PHP_EOL;
echo $error . PHP_EOL;
echo '---------------------------' . PHP_EOL;
} elseif ($expectedHead[$type] !== $outputHead) {
echo " Output: NOT $type FILE" . PHP_EOL;
if ($preservingFiles) {
echo ' Output file: ' . $outputFile . PHP_EOL;
}
echo ' Logs:' . PHP_EOL;
echo '---------------------------' . PHP_EOL;
// cut before the output starts and destroys the final logs
$output = file_get_contents($outputFile);
$headMarker = strpos($output, $expectedHead[$type]);
if (false !== $headMarker) {
echo substr($output, 0, $headMarker) . PHP_EOL;
} else {
echo $output . PHP_EOL;
}
echo '---------------------------' . PHP_EOL;
} elseif ('PDF' === $type && !$this->isPdfFile($outputFile)) {
echo " Output: NOT PDF FILE" . PHP_EOL;
if ($preservingFiles) {
echo ' Output file: ' . $outputFile . PHP_EOL;
}
} else {
$valid = true;
echo " Output: $type" . PHP_EOL;
if ($preservingFiles) {
echo ' Output file: ' . $outputFile . PHP_EOL;
}
}
return $valid;
}
/**
* @return string
*/
private function getPhpExtensionCliOptions()
{
if (null === $this->cliExtensionOptions) {
$extensions = array();
foreach ($this->extensionsToLoad() as $extension) {
$extensions[] = '-d extension=' . $this->phpExecutor->makePhpExtensionFileName($extension);
}
$this->cliExtensionOptions = implode(' ', $extensions);
}
return $this->cliExtensionOptions;
}
/**
* @return string
*/
private function getPhpCliOptions()
{
if (null === $this->cliOptions) {
// Some examples load a bit more into memory (this is why the limit is set to 1G)
// Avoid side effects on classes installed on the system, set include_path to
// a folder without php classes (include_path)
$extensionDir = $this->phpExecutor->makeCliOption(
'extension_dir',
$this->phpExecutor->getPhpExtensionDir()
);
$includePath = $this->phpExecutor->makeCliOption(
'include_path',
$this->tempDir
);
$autoPrependFile = $this->phpExecutor->makeCliOption(
'auto_prepend_file',
$this->testsDir . 'coverage.php'
);
$this->cliOptions = implode(' ', array(
'-n',
'-d date.timezone=UTC',
'-d display_errors=on',
'-d error_reporting=-1',
'-d memory_limit=1G',
$includePath,
$extensionDir,
$this->getPhpExtensionCliOptions(),
$autoPrependFile,
));
}
return $this->cliOptions;
}
}

View File

@@ -0,0 +1,379 @@
<?php
/**
* Helper class to execute the TCPDF test suite
*
* @author Philippe Jausions
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
class TestRunner
{
/**
* @var string
*/
private $exampleDir;
/**
* @var TestExecutor
*/
private $testExecutor;
/**
* @var string[]
*/
private $excludedFiles;
/**
* @var bool
*/
private $preserveFiles = false;
/**
* @var array
*/
private $failed = array();
/**
* @var array
*/
private $generatedFiles = array();
/**
* @var array
*/
private $ignored = array();
/**
* @var array|null
*/
private $onlyFiles = null;
/**
* Test count
* @var int
*/
private $count;
/**
* @var array
*/
private $stopOn = array();
/**
* @var int|null
*/
private $runTime = null;
/**
* @var array|null
*/
private $groups = null;
public function __construct($exampleDir)
{
$this->exampleDir = rtrim($exampleDir, '/\\') . DIRECTORY_SEPARATOR;
}
/**
* @param TestExecutor $testExecutor
* @return $this
*/
public function withTestExecutor(TestExecutor $testExecutor)
{
$this->testExecutor = $testExecutor;
return $this;
}
/**
* @param bool $preserve
* @return $this
*/
public function preserveOutputFiles($preserve = true)
{
$this->preserveFiles = (bool)$preserve;
return $this;
}
/**
* @param array $excluded
* @return $this
*/
public function excludeTests(array $excluded)
{
$this->excludedFiles = $excluded;
return $this;
}
/**
* @param array $files
* @return $this
*/
public function only(array $files)
{
$this->onlyFiles = empty($files) ? null : $files;
return $this;
}
/**
* @param array $groups
* @return $this
*/
public function filterByGroup(array $groups)
{
$this->groups = (empty($groups)) ? null : $groups;
return $this;
}
/**
* @param string[] $conditions
* @return $this
*/
public function stopOn(array $conditions)
{
$this->stopOn = $conditions;
return $this;
}
/**
* @param string $condition
* @return bool
*/
private function shouldStopOn($condition)
{
if (in_array('defect', $this->stopOn, true)) {
return true;
}
if (in_array($condition, $this->stopOn, true)) {
return true;
}
return false;
}
/**
* @return string[]
*/
public function getTestFiles()
{
chdir($this->exampleDir);
$exampleFiles = array_flip(glob('example*.php'));
$exampleFiles = array_flip($exampleFiles);
$exampleBarcodeFiles = glob('barcodes/example*.php');
$files = array();
foreach ($exampleFiles as $exampleFile) {
$files[$exampleFile] = 'PDF';
}
foreach ($exampleBarcodeFiles as $exampleFile) {
$type = preg_replace('/^.+(html|png|svgi?)$/', '\1', basename($exampleFile, '.php'));
if ('svgi' === $type) {
$files[$exampleFile] = 'SVG';
} else {
$files[$exampleFile] = strtoupper($type);
}
}
if (null !== $this->onlyFiles) {
foreach ($files as $file => $type) {
if (!in_array($file, $this->onlyFiles, true)) {
unset($files[$file]);
}
}
}
if (null !== $this->groups) {
$regExp = '/\*\s*@group\s+(' . implode('|', $this->groups) . ')\s/';
foreach ($files as $file => $type) {
$source = file_get_contents($file);
if (!preg_match($regExp, $source)) {
unset($files[$file]);
}
}
}
return $files;
}
/**
* @param string $outputDir Path to output folder
* @return bool TRUE if all tests passed, FALSE otherwise
*/
public function runTests($outputDir)
{
if (!isset($this->testExecutor)) {
throw new \RuntimeException("Test executor is missing. Did you forget to call withTestExecutor()?");
}
$this->runTime = null;
$startTime = time();
$outputFolder = rtrim($outputDir, '/\\') . DIRECTORY_SEPARATOR;
chdir($this->exampleDir);
$this->failed = array();
$this->ignored = array();
$this->generatedFiles = array();
$this->count = 0;
foreach ($this->getTestFiles() as $file => $type) {
++$this->count;
echo 'File: ' . $file . PHP_EOL;
if (in_array($file, $this->excludedFiles, true)) {
echo ' Run: SKIPPED' . PHP_EOL;
$this->ignored[] = $file;
continue;
}
if (!$this->testExecutor->assertIsPhpValidFile($this->exampleDir . $file)) {
echo ' Lint: FAILED' . PHP_EOL;
$this->failed[] = $file;
if ($this->shouldStopOn('failure')) {
break;
}
continue;
}
echo ' Lint: PASSED' . PHP_EOL;
if (!$this->preserveFiles) {
$outputFile = $outputFolder . 'output.pdf';
$outputFileError = $outputFolder . 'errors.txt';
} else {
$baseName = $outputFolder . basename($file, '.php');
$outputFile = $baseName . '.output.' . strtolower($type);
$outputFileError = $baseName . '.errors.txt';
}
$this->generatedFiles[$outputFile] = $file;
$this->generatedFiles[$outputFileError] = $file;
$isSuccess = $this->testExecutor->execute(
$this->exampleDir . $file,
$outputFile,
$outputFileError
);
if (!$isSuccess) {
echo ' Run: FAILED' . PHP_EOL;
$this->failed[] = $file;
$this->testExecutor->assertIsFileType(
$outputFile,
$outputFileError,
$type,
$this->preserveFiles
);
if ($this->shouldStopOn('failure')) {
break;
}
} else {
echo ' Run: PASSED' . PHP_EOL;
$isFileType = $this->testExecutor->assertIsFileType(
$outputFile,
$outputFileError,
$type,
$this->preserveFiles
);
if (!$isFileType) {
$this->failed[] = $file;
if ($this->shouldStopOn('failure')) {
break;
}
}
}
}
$this->runTime = time() - $startTime;
$this->cleanUp();
return empty($this->failed);
}
/**
* @return string[]
*/
public function getFailedTests()
{
return $this->failed;
}
/**
* @return string[]
*/
public function getGeneratedFiles()
{
return array_keys($this->generatedFiles);
}
/**
* @return string[]
*/
public function getSkippedTests()
{
return $this->ignored;
}
/**
* @return int
*/
public function getTotalTestCount()
{
return $this->count;
}
/**
* Get last run time in seconds
* @return int|null
*/
public function getRunTime()
{
return $this->runTime;
}
/**
* @return void
*/
private function cleanUp()
{
if ($this->preserveFiles) {
echo 'Generated files remaining on disk: ' . count($this->generatedFiles) . PHP_EOL;
return;
}
foreach ($this->getGeneratedFiles() as $generatedFile) {
if (file_exists($generatedFile)) {
unlink($generatedFile);
}
}
}
/**
* Outputs a summary of the last test suite run
* @return $this
*/
public function printSummary()
{
$failed = $this->getFailedTests();
$ignored = $this->getSkippedTests();
$failedCount = count($failed);
$ignoredCount = count($ignored);
if ($failedCount === 0) {
echo 'Test suite: PASSED' . PHP_EOL;
} else {
echo 'Test suite: FAILED' . PHP_EOL;
}
echo ' Runtime: ' . $this->getRunTime() . 's' . PHP_EOL;
echo ' Total tests: ' . $this->getTotalTestCount() . PHP_EOL;
if ($ignoredCount > 0) {
echo ' SKipped tests: ' . $ignoredCount . PHP_EOL;
foreach ($ignored as $ignoredFile) {
echo ' ' . $ignoredFile . PHP_EOL;
}
}
if ($failedCount > 0) {
echo ' Failed tests: ' . $failedCount . PHP_EOL;
foreach ($failed as $failedFile) {
echo ' ' . $failedFile . PHP_EOL;
}
}
return $this;
}
}