mirror of
https://github.com/tecnickcom/TCPDF.git
synced 2025-01-16 13:50:01 +01:00
Add ability to run tests on various operating systems (#566)
Co-authored-by: Philippe Jausions <Philippe.Jausions@11abacus.com> Co-authored-by: Nicola Asuni <nicolaasuni@users.noreply.github.com>
This commit is contained in:
parent
ef356f0bc7
commit
8872a9cdae
2
.github/workflows/lint-docs.yml
vendored
2
.github/workflows/lint-docs.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
lint-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: lint php documentation
|
||||
uses: sudo-bot/action-doctum@dev
|
||||
with:
|
||||
|
94
.github/workflows/tests.yml
vendored
94
.github/workflows/tests.yml
vendored
@ -15,58 +15,116 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version: ["5.3", "5.4", "5.5", "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"]
|
||||
os: [macos-latest, windows-latest]
|
||||
experimental: [false]
|
||||
coverage-extension: [pcov]
|
||||
php-version: ["7.1", "7.2", "7.3", "7.4", "8.0", "8.1"]
|
||||
os: [ubuntu-latest]
|
||||
php-extensions: ["bcmath, imagick, gd"]
|
||||
coverage-extension: ["none"]
|
||||
exclude:
|
||||
# For now, we do not know how to run workflow on Windows
|
||||
# with imagick PHP extension for PHP 5.3 - 5.6
|
||||
- { php-version: '5.3', os: windows-latest }
|
||||
- { php-version: '5.4', os: windows-latest }
|
||||
- { php-version: '5.5', os: windows-latest }
|
||||
- { php-version: '5.6', os: windows-latest }
|
||||
# Somehow some tests fail under Windows and PHP 7.0,
|
||||
# so we disable that run for now
|
||||
- { php-version: '7.0', os: windows-latest }
|
||||
include:
|
||||
- { php-version: '5.3', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.4', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.5', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.6', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' }
|
||||
- { php-version: 'nightly', experimental: true, os: ubuntu-latest, coverage-extension: 'pcov' }
|
||||
- { php-version: '5.3', os: windows-latest, experimental: false, php-extensions: 'bcmath, gd', coverage-extension: 'none' }
|
||||
- { php-version: '5.4', os: windows-latest, experimental: false, php-extensions: 'bcmath, gd', coverage-extension: 'none' }
|
||||
- { php-version: '5.5', os: windows-latest, experimental: false, php-extensions: 'bcmath, gd', coverage-extension: 'none' }
|
||||
- { php-version: '5.6', os: windows-latest, experimental: false, php-extensions: 'bcmath, gd', coverage-extension: 'none' }
|
||||
# Specify coverage extension for Ubuntu runs
|
||||
- { php-version: '5.3', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.4', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.5', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'xdebug' }
|
||||
- { php-version: '5.6', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'xdebug' }
|
||||
- { php-version: '7.0', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'xdebug' }
|
||||
# pcov is available from PHP 7.1
|
||||
- { php-version: '7.1', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '7.2', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '7.3', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '7.4', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '8.0', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '8.1', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: '8.2', os: ubuntu-latest, experimental: false, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
- { php-version: 'nightly', os: ubuntu-latest, experimental: true, php-extensions: 'bcmath, imagick, gd', coverage-extension: 'pcov' }
|
||||
env:
|
||||
PDFINFO_BINARY: ${{ (matrix.os == 'ubuntu-latest') && '/usr/bin/pdfinfo' || ((matrix.os == 'macos-latest') && '/usr/local/bin/pdfinfo' || 'C:\ProgramData\Chocolatey\bin\pdfinfo.exe') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install pdfinfo
|
||||
run: sudo apt-get install -y poppler-utils
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install pdfinfo, pdftopng or pdftoppm
|
||||
uses: ConorMacBride/install-package@v1
|
||||
with:
|
||||
apt: poppler-utils
|
||||
brew: poppler
|
||||
choco: xpdf-utils
|
||||
- name: Install magick
|
||||
if: runner.os == 'Linux'
|
||||
uses: mfinelli/setup-imagemagick@v2
|
||||
- name: Install magick
|
||||
uses: ConorMacBride/install-package@v1
|
||||
with:
|
||||
brew: imagemagick@6
|
||||
choco: imagemagick
|
||||
- name: Use php ${{ matrix.php-version }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
coverage: ${{ matrix.coverage-extension }}
|
||||
extensions: bcmath, imagick, gd
|
||||
ini-values: display_errors=on, error_reporting=-1
|
||||
extensions: ${{ matrix.php-extensions }}
|
||||
ini-values: display_errors=on, display_startup_errors=on, error_reporting=-1
|
||||
- name: List php modules
|
||||
run: php -m
|
||||
- name: List php modules using "no php ini" mode
|
||||
run: php -m -n
|
||||
- name: Cache module
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.composer/cache/
|
||||
key: composer-cache
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction
|
||||
- name: Run php tests
|
||||
- name: Install test dependencies
|
||||
run: cd ./tests && composer install --no-interaction && cd ../
|
||||
- name: Run shell-based test suite
|
||||
if: runner.os == 'Linux'
|
||||
run: ./tests/launch.sh
|
||||
- name: Send coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
if: matrix.coverage-extension != 'none'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
flags: php-${{ matrix.php-version }}-${{ matrix.os }}
|
||||
name: php-${{ matrix.php-version }}-${{ matrix.os }}
|
||||
- name: Create output folder
|
||||
run: mkdir ./tests/output
|
||||
- name: Run PHP-based test suite
|
||||
run: php ./tests/launch.php --output-dir ./tests/output
|
||||
# The PHP_BINARY environment variable is only available since PHP 5.4
|
||||
env:
|
||||
PHP_BINARY: ${{ (matrix.os == 'ubuntu-latest') && '/usr/bin/php' || ((matrix.os == 'macos-latest') && '/usr/local/bin/php' || 'C:\tools\php\php.exe') }}
|
||||
# For debugging issues
|
||||
- name: Archive test results
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-run-output-${{ matrix.php-version }}-${{ matrix.os }}
|
||||
retention-days: 1
|
||||
path: ./tests/output
|
||||
|
||||
analyse-php:
|
||||
name: Static Analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use php 8.0
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: composer:v2
|
||||
- name: Cache module
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.composer/cache/
|
||||
key: composer-cache
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
*.bak
|
||||
/vendor/
|
||||
/composer.lock
|
||||
/composer.phar
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.000
|
||||
* @group barcode
|
||||
* @group 1d
|
||||
* @group html
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 1D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.000
|
||||
* @group barcode
|
||||
* @group 1d
|
||||
* @group png
|
||||
*/
|
||||
|
||||
// include 1D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.000
|
||||
* @group barcode
|
||||
* @group 1d
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 1D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.000
|
||||
* @group barcode
|
||||
* @group 1d
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 1D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group datamatrix
|
||||
* @group html
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group datamatrix
|
||||
* @group png
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group datamatrix
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group datamatrix
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group pdf417
|
||||
* @group html
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group pdf417
|
||||
* @group png
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group pdf417
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,10 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group pdf417
|
||||
* @group svg
|
||||
* @group comparable
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group qrcode
|
||||
* @group html
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group qrcode
|
||||
* @group png
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group qrcode
|
||||
* @group svg
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -37,6 +37,9 @@
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.009
|
||||
* @group barcode
|
||||
* @group qrcode
|
||||
* @group svg
|
||||
*/
|
||||
|
||||
// include 2D barcode class (search for installation path)
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @abstract TCPDF - Example: Default Header and Footer
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group header
|
||||
* @group footer
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @abstract TCPDF - Example: Removing Header and Footer
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group header
|
||||
* @group footer
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @abstract TCPDF - Example: Custom Header and Footer
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group header
|
||||
* @group footer
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Cell stretching
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Multicell
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: WriteHTML and RTL support
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group html
|
||||
* @group rtl
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,10 @@
|
||||
* @abstract TCPDF - Example: Two independent columns with WriteHTMLCell()
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group column
|
||||
* @group cell
|
||||
* @group html
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Include external UTF-8 text file
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group unicode
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
@ -75,7 +77,7 @@ $pdf->setFont('freeserif', '', 12);
|
||||
// add a page
|
||||
$pdf->AddPage();
|
||||
|
||||
// get esternal file content
|
||||
// get external file content
|
||||
$utf8text = file_get_contents('data/utf8test.txt', false);
|
||||
|
||||
// set color for text
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Test Image
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group image
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Text on multiple columns
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group column
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Colored Table
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group table
|
||||
* @group color
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Graphic Functions
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group drawing
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Graphic Transformations
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group drawing
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Javascript Form and user rights (only works on Adobe Acrobat)
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group javascript
|
||||
* @group form
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
* @abstract TCPDF - Example: Bookmarks (Table of Content)
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group toc
|
||||
* @group bookmark
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Document Encryption / Security
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group security
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Two independent columns with MultiCell
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group column
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: RTL document with Persian language
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-06
|
||||
* @group rtl
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Non unicode with alternative config file
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group unicode
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -23,6 +23,9 @@
|
||||
* @abstract TCPDF - Example: Two columns composed by MultiCell of different heights
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group column
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: WriteHTML text flow.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group html
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: CMYK colors.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group color
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Page Groups.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Object Visibility and Layers
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group drawing
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Object Transparency
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group drawing
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,7 @@
|
||||
* @abstract TCPDF - Example: Text Rendering Modes and Text Clipping
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: 1D Barcodes.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group barcode
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: changing page formats
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Set PDF viewer display preferences.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-06-09
|
||||
* @group viewer
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Colour gradients
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-06-09
|
||||
* @group color
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Pie Chart
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-06-09
|
||||
* @group drawing
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: EPS/AI image
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-06-09
|
||||
* @group image
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Mixed font types
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-06-24
|
||||
* @group font
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Clipping
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Line styles with cells and multicells
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Annotations
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-08-08
|
||||
* @group annotation
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Spot colors.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-09-12
|
||||
* @group color
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: CID-0 CJK unembedded font
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-09-15
|
||||
* @group font
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: HTML justification
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-10-18
|
||||
* @group html
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Booklet mode (double-sided pages)
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-10-28
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Annotation - FileAttachment
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-12-07
|
||||
* @group annotation
|
||||
* @group attachment
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Test Image with alpha channel
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-12-23
|
||||
* @group image
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Disk caching
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-01-02
|
||||
* @group cache
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Move, copy and delete pages
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-01-02
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Bookmarks and Table of Content
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group toc
|
||||
* @group bookmark
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: text Hyphenation
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-02-28
|
||||
* @group text
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Transactions
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-03-19
|
||||
* @group transaction
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: HTML tables and table headers
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-03-20
|
||||
* @group html
|
||||
* @group table
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: WriteHTML with TCPDF callback functions
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group html
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: 2D barcodes.
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group barcode
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Full page background
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-04-16
|
||||
* @group background
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Certification Signature (experimental)
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-05-07
|
||||
* @group security
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Javascript example.
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-09-02
|
||||
* @group javascript
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: XHTML Forms
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-09-07
|
||||
* @group html
|
||||
* @group form
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: XHTML Forms
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-10-21
|
||||
* @group html
|
||||
* @group form
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Crop marks and color registration bars
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-03-26
|
||||
* @group color
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Cell vertical alignments
|
||||
* @author Nicola Asuni
|
||||
* @since 2008-03-04
|
||||
* @group cell
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: SVG Image
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-05-02
|
||||
* @group svg
|
||||
* @group image
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: Table Of Content using HTML templates.
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-05-06
|
||||
* @group toc
|
||||
* @group html
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Advanced page settings.
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-05-17
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: XHTML + CSS
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-05-25
|
||||
* @group html
|
||||
* @group css
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: XObject Template
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-08-25
|
||||
* @group object
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: Text stretching and spacing (tracking)
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-09-29
|
||||
* @group text
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: No-write page regions
|
||||
* @author Nicola Asuni
|
||||
* @since 2010-10-14
|
||||
* @group page
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -22,6 +22,8 @@
|
||||
* @abstract TCPDF - Example: PDF/A-1b mode
|
||||
* @author Nicola Asuni
|
||||
* @since 2011-09-28
|
||||
* @group A-1b
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -14,6 +14,8 @@
|
||||
* @abstract TCPDF - Example: PDF/A-1b mode
|
||||
* @author Nicola Asuni
|
||||
* @since 2021-03-26
|
||||
* @group A-1b
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Load the autoloader, move one folder back from examples
|
||||
|
@ -22,6 +22,9 @@
|
||||
* @abstract TCPDF - Example: HTML tables and table headers
|
||||
* @author Nicola Asuni
|
||||
* @since 2009-03-20
|
||||
* @group html
|
||||
* @group table
|
||||
* @group pdf
|
||||
*/
|
||||
|
||||
// Include the main TCPDF library (search for installation path).
|
||||
|
@ -6,6 +6,7 @@ parameters:
|
||||
- vendor/
|
||||
# remove once https://github.com/phpstan/phpstan/issues/7955 is fixed
|
||||
- fonts/
|
||||
- tests/
|
||||
|
||||
scanFiles:
|
||||
- tcpdf_autoconfig.php
|
||||
|
4
tests/.gitignore
vendored
4
tests/.gitignore
vendored
@ -1 +1,5 @@
|
||||
/composer.lock
|
||||
/composer.phar
|
||||
/coverage.lcov
|
||||
/runs
|
||||
/vendor
|
||||
|
471
tests/compare_runs.php
Normal file
471
tests/compare_runs.php
Normal file
@ -0,0 +1,471 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* This script compares two runs of the test suite.
|
||||
*
|
||||
* The comparison is not bit by bit, as most of the generated
|
||||
* files have some time-induced differences.
|
||||
*
|
||||
* This script will however point out gross discrepancies.
|
||||
*
|
||||
* PDF documents will be compared as PNG images.
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
|
||||
*/
|
||||
|
||||
namespace Tecnickcom\TCPDF\Tests;
|
||||
|
||||
use LocateBinaries\LocateBinaries;
|
||||
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
echo 'Run `composer install` in the tests/ directory first.' . PHP_EOL;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$options = getopt('o:vhr:', array(
|
||||
'group:',
|
||||
'output-dir:',
|
||||
'reference-dir:',
|
||||
'stop-on-defect',
|
||||
'verbose',
|
||||
'help'
|
||||
));
|
||||
|
||||
function printCompareRunsHelp()
|
||||
{
|
||||
echo 'Usage:' . PHP_EOL;
|
||||
echo ' php compare_runs.php [-chv] [-o <path>] -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 <path>, --output-dir=<path>' . 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 <path>, --reference-dir=<path>' . 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=<name>' . 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);
|
36
tests/composer.json
Normal file
36
tests/composer.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
279
tests/launch.php
Normal file
279
tests/launch.php
Normal file
@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Test runner
|
||||
*
|
||||
* Usage: php launch.php --help
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
|
||||
*/
|
||||
|
||||
namespace Tecnickcom\TCPDF\Tests;
|
||||
|
||||
use LocateBinaries\LocateBinaries;
|
||||
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
echo 'Run `composer install` in the tests/ directory first.' . PHP_EOL;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$options = getopt('o:vh', array(
|
||||
'group:',
|
||||
'output-dir:',
|
||||
'stop-on-defect',
|
||||
'verbose',
|
||||
'help'
|
||||
));
|
||||
|
||||
function printLaunchHelp()
|
||||
{
|
||||
echo 'Usage:' . PHP_EOL;
|
||||
echo ' php launch.php [-chv] [-o <path>] [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 <path>, --output-dir=<path>' . 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=<name>' . 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);
|
@ -51,6 +51,13 @@ if [ "$(${PHP_BINARY} -r 'echo PHP_MAJOR_VERSION;')" = "5" ];then
|
||||
|
||||
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
|
||||
|
107
tests/src/ImageMagick.php
Normal file
107
tests/src/ImageMagick.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper class to execute magick via shell
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://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;
|
||||
}
|
||||
}
|
198
tests/src/PdfTools.php
Normal file
198
tests/src/PdfTools.php
Normal file
@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper class to execute PDF-related commands via shell
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://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;
|
||||
}
|
||||
}
|
281
tests/src/PhpExecutor.php
Normal file
281
tests/src/PhpExecutor.php
Normal file
@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper class to execute PHP via shell
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://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);
|
||||
}
|
||||
}
|
255
tests/src/TestExecutor.php
Normal file
255
tests/src/TestExecutor.php
Normal file
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper class to execute TCPDF test
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://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;
|
||||
}
|
||||
}
|
379
tests/src/TestRunner.php
Normal file
379
tests/src/TestRunner.php
Normal file
@ -0,0 +1,379 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Helper class to execute the TCPDF test suite
|
||||
*
|
||||
* @author Philippe Jausions
|
||||
* @license http://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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user