diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67fc091..09e51f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,11 @@ jobs: extensions: iconv, imagick, gd coverage: xdebug + - name: Setup Node + uses: actions/setup-node@v6 + with: + node-version: 24 + - name: Get composer cache directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT @@ -47,9 +52,12 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - - name: Install dependencies + - name: Install PHP dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Install Node dependencies + run: npm install + - name: Test with phpunit run: vendor/bin/phpunit --coverage-clover clover.xml @@ -58,7 +66,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: ./clover.xml - + release: needs: [lint, test] runs-on: ubuntu-latest diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 870931b..f7071a6 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: operating-system: [ubuntu-latest] - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4'] runs-on: ${{ matrix.operating-system }} steps: - uses: actions/checkout@v4 @@ -36,6 +36,11 @@ jobs: extensions: iconv, imagick coverage: xdebug + - name: Setup Node + uses: actions/setup-node@v6 + with: + node-version: 24 + - name: Get composer cache directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT @@ -47,9 +52,12 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - - name: Install dependencies + - name: Install PHP dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Install Node dependencies + run: npm install + - name: Test with phpunit run: vendor/bin/phpunit --coverage-clover clover.xml diff --git a/.gitignore b/.gitignore index 9d5cbb4..3edc4a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /composer.lock /vendor +/node_modules /.phpunit.result.cache /.phpunit.cache diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4bafbf4..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM php:8.1-cli - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get update && apt-get install -y libmagickwand-dev libzip-dev zip --no-install-recommends && rm -rf /var/lib/apt/lists/* -RUN pecl install imagick && docker-php-ext-enable imagick && docker-php-ext-install zip -RUN alias composer='php /usr/bin/composer' - -WORKDIR /app diff --git a/LICENSE b/LICENSE index d45a356..aa22018 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2017, Ben Scholzen 'DASPRiD' +Copyright (c) 2017-present, Ben Scholzen 'DASPRiD' All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index e429889..8291c26 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,8 @@ $renderer = new GDLibRenderer(400); $writer = new Writer($renderer); $writer->writeFile('Hello World!', 'qrcode.png'); ``` + +## Development + +To run unit tests, you need to have [Node.js](https://nodejs.org/en) and the pixelmatch library installed. Running +`npm install` will install this for you. diff --git a/composer.json b/composer.json index d086357..37e8c75 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "require-dev": { "phpunit/phpunit": "^10.5.11 || ^11.0.4", "spatie/phpunit-snapshot-assertions": "^5.1.5", + "spatie/pixelmatch-php": "^1.2.0", "squizlabs/php_codesniffer": "^3.9", "phly/keep-a-changelog": "^2.12" }, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..810fd07 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,34 @@ +{ + "name": "baconqrcode", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "baconqrcode", + "dependencies": { + "pixelmatch": "^7.1.0" + } + }, + "node_modules/pixelmatch": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", + "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1bc4886 --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "baconqrcode", + "private": true, + "dependencies": { + "pixelmatch": "^7.1.0" + } +} diff --git a/test/Integration/GDLibRenderingTest.php b/test/Integration/GDLibRenderingTest.php index 47b1e28..8e78e6d 100644 --- a/test/Integration/GDLibRenderingTest.php +++ b/test/Integration/GDLibRenderingTest.php @@ -5,22 +5,14 @@ namespace BaconQrCodeTest\Integration; use BaconQrCode\Exception\InvalidArgumentException; -use BaconQrCode\Exception\RuntimeException; use BaconQrCode\Renderer\Color\Alpha; use BaconQrCode\Renderer\Color\Rgb; -use BaconQrCode\Renderer\Eye\EyeInterface; -use BaconQrCode\Renderer\Eye\SimpleCircleEye; -use BaconQrCode\Renderer\Eye\SquareEye; use BaconQrCode\Renderer\GDLibRenderer; -use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\Image\GDImageBackEnd; -use BaconQrCode\Renderer\Module\DotsModule; -use BaconQrCode\Renderer\Module\RoundnessModule; use BaconQrCode\Renderer\RendererStyle\EyeFill; use BaconQrCode\Renderer\RendererStyle\Fill; use BaconQrCode\Renderer\RendererStyle\Gradient; use BaconQrCode\Renderer\RendererStyle\GradientType; -use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Writer; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -40,7 +32,7 @@ public function testGenericQrCode(): void $tempName = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer->writeFile('Hello World!', $tempName); - $this->assertMatchesFileSnapshot($tempName); + $this->assertMatchesImageSnapshot($tempName); unlink($tempName); } @@ -64,7 +56,7 @@ public function testDifferentColorsQrCode(): void $tempName = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer->writeFile('Hello World!', $tempName); - $this->assertMatchesFileSnapshot($tempName); + $this->assertMatchesImageSnapshot($tempName); unlink($tempName); } diff --git a/test/Integration/ImagickRenderingTest.php b/test/Integration/ImagickRenderingTest.php index a523839..f51e7eb 100644 --- a/test/Integration/ImagickRenderingTest.php +++ b/test/Integration/ImagickRenderingTest.php @@ -36,7 +36,7 @@ public function testGenericQrCode() : void $tempName = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer->writeFile('Hello World!', $tempName); - $this->assertMatchesFileSnapshot($tempName); + $this->assertMatchesImageSnapshot($tempName); unlink($tempName); } @@ -63,10 +63,11 @@ public function testIssue79() : void $tempName = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer->writeFile('https://apiroad.net/very-long-url', $tempName); - $this->assertMatchesFileSnapshot($tempName); + $this->assertMatchesImageSnapshot($tempName); unlink($tempName); } + #[RequiresPhpExtension('imagick')] public function testIssue105() : void { $squareModule = SquareModule::instance(); @@ -86,7 +87,7 @@ public function testIssue105() : void $tempName1 = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer1->writeFile('rotation without eye color', $tempName1); - $this->assertMatchesFileSnapshot($tempName1); + $this->assertMatchesImageSnapshot($tempName1); unlink($tempName1); $eyeFill = new EyeFill(new Rgb(255, 0, 0), new Rgb(0, 255, 0)); @@ -105,7 +106,7 @@ public function testIssue105() : void $tempName2 = tempnam(sys_get_temp_dir(), 'test') . '.png'; $writer2->writeFile('rotation with eye color', $tempName2); - $this->assertMatchesFileSnapshot($tempName2); + $this->assertMatchesImageSnapshot($tempName2); unlink($tempName2); } } diff --git a/test/Integration/SVGRenderingTest.php b/test/Integration/SVGRenderingTest.php index 2eb71d9..1655950 100644 --- a/test/Integration/SVGRenderingTest.php +++ b/test/Integration/SVGRenderingTest.php @@ -15,10 +15,13 @@ use BaconQrCode\Writer; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; +use Spatie\Snapshots\MatchesSnapshots; #[Group('integration')] final class SVGRenderingTest extends TestCase { + use MatchesSnapshots; + public function testGenericQrCode(): void { $renderer = new ImageRenderer( @@ -26,18 +29,15 @@ public function testGenericQrCode(): void new SvgImageBackEnd() ); $writer = new Writer($renderer); + $svg = $writer->writeString('Hello World!'); - $svgCode = $writer->writeString('Hello World!'); - $expected = file_get_contents(__DIR__.'/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg'); - - $this->assertEquals($expected, $svgCode); + $this->assertMatchesXmlSnapshot($svg); } - // SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients_horizontal - //SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients_vertical public function testQrWithGradientGeneratesDifferentIdsForDifferentGradients() { $types = ['HORIZONTAL', 'VERTICAL']; + foreach ($types as $type) { $gradient = new Gradient( new Rgb(0, 0, 0), @@ -58,13 +58,9 @@ public function testQrWithGradientGeneratesDifferentIdsForDifferentGradients() new SvgImageBackEnd() ); $writer = new Writer($renderer); - $qr = $writer->writeString('Hello World!'); - $expectedFile = __DIR__ . '/__snapshots__/files/'; - $expectedFile .= 'SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__'; - $expectedFile .= strtolower($type) . '.svg'; - $expected = file_get_contents($expectedFile); + $svg = $writer->writeString('Hello World!'); - $this->assertEquals($expected, $qr); + $this->assertMatchesXmlSnapshot($svg); } } } diff --git a/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png b/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png new file mode 100644 index 0000000..c2d6ae6 Binary files /dev/null and b/test/Integration/__snapshots__/GDLibRenderingTest__testDifferentColorsQrCode__1.png differ diff --git a/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png b/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png new file mode 100644 index 0000000..4c1faa8 Binary files /dev/null and b/test/Integration/__snapshots__/GDLibRenderingTest__testGenericQrCode__1.png differ diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testGenericQrCode__1.png similarity index 100% rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png rename to test/Integration/__snapshots__/ImagickRenderingTest__testGenericQrCode__1.png diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__1.png similarity index 100% rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__1.png rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__1.png diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__2.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__2.png similarity index 100% rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue105__2.png rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue105__2.png diff --git a/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png b/test/Integration/__snapshots__/ImagickRenderingTest__testIssue79__1.png similarity index 100% rename from test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png rename to test/Integration/__snapshots__/ImagickRenderingTest__testIssue79__1.png diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml b/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml new file mode 100644 index 0000000..b602bbb --- /dev/null +++ b/test/Integration/__snapshots__/SVGRenderingTest__testGenericQrCode__1.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml new file mode 100644 index 0000000..5ebaedd --- /dev/null +++ b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__1.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml new file mode 100644 index 0000000..466151f --- /dev/null +++ b/test/Integration/__snapshots__/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__2.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg deleted file mode 100644 index 8c8607e..0000000 --- a/test/Integration/__snapshots__/files/SVGRenderingTest__testGenericQrCode__1.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg deleted file mode 100644 index aa79f5d..0000000 --- a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__horizontal.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg b/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg deleted file mode 100644 index 60c25da..0000000 --- a/test/Integration/__snapshots__/files/SVGRenderingTest__testQrWithGradientGeneratesDifferentIdsForDifferentGradients__vertical.svg +++ /dev/null @@ -1,2 +0,0 @@ - -