From f815fbe5fcc805844186814768edeb6842d395ec Mon Sep 17 00:00:00 2001 From: Llewellyn van der Merwe Date: Sun, 11 Feb 2024 18:31:39 +0200 Subject: [PATCH] Update to v6.6.5 --- .gitattributes | 6 - .gitignore | 6 - CHANGELOG.TXT | 20 ++ LICENSE.TXT | 2 +- README.md | 7 +- README.txt | 7 +- VERSION | 2 +- composer.json | 4 +- include/barcodes/qrcode.php | 1 + include/tcpdf_fonts.php | 50 ++-- include/tcpdf_static.php | 10 +- phpstan.neon.dist | 33 --- scripts/doctum.php | 34 --- tcpdf.php | 28 ++- tcpdf.xml | 6 +- tcpdf_barcodes_1d.php | 6 +- tests/.gitignore | 5 - tests/compare_runs.php | 471 ------------------------------------ tests/composer.json | 36 --- tests/coverage.php | 66 ----- tests/launch.php | 279 --------------------- tests/launch.sh | 198 --------------- tests/src/ImageMagick.php | 107 -------- tests/src/PdfTools.php | 198 --------------- tests/src/PhpExecutor.php | 281 --------------------- tests/src/TestExecutor.php | 255 ------------------- tests/src/TestRunner.php | 379 ----------------------------- updates/extension.xml | 18 +- 28 files changed, 103 insertions(+), 2412 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .gitignore delete mode 100644 phpstan.neon.dist delete mode 100644 scripts/doctum.php delete mode 100644 tests/.gitignore delete mode 100644 tests/compare_runs.php delete mode 100644 tests/composer.json delete mode 100644 tests/coverage.php delete mode 100644 tests/launch.php delete mode 100755 tests/launch.sh delete mode 100644 tests/src/ImageMagick.php delete mode 100644 tests/src/PdfTools.php delete mode 100644 tests/src/PhpExecutor.php delete mode 100644 tests/src/TestExecutor.php delete mode 100644 tests/src/TestRunner.php diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 9e509a5..0000000 --- a/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -/.github export-ignore -/.gitignore export-ignore -/.gitattributes export-ignore -/tests export-ignore -/scripts export-ignore -/phpstan.neon.dist export-ignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 97ebb12..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.idea -.phpdoc -*.bak -/vendor/ -/composer.lock -/composer.phar diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 39970db..efd3b52 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,3 +1,23 @@ +6.6.5 (2023-09-06) + - Fix corrupted file. + +6.6.4 (2023-09-06) + - Fix GitHub automation tests. + +6.6.3 (2023-09-06) + - Fix SPDX license ID (#591) + - Fix warning "array offset on value of type null" (#620) + - Improve the README about the status of this library (#589) + - Fix deprecation warning with PHP 8.1 (#614) + - Fixes for PHP 8.2 in tcpdf_fonts.php (#632) + - Fix some php 8+ edge cases (#630) + - Fix composite glyph output (#581) + - Fix "access array offset on value of type bool" with PDF/A (#583) + - Fix non-numeric value warning (#627) + - Fix issues with S25 barcode (#611) + - Fix return type annotations (#613) + - Fix some inconsistencies in type hints (#598) + 6.6.2 (2022-12-17) - Ensure pregSplit return type is always array. - Add ability to run tests on various operating systems (#566) diff --git a/LICENSE.TXT b/LICENSE.TXT index ec191e2..072e73a 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -7,7 +7,7 @@ published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - 2002-2022 Nicola Asuni - Tecnick.com LTD + 2002-2023 Nicola Asuni - Tecnick.com LTD ********************************************************************** ********************************************************************** diff --git a/README.md b/README.md index 1b1cd33..42a30a7 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ __If you already know how to use TCPDF and you need it for a Joomla! project, th TCPDF is a PHP class for generating PDF files on-the-fly without requiring external extensions. This library includes also a class to extract data from existing PDF documents and classes to generate 1D and 2D barcodes in various formats. +## NOTE +A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this library is in support only mode. + ## Main Features: * no external libraries are required for the basic functions; * all standard page formats, custom page formats, custom margins and units of measure; @@ -63,7 +66,7 @@ https://packages.debian.org/source/stable/icc-profiles-free * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2022 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2023 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF @@ -72,7 +75,7 @@ https://packages.debian.org/source/stable/icc-profiles-free * Nicola Asuni -> Compiled into an installer for Joomla 3 by [Llewellyn van der Merwe](mailto:joomla@vdm.io) at [Vast Development Method](https://www.vdm.io/) +> Compiled into an installer for Joomla 3|4|5 by [Llewellyn van der Merwe](mailto:joomla@vdm.io) at [Vast Development Method](https://www.vdm.io/) # Usage in Joomla (PHP) ```php diff --git a/README.txt b/README.txt index cf84322..39ea1c4 100644 --- a/README.txt +++ b/README.txt @@ -6,15 +6,14 @@ * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2022 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2023 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF -## IMPORTANT -A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this version will not receive any additional development or support. -This version should be considered obsolete, new projects should use the new version as soon it will become stable. +## NOTE +A new version of this library is under development at https://github.com/tecnickcom/tc-lib-pdf and as a consequence this library is in support only mode. diff --git a/VERSION b/VERSION index 28179fc..5dbe61b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.6.2 +6.6.5 diff --git a/composer.json b/composer.json index f06c733..f24d581 100644 --- a/composer.json +++ b/composer.json @@ -12,8 +12,8 @@ "barcodes" ], "homepage": "http://www.tcpdf.org/", - "version": "6.6.2", - "license": "LGPL-3.0-only", + "version": "6.6.5", + "license": "LGPL-3.0-or-later", "authors": [ { "name": "Nicola Asuni", diff --git a/include/barcodes/qrcode.php b/include/barcodes/qrcode.php index 322cace..1a64a4c 100644 --- a/include/barcodes/qrcode.php +++ b/include/barcodes/qrcode.php @@ -888,6 +888,7 @@ class QRcode { if ($col >= $this->rsblocks[0]['dataLength']) { $row += $this->b1; } + $row = (int) $row; $ret = $this->rsblocks[$row]['data'][$col]; } elseif ($this->count < $this->dataLength + $this->eccLength) { $row = ($this->count - $this->dataLength) % $this->blocks; diff --git a/include/tcpdf_fonts.php b/include/tcpdf_fonts.php index 30053d3..a71c84b 100644 --- a/include/tcpdf_fonts.php +++ b/include/tcpdf_fonts.php @@ -1323,43 +1323,43 @@ class TCPDF_FONTS { // set the checkSumAdjustment to 0 $table[$tag]['data'] = substr($table[$tag]['data'], 0, 8)."\x0\x0\x0\x0".substr($table[$tag]['data'], 12); } - $pad = 4 - ($table[$tag]['length'] % 4); - if ($pad != 4) { - // the length of a table must be a multiple of four bytes - $table[$tag]['length'] += $pad; - $table[$tag]['data'] .= str_repeat("\x0", $pad); - } $table[$tag]['offset'] = $offset; $offset += $table[$tag]['length']; + $numPad = ($offset + 3 & ~3) - $offset; + if($numPad > 0) { + $table[$tag]['data'] .= str_repeat("\x0", $numPad); + $offset += $numPad; + } // check sum is not changed (so keep the following line commented) - //$table[$tag]['checkSum'] = self::_getTTFtableChecksum($table[$tag]['data'], $table[$tag]['length']); + //$table[$tag]['checkSum'] = self::_getTTFtableChecksum($table[$tag]['data'], $table[$tag]['length'] + $numPad); } else { unset($table[$tag]); } } // add loca + $table['loca'] = array(); $table['loca']['data'] = $loca; $table['loca']['length'] = strlen($loca); - $pad = 4 - ($table['loca']['length'] % 4); - if ($pad != 4) { - // the length of a table must be a multiple of four bytes - $table['loca']['length'] += $pad; - $table['loca']['data'] .= str_repeat("\x0", $pad); - } $table['loca']['offset'] = $offset; - $table['loca']['checkSum'] = self::_getTTFtableChecksum($table['loca']['data'], $table['loca']['length']); $offset += $table['loca']['length']; + $numPad = ($offset + 3 & ~3) - $offset; + if($numPad > 0) { + $table['loca']['data'] .= str_repeat("\x0", $numPad); + $offset += $numPad; + } + $table['loca']['checkSum'] = self::_getTTFtableChecksum($table['loca']['data'], $table['loca']['length'] + $numPad); // add glyf + $table['glyf'] = array(); $table['glyf']['data'] = $glyf; $table['glyf']['length'] = strlen($glyf); - $pad = 4 - ($table['glyf']['length'] % 4); - if ($pad != 4) { - // the length of a table must be a multiple of four bytes - $table['glyf']['length'] += $pad; - $table['glyf']['data'] .= str_repeat("\x0", $pad); - } $table['glyf']['offset'] = $offset; - $table['glyf']['checkSum'] = self::_getTTFtableChecksum($table['glyf']['data'], $table['glyf']['length']); + $offset += $table['glyf']['length']; + $numPad = ($offset + 3 & ~3) - $offset; + if($numPad > 0) { + $table['glyf']['data'] .= str_repeat("\x0", $numPad); + $offset += $numPad; + } + $table['glyf']['checkSum'] = self::_getTTFtableChecksum($table['glyf']['data'], $table['glyf']['length'] + $numPad); // rebuild font $font = ''; $font .= pack('N', 0x10000); // sfnt version @@ -1383,7 +1383,7 @@ class TCPDF_FONTS { } // set checkSumAdjustment on head table $checkSumAdjustment = 0xB1B0AFBA - self::_getTTFtableChecksum($font, strlen($font)); - $font = substr($font, 0, $table['head']['offset'] + 8).pack('N', $checkSumAdjustment).substr($font, $table['head']['offset'] + 12); + $font = substr($font, 0, $table['head']['offset'] + $offset + 8).pack('N', $checkSumAdjustment).substr($font, $table['head']['offset'] + $offset + 12); return $font; } @@ -1780,9 +1780,9 @@ class TCPDF_FONTS { */ public static function UTF8ArrayToUniArray($ta, $isunicode=true) { if ($isunicode) { - return array_map(array('TCPDF_FONTS', 'unichrUnicode'), $ta); + return array_map(get_called_class().'::unichrUnicode', $ta); } - return array_map(array('TCPDF_FONTS', 'unichrASCII'), $ta); + return array_map(get_called_class().'::unichrASCII', $ta); } /** @@ -2002,7 +2002,7 @@ class TCPDF_FONTS { if ($isunicode) { // requires PCRE unicode support turned on $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY); - $carr = array_map(array('TCPDF_FONTS', 'uniord'), $chars); + $carr = array_map(get_called_class().'::uniord', $chars); } else { $chars = str_split($str); $carr = array_map('ord', $chars); diff --git a/include/tcpdf_static.php b/include/tcpdf_static.php index 5700655..4c28850 100644 --- a/include/tcpdf_static.php +++ b/include/tcpdf_static.php @@ -3,11 +3,11 @@ // File name : tcpdf_static.php // Version : 1.1.4 // Begin : 2002-08-03 -// Last Update : 2022-08-12 +// Last Update : 2023-09-06 // Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com // License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html) // ------------------------------------------------------------------- -// Copyright (C) 2002-2022 Nicola Asuni - Tecnick.com LTD +// Copyright (C) 2002-2023 Nicola Asuni - Tecnick.com LTD // // This file is part of TCPDF software library. // @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.6.2'; + private static $tcpdf_version = '6.6.5'; /** * String alias for total number of pages. @@ -1780,7 +1780,7 @@ class TCPDF_STATIC { if ($ret === false) { return array(); } - return $ret; + return is_array($ret) ? $ret : array(); } // preg_split is bugged - try alternative solution $ret = array(); @@ -2124,7 +2124,7 @@ class TCPDF_STATIC { * Array of page formats * measures are calculated in this way: (inches * 72) or (millimeters * 72 / 25.4) * @public static - * + * * @var array */ public static $page_formats = array( diff --git a/phpstan.neon.dist b/phpstan.neon.dist deleted file mode 100644 index a5e7a43..0000000 --- a/phpstan.neon.dist +++ /dev/null @@ -1,33 +0,0 @@ -parameters: - level: 1 - paths: - - ./ - excludePaths: - - vendor/ - # remove once https://github.com/phpstan/phpstan/issues/7955 is fixed - - fonts/ - - tests/ - - scanFiles: - - tcpdf_autoconfig.php - - ignoreErrors: - - '~^Constant (PDF_HEADER_LOGO|K_PATH_CACHE|K_PATH_FONTS|K_PATH_IMAGES|K_PATH_URL) not found\.$~' - - '~^Constructor of class TCPDF has an unused parameter \$diskcache\.$~' - - '~^Variable \$\w+ might not be defined\.$~' - - '~^Method TCPDF(_FILTERS)?::\w+\(\) should return .+ but return statement is missing\.$~' - - # mcrypt does not support PHP 7.2 or later - - - message: '~^(Constant MCRYPT_RIJNDAEL_128 not found\.|Function mcrypt_get_cipher_name not found\.)$~' - path: tcpdf.php - count: 2 - - - message: '~^(Constant (MCRYPT_ARCFOUR|MCRYPT_MODE_CBC|MCRYPT_MODE_STREAM|MCRYPT_RAND|MCRYPT_RIJNDAEL_128) not found\.|Function (mcrypt_create_iv|mcrypt_encrypt|mcrypt_get_iv_size) not found\.)$~' - path: include/tcpdf_static.php - count: 16 - - - - message: '~^(Call to static method create\(\) on an unknown class Symfony\\Component\\Finder\\Finder\.|Instantiated class Doctum\\(Doctum|RemoteRepository\\GitHubRemoteRepository) not found\.)$~' - path: scripts/doctum.php - count: 3 diff --git a/scripts/doctum.php b/scripts/doctum.php deleted file mode 100644 index 4a9c98b..0000000 --- a/scripts/doctum.php +++ /dev/null @@ -1,34 +0,0 @@ -files() - ->name('*.php') - ->notPath('cache') - ->notPath('build') - ->notPath('fonts') - ->notPath('vendor') - ->notPath('tests') - ->notPath('examples') - ->in($rootDir); - -return new Doctum($iterator, [ - 'title' => 'TCPDF', - 'build_dir' => $rootDir . '/build', - 'cache_dir' => $rootDir . '/cache', - 'source_dir' => $rootDir, - 'remote_repository' => new GitHubRemoteRepository('tecnickcom/TCPDF', $rootDir), - 'footer_link' => [ - 'href' => 'https://github.com/tecnickcom/TCPDF#readme', - 'rel' => 'noreferrer noopener', - 'target' => '_blank', - 'before_text' => 'This documentation is for', - 'link_text' => 'TCPDF', - 'after_text' => 'the PHP library to build PDFs.', - ], -]); diff --git a/tcpdf.php b/tcpdf.php index 667b004..cd02051 100644 --- a/tcpdf.php +++ b/tcpdf.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @author Nicola Asuni - * @version 6.6.2 + * @version 6.6.5 */ // TCPDF configuration @@ -128,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php'); * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.
* @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 6.6.2 + * @version 6.6.5 * @author Nicola Asuni - info@tecnick.com * @IgnoreAnnotation("protected") * @IgnoreAnnotation("public") @@ -574,12 +574,14 @@ class TCPDF { /** * Minimum distance between header and top page margin. * @protected + * @var float */ protected $header_margin; /** * Minimum distance between footer and bottom page margin. * @protected + * @var float */ protected $footer_margin; @@ -2461,7 +2463,7 @@ class TCPDF { */ public function getCellHeight($fontsize, $padding=TRUE) { $height = ($fontsize * $this->cell_height_ratio); - if ($padding) { + if ($padding && !empty($this->cell_padding)) { $height += ($this->cell_padding['T'] + $this->cell_padding['B']); } return round($height, 6); @@ -3372,7 +3374,7 @@ class TCPDF { /** * Set header margin. * (minimum distance between header and top page margin) - * @param int $hm distance in user units + * @param float $hm distance in user units * @public */ public function setHeaderMargin($hm=10) { @@ -3392,7 +3394,7 @@ class TCPDF { /** * Set footer margin. * (minimum distance between footer and bottom page margin) - * @param int $fm distance in user units + * @param float $fm distance in user units * @public */ public function setFooterMargin($fm=10) { @@ -4102,6 +4104,7 @@ class TCPDF { * @param float $fontsize Font size in points. The default value is the current size. * @param boolean $getarray if true returns an array of characters widths, if false returns the total length. * @return float[]|float total string length or array of characted widths + * @phpstan-return ($getarray is true ? float[] : float) total string length or array of characted widths * @author Nicola Asuni * @public * @since 1.2 @@ -4118,6 +4121,7 @@ class TCPDF { * @param float $fontsize Font size in points. The default value is the current size. * @param boolean $getarray if true returns an array of characters widths, if false returns the total length. * @return float[]|float total string length or array of characted widths + * @phpstan-return ($getarray is true ? float[] : float) total string length or array of characted widths * @author Nicola Asuni * @public * @since 2.4.000 (2008-03-06) @@ -6409,7 +6413,7 @@ class TCPDF { // calculate maximum width for a single character on string $chrw = $this->GetArrStringWidth($chars, '', '', 0, true); array_walk($chrw, array($this, 'getRawCharWidth')); - $maxchwidth = max($chrw); + $maxchwidth = ((is_array($chrw) || $chrw instanceof Countable) && count($chrw) > 0) ? max($chrw) : 0; // get array of chars $uchars = TCPDF_FONTS::UTF8ArrayToUniArray($chars, $this->isunicode); // get the number of characters @@ -6872,6 +6876,8 @@ class TCPDF { } // resize the block to be contained on the remaining available page or column space if ($fitonpage) { + // fallback to avoid division by zero + $h = $h == 0 ? 1 : $h; $ratio_wh = ($w / $h); if (($y + $h) > $this->PageBreakTrigger) { $h = $this->PageBreakTrigger - $y; @@ -9925,7 +9931,7 @@ class TCPDF { } $out .= ' >> >>'; } - $font = $this->getFontBuffer('helvetica'); + $font = $this->getFontBuffer((($this->pdfa_mode) ? 'pdfa' : '') .'helvetica'); $out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)'; $out .= ' /Q '.(($this->rtl)?'2':'0'); //$out .= ' /XFA '; @@ -22055,7 +22061,7 @@ Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: public function setTextRenderingMode($stroke=0, $fill=true, $clip=false) { // Ref.: PDF 32000-1:2008 - 9.3.6 Text Rendering Mode // convert text rendering parameters - if ($stroke < 0) { + if ($stroke < 0 || !is_numeric($stroke)) { $stroke = 0; } if ($fill === true) { diff --git a/tcpdf.xml b/tcpdf.xml index 344d139..b2f2446 100644 --- a/tcpdf.xml +++ b/tcpdf.xml @@ -1,5 +1,5 @@ - + TCPDF tcpdf Nicola Asuni @@ -8,7 +8,7 @@ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL info@tecnick.com www.tecnick.com - 6.6.2 + 6.6.5 This is a PHP class for generating PDF documents without requiring external extensions. @@ -23,7 +23,7 @@ tcpdf_import.php tcpdf_parser.php - + http://raw.githubusercontent.com/vdm-io/tcpdf/master/updates/extension.xml diff --git a/tcpdf_barcodes_1d.php b/tcpdf_barcodes_1d.php index 10a79a7..45d3561 100644 --- a/tcpdf_barcodes_1d.php +++ b/tcpdf_barcodes_1d.php @@ -828,7 +828,7 @@ class TCPDFBarcode { $chr['5'] = '11101011101010'; $chr['6'] = '10111011101010'; $chr['7'] = '10101011101110'; - $chr['8'] = '10101110111010'; + $chr['8'] = '11101010111010'; $chr['9'] = '10111010111010'; if ($checksum) { // add checksum @@ -838,7 +838,7 @@ class TCPDFBarcode { // add leading zero if code-length is odd $code = '0'.$code; } - $seq = '11011010'; + $seq = '1110111010'; $clen = strlen($code); for ($i = 0; $i < $clen; ++$i) { $digit = $code[$i]; @@ -848,7 +848,7 @@ class TCPDFBarcode { } $seq .= $chr[$digit]; } - $seq .= '1101011'; + $seq .= '111010111'; $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); return $this->binseq_to_array($seq, $bararray); } diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 862179b..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/composer.lock -/composer.phar -/coverage.lcov -/runs -/vendor diff --git a/tests/compare_runs.php b/tests/compare_runs.php deleted file mode 100644 index d9e804d..0000000 --- a/tests/compare_runs.php +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/env php -] -r referenceDir compareDir' . PHP_EOL; - echo 'Description:' . PHP_EOL; - echo ' Compares 2 runs of the TCPDF test suite.' . PHP_EOL; - echo " PDF files are first converted to PNG images using XpdfReader's `pdftopng` tool" . PHP_EOL; - echo " or using Poppler's `pdftoppm`." . PHP_EOL; - echo " PNG images are compared using ImageMagick's `magick` tool." . PHP_EOL; - echo 'Supported environment variables:' . PHP_EOL; - echo ' PDFINFO_BINARY Path to pdfinfo executable to use.' . PHP_EOL; - echo ' For more information on pdfinfo, visit https://www.xpdfreader.com/' . PHP_EOL; - echo ' or https://poppler.freedesktop.org/' . PHP_EOL; - echo ' PDFTOPNG_BINARY Path to pdftopng executable to use.' . PHP_EOL; - echo ' For more information on pdftopng, visit https://www.xpdfreader.com/' . PHP_EOL; - echo ' PDFTOPPM_BINARY Path to pdftoppm executable to use.' . PHP_EOL; - echo ' For more information on pdftoppm, visit https://poppler.freedesktop.org/' . PHP_EOL; - echo ' MAGICK_BINARY Path to magick executable to use.' . PHP_EOL; - echo ' For more information on magick, visit https://imagemagick.org/' . PHP_EOL; - echo 'Arguments:' . PHP_EOL; - echo ' compareDir' . PHP_EOL; - echo ' Path to the folder containing the results of test run to compare' . PHP_EOL; - echo ' with the reference.' . PHP_EOL; - echo 'Options:' . PHP_EOL; - echo ' -c, --clean-up' . PHP_EOL; - echo ' Clean up generated files. NOT IMPLEMENTED YET.' . PHP_EOL; - echo ' -o , --output-dir=' . PHP_EOL; - echo ' The folder in which files should be generated.' . PHP_EOL; - echo ' Default is to create a folder in the system\'s temporary folder.' . PHP_EOL; - echo ' -r , --reference-dir=' . PHP_EOL; - echo ' Path to the folder containing the results of the test run of reference.' . PHP_EOL; - echo ' If no reference folder is provided, a set will be automatically downloaded.' . PHP_EOL; - echo ' --group=' . PHP_EOL; - echo ' Filter the tests to compare based on the @group annotation present in the file.' . PHP_EOL; - echo ' --stop-on-defect' . PHP_EOL; - echo ' Stop execution upon first difference.' . PHP_EOL; - echo ' -v, --verbose' . PHP_EOL; - echo ' Outputs more information.' . PHP_EOL; - echo ' -h, --help' . PHP_EOL; - echo ' Prints this message.' . PHP_EOL; -} - -if (false === $options - || array_key_exists('h', $options) - || array_key_exists('help', $options)) { - printCompareRunsHelp(); - exit(false === $options ? -1 : 0); -} - -if (!empty($options['o'])) { - $outputDir = $options['o']; -} -if (!empty($options['output-dir'])) { - $outputDir = $options['output-dir']; -} - -if (!empty($options['r'])) { - $referenceDirArg = $options['r']; -} -if (!empty($options['reference-dir'])) { - $referenceDirArg = $options['reference-dir']; -} -if (!isset($referenceDirArg)) { - echo "Please provide the reference folder using the -r or --reference-dir argument." . PHP_EOL; - exit(-1); -} - -// TODO Automate the cleanup of generated files (PNG images from PDF conversion) -if (array_key_exists('c', $options) || array_key_exists('clean-up', $options)) { - $preserveOutputFiles = false; -} elseif (isset($outputDir)) { - $preserveOutputFiles = true; -} else { - $preserveOutputFiles = false; -} - -$stopOnDefect = array_key_exists('stop-on-defect', $options); - -$verbose = array_key_exists('v', $options) || array_key_exists('verbose', $options); - -$groups = array(); -if (!empty($options['group'])) { - if (is_array($options['group'])) { - $groups = $options['group']; - } else { - $groups = explode(',', $options['group']); - } -} - -// Yes, this is a very basic check. -if ($argc < 2) { - echo "Please provide folder path" . PHP_EOL; - exit(-1); -} -$compareDirArg = $argv[$argc - 1]; - -if (!is_dir(realpath($compareDirArg))) { - echo "Could not find folder to compare: $compareDirArg" . PHP_EOL; - exit(-1); -} -// Normalize the folder path to end with a slash -$compareDir = rtrim(realpath($compareDirArg), '/\\') . DIRECTORY_SEPARATOR; - -if (!is_dir(realpath($referenceDirArg))) { - echo "Could not find reference folder: $referenceDirArg" . PHP_EOL; - exit(-1); -} -// Normalize the folder path to end with a slash -$referenceDir = trim(realpath($referenceDirArg), '/\\') . DIRECTORY_SEPARATOR; - -$rootDir = realpath(dirname(__DIR__)) . DIRECTORY_SEPARATOR; -$exampleDir = $rootDir . 'examples' . DIRECTORY_SEPARATOR; - -$isBinaryLocatorAvailable = class_exists('\LocateBinaries\LocateBinaries'); - -$pdfinfo = getenv('PDFINFO_BINARY'); -if (empty($pdfinfo)) { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('pdfinfo') - : array(); - if (empty($paths)) { - echo 'pdfinfo could not be located.' . PHP_EOL; - echo 'Please set the PDFINFO_BINARY environment variable.' . PHP_EOL; - if (!$isBinaryLocatorAvailable) { - echo 'You could install rosell-dk/locate-binaries via composer to detect binaries.' . PHP_EOL; - } - exit(-1); - } - $pdfinfo = reset($paths); -} -$pdftopng = getenv('PDFTOPNG_BINARY'); -if (empty($pdftopng)) { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('pdftopng') - : array(); - if (!empty($paths)) { - $pdftopng = reset($paths); - } -} -$pdftoppm = getenv('PDFTOPPM_BINARY'); -if (empty($pdftoppm)) { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('pdftoppm') - : array(); - if (!empty($paths)) { - $pdftoppm = reset($paths); - } -} -if (empty($pdftopng) && empty($pdftoppm)) { - echo 'pdftopng nor pdftoppm could not be located.' . PHP_EOL; - echo 'Please set the PDFTOPNG_BINARY or PDFTOPPM_BINARY environment variable.' . PHP_EOL; - if (!$isBinaryLocatorAvailable) { - echo 'You could install rosell-dk/locate-binaries via composer to detect binaries.' . PHP_EOL; - } - exit(-1); -} - -$tools = array( - 'pdfinfo' => $pdfinfo, - 'pdftopng' => $pdftopng, - 'pdftoppm' => $pdftoppm, -); -$pdfTools = new PdfTools($tools, $verbose); -echo 'pdfinfo: ' . $pdfinfo . PHP_EOL; -echo 'pdfinfo version: ' . $pdfTools->getPdfinfoVersionInfo() . PHP_EOL; -echo PHP_EOL; -echo 'pdftopng: ' . $pdftopng . PHP_EOL; -echo 'pdftopng version: ' . $pdfTools->getPdftopngVersionInfo() . PHP_EOL; -echo PHP_EOL; - -$magick = getenv('MAGICK_BINARY'); -if (empty($magick)) { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('magick') - : array(); - if (empty($paths)) { - echo 'magick could not be located.' . PHP_EOL; - echo 'Please set the MAGICK_BINARY environment variable.' . PHP_EOL; - if (!$isBinaryLocatorAvailable) { - echo 'You could install rosell-dk/locate-binaries via composer to detect binaries.' . PHP_EOL; - } - exit(-1); - } - $magick = reset($paths); -} -$imagemagick = new ImageMagick($magick, $verbose); -echo 'magick: ' . $magick . PHP_EOL; -echo 'magick version: ' . $imagemagick->getMagickVersionInfo() . PHP_EOL; -echo PHP_EOL; - -$isGeneratedTempDir = false; -if (!isset($outputDir)) { - echo PHP_EOL; - echo "The --output-dir option was not used, a temporary folder will be necessary." . PHP_EOL; - try { - $outputDir = \Cs278\Mktemp\temporaryDir('TCPDF-tests.XXXXXXXXX') . DIRECTORY_SEPARATOR; - } catch (\Exception $e) { - echo $e->getMessage(); - exit(-1); - } - $isGeneratedTempDir = true; -} - -if (!is_dir(realpath($outputDir))) { - echo "Could not find output folder: $outputDir" . PHP_EOL; - exit(-1); -} - -echo "Example folder: $exampleDir" . PHP_EOL; - -$outputDir = realpath($outputDir); -$outputDir = rtrim($outputDir, '/\\') . DIRECTORY_SEPARATOR; -echo "Output folder: $outputDir" . PHP_EOL; -echo PHP_EOL; - -echo 'Comparing folders:' . PHP_EOL; -echo "< $referenceDir" . PHP_EOL; -echo "> $compareDir" . PHP_EOL; - -$separator = '----------------------------------'; - -$testRunner = new TestRunner($exampleDir); - -$differences = array(); -$ignored = array(); -$comparisons = 0; -$bitByBitComparisons = 0; - -$testFiles = $testRunner - ->filterByGroup($groups) - ->getTestFiles() -; -foreach ($testFiles as $file => $type) { - ++$comparisons; - $outputFile = basename($file, '.php') . '.output.' . strtolower($type); - - $outputFile1 = $referenceDir . $outputFile; - $outputFile2 = $compareDir . $outputFile; - - $exists1 = file_exists($outputFile1); - $exists2 = file_exists($outputFile2); - - if (!$exists1 && !$exists2) { - $ignored[] = $file; - continue; - } - if ($exists1 && !$exists2) { - $differences[] = $file . ' (FILE PRESENCE)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< PRESENT' . PHP_EOL; - echo '> MISSING' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - if (!$exists1 && $exists2) { - $differences[] = $file . ' (FILE PRESENCE)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< ABSENT' . PHP_EOL; - echo '> PRESENT' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - - // Exact size comparison is not workable for most of the files - $size1 = filesize($outputFile1); - $size2 = filesize($outputFile2); - if ($size1 === 0 && $size2 > 0) { - $differences[] = $file . ' (FILE SIZE)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< EMPTY' . PHP_EOL; - echo '> HAS CONTENT' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - if ($size1 > 0 && $size2 === 0) { - $differences[] = $file . ' (FILE SIZE)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< HAS CONTENT' . PHP_EOL; - echo '> EMPTY' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - if ($size1 === 0 && $size2 === 0) { - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< EMPTY' . PHP_EOL; - echo '> EMPTY' . PHP_EOL; - continue; - } - - // Can we compare files? - // For now, just some example files are easily comparable. - // (See the @group comparable docBlock annotation) - $examplePHPSource = file_get_contents($exampleDir . $file); - if (strpos($examplePHPSource, '* @group comparable') !== false) { - ++$bitByBitComparisons; - - $pngFiles1 = null; - $pngFiles2 = null; - - if ('PDF' !== $type) { - $hash1 = sha1_file($outputFile1); - $hash2 = sha1_file($outputFile2); - if ($hash1 !== $hash2) { - $differences[] = $file . ' (CONTENT)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< ORIGIN' . PHP_EOL; - echo '> DIFFERENT' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - } - - if ('PNG' === $type) { - $pngFiles1 = array($outputFile1); - $pngFiles2 = array($outputFile2); - } - - // For PDF files, we generate PNG files (one per page) with pdftopng - if ('PDF' === $type) { - // Let's first check there are both valid PDF files - $isPdf1 = $pdfTools->isPdf($outputFile1); - $isPdf2 = $pdfTools->isPdf($outputFile2); - if ($isPdf1 && !$isPdf2) { - $differences[] = $file . ' (CONTENT)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< PDF' . PHP_EOL; - echo '> NOT PDF' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - if (!$isPdf1 && $isPdf2) { - $differences[] = $file . ' (CONTENT)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< NOT PDF' . PHP_EOL; - echo '> PDF' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - if (!$isPdf1 && !$isPdf2) { - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< NOT PDF' . PHP_EOL; - echo '> NOT PDF' . PHP_EOL; - continue; - } - - // Now we convert each page of the PDF into PNG - $conversionDir = $outputDir . basename($file, '.php') . DIRECTORY_SEPARATOR; - $pngFiles1 = $pdfTools->convertToPng($outputFile1, $conversionDir . 'ref'); - $pngFiles2 = $pdfTools->convertToPng($outputFile2, $conversionDir . 'cmp'); - - if (count($pngFiles1) !== count($pngFiles2)) { - $differences[] = $file . ' (CONTENT)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< ' . count($pngFiles1) . ' page(s)' . PHP_EOL; - echo '> ' . count($pngFiles2) . ' page(s)' . PHP_EOL; - if ($stopOnDefect) { - break; - } - continue; - } - } - - if (isset($pngFiles1, $pngFiles2)) { - $pngCount = count($pngFiles1); - for ($i = 0; $i < $pngCount; ++$i) { - if (!$imagemagick->areSimilar($pngFiles1[$i], $pngFiles2[$i])) { - $differences[] = $file . ' (CONTENT)'; - echo $separator . PHP_EOL; - echo $outputFile . PHP_EOL; - echo '< ORIGIN' . PHP_EOL; - echo '> DIFFERENT' . PHP_EOL; - if ($stopOnDefect) { - break 2; - } - continue 2; - } - } - } - } -} - -$passed = empty($differences); -echo PHP_EOL; -if ($passed) { - echo 'Comparison: IDENTICAL' . PHP_EOL; -} else { - echo 'Comparison: DIFFERENCES EXIST' . PHP_EOL; -} -echo " Total tests: $comparisons" . PHP_EOL; - -$ignoredCount = count($ignored); -if ($ignoredCount > 0) { - echo ' Probably skipped tests: ' . $ignoredCount . PHP_EOL; - foreach ($ignored as $ignoredFile) { - echo ' ' . $ignoredFile . PHP_EOL; - } -} - -echo " Exact content comparisons: " . $bitByBitComparisons . PHP_EOL; - -if ($differences) { - echo ' Differences: ' . count($differences) . PHP_EOL; - echo ' Files:' . PHP_EOL; - foreach ($differences as $file) { - echo " $file" . PHP_EOL; - } -} - -$exitCode = (!$passed) ? 1 : 0; -echo 'Exit code: ' . $exitCode . PHP_EOL; -exit($exitCode); diff --git a/tests/composer.json b/tests/composer.json deleted file mode 100644 index 065fcbe..0000000 --- a/tests/composer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "tecnickcom/tcpdf-tests", - "type": "metapackage", - "description": "Dependencies for the test suite", - "keywords": [ - "PDF", - "tcpdf", - "test" - ], - "homepage": "http://www.tcpdf.org/", - "license": "LGPL-3.0-only", - "authors": [ - { - "name": "Philippe Jausions", - "email": "jausions@11abacus.com", - "role": "contributor" - } - ], - "require": { - "PHP": ">=5.3.0", - "cs278/mktemp": "*" - }, - "suggest": { - "rosell-dk/locate-binaries": "Allows to detect executables such as pdfinfo" - }, - "autoload": { - "psr-4": { - "Tecnickcom\\TCPDF\\Tests\\": "src/" - } - }, - "archive": { - "exclude": [ - "/examples" - ] - } -} diff --git a/tests/coverage.php b/tests/coverage.php deleted file mode 100644 index 7c9beb7..0000000 --- a/tests/coverage.php +++ /dev/null @@ -1,66 +0,0 @@ - $coverageForFile) { - $coverageData .= 'SF:' . $file . "\n"; - $coverageData .= 'TN:' . str_replace($rootDir, '', $_SERVER['PHP_SELF']) . "\n"; - foreach ($coverageForFile as $line => $coverageValue) { - $coverageValue = $coverageValue === -1 ? 0 : $coverageValue; - $coverageData .= 'DA:' . $line . ',' . $coverageValue . "\n"; - } - $coverageData .= 'end_of_record' . "\n"; - } - file_put_contents($coverageFile, $coverageData, LOCK_EX | FILE_APPEND); - } - - } - - $a = new CoverageObjectPcov(); -} -if (extension_loaded('xdebug')) { - \xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE); - - class CoverageObjectXdebug - { - - public function __destruct() - { - $rootDir = realpath(__DIR__ . '/../') . '/'; - $coverageFile = $rootDir . 'tests/coverage.lcov'; - $covData = xdebug_get_code_coverage(); - $coverageData = ''; - foreach ($covData as $file => $coverageForFile) { - $coverageData .= 'SF:' . $file . "\n"; - $coverageData .= 'TN:' . str_replace($rootDir, '', $_SERVER['PHP_SELF']) . "\n"; - foreach ($coverageForFile as $line => $coverageValue) { - $coverageValue = $coverageValue > 0 ? $coverageValue : 0; - $coverageData .= 'DA:' . $line . ',' . $coverageValue . "\n"; - } - $coverageData .= 'end_of_record' . "\n"; - } - file_put_contents($coverageFile, $coverageData, LOCK_EX | FILE_APPEND); - \xdebug_stop_code_coverage(true); - } - - } - - $a = new CoverageObjectXdebug(); -} diff --git a/tests/launch.php b/tests/launch.php deleted file mode 100644 index 0ece8cd..0000000 --- a/tests/launch.php +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env php -] [file...]' . PHP_EOL; - echo 'Description:' . PHP_EOL; - echo ' Launches the test suite for Tecnickcom\'s TCPDF.' . PHP_EOL; - echo 'Supported environment variables:' . PHP_EOL; - echo ' PHP_BINARY Path to php executable to use.' . PHP_EOL; - echo ' PDFINFO_BINARY Path to pdfinfo executable to use.' . PHP_EOL; - echo ' For more information on pdfinfo, visit https://www.xpdfreader.com/' . PHP_EOL; - echo 'Arguments:' . PHP_EOL; - echo ' file' . PHP_EOL; - echo ' Test file(s) to run. If not provided all the tests are considered for the run.' . PHP_EOL; - echo ' Usage example:' . PHP_EOL; - echo ' php launch.php example_001.php barcodes/example_1d_html.php' . PHP_EOL; - echo 'Options:' . PHP_EOL; - echo ' -c, --clean-up' . PHP_EOL; - echo ' Clean up generated files.' . PHP_EOL; - echo ' The default is to NOT clean up if the -o option is provided,' . PHP_EOL; - echo ' and to clean up if the -o option is NOT provided.' . PHP_EOL; - echo ' -o , --output-dir=' . PHP_EOL; - echo ' The folder in which files should be generated.' . PHP_EOL; - echo ' Default is to create a folder in the system\'s temporary folder.' . PHP_EOL; - echo ' --group=' . PHP_EOL; - echo ' Filter the tests to run based on the @group annotation present in the file.' . PHP_EOL; - echo ' --stop-on-defect' . PHP_EOL; - echo ' Stop execution upon first not-passed test.' . PHP_EOL; - echo ' -v, --verbose' . PHP_EOL; - echo ' Outputs more information.' . PHP_EOL; - echo ' -h, --help' . PHP_EOL; - echo ' Prints this message.' . PHP_EOL; -} - -if (false === $options - || array_key_exists('h', $options) - || array_key_exists('help', $options)) { - printLaunchHelp(); - exit(false === $options ? -1 : 0); -} - -if (!empty($options['o'])) { - $outputDir = $options['o']; -} -if (!empty($options['output-dir'])) { - $outputDir = $options['output-dir']; -} - -if (array_key_exists('c', $options) || array_key_exists('clean-up', $options)) { - $preserveOutputFiles = false; -} elseif (isset($outputDir)) { - $preserveOutputFiles = true; -} else { - $preserveOutputFiles = false; -} - -$stopOn = array(); -if (array_key_exists('stop-on-defect', $options)) { - $stopOn[] = 'defect'; -} - -$verbose = array_key_exists('v', $options) || array_key_exists('verbose', $options); - -$groups = array(); -if (!empty($options['group'])) { - if (is_array($options['group'])) { - $groups = $options['group']; - } else { - $groups = explode(',', $options['group']); - } -} - -$isBinaryLocatorAvailable = class_exists('\LocateBinaries\LocateBinaries'); - -$pdfinfo = getenv('PDFINFO_BINARY'); -if (empty($pdfinfo)) { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('pdfinfo') - : array(); - if (empty($paths)) { - echo 'pdfinfo could not be located.' . PHP_EOL; - echo 'Please set the PDFINFO_BINARY environment variable.' . PHP_EOL; - if (!$isBinaryLocatorAvailable) { - echo 'You could install rosell-dk/locate-binaries via composer to detect binaries.' . PHP_EOL; - } - exit(-1); - } - $pdfinfo = reset($paths); -} -$pdfTools = new PdfTools(array('pdfinfo' => $pdfinfo), $verbose); -echo 'pdfinfo: ' . $pdfinfo . PHP_EOL; -echo 'pdfinfo version: ' . $pdfTools->getPdfinfoVersionInfo() . PHP_EOL; -echo PHP_EOL; - -// Allows you to use PHP_BINARY=/usr/bin/php5.3 php ./tests/launch.php -$phpBinary = getenv('PHP_BINARY'); -if (empty($phpBinary)) { - // PHP_BINARY only exists since PHP 5.4 - if (defined('PHP_BINARY')) { - $phpBinary = PHP_BINARY; - } else { - $paths = ($isBinaryLocatorAvailable) - ? LocateBinaries::locateInstalledBinaries('php') - : array(); - if (empty($paths)) { - echo 'php could not be located. Please set PHP_BINARY environment variable.' . PHP_EOL; - if (!$isBinaryLocatorAvailable) { - echo 'You could install rosell-dk/locate-binaries via composer to detect binaries.' . PHP_EOL; - } - exit(-1); - } - $phpBinary = reset($paths); - } -} - -$isWindows = (stripos(PHP_OS, 'WIN') === 0); - -$phpExecutor = new PhpExecutor($phpBinary, $verbose); - -echo 'PHP: ' . ((string)$phpExecutor) . PHP_EOL; -echo 'PHP version: ' . $phpExecutor->getPhpVersionInfo() . PHP_EOL; -echo PHP_EOL; - -/** - * Map of extension availability. - * Possible values: - * - true: built in PHP, - * - false: available, - * - null: not available (not detected). - */ -$phpExtensions = array( - 'bcmath' => null, - 'gd' => null, - 'imagick' => null, - 'json' => null, - 'openssl' => null, - 'xml' => null, -); -$phpExtensionDir = $phpExecutor->getPhpExtensionDir(); -echo 'PHP extension folder: ' . $phpExtensionDir . PHP_EOL; -if (strpos($phpExtensionDir, ' ') !== false) { - echo "WARNING: Spaces in extension_dir might cause problems." . PHP_EOL; - if ($isWindows) { - echo " You should use `dir /x` to get the short name of the path," . PHP_EOL; - echo " then adjust the extension_dir option of your php.ini file." . PHP_EOL; - } - if (!in_array('defect', $stopOn, true)) { - $stopOn[] = 'defect'; - echo " --stop-on-defect as been forced to avoid too many failing tests." . PHP_EOL; - } -} -echo 'Extensions:' . PHP_EOL; -foreach ($phpExtensions as $extension => $_) { - $status = $phpExecutor->getExtensionStatus($extension); - $phpExtensions[$extension] = $status; - echo " $extension: "; - if (true === $status) { - echo 'BUILT-IN'; - } elseif (false === $status) { - echo 'AVAILABLE'; - } else { - echo 'NO'; - } - echo PHP_EOL; -} - -if (null === $phpExtensions['gd'] && null === $phpExtensions['imagick']) { - echo 'gd or imagick extension required.' . PHP_EOL; - echo 'Exit code: 1' . PHP_EOL; - exit(1); -} - -if (null === $phpExtensions['openssl']) { - echo 'openssl extension required.' . PHP_EOL; - echo 'Exit code: 1' . PHP_EOL; - exit(1); -} -echo PHP_EOL; - -$rootDir = dirname(realpath(__DIR__)) . DIRECTORY_SEPARATOR; -echo "Root folder: $rootDir" . PHP_EOL; - -$isGeneratedTempDir = false; -if (!isset($outputDir)) { - echo PHP_EOL; - echo "The --output-dir option was not used, a temporary folder will be necessary." . PHP_EOL; - try { - $outputDir = \Cs278\Mktemp\temporaryDir('TCPDF-tests.XXXXXXXXX') . DIRECTORY_SEPARATOR; - } catch (\Exception $e) { - echo $e->getMessage(); - exit(-1); - } - $isGeneratedTempDir = true; -} - -if (!is_dir(realpath($outputDir))) { - echo "Could not find output folder: $outputDir" . PHP_EOL; - exit(-1); -} -$outputDir = realpath($outputDir); -echo "Output folder: $outputDir" . PHP_EOL; -echo PHP_EOL; - -$testsDir = $rootDir . 'tests' . DIRECTORY_SEPARATOR; -echo "Test folder: $testsDir" . PHP_EOL; - -$testExecutor = new TestExecutor( - $phpExecutor, - array_keys($phpExtensions), - $pdfTools, - $outputDir, - $testsDir, - $verbose -); - -// Files that should be excluded from the test suite -$ignored = array( - 'example_006.php', -); - -// Check if the script is run for specific test files -$requestedTests = array(); -foreach (array_reverse($argv) as $value) { - // This is a crude way to work around how getopt() parses arguments to script - if (preg_match('~^(barcodes/)?example_\d[\d_a-z]+\.php$~', $value)) { - $requestedTests[] = $value; - } -} - -$testRunner = new TestRunner($rootDir . 'examples'); -$passed = $testRunner - ->withTestExecutor($testExecutor) - ->preserveOutputFiles($preserveOutputFiles) - ->excludeTests($ignored) - ->only($requestedTests) - ->filterByGroup($groups) - ->stopOn($stopOn) - ->runTests($outputDir) -; - -if (!$preserveOutputFiles && $isGeneratedTempDir) { - rmdir($outputDir); -} - -// Final result -$testRunner->printSummary(); -$exitCode = (!$passed) ? 1 : 0; -echo 'Exit code: ' . $exitCode . PHP_EOL; -exit($exitCode); diff --git a/tests/launch.sh b/tests/launch.sh deleted file mode 100755 index bf24718..0000000 --- a/tests/launch.sh +++ /dev/null @@ -1,198 +0,0 @@ -#!/bin/sh - - -command -v pdfinfo > /dev/null -if [ $? -gt 0 ]; then - echo "pdfinfo could not be found" - echo "On Debian based systems you can run: apt install -y poppler-utils" - exit 1 -fi - -# Only start here, the command checking can exit code > 0 -set -eu - -EXAMPLE_FILES="$(find examples/ -type f -name 'example*.php' \ - -not -path '*/barcodes/*' \ - -not -wholename 'examples/example_006.php' \ - | sort -df)" - -EXAMPLE_BARCODE_FILES="$(find examples/barcodes -type f -name 'example*.php' \ - | sort -df)" - -TEMP_FOLDER="$(mktemp -d /tmp/TCPDF-tests.XXXXXXXXX)" -OUTPUT_FILE="${TEMP_FOLDER}/output.pdf" -OUTPUT_FILE_ERROR="${TEMP_FOLDER}/errors.txt" -# Allows you to use PHP_BINARY="php8.1" ./tests/launch.sh -PHP_BINARY="${PHP_BINARY:-php}" -ROOT_DIR="$(${PHP_BINARY} -r 'echo realpath(__DIR__);')" -TESTS_DIR="${ROOT_DIR}/tests/" - -PHP_EXT_DIR="$(${PHP_BINARY} -r 'echo ini_get("extension_dir");')" - -echo "php extension dir: ${PHP_EXT_DIR}" - -BCMATH_EXT="-d extension=$(find ${PHP_EXT_DIR} -type f -name 'bcmath.so')" -echo "bcmath found at: ${BCMATH_EXT}" - -COVERAGE_EXTENSION="-d extension=pcov.so" -IMAGICK_OR_GD="-dextension=gd.so" -JSON_EXT="-dextension=json.so" -XML_EXT="-dextension=xml.so" -if [ "$(${PHP_BINARY} -r 'echo PHP_MAJOR_VERSION;')" = "5" ];then - X_DEBUG_EXT="$(find ${PHP_EXT_DIR} -type f -name 'xdebug.so' || '')" - echo "Xdebug found at: ${X_DEBUG_EXT}" - # pcov does not exist for PHP 5 - COVERAGE_EXTENSION="-d zend_extension=${X_DEBUG_EXT} -d xdebug.mode=coverage" - - # 5.5, 5.4, 5.3 - if [ "$(${PHP_BINARY} -r 'echo (PHP_MINOR_VERSION < 6) ? "true" : "false";')" = "true" ];then - IMAGICK_OR_GD="-dextension=imagick.so" - fi - -fi - -if [ "$(${PHP_BINARY} -r 'echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;')" = "70" ];then - X_DEBUG_EXT="$(find ${PHP_EXT_DIR} -type f -name 'xdebug.so' || '')" - echo "Xdebug found at: ${X_DEBUG_EXT}" - # pcov does not exist for PHP 7.0 - COVERAGE_EXTENSION="-d zend_extension=${X_DEBUG_EXT} -d xdebug.mode=coverage" -fi - -# PHP >= 8.x.x -if [ "$(${PHP_BINARY} -r 'echo (PHP_MAJOR_VERSION >= 8) ? "true" : "false";')" = "true" ];then - # The json ext is bundled into PHP 8.0 - JSON_EXT="" -fi - -echo "Root folder: ${ROOT_DIR}" -echo "Temporary folder: ${TEMP_FOLDER}" -echo "PHP version: $(${PHP_BINARY} -v)" - -FAILED_FLAG=0 - -cd "${ROOT_DIR}/examples" - -for file in $EXAMPLE_FILES; do - echo "File: $file" - ${PHP_BINARY} -l "${ROOT_DIR}/$file" > /dev/null - if [ $? -eq 0 ]; then - echo "File-lint-passed: $file" - fi - set +e - # 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 wihout php classes (include_path) - ${PHP_BINARY} -n \ - -d include_path="${TEMP_FOLDER}" \ - -d date.timezone=UTC \ - ${IMAGICK_OR_GD} ${COVERAGE_EXTENSION} \ - ${BCMATH_EXT} \ - ${JSON_EXT} \ - ${XML_EXT} \ - -d display_errors=on \ - -d error_reporting=-1 \ - -d memory_limit=1G \ - -d pcov.directory="${ROOT_DIR}" \ - -d auto_prepend_file="${TESTS_DIR}/coverage.php" \ - "${ROOT_DIR}/$file" 1> "${OUTPUT_FILE}" 2> "${OUTPUT_FILE_ERROR}" - set -e - if [ $? -eq 0 ]; then - echo "File-run-passed: $file" - ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" - if [ ! -z "${ERROR_LOGS}" ]; then - FAILED_FLAG=1 - echo "Logs: $file" - echo "---------------------------" - echo "${ERROR_LOGS}" - echo "---------------------------" - fi - if [ $(head -c 4 "${OUTPUT_FILE}") != "%PDF" ]; then - FAILED_FLAG=1 - # cut before the PDF output starts and destroys the final logs - OUT_LOGS="$(cat "${OUTPUT_FILE}" | sed '/%PDF/q')" - echo "Generated-not-a-pdf: $file" - echo "Logs (cut before PDF output eventually starts): $file" - echo "---------------------------" - echo "${OUT_LOGS}" - echo "---------------------------" - continue - fi - pdfinfo "${OUTPUT_FILE}" > /dev/null - if [ $? -gt 0 ]; then - FAILED_FLAG=1 - echo "Generated-invalid-file: $file" - fi - else - FAILED_FLAG=1 - echo "File-run-failed: $file" - ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" - if [ ! -z "${ERROR_LOGS}" ]; then - echo "Logs: $file" - echo "---------------------------" - echo "${ERROR_LOGS}" - echo "---------------------------" - else - # cut before the PDF output starts and destroys the final logs - OUT_LOGS="$(cat "${OUTPUT_FILE}" | sed '/%PDF/q')" - echo "Logs: $file" - echo "---------------------------" - echo "${OUT_LOGS}" - echo "---------------------------" - fi - fi -done - -for file in $EXAMPLE_BARCODE_FILES; do - echo "File: $file" - ${PHP_BINARY} -l "${ROOT_DIR}/$file" > /dev/null - if [ $? -eq 0 ]; then - echo "File-lint-passed: $file" - fi - set +e - # Avoid side effects on classes installed on the system, set include_path to a folder wihout php classes (include_path) - ${PHP_BINARY} -n \ - -d include_path="${TEMP_FOLDER}" \ - -d date.timezone=UTC \ - ${BCMATH_EXT} ${COVERAGE_EXTENSION} \ - -d display_errors=on \ - -d error_reporting=-1 \ - -d pcov.directory="${ROOT_DIR}" \ - -d auto_prepend_file="${TESTS_DIR}/coverage.php" \ - "${ROOT_DIR}/$file" 1> "${OUTPUT_FILE}" 2> "${OUTPUT_FILE_ERROR}" - set -e - if [ $? -eq 0 ]; then - echo "File-run-passed: $file" - ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" - if [ ! -z "${ERROR_LOGS}" ]; then - FAILED_FLAG=1 - echo "Logs: $file" - echo "---------------------------" - echo "${ERROR_LOGS}" - echo "---------------------------" - fi - else - FAILED_FLAG=1 - echo "File-run-failed: $file" - ERROR_LOGS="$(cat "${OUTPUT_FILE_ERROR}")" - if [ ! -z "${ERROR_LOGS}" ]; then - echo "Logs: $file" - echo "---------------------------" - echo "${ERROR_LOGS}" - echo "---------------------------" - fi - # cut before the PDF output starts and destroys the final logs - OUT_LOGS="$(cat "${OUTPUT_FILE}" | sed '/%PDF/q')" - if [ ! -z "${OUT_LOGS}" ]; then - echo "Logs (cut before PDF output eventually starts): $file" - echo "---------------------------" - echo "${OUT_LOGS}" - echo "---------------------------" - fi - fi -done - -cd - > /dev/null - -rm -rf "${TEMP_FOLDER}" - -echo "Exit code: ${FAILED_FLAG}" -exit "${FAILED_FLAG}" diff --git a/tests/src/ImageMagick.php b/tests/src/ImageMagick.php deleted file mode 100644 index 5ba7d2e..0000000 --- a/tests/src/ImageMagick.php +++ /dev/null @@ -1,107 +0,0 @@ -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; - } -} diff --git a/tests/src/PdfTools.php b/tests/src/PdfTools.php deleted file mode 100644 index c63c61a..0000000 --- a/tests/src/PdfTools.php +++ /dev/null @@ -1,198 +0,0 @@ -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 $pngRoot = '/usr/home/TCPDF/compare_runs/my-root', - * the generated PNG files will be as follows: - *
    - *
  • /usr/home/TCPDF/compare_runs/my-root-0000001.png,
  • - *
  • /usr/home/TCPDF/compare_runs/my-root-0000002.png,
  • - *
  • ...
  • - *
- * @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; - } -} diff --git a/tests/src/PhpExecutor.php b/tests/src/PhpExecutor.php deleted file mode 100644 index 838f96e..0000000 --- a/tests/src/PhpExecutor.php +++ /dev/null @@ -1,281 +0,0 @@ -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 - *
    - *
  • true: built in PHP,
  • - *
  • false: available,
  • - *
  • null: not available (not detected).
  • - *
- */ - 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); - } -} diff --git a/tests/src/TestExecutor.php b/tests/src/TestExecutor.php deleted file mode 100644 index 5824b73..0000000 --- a/tests/src/TestExecutor.php +++ /dev/null @@ -1,255 +0,0 @@ -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' => '
'', - ); - - $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; - } -} diff --git a/tests/src/TestRunner.php b/tests/src/TestRunner.php deleted file mode 100644 index 505902e..0000000 --- a/tests/src/TestRunner.php +++ /dev/null @@ -1,379 +0,0 @@ -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; - } -} diff --git a/updates/extension.xml b/updates/extension.xml index 8f6c78a..8dbc38f 100644 --- a/updates/extension.xml +++ b/updates/extension.xml @@ -70,7 +70,7 @@ library site - 6.4.1 + 6.6.2 https://github.com/vdm-io/tcpdf https://github.com/vdm-io/tcpdf/archive/v6.6.2.zip @@ -79,4 +79,20 @@ https://github.com/llewellynvdm + + TCPDF + This is a PHP class for generating PDF documents without requiring external extensions. + tcpdf + library + site + + 6.6.5 + https://github.com/vdm-io/tcpdf + + https://github.com/vdm-io/tcpdf/archive/v6.6.5.zip + + Llewellyn van der Merwe + https://github.com/llewellynvdm + +