diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index bece1303..27970385 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -11,9 +11,6 @@ jobs: name: "CS Fixer & PHPStan" runs-on: "ubuntu-20.04" - env: - SYMFONY_PHPUNIT_VERSION: 7.5 - steps: - name: "Checkout" uses: "actions/checkout@v2" @@ -30,14 +27,11 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" - - name: "Install PHPStan" - run: "composer require phpstan/phpstan phpstan/phpstan-phpunit --dev --no-progress --no-suggest" + - name: "Install dev tools" + run: "make install-dev-tools" - name: "Run PHP CS Fixer" - run: "php vendor/bin/php-cs-fixer fix --verbose --dry-run --format=checkstyle | cs2pr" - - - name: "Install PHPUnit for PHPStan" - run: "php vendor/bin/simple-phpunit install" + run: "make run-php-cs-fixer ARGS="--verbose --dry-run --format=checkstyle" | cs2pr" - name: "Run PHPStan" - run: "php vendor/bin/phpstan analyse --no-progress --error-format=checkstyle | cs2pr" + run: "make run-phpstan ARGS="--no-progress --error-format=checkstyle" | cs2pr" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index bf99517b..d22b4879 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -14,15 +14,13 @@ jobs: name: "PHPUnit (PHP ${{ matrix.php }})" runs-on: "ubuntu-20.04" - env: - SYMFONY_PHPUNIT_VERSION: 7.5 - strategy: matrix: php: - "7.2" - "7.3" - "7.4" + - "8.0" steps: - name: "Checkout" @@ -40,11 +38,11 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" - - name: "Remove PHP-CS-Fixer" - run: "composer remove friendsofphp/php-cs-fixer --dev --no-progress --no-update" + - name: "Install dev tools" + run: "make install-dev-tools" - name: "Run PHPUnit" - run: "php vendor/bin/simple-phpunit -v" + run: "make run-phpunit" phpunit-lower-php: name: "PHPUnit (PHP ${{ matrix.php }})" @@ -53,8 +51,6 @@ jobs: strategy: matrix: php: - - "5.6" - - "7.0" - "7.1" steps: @@ -73,19 +69,16 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" - - name: "Remove PHP-CS-Fixer" - run: "composer remove friendsofphp/php-cs-fixer --dev --no-progress --no-update" + - name: "Install dev tools" + run: "make install-dev-tools" - name: "Run PHPUnit" - run: "php vendor/bin/simple-phpunit -v" + run: "make run-phpunit" phpunit-coverage: name: "PHPUnit coverage (PHP ${{ matrix.php }})" runs-on: "ubuntu-20.04" - env: - SYMFONY_PHPUNIT_VERSION: 7.5 - strategy: matrix: php: @@ -107,16 +100,16 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" - - name: "Run PHPUnit (with coverage)" - run: "php vendor/bin/simple-phpunit -v --coverage-clover coverage/clover.xml" + - name: "Install dev tools" + run: "make install-dev-tools" + + - name: "Run PHPUnit" + run: make run-phpunit ARGS="-v --coverage-clover coverage/clover.xml" phpunit-composerv2: name: "PHPUnit Composer v2 (PHP ${{ matrix.php }})" runs-on: "ubuntu-20.04" - env: - SYMFONY_PHPUNIT_VERSION: 7.5 - strategy: matrix: php: @@ -138,8 +131,11 @@ jobs: - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v1" + - name: "Install dev tools" + run: "make install-dev-tools" + - name: "Run PHPUnit" - run: "php vendor/bin/simple-phpunit -v" + run: "make run-phpunit" alt-autoload: name: "Tests alternative autoloader (PHP ${{ matrix.php }})" @@ -175,10 +171,6 @@ jobs: name: "PHPUnit lowest deps (PHP ${{ matrix.php }})" runs-on: "ubuntu-20.04" - env: - SYMFONY_PHPUNIT_VERSION: 7.5 - SYMFONY_DEPRECATIONS_HELPER: disabled=1 - strategy: matrix: php: @@ -202,5 +194,8 @@ jobs: with: dependency-versions: "lowest" + - name: "Install dev tools" + run: "make install-dev-tools" + - name: "Run PHPUnit" - run: "php vendor/bin/simple-phpunit -v" + run: "make run-phpunit" diff --git a/.gitignore b/.gitignore index c685f194..9caaf9fc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,9 @@ /vendor/* /xdebug/* /composer.phar +/dev-tools/vendor /composer debug* composer.lock /.php_cs.cache +/.phpunit.result.cache diff --git a/.scrutinizer.yml b/.scrutinizer.yml index cd41105c..382722ce 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -5,7 +5,7 @@ build: override: - php-scrutinizer-run - - command: SYMFONY_PHPUNIT_VERSION=7.5 php vendor/bin/simple-phpunit --coverage-clover coverage/clover.xml + command: make install-dev-tools && make run-phpunit ARGS="--coverage-clover coverage/clover.xml" coverage: file: coverage/clover.xml format: clover diff --git a/DEVELOPER.md b/DEVELOPER.md new file mode 100644 index 00000000..d33bb60b --- /dev/null +++ b/DEVELOPER.md @@ -0,0 +1,40 @@ +# Developers + +## .editorconfig + +Please make sure your editor uses our `.editorconfig` file. It contains rules about our coding styles. + +## Development Tools and Tests + +Our test related files are located in `tests` folder. +Tests are written using PHPUnit. + +To install (and update) development tools like PHPUnit or PHP-CS-Fixer run: + +> make install-dev-tools + +Development tools are getting installed in `dev-tools/vendor`. +Please check `dev-tools/composer.json` for more information about versions etc. +To run a tool manually you use `dev-tools/vendor/bin`, for instance: + +> dev-tools/vendor/bin/php-cs-fixer fix --verbose --dry-run + +Below are a few shortcuts to improve your developer experience. + +### PHPUnit + +To run all tests run: + +> make run-phpunit + +### PHP-CS-Fixer + +To check coding styles run: + +> make run-php-cs-fixer + +### PHPStan + +To run a static code analysis use: + +> make run-phpstan diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..06d1eac2 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +install-dev-tools: + composer update --working-dir=dev-tools + +run-php-cs-fixer: + dev-tools/vendor/bin/php-cs-fixer fix $(ARGS) + +run-phpstan: + dev-tools/vendor/bin/phpstan/phpstan/phpstan analyze $(ARGS) + +run-phpunit: + dev-tools/vendor/bin/phpunit $(ARGS) diff --git a/README.md b/README.md index b9162bcf..1716af72 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ As a result, users must expect BC breaks when using the master version. Original PDF References files can be downloaded from this url: http://www.adobe.com/devnet/pdf/pdf_reference_archive.html +**For developers**: Please read [DEVELOPER.md](DEVELOPER.md) for more information about local development of the PDFParser library. + ## Installation ### Using Composer diff --git a/composer.json b/composer.json index 0af9754c..7a39e8a7 100644 --- a/composer.json +++ b/composer.json @@ -15,14 +15,10 @@ }, "homepage": "https://www.pdfparser.org", "require": { - "php": ">=5.6", + "php": ">=7.1", "symfony/polyfill-mbstring": "^1.18", "ext-zlib": "*" }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "symfony/phpunit-bridge": "^5.2" - }, "autoload": { "psr-0": { "Smalot\\PdfParser\\": "src/" diff --git a/dev-tools/composer.json b/dev-tools/composer.json new file mode 100644 index 00000000..7d9a5fed --- /dev/null +++ b/dev-tools/composer.json @@ -0,0 +1,9 @@ +{ + "description": "This file provides development-only dependencies.", + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.81", + "phpstan/phpstan-phpunit": "^0.12.18", + "phpunit/phpunit": ">=7.5" + } +} diff --git a/phpstan.neon b/phpstan.neon index 8ef267e2..8dd084ae 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,6 @@ includes: - - vendor/phpstan/phpstan-phpunit/extension.neon - - vendor/phpstan/phpstan-phpunit/rules.neon + - dev-tools/vendor/phpstan/phpstan-phpunit/extension.neon + - dev-tools/vendor/phpstan/phpstan-phpunit/rules.neon parameters: level: 3 @@ -9,4 +9,4 @@ parameters: - tests bootstrapFiles: - - vendor/bin/.phpunit/phpunit-7.5-0/vendor/autoload.php + - vendor/autoload.php diff --git a/src/Smalot/PdfParser/Element/ElementXRef.php b/src/Smalot/PdfParser/Element/ElementXRef.php index b53ddf40..37b80716 100644 --- a/src/Smalot/PdfParser/Element/ElementXRef.php +++ b/src/Smalot/PdfParser/Element/ElementXRef.php @@ -56,6 +56,24 @@ public function getObject() */ public function equals($value) { + /** + * In case $value is a number and $this->value is a string like 5_0 + * + * Without this if-clause code like: + * + * $element = new ElementXRef('5_0'); + * $this->assertTrue($element->equals(5)); + * + * would fail (= 5_0 and 5 are not equal in PHP 8.0+). + */ + if ( + true === is_numeric($value) + && true === \is_string($this->getContent()) + && 1 === preg_match('/[0-9]+\_[0-9]+/', $this->getContent(), $matches) + ) { + return (float) ($this->getContent()) == $value; + } + $id = ($value instanceof self) ? $value->getId() : $value; return $this->getId() == $id; diff --git a/tests/Integration/PageTest.php b/tests/Integration/PageTest.php index 93525954..ed9365ee 100644 --- a/tests/Integration/PageTest.php +++ b/tests/Integration/PageTest.php @@ -131,14 +131,14 @@ public function testGetText() $text = $page->getText(); $this->assertTrue(150 < \strlen($text)); - $this->assertContains('Document title', $text); - $this->assertContains('Lorem ipsum', $text); - - $this->assertContains('Calibri', $text); - $this->assertContains('Arial', $text); - $this->assertContains('Times', $text); - $this->assertContains('Courier New', $text); - $this->assertContains('Verdana', $text); + $this->assertStringContainsString('Document title', $text); + $this->assertStringContainsString('Lorem ipsum', $text); + + $this->assertStringContainsString('Calibri', $text); + $this->assertStringContainsString('Arial', $text); + $this->assertStringContainsString('Times', $text); + $this->assertStringContainsString('Courier New', $text); + $this->assertStringContainsString('Verdana', $text); } public function testExtractRawData() @@ -168,8 +168,8 @@ public function testExtractRawData() $this->assertArrayHasKey('o', $tmItem); $this->assertArrayHasKey('c', $tmItem); - $this->assertContains('Tm', $tmItem['o']); - $this->assertContains('0.999429 0 0 1 201.96 720.68', $tmItem['c']); + $this->assertStringContainsString('Tm', $tmItem['o']); + $this->assertStringContainsString('0.999429 0 0 1 201.96 720.68', $tmItem['c']); } public function testExtractDecodedRawData() @@ -189,8 +189,8 @@ public function testExtractDecodedRawData() $this->assertArrayHasKey('o', $tmItem); $this->assertArrayHasKey('c', $tmItem); - $this->assertContains('Tm', $tmItem['o']); - $this->assertContains('0.999429 0 0 1 201.96 720.68', $tmItem['c']); + $this->assertStringContainsString('Tm', $tmItem['o']); + $this->assertStringContainsString('0.999429 0 0 1 201.96 720.68', $tmItem['c']); $this->assertCount(3, $tmItem); $this->assertArrayHasKey('t', $tmItem); @@ -198,13 +198,13 @@ public function testExtractDecodedRawData() $this->assertArrayHasKey('c', $tmItem); $tjItem = $extractedDecodedRawData[3]; - $this->assertContains('TJ', $tjItem['o']); - $this->assertContains('(', $tjItem['c'][0]['t']); - $this->assertContains('D', $tjItem['c'][0]['c']); - $this->assertContains('n', $tjItem['c'][1]['t']); - $this->assertContains('0.325008', $tjItem['c'][1]['c']); - $this->assertContains('(', $tjItem['c'][2]['t']); - $this->assertContains('o', $tjItem['c'][2]['c']); + $this->assertStringContainsString('TJ', $tjItem['o']); + $this->assertStringContainsString('(', $tjItem['c'][0]['t']); + $this->assertStringContainsString('D', $tjItem['c'][0]['c']); + $this->assertStringContainsString('n', $tjItem['c'][1]['t']); + $this->assertStringContainsString('0.325008', $tjItem['c'][1]['c']); + $this->assertStringContainsString('(', $tjItem['c'][2]['t']); + $this->assertStringContainsString('o', $tjItem['c'][2]['c']); } public function testExtractRawDataWithCorruptedPdf() @@ -235,8 +235,8 @@ public function testGetDataCommands() $this->assertArrayHasKey('o', $tmItem); $this->assertArrayHasKey('c', $tmItem); - $this->assertContains('Tm', $tmItem['o']); - $this->assertContains('0.999429 0 0 1 201.96 720.68', $tmItem['c']); + $this->assertStringContainsString('Tm', $tmItem['o']); + $this->assertStringContainsString('0.999429 0 0 1 201.96 720.68', $tmItem['c']); $tjItem = $dataCommands[2]; $this->assertCount(3, $tjItem); @@ -244,13 +244,13 @@ public function testGetDataCommands() $this->assertArrayHasKey('o', $tjItem); $this->assertArrayHasKey('c', $tjItem); - $this->assertContains('TJ', $tjItem['o']); - $this->assertContains('(', $tjItem['c'][0]['t']); - $this->assertContains('D', $tjItem['c'][0]['c']); - $this->assertContains('n', $tjItem['c'][1]['t']); - $this->assertContains('0.325008', $tjItem['c'][1]['c']); - $this->assertContains('(', $tjItem['c'][2]['t']); - $this->assertContains('o', $tjItem['c'][2]['c']); + $this->assertStringContainsString('TJ', $tjItem['o']); + $this->assertStringContainsString('(', $tjItem['c'][0]['t']); + $this->assertStringContainsString('D', $tjItem['c'][0]['c']); + $this->assertStringContainsString('n', $tjItem['c'][1]['t']); + $this->assertStringContainsString('0.325008', $tjItem['c'][1]['c']); + $this->assertStringContainsString('(', $tjItem['c'][2]['t']); + $this->assertStringContainsString('o', $tjItem['c'][2]['c']); } public function testGetDataTm() @@ -280,7 +280,7 @@ public function testGetDataTm() $item[0] ); - $this->assertContains('Document title', $item[1]); + $this->assertStringContainsString('Document title', $item[1]); $item = $dataTm[2]; $this->assertEquals( [ @@ -294,7 +294,7 @@ public function testGetDataTm() $item[0] ); - $this->assertContains('Calibri : Lorem ipsum dolor sit amet, consectetur a', $item[1]); + $this->assertStringContainsString('Calibri : Lorem ipsum dolor sit amet, consectetur a', $item[1]); $item = $dataTm[80]; $this->assertEquals( @@ -308,7 +308,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('nenatis.', $item[1]); + $this->assertStringContainsString('nenatis.', $item[1]); // ------------------------------------------------------ // Document is a form @@ -332,7 +332,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('MyName MyLastName', $item[1]); + $this->assertStringContainsString('MyName MyLastName', $item[1]); $item = $dataTm[6]; $this->assertEquals( @@ -346,7 +346,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('1/1/2020', $item[1]); + $this->assertStringContainsString('1/1/2020', $item[1]); $item = $dataTm[8]; $this->assertEquals( @@ -360,7 +360,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('Purchase 1', $item[1]); + $this->assertStringContainsString('Purchase 1', $item[1]); // ------------------------------------------------------ // Document is another form of the same type @@ -385,7 +385,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains("Other'sName Other'sLastName", $item[1]); + $this->assertStringContainsString("Other'sName Other'sLastName", $item[1]); $item = $dataTm[6]; $this->assertEquals( @@ -399,7 +399,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('2/2/2020', $item[1]); + $this->assertStringContainsString('2/2/2020', $item[1]); $item = $dataTm[8]; $this->assertEquals( @@ -413,7 +413,7 @@ public function testGetDataTm() ], $item[0] ); - $this->assertContains('Purchase 2', $item[1]); + $this->assertStringContainsString('Purchase 2', $item[1]); } /** @@ -495,7 +495,7 @@ public function testGetTextXY() ], $result[0][0] ); - $this->assertContains('Document title', $result[0][1]); + $this->assertStringContainsString('Document title', $result[0][1]); $result = $page->getTextXY(201, 720); $this->assertCount(0, $result); @@ -514,7 +514,7 @@ public function testGetTextXY() ], $result[0][0] ); - $this->assertContains('Document title', $result[0][1]); + $this->assertStringContainsString('Document title', $result[0][1]); // ------------------------------------------------------ // Document is a form @@ -536,13 +536,13 @@ public function testGetTextXY() ], $result[0][0] ); - $this->assertContains('MyName MyLastName', $result[0][1]); + $this->assertStringContainsString('MyName MyLastName', $result[0][1]); $result = $page->getTextXY(681, 877, 1, 1); - $this->assertContains('1/1/2020', $result[0][1]); + $this->assertStringContainsString('1/1/2020', $result[0][1]); $result = $page->getTextXY(174, 827, 1, 1); - $this->assertContains('Purchase 1', $result[0][1]); + $this->assertStringContainsString('Purchase 1', $result[0][1]); // ------------------------------------------------------ // Document is another form of the same type @@ -562,12 +562,12 @@ public function testGetTextXY() ], $result[0][0] ); - $this->assertContains("Other'sName Other'sLastName", $result[0][1]); + $this->assertStringContainsString("Other'sName Other'sLastName", $result[0][1]); $result = $page->getTextXY(681, 877, 1, 1); - $this->assertContains('2/2/2020', $result[0][1]); + $this->assertStringContainsString('2/2/2020', $result[0][1]); $result = $page->getTextXY(174, 827, 1, 1); - $this->assertContains('Purchase 2', $result[0][1]); + $this->assertStringContainsString('Purchase 2', $result[0][1]); } } diff --git a/tests/Integration/ParserTest.php b/tests/Integration/ParserTest.php index dee42d27..dc7b62d7 100644 --- a/tests/Integration/ParserTest.php +++ b/tests/Integration/ParserTest.php @@ -41,7 +41,7 @@ class ParserTest extends TestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Integration/RawData/FilterHelperTest.php b/tests/Integration/RawData/FilterHelperTest.php index 708e5601..f86c7af4 100644 --- a/tests/Integration/RawData/FilterHelperTest.php +++ b/tests/Integration/RawData/FilterHelperTest.php @@ -38,7 +38,7 @@ class FilterHelperTest extends TestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Integration/RawData/RawDataParserTest.php b/tests/Integration/RawData/RawDataParserTest.php index de2c5af0..99dee847 100644 --- a/tests/Integration/RawData/RawDataParserTest.php +++ b/tests/Integration/RawData/RawDataParserTest.php @@ -48,7 +48,7 @@ public function exposeGetRawObject($pdfData, $offset = 0) class RawDataParserTest extends TestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/TestCase.php b/tests/TestCase.php index 2296547d..a4bdca2e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -46,7 +46,7 @@ abstract class TestCase extends PHPTestCase protected $rootDir; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index a845e56b..bd3a5a55 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -34,7 +34,7 @@ class ConfigTest extends TestCase { - protected function setUp() + protected function setUp(): void { parent::setUp();